Import glpk-4.45
authorAlpar Juttner <alpar@cs.elte.hu>
Mon, 06 Dec 2010 13:09:21 +0100
changeset 1c445c931472f
parent 0 d59bea55db9b
child 2 4c8956a7bdf4
Import glpk-4.45

- Generated files and doc/notes are removed
AUTHORS
COPYING
ChangeLog
INSTALL
Makefile.am
Makefile_MMIX
NEWS
README
THANKS
configure.ac
doc/glpk.tex
doc/glpk01.tex
doc/glpk02.tex
doc/glpk03.tex
doc/glpk04.tex
doc/glpk05.tex
doc/glpk06.tex
doc/glpk07.tex
doc/glpk08.tex
doc/glpk09.tex
doc/glpk10.tex
doc/glpk11.tex
doc/glpk12.tex
doc/glpk_faq.txt
doc/gmpl.tex
doc/graphs.tex
doc/miplib2.txt
doc/miplib3.txt
doc/netlib.txt
examples/INDEX
examples/Makefile.am
examples/assign.mod
examples/bpp.mod
examples/cal.mod
examples/cf12a.mod
examples/cf12b.mod
examples/cflsq.mod
examples/color.mod
examples/cplex/README
examples/cplex/concorde.txt
examples/cplex/cplex.c
examples/cplex/cplex.h
examples/cpp.mod
examples/crypto.mod
examples/csv/distances.csv
examples/csv/markets.csv
examples/csv/parameters.csv
examples/csv/plants.csv
examples/csv/transp_csv.mod
examples/dbf/ForestMgt_Model_I_GIS_dbf.mod
examples/dbf/Forest_Cost.dbf
examples/dbf/NetRev_Table.dbf
examples/dbf/README
examples/dbf/TCost_Table.dbf
examples/dbf/Yield_Table_Vol.dbf
examples/dbf/cultural_pres.dbf
examples/dbf/mgt_year.dbf
examples/dbf/stands.dbf
examples/dbf/standtype.dbf
examples/dea.mod
examples/diet.mod
examples/dist.mod
examples/dragon.dat
examples/egypt.mod
examples/fctp.mod
examples/food.mod
examples/food2.mod
examples/gap.mod
examples/glpsol.c
examples/graph.mod
examples/hashi.mod
examples/huge.mod
examples/iptsamp.c
examples/jssp.mod
examples/magic.mod
examples/maxcut.mod
examples/maxflow.mod
examples/mfasp.mod
examples/mfvsp.mod
examples/min01ks.mod
examples/misp.mod
examples/money.mod
examples/mplsamp1.c
examples/mplsamp2.c
examples/murtagh.mps
examples/mvcp.mod
examples/netgen.c
examples/numbrix.mod
examples/pbn.mod
examples/plan.lp
examples/plan.mod
examples/plan.mps
examples/prod.mod
examples/qfit.mod
examples/queens.mod
examples/samp1.mps
examples/samp2.mps
examples/sample.asn
examples/sample.c
examples/sample.clq
examples/sample.col
examples/sample.max
examples/sample.min
examples/sat.mod
examples/shiftcover.mod
examples/shikaku.mod
examples/sorting.mod
examples/spp.mod
examples/spxsamp1.c
examples/spxsamp2.c
examples/sql/README
examples/sql/mysql_setup.sh
examples/sql/sudoku.sql
examples/sql/sudoku_mysql.mod
examples/sql/sudoku_odbc.mod
examples/sql/transp.sql
examples/sql/transp_mysql.mod
examples/sql/transp_odbc.mod
examples/stigler.mod
examples/sudoku.dat
examples/sudoku.mod
examples/t1.cs
examples/tas.mod
examples/todd.mod
examples/train.mod
examples/transp.mod
examples/trick.mod
examples/tsp.mod
examples/xyacfs.mod
examples/yacfs.mod
examples/zebra.mod
include/Makefile.am
include/glpk.h
src/Makefile.am
src/amd/COPYING
src/amd/README
src/amd/amd.h
src/amd/amd_1.c
src/amd/amd_2.c
src/amd/amd_aat.c
src/amd/amd_control.c
src/amd/amd_defaults.c
src/amd/amd_dump.c
src/amd/amd_info.c
src/amd/amd_internal.h
src/amd/amd_order.c
src/amd/amd_post_tree.c
src/amd/amd_postorder.c
src/amd/amd_preprocess.c
src/amd/amd_valid.c
src/colamd/COPYING
src/colamd/README
src/colamd/colamd.c
src/colamd/colamd.h
src/glpapi.h
src/glpapi01.c
src/glpapi02.c
src/glpapi03.c
src/glpapi04.c
src/glpapi05.c
src/glpapi06.c
src/glpapi07.c
src/glpapi08.c
src/glpapi09.c
src/glpapi10.c
src/glpapi11.c
src/glpapi12.c
src/glpapi13.c
src/glpapi14.c
src/glpapi15.c
src/glpapi16.c
src/glpapi17.c
src/glpapi18.c
src/glpapi19.c
src/glpavl.c
src/glpavl.h
src/glpbfd.c
src/glpbfd.h
src/glpbfx.c
src/glpbfx.h
src/glpcpx.c
src/glpdmp.c
src/glpdmp.h
src/glpdmx.c
src/glpenv.h
src/glpenv01.c
src/glpenv02.c
src/glpenv03.c
src/glpenv04.c
src/glpenv05.c
src/glpenv06.c
src/glpenv07.c
src/glpenv08.c
src/glpfhv.c
src/glpfhv.h
src/glpgmp.c
src/glpgmp.h
src/glphbm.c
src/glphbm.h
src/glpini01.c
src/glpini02.c
src/glpios.h
src/glpios01.c
src/glpios02.c
src/glpios03.c
src/glpios04.c
src/glpios05.c
src/glpios06.c
src/glpios07.c
src/glpios08.c
src/glpios09.c
src/glpios10.c
src/glpios11.c
src/glpios12.c
src/glpipm.c
src/glpipm.h
src/glplib.h
src/glplib01.c
src/glplib02.c
src/glplib03.c
src/glplpf.c
src/glplpf.h
src/glplpx01.c
src/glplpx02.c
src/glplpx03.c
src/glpluf.c
src/glpluf.h
src/glplux.c
src/glplux.h
src/glpmat.c
src/glpmat.h
src/glpmpl.h
src/glpmpl01.c
src/glpmpl02.c
src/glpmpl03.c
src/glpmpl04.c
src/glpmpl05.c
src/glpmpl06.c
src/glpmps.c
src/glpnet.h
src/glpnet01.c
src/glpnet02.c
src/glpnet03.c
src/glpnet04.c
src/glpnet05.c
src/glpnet06.c
src/glpnet07.c
src/glpnet08.c
src/glpnet09.c
src/glpnpp.h
src/glpnpp01.c
src/glpnpp02.c
src/glpnpp03.c
src/glpnpp04.c
src/glpnpp05.c
src/glpqmd.c
src/glpqmd.h
src/glprgr.c
src/glprgr.h
src/glprng.h
src/glprng01.c
src/glprng02.c
src/glpscf.c
src/glpscf.h
src/glpscl.c
src/glpsdf.c
src/glpspm.c
src/glpspm.h
src/glpspx.h
src/glpspx01.c
src/glpspx02.c
src/glpsql.c
src/glpsql.h
src/glpssx.h
src/glpssx01.c
src/glpssx02.c
src/glpstd.h
src/glptsp.c
src/glptsp.h
w32/Build_GLPK_with_VC10.bat
w32/Build_GLPK_with_VC10_DLL.bat
w32/Build_GLPK_with_VC9.bat
w32/Build_GLPK_with_VC9_DLL.bat
w32/Makefile_VC
w32/Makefile_VC_DLL
w32/config_VC
w32/glpk_4_45.def
w32/readme.txt
w64/Build_GLPK_with_VC10.bat
w64/Build_GLPK_with_VC10_DLL.bat
w64/Build_GLPK_with_VC9.bat
w64/Build_GLPK_with_VC9_DLL.bat
w64/config_VC
w64/glpk_4_45.def
w64/makefile_VC
w64/makefile_VC_DLL
w64/readme.txt
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/AUTHORS	Mon Dec 06 13:09:21 2010 +0100
     1.3 @@ -0,0 +1,33 @@
     1.4 +The GLPK package was developed and programmed by Andrew Makhorin,
     1.5 +Department for Applied Informatics, Moscow Aviation Institute, Moscow,
     1.6 +Russia.
     1.7 +
     1.8 +E-mail:         <mao@gnu.org>
     1.9 +
    1.10 +Paper mail:     125871, Russia, Moscow, Volokolamskoye sh., 4,
    1.11 +                Moscow Aviation Institute, Andrew O. Makhorin
    1.12 +
    1.13 +-----BEGIN PGP PUBLIC KEY BLOCK-----
    1.14 +Version: GnuPG v1.2.2 (MingW32)
    1.15 +
    1.16 +mQGiBD8UdT8RBAC6yWYxoa1b7U973J0jBuQpgZnhXlGJJpMZgAW9efDBD17vhkJm
    1.17 +hPVOQBKRUeOOLcW3/a7NMoNLMdmF1Rgz1FPVy3RgBDsYj4Sp4RBCsX/o0xXh+jxe
    1.18 +gncr4bdN0Ruk03pezVtLi9oYygdxfI51SsjZ2vwYP6BhMwv+xrIgcnc4qwCgoCit
    1.19 +26mTd0FoGOmsQuipo6X5LaUD/1l7NqFIjiGdWthyG3TqsiK5Ew7xF3fLEABXKPjb
    1.20 +PMRTMucX8XXHmW8RUD1vP1uGDnEn6s+fjc3/RtaqKjqGMdLt4XgHQkImaVguNpSS
    1.21 +IxN3LaK600BgAbwSd1bomRqWNlczAM7469VvGG9ASpCBveUUrqwerHZcUbvngL62
    1.22 +pIcqA/41dO0xYrOTqMRhuguYMgHL2xbwB2Aj2TqRwBm697DIS25B9nE+8UsbjGRx
    1.23 +q3EmeuHeZ5kN5RbESXkGUB8whIcYxvH16HRNmM1ZjmFoBVL2Z6S2gpa2ZUqsq7BZ
    1.24 +s+hriElm3dfOQCt79/o852uKWu5bSjw2yiemVA2T8tG4OoN6DrQjQW5kcmV3IE1h
    1.25 +a2hvcmluIDxtYW9AbWFpMi5yY25ldC5ydT6IWwQTEQIAGwUCPxR1PwYLCQgHAwID
    1.26 +FQIDAxYCAQIeAQIXgAAKCRDRe/IwWYHoGKpHAJ44MmzWKr8OiTc0Bb6/RD56aekp
    1.27 +3wCdGznQMCfWFkehQPbeNaB5yFIs+8a5AQ0EPxR1UBAEAO3U3H5M0iYv06C4kKty
    1.28 +6ReWyYH4CzMAfp2lPVUKzRSjPtoAJ6SkrBSKMT+U+DahxZ4K4HbinvHq3uvlwWax
    1.29 +xw0wKxJl4oY6EGE1Jqn3B//Ak47RaNMnrs9V739WT1YNRpQvh4wOCeMekBzksf43
    1.30 +hm4dSV4PMQkLmrEeG2+BYaZnAAMFA/4tVHhjGRkxzcTcfHCB+Yo3PXeIQMuIs00c
    1.31 +VKCrNReLni/3BWZC0w9tFzZSdz+URXefPWDGuAC16vLCVOD06NcIQGutPe189dUn
    1.32 +Kf9Bl6qc9DyWsxSTdF/PbLqcLfEe9g7fHhIwdY+w/hSq2n3NEURMzHiMT1U3CvHd
    1.33 +As5IzV/yD4hGBBgRAgAGBQI/FHVQAAoJENF78jBZgegYRZEAmwReJkMSrbs0EQs2
    1.34 +wjyTCMd5KDh3AKCR2/RvVad9RT3ShYnUiPPYTL2/Nw==
    1.35 +=OfLQ
    1.36 +-----END PGP PUBLIC KEY BLOCK-----
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/COPYING	Mon Dec 06 13:09:21 2010 +0100
     2.3 @@ -0,0 +1,676 @@
     2.4 +
     2.5 +                    GNU GENERAL PUBLIC LICENSE
     2.6 +                       Version 3, 29 June 2007
     2.7 +
     2.8 + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
     2.9 + Everyone is permitted to copy and distribute verbatim copies
    2.10 + of this license document, but changing it is not allowed.
    2.11 +
    2.12 +                            Preamble
    2.13 +
    2.14 +  The GNU General Public License is a free, copyleft license for
    2.15 +software and other kinds of works.
    2.16 +
    2.17 +  The licenses for most software and other practical works are designed
    2.18 +to take away your freedom to share and change the works.  By contrast,
    2.19 +the GNU General Public License is intended to guarantee your freedom to
    2.20 +share and change all versions of a program--to make sure it remains free
    2.21 +software for all its users.  We, the Free Software Foundation, use the
    2.22 +GNU General Public License for most of our software; it applies also to
    2.23 +any other work released this way by its authors.  You can apply it to
    2.24 +your programs, too.
    2.25 +
    2.26 +  When we speak of free software, we are referring to freedom, not
    2.27 +price.  Our General Public Licenses are designed to make sure that you
    2.28 +have the freedom to distribute copies of free software (and charge for
    2.29 +them if you wish), that you receive source code or can get it if you
    2.30 +want it, that you can change the software or use pieces of it in new
    2.31 +free programs, and that you know you can do these things.
    2.32 +
    2.33 +  To protect your rights, we need to prevent others from denying you
    2.34 +these rights or asking you to surrender the rights.  Therefore, you have
    2.35 +certain responsibilities if you distribute copies of the software, or if
    2.36 +you modify it: responsibilities to respect the freedom of others.
    2.37 +
    2.38 +  For example, if you distribute copies of such a program, whether
    2.39 +gratis or for a fee, you must pass on to the recipients the same
    2.40 +freedoms that you received.  You must make sure that they, too, receive
    2.41 +or can get the source code.  And you must show them these terms so they
    2.42 +know their rights.
    2.43 +
    2.44 +  Developers that use the GNU GPL protect your rights with two steps:
    2.45 +(1) assert copyright on the software, and (2) offer you this License
    2.46 +giving you legal permission to copy, distribute and/or modify it.
    2.47 +
    2.48 +  For the developers' and authors' protection, the GPL clearly explains
    2.49 +that there is no warranty for this free software.  For both users' and
    2.50 +authors' sake, the GPL requires that modified versions be marked as
    2.51 +changed, so that their problems will not be attributed erroneously to
    2.52 +authors of previous versions.
    2.53 +
    2.54 +  Some devices are designed to deny users access to install or run
    2.55 +modified versions of the software inside them, although the manufacturer
    2.56 +can do so.  This is fundamentally incompatible with the aim of
    2.57 +protecting users' freedom to change the software.  The systematic
    2.58 +pattern of such abuse occurs in the area of products for individuals to
    2.59 +use, which is precisely where it is most unacceptable.  Therefore, we
    2.60 +have designed this version of the GPL to prohibit the practice for those
    2.61 +products.  If such problems arise substantially in other domains, we
    2.62 +stand ready to extend this provision to those domains in future versions
    2.63 +of the GPL, as needed to protect the freedom of users.
    2.64 +
    2.65 +  Finally, every program is threatened constantly by software patents.
    2.66 +States should not allow patents to restrict development and use of
    2.67 +software on general-purpose computers, but in those that do, we wish to
    2.68 +avoid the special danger that patents applied to a free program could
    2.69 +make it effectively proprietary.  To prevent this, the GPL assures that
    2.70 +patents cannot be used to render the program non-free.
    2.71 +
    2.72 +  The precise terms and conditions for copying, distribution and
    2.73 +modification follow.
    2.74 +
    2.75 +                       TERMS AND CONDITIONS
    2.76 +
    2.77 +  0. Definitions.
    2.78 +
    2.79 +  "This License" refers to version 3 of the GNU General Public License.
    2.80 +
    2.81 +  "Copyright" also means copyright-like laws that apply to other kinds of
    2.82 +works, such as semiconductor masks.
    2.83 +
    2.84 +  "The Program" refers to any copyrightable work licensed under this
    2.85 +License.  Each licensee is addressed as "you".  "Licensees" and
    2.86 +"recipients" may be individuals or organizations.
    2.87 +
    2.88 +  To "modify" a work means to copy from or adapt all or part of the work
    2.89 +in a fashion requiring copyright permission, other than the making of an
    2.90 +exact copy.  The resulting work is called a "modified version" of the
    2.91 +earlier work or a work "based on" the earlier work.
    2.92 +
    2.93 +  A "covered work" means either the unmodified Program or a work based
    2.94 +on the Program.
    2.95 +
    2.96 +  To "propagate" a work means to do anything with it that, without
    2.97 +permission, would make you directly or secondarily liable for
    2.98 +infringement under applicable copyright law, except executing it on a
    2.99 +computer or modifying a private copy.  Propagation includes copying,
   2.100 +distribution (with or without modification), making available to the
   2.101 +public, and in some countries other activities as well.
   2.102 +
   2.103 +  To "convey" a work means any kind of propagation that enables other
   2.104 +parties to make or receive copies.  Mere interaction with a user through
   2.105 +a computer network, with no transfer of a copy, is not conveying.
   2.106 +
   2.107 +  An interactive user interface displays "Appropriate Legal Notices"
   2.108 +to the extent that it includes a convenient and prominently visible
   2.109 +feature that (1) displays an appropriate copyright notice, and (2)
   2.110 +tells the user that there is no warranty for the work (except to the
   2.111 +extent that warranties are provided), that licensees may convey the
   2.112 +work under this License, and how to view a copy of this License.  If
   2.113 +the interface presents a list of user commands or options, such as a
   2.114 +menu, a prominent item in the list meets this criterion.
   2.115 +
   2.116 +  1. Source Code.
   2.117 +
   2.118 +  The "source code" for a work means the preferred form of the work
   2.119 +for making modifications to it.  "Object code" means any non-source
   2.120 +form of a work.
   2.121 +
   2.122 +  A "Standard Interface" means an interface that either is an official
   2.123 +standard defined by a recognized standards body, or, in the case of
   2.124 +interfaces specified for a particular programming language, one that
   2.125 +is widely used among developers working in that language.
   2.126 +
   2.127 +  The "System Libraries" of an executable work include anything, other
   2.128 +than the work as a whole, that (a) is included in the normal form of
   2.129 +packaging a Major Component, but which is not part of that Major
   2.130 +Component, and (b) serves only to enable use of the work with that
   2.131 +Major Component, or to implement a Standard Interface for which an
   2.132 +implementation is available to the public in source code form.  A
   2.133 +"Major Component", in this context, means a major essential component
   2.134 +(kernel, window system, and so on) of the specific operating system
   2.135 +(if any) on which the executable work runs, or a compiler used to
   2.136 +produce the work, or an object code interpreter used to run it.
   2.137 +
   2.138 +  The "Corresponding Source" for a work in object code form means all
   2.139 +the source code needed to generate, install, and (for an executable
   2.140 +work) run the object code and to modify the work, including scripts to
   2.141 +control those activities.  However, it does not include the work's
   2.142 +System Libraries, or general-purpose tools or generally available free
   2.143 +programs which are used unmodified in performing those activities but
   2.144 +which are not part of the work.  For example, Corresponding Source
   2.145 +includes interface definition files associated with source files for
   2.146 +the work, and the source code for shared libraries and dynamically
   2.147 +linked subprograms that the work is specifically designed to require,
   2.148 +such as by intimate data communication or control flow between those
   2.149 +subprograms and other parts of the work.
   2.150 +
   2.151 +  The Corresponding Source need not include anything that users
   2.152 +can regenerate automatically from other parts of the Corresponding
   2.153 +Source.
   2.154 +
   2.155 +  The Corresponding Source for a work in source code form is that
   2.156 +same work.
   2.157 +
   2.158 +  2. Basic Permissions.
   2.159 +
   2.160 +  All rights granted under this License are granted for the term of
   2.161 +copyright on the Program, and are irrevocable provided the stated
   2.162 +conditions are met.  This License explicitly affirms your unlimited
   2.163 +permission to run the unmodified Program.  The output from running a
   2.164 +covered work is covered by this License only if the output, given its
   2.165 +content, constitutes a covered work.  This License acknowledges your
   2.166 +rights of fair use or other equivalent, as provided by copyright law.
   2.167 +
   2.168 +  You may make, run and propagate covered works that you do not
   2.169 +convey, without conditions so long as your license otherwise remains
   2.170 +in force.  You may convey covered works to others for the sole purpose
   2.171 +of having them make modifications exclusively for you, or provide you
   2.172 +with facilities for running those works, provided that you comply with
   2.173 +the terms of this License in conveying all material for which you do
   2.174 +not control copyright.  Those thus making or running the covered works
   2.175 +for you must do so exclusively on your behalf, under your direction
   2.176 +and control, on terms that prohibit them from making any copies of
   2.177 +your copyrighted material outside their relationship with you.
   2.178 +
   2.179 +  Conveying under any other circumstances is permitted solely under
   2.180 +the conditions stated below.  Sublicensing is not allowed; section 10
   2.181 +makes it unnecessary.
   2.182 +
   2.183 +  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
   2.184 +
   2.185 +  No covered work shall be deemed part of an effective technological
   2.186 +measure under any applicable law fulfilling obligations under article
   2.187 +11 of the WIPO copyright treaty adopted on 20 December 1996, or
   2.188 +similar laws prohibiting or restricting circumvention of such
   2.189 +measures.
   2.190 +
   2.191 +  When you convey a covered work, you waive any legal power to forbid
   2.192 +circumvention of technological measures to the extent such circumvention
   2.193 +is effected by exercising rights under this License with respect to
   2.194 +the covered work, and you disclaim any intention to limit operation or
   2.195 +modification of the work as a means of enforcing, against the work's
   2.196 +users, your or third parties' legal rights to forbid circumvention of
   2.197 +technological measures.
   2.198 +
   2.199 +  4. Conveying Verbatim Copies.
   2.200 +
   2.201 +  You may convey verbatim copies of the Program's source code as you
   2.202 +receive it, in any medium, provided that you conspicuously and
   2.203 +appropriately publish on each copy an appropriate copyright notice;
   2.204 +keep intact all notices stating that this License and any
   2.205 +non-permissive terms added in accord with section 7 apply to the code;
   2.206 +keep intact all notices of the absence of any warranty; and give all
   2.207 +recipients a copy of this License along with the Program.
   2.208 +
   2.209 +  You may charge any price or no price for each copy that you convey,
   2.210 +and you may offer support or warranty protection for a fee.
   2.211 +
   2.212 +  5. Conveying Modified Source Versions.
   2.213 +
   2.214 +  You may convey a work based on the Program, or the modifications to
   2.215 +produce it from the Program, in the form of source code under the
   2.216 +terms of section 4, provided that you also meet all of these conditions:
   2.217 +
   2.218 +    a) The work must carry prominent notices stating that you modified
   2.219 +    it, and giving a relevant date.
   2.220 +
   2.221 +    b) The work must carry prominent notices stating that it is
   2.222 +    released under this License and any conditions added under section
   2.223 +    7.  This requirement modifies the requirement in section 4 to
   2.224 +    "keep intact all notices".
   2.225 +
   2.226 +    c) You must license the entire work, as a whole, under this
   2.227 +    License to anyone who comes into possession of a copy.  This
   2.228 +    License will therefore apply, along with any applicable section 7
   2.229 +    additional terms, to the whole of the work, and all its parts,
   2.230 +    regardless of how they are packaged.  This License gives no
   2.231 +    permission to license the work in any other way, but it does not
   2.232 +    invalidate such permission if you have separately received it.
   2.233 +
   2.234 +    d) If the work has interactive user interfaces, each must display
   2.235 +    Appropriate Legal Notices; however, if the Program has interactive
   2.236 +    interfaces that do not display Appropriate Legal Notices, your
   2.237 +    work need not make them do so.
   2.238 +
   2.239 +  A compilation of a covered work with other separate and independent
   2.240 +works, which are not by their nature extensions of the covered work,
   2.241 +and which are not combined with it such as to form a larger program,
   2.242 +in or on a volume of a storage or distribution medium, is called an
   2.243 +"aggregate" if the compilation and its resulting copyright are not
   2.244 +used to limit the access or legal rights of the compilation's users
   2.245 +beyond what the individual works permit.  Inclusion of a covered work
   2.246 +in an aggregate does not cause this License to apply to the other
   2.247 +parts of the aggregate.
   2.248 +
   2.249 +  6. Conveying Non-Source Forms.
   2.250 +
   2.251 +  You may convey a covered work in object code form under the terms
   2.252 +of sections 4 and 5, provided that you also convey the
   2.253 +machine-readable Corresponding Source under the terms of this License,
   2.254 +in one of these ways:
   2.255 +
   2.256 +    a) Convey the object code in, or embodied in, a physical product
   2.257 +    (including a physical distribution medium), accompanied by the
   2.258 +    Corresponding Source fixed on a durable physical medium
   2.259 +    customarily used for software interchange.
   2.260 +
   2.261 +    b) Convey the object code in, or embodied in, a physical product
   2.262 +    (including a physical distribution medium), accompanied by a
   2.263 +    written offer, valid for at least three years and valid for as
   2.264 +    long as you offer spare parts or customer support for that product
   2.265 +    model, to give anyone who possesses the object code either (1) a
   2.266 +    copy of the Corresponding Source for all the software in the
   2.267 +    product that is covered by this License, on a durable physical
   2.268 +    medium customarily used for software interchange, for a price no
   2.269 +    more than your reasonable cost of physically performing this
   2.270 +    conveying of source, or (2) access to copy the
   2.271 +    Corresponding Source from a network server at no charge.
   2.272 +
   2.273 +    c) Convey individual copies of the object code with a copy of the
   2.274 +    written offer to provide the Corresponding Source.  This
   2.275 +    alternative is allowed only occasionally and noncommercially, and
   2.276 +    only if you received the object code with such an offer, in accord
   2.277 +    with subsection 6b.
   2.278 +
   2.279 +    d) Convey the object code by offering access from a designated
   2.280 +    place (gratis or for a charge), and offer equivalent access to the
   2.281 +    Corresponding Source in the same way through the same place at no
   2.282 +    further charge.  You need not require recipients to copy the
   2.283 +    Corresponding Source along with the object code.  If the place to
   2.284 +    copy the object code is a network server, the Corresponding Source
   2.285 +    may be on a different server (operated by you or a third party)
   2.286 +    that supports equivalent copying facilities, provided you maintain
   2.287 +    clear directions next to the object code saying where to find the
   2.288 +    Corresponding Source.  Regardless of what server hosts the
   2.289 +    Corresponding Source, you remain obligated to ensure that it is
   2.290 +    available for as long as needed to satisfy these requirements.
   2.291 +
   2.292 +    e) Convey the object code using peer-to-peer transmission, provided
   2.293 +    you inform other peers where the object code and Corresponding
   2.294 +    Source of the work are being offered to the general public at no
   2.295 +    charge under subsection 6d.
   2.296 +
   2.297 +  A separable portion of the object code, whose source code is excluded
   2.298 +from the Corresponding Source as a System Library, need not be
   2.299 +included in conveying the object code work.
   2.300 +
   2.301 +  A "User Product" is either (1) a "consumer product", which means any
   2.302 +tangible personal property which is normally used for personal, family,
   2.303 +or household purposes, or (2) anything designed or sold for incorporation
   2.304 +into a dwelling.  In determining whether a product is a consumer product,
   2.305 +doubtful cases shall be resolved in favor of coverage.  For a particular
   2.306 +product received by a particular user, "normally used" refers to a
   2.307 +typical or common use of that class of product, regardless of the status
   2.308 +of the particular user or of the way in which the particular user
   2.309 +actually uses, or expects or is expected to use, the product.  A product
   2.310 +is a consumer product regardless of whether the product has substantial
   2.311 +commercial, industrial or non-consumer uses, unless such uses represent
   2.312 +the only significant mode of use of the product.
   2.313 +
   2.314 +  "Installation Information" for a User Product means any methods,
   2.315 +procedures, authorization keys, or other information required to install
   2.316 +and execute modified versions of a covered work in that User Product from
   2.317 +a modified version of its Corresponding Source.  The information must
   2.318 +suffice to ensure that the continued functioning of the modified object
   2.319 +code is in no case prevented or interfered with solely because
   2.320 +modification has been made.
   2.321 +
   2.322 +  If you convey an object code work under this section in, or with, or
   2.323 +specifically for use in, a User Product, and the conveying occurs as
   2.324 +part of a transaction in which the right of possession and use of the
   2.325 +User Product is transferred to the recipient in perpetuity or for a
   2.326 +fixed term (regardless of how the transaction is characterized), the
   2.327 +Corresponding Source conveyed under this section must be accompanied
   2.328 +by the Installation Information.  But this requirement does not apply
   2.329 +if neither you nor any third party retains the ability to install
   2.330 +modified object code on the User Product (for example, the work has
   2.331 +been installed in ROM).
   2.332 +
   2.333 +  The requirement to provide Installation Information does not include a
   2.334 +requirement to continue to provide support service, warranty, or updates
   2.335 +for a work that has been modified or installed by the recipient, or for
   2.336 +the User Product in which it has been modified or installed.  Access to a
   2.337 +network may be denied when the modification itself materially and
   2.338 +adversely affects the operation of the network or violates the rules and
   2.339 +protocols for communication across the network.
   2.340 +
   2.341 +  Corresponding Source conveyed, and Installation Information provided,
   2.342 +in accord with this section must be in a format that is publicly
   2.343 +documented (and with an implementation available to the public in
   2.344 +source code form), and must require no special password or key for
   2.345 +unpacking, reading or copying.
   2.346 +
   2.347 +  7. Additional Terms.
   2.348 +
   2.349 +  "Additional permissions" are terms that supplement the terms of this
   2.350 +License by making exceptions from one or more of its conditions.
   2.351 +Additional permissions that are applicable to the entire Program shall
   2.352 +be treated as though they were included in this License, to the extent
   2.353 +that they are valid under applicable law.  If additional permissions
   2.354 +apply only to part of the Program, that part may be used separately
   2.355 +under those permissions, but the entire Program remains governed by
   2.356 +this License without regard to the additional permissions.
   2.357 +
   2.358 +  When you convey a copy of a covered work, you may at your option
   2.359 +remove any additional permissions from that copy, or from any part of
   2.360 +it.  (Additional permissions may be written to require their own
   2.361 +removal in certain cases when you modify the work.)  You may place
   2.362 +additional permissions on material, added by you to a covered work,
   2.363 +for which you have or can give appropriate copyright permission.
   2.364 +
   2.365 +  Notwithstanding any other provision of this License, for material you
   2.366 +add to a covered work, you may (if authorized by the copyright holders of
   2.367 +that material) supplement the terms of this License with terms:
   2.368 +
   2.369 +    a) Disclaiming warranty or limiting liability differently from the
   2.370 +    terms of sections 15 and 16 of this License; or
   2.371 +
   2.372 +    b) Requiring preservation of specified reasonable legal notices or
   2.373 +    author attributions in that material or in the Appropriate Legal
   2.374 +    Notices displayed by works containing it; or
   2.375 +
   2.376 +    c) Prohibiting misrepresentation of the origin of that material, or
   2.377 +    requiring that modified versions of such material be marked in
   2.378 +    reasonable ways as different from the original version; or
   2.379 +
   2.380 +    d) Limiting the use for publicity purposes of names of licensors or
   2.381 +    authors of the material; or
   2.382 +
   2.383 +    e) Declining to grant rights under trademark law for use of some
   2.384 +    trade names, trademarks, or service marks; or
   2.385 +
   2.386 +    f) Requiring indemnification of licensors and authors of that
   2.387 +    material by anyone who conveys the material (or modified versions of
   2.388 +    it) with contractual assumptions of liability to the recipient, for
   2.389 +    any liability that these contractual assumptions directly impose on
   2.390 +    those licensors and authors.
   2.391 +
   2.392 +  All other non-permissive additional terms are considered "further
   2.393 +restrictions" within the meaning of section 10.  If the Program as you
   2.394 +received it, or any part of it, contains a notice stating that it is
   2.395 +governed by this License along with a term that is a further
   2.396 +restriction, you may remove that term.  If a license document contains
   2.397 +a further restriction but permits relicensing or conveying under this
   2.398 +License, you may add to a covered work material governed by the terms
   2.399 +of that license document, provided that the further restriction does
   2.400 +not survive such relicensing or conveying.
   2.401 +
   2.402 +  If you add terms to a covered work in accord with this section, you
   2.403 +must place, in the relevant source files, a statement of the
   2.404 +additional terms that apply to those files, or a notice indicating
   2.405 +where to find the applicable terms.
   2.406 +
   2.407 +  Additional terms, permissive or non-permissive, may be stated in the
   2.408 +form of a separately written license, or stated as exceptions;
   2.409 +the above requirements apply either way.
   2.410 +
   2.411 +  8. Termination.
   2.412 +
   2.413 +  You may not propagate or modify a covered work except as expressly
   2.414 +provided under this License.  Any attempt otherwise to propagate or
   2.415 +modify it is void, and will automatically terminate your rights under
   2.416 +this License (including any patent licenses granted under the third
   2.417 +paragraph of section 11).
   2.418 +
   2.419 +  However, if you cease all violation of this License, then your
   2.420 +license from a particular copyright holder is reinstated (a)
   2.421 +provisionally, unless and until the copyright holder explicitly and
   2.422 +finally terminates your license, and (b) permanently, if the copyright
   2.423 +holder fails to notify you of the violation by some reasonable means
   2.424 +prior to 60 days after the cessation.
   2.425 +
   2.426 +  Moreover, your license from a particular copyright holder is
   2.427 +reinstated permanently if the copyright holder notifies you of the
   2.428 +violation by some reasonable means, this is the first time you have
   2.429 +received notice of violation of this License (for any work) from that
   2.430 +copyright holder, and you cure the violation prior to 30 days after
   2.431 +your receipt of the notice.
   2.432 +
   2.433 +  Termination of your rights under this section does not terminate the
   2.434 +licenses of parties who have received copies or rights from you under
   2.435 +this License.  If your rights have been terminated and not permanently
   2.436 +reinstated, you do not qualify to receive new licenses for the same
   2.437 +material under section 10.
   2.438 +
   2.439 +  9. Acceptance Not Required for Having Copies.
   2.440 +
   2.441 +  You are not required to accept this License in order to receive or
   2.442 +run a copy of the Program.  Ancillary propagation of a covered work
   2.443 +occurring solely as a consequence of using peer-to-peer transmission
   2.444 +to receive a copy likewise does not require acceptance.  However,
   2.445 +nothing other than this License grants you permission to propagate or
   2.446 +modify any covered work.  These actions infringe copyright if you do
   2.447 +not accept this License.  Therefore, by modifying or propagating a
   2.448 +covered work, you indicate your acceptance of this License to do so.
   2.449 +
   2.450 +  10. Automatic Licensing of Downstream Recipients.
   2.451 +
   2.452 +  Each time you convey a covered work, the recipient automatically
   2.453 +receives a license from the original licensors, to run, modify and
   2.454 +propagate that work, subject to this License.  You are not responsible
   2.455 +for enforcing compliance by third parties with this License.
   2.456 +
   2.457 +  An "entity transaction" is a transaction transferring control of an
   2.458 +organization, or substantially all assets of one, or subdividing an
   2.459 +organization, or merging organizations.  If propagation of a covered
   2.460 +work results from an entity transaction, each party to that
   2.461 +transaction who receives a copy of the work also receives whatever
   2.462 +licenses to the work the party's predecessor in interest had or could
   2.463 +give under the previous paragraph, plus a right to possession of the
   2.464 +Corresponding Source of the work from the predecessor in interest, if
   2.465 +the predecessor has it or can get it with reasonable efforts.
   2.466 +
   2.467 +  You may not impose any further restrictions on the exercise of the
   2.468 +rights granted or affirmed under this License.  For example, you may
   2.469 +not impose a license fee, royalty, or other charge for exercise of
   2.470 +rights granted under this License, and you may not initiate litigation
   2.471 +(including a cross-claim or counterclaim in a lawsuit) alleging that
   2.472 +any patent claim is infringed by making, using, selling, offering for
   2.473 +sale, or importing the Program or any portion of it.
   2.474 +
   2.475 +  11. Patents.
   2.476 +
   2.477 +  A "contributor" is a copyright holder who authorizes use under this
   2.478 +License of the Program or a work on which the Program is based.  The
   2.479 +work thus licensed is called the contributor's "contributor version".
   2.480 +
   2.481 +  A contributor's "essential patent claims" are all patent claims
   2.482 +owned or controlled by the contributor, whether already acquired or
   2.483 +hereafter acquired, that would be infringed by some manner, permitted
   2.484 +by this License, of making, using, or selling its contributor version,
   2.485 +but do not include claims that would be infringed only as a
   2.486 +consequence of further modification of the contributor version.  For
   2.487 +purposes of this definition, "control" includes the right to grant
   2.488 +patent sublicenses in a manner consistent with the requirements of
   2.489 +this License.
   2.490 +
   2.491 +  Each contributor grants you a non-exclusive, worldwide, royalty-free
   2.492 +patent license under the contributor's essential patent claims, to
   2.493 +make, use, sell, offer for sale, import and otherwise run, modify and
   2.494 +propagate the contents of its contributor version.
   2.495 +
   2.496 +  In the following three paragraphs, a "patent license" is any express
   2.497 +agreement or commitment, however denominated, not to enforce a patent
   2.498 +(such as an express permission to practice a patent or covenant not to
   2.499 +sue for patent infringement).  To "grant" such a patent license to a
   2.500 +party means to make such an agreement or commitment not to enforce a
   2.501 +patent against the party.
   2.502 +
   2.503 +  If you convey a covered work, knowingly relying on a patent license,
   2.504 +and the Corresponding Source of the work is not available for anyone
   2.505 +to copy, free of charge and under the terms of this License, through a
   2.506 +publicly available network server or other readily accessible means,
   2.507 +then you must either (1) cause the Corresponding Source to be so
   2.508 +available, or (2) arrange to deprive yourself of the benefit of the
   2.509 +patent license for this particular work, or (3) arrange, in a manner
   2.510 +consistent with the requirements of this License, to extend the patent
   2.511 +license to downstream recipients.  "Knowingly relying" means you have
   2.512 +actual knowledge that, but for the patent license, your conveying the
   2.513 +covered work in a country, or your recipient's use of the covered work
   2.514 +in a country, would infringe one or more identifiable patents in that
   2.515 +country that you have reason to believe are valid.
   2.516 +
   2.517 +  If, pursuant to or in connection with a single transaction or
   2.518 +arrangement, you convey, or propagate by procuring conveyance of, a
   2.519 +covered work, and grant a patent license to some of the parties
   2.520 +receiving the covered work authorizing them to use, propagate, modify
   2.521 +or convey a specific copy of the covered work, then the patent license
   2.522 +you grant is automatically extended to all recipients of the covered
   2.523 +work and works based on it.
   2.524 +
   2.525 +  A patent license is "discriminatory" if it does not include within
   2.526 +the scope of its coverage, prohibits the exercise of, or is
   2.527 +conditioned on the non-exercise of one or more of the rights that are
   2.528 +specifically granted under this License.  You may not convey a covered
   2.529 +work if you are a party to an arrangement with a third party that is
   2.530 +in the business of distributing software, under which you make payment
   2.531 +to the third party based on the extent of your activity of conveying
   2.532 +the work, and under which the third party grants, to any of the
   2.533 +parties who would receive the covered work from you, a discriminatory
   2.534 +patent license (a) in connection with copies of the covered work
   2.535 +conveyed by you (or copies made from those copies), or (b) primarily
   2.536 +for and in connection with specific products or compilations that
   2.537 +contain the covered work, unless you entered into that arrangement,
   2.538 +or that patent license was granted, prior to 28 March 2007.
   2.539 +
   2.540 +  Nothing in this License shall be construed as excluding or limiting
   2.541 +any implied license or other defenses to infringement that may
   2.542 +otherwise be available to you under applicable patent law.
   2.543 +
   2.544 +  12. No Surrender of Others' Freedom.
   2.545 +
   2.546 +  If conditions are imposed on you (whether by court order, agreement or
   2.547 +otherwise) that contradict the conditions of this License, they do not
   2.548 +excuse you from the conditions of this License.  If you cannot convey a
   2.549 +covered work so as to satisfy simultaneously your obligations under this
   2.550 +License and any other pertinent obligations, then as a consequence you may
   2.551 +not convey it at all.  For example, if you agree to terms that obligate you
   2.552 +to collect a royalty for further conveying from those to whom you convey
   2.553 +the Program, the only way you could satisfy both those terms and this
   2.554 +License would be to refrain entirely from conveying the Program.
   2.555 +
   2.556 +  13. Use with the GNU Affero General Public License.
   2.557 +
   2.558 +  Notwithstanding any other provision of this License, you have
   2.559 +permission to link or combine any covered work with a work licensed
   2.560 +under version 3 of the GNU Affero General Public License into a single
   2.561 +combined work, and to convey the resulting work.  The terms of this
   2.562 +License will continue to apply to the part which is the covered work,
   2.563 +but the special requirements of the GNU Affero General Public License,
   2.564 +section 13, concerning interaction through a network will apply to the
   2.565 +combination as such.
   2.566 +
   2.567 +  14. Revised Versions of this License.
   2.568 +
   2.569 +  The Free Software Foundation may publish revised and/or new versions of
   2.570 +the GNU General Public License from time to time.  Such new versions will
   2.571 +be similar in spirit to the present version, but may differ in detail to
   2.572 +address new problems or concerns.
   2.573 +
   2.574 +  Each version is given a distinguishing version number.  If the
   2.575 +Program specifies that a certain numbered version of the GNU General
   2.576 +Public License "or any later version" applies to it, you have the
   2.577 +option of following the terms and conditions either of that numbered
   2.578 +version or of any later version published by the Free Software
   2.579 +Foundation.  If the Program does not specify a version number of the
   2.580 +GNU General Public License, you may choose any version ever published
   2.581 +by the Free Software Foundation.
   2.582 +
   2.583 +  If the Program specifies that a proxy can decide which future
   2.584 +versions of the GNU General Public License can be used, that proxy's
   2.585 +public statement of acceptance of a version permanently authorizes you
   2.586 +to choose that version for the Program.
   2.587 +
   2.588 +  Later license versions may give you additional or different
   2.589 +permissions.  However, no additional obligations are imposed on any
   2.590 +author or copyright holder as a result of your choosing to follow a
   2.591 +later version.
   2.592 +
   2.593 +  15. Disclaimer of Warranty.
   2.594 +
   2.595 +  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
   2.596 +APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
   2.597 +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
   2.598 +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
   2.599 +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   2.600 +PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
   2.601 +IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
   2.602 +ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
   2.603 +
   2.604 +  16. Limitation of Liability.
   2.605 +
   2.606 +  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
   2.607 +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
   2.608 +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
   2.609 +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
   2.610 +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
   2.611 +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
   2.612 +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
   2.613 +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
   2.614 +SUCH DAMAGES.
   2.615 +
   2.616 +  17. Interpretation of Sections 15 and 16.
   2.617 +
   2.618 +  If the disclaimer of warranty and limitation of liability provided
   2.619 +above cannot be given local legal effect according to their terms,
   2.620 +reviewing courts shall apply local law that most closely approximates
   2.621 +an absolute waiver of all civil liability in connection with the
   2.622 +Program, unless a warranty or assumption of liability accompanies a
   2.623 +copy of the Program in return for a fee.
   2.624 +
   2.625 +                     END OF TERMS AND CONDITIONS
   2.626 +
   2.627 +            How to Apply These Terms to Your New Programs
   2.628 +
   2.629 +  If you develop a new program, and you want it to be of the greatest
   2.630 +possible use to the public, the best way to achieve this is to make it
   2.631 +free software which everyone can redistribute and change under these terms.
   2.632 +
   2.633 +  To do so, attach the following notices to the program.  It is safest
   2.634 +to attach them to the start of each source file to most effectively
   2.635 +state the exclusion of warranty; and each file should have at least
   2.636 +the "copyright" line and a pointer to where the full notice is found.
   2.637 +
   2.638 +    <one line to give the program's name and a brief idea of what it does.>
   2.639 +    Copyright (C) <year>  <name of author>
   2.640 +
   2.641 +    This program is free software: you can redistribute it and/or modify
   2.642 +    it under the terms of the GNU General Public License as published by
   2.643 +    the Free Software Foundation, either version 3 of the License, or
   2.644 +    (at your option) any later version.
   2.645 +
   2.646 +    This program is distributed in the hope that it will be useful,
   2.647 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
   2.648 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   2.649 +    GNU General Public License for more details.
   2.650 +
   2.651 +    You should have received a copy of the GNU General Public License
   2.652 +    along with this program.  If not, see <http://www.gnu.org/licenses/>.
   2.653 +
   2.654 +Also add information on how to contact you by electronic and paper mail.
   2.655 +
   2.656 +  If the program does terminal interaction, make it output a short
   2.657 +notice like this when it starts in an interactive mode:
   2.658 +
   2.659 +    <program>  Copyright (C) <year>  <name of author>
   2.660 +    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
   2.661 +    This is free software, and you are welcome to redistribute it
   2.662 +    under certain conditions; type `show c' for details.
   2.663 +
   2.664 +The hypothetical commands `show w' and `show c' should show the appropriate
   2.665 +parts of the General Public License.  Of course, your program's commands
   2.666 +might be different; for a GUI interface, you would use an "about box".
   2.667 +
   2.668 +  You should also get your employer (if you work as a programmer) or school,
   2.669 +if any, to sign a "copyright disclaimer" for the program, if necessary.
   2.670 +For more information on this, and how to apply and follow the GNU GPL, see
   2.671 +<http://www.gnu.org/licenses/>.
   2.672 +
   2.673 +  The GNU General Public License does not permit incorporating your program
   2.674 +into proprietary programs.  If your program is a subroutine library, you
   2.675 +may consider it more useful to permit linking proprietary applications with
   2.676 +the library.  If this is what you want to do, use the GNU Lesser General
   2.677 +Public License instead of this License.  But first, please read
   2.678 +<http://www.gnu.org/philosophy/why-not-lgpl.html>.
   2.679 +
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/ChangeLog	Mon Dec 06 13:09:21 2010 +0100
     3.3 @@ -0,0 +1,2356 @@
     3.4 +Sun Dec 05 12:00:00 2010 Andrew Makhorin <mao@gnu.org>
     3.5 +
     3.6 +        * GLPK 4.45 (30:0:30) has been released
     3.7 +
     3.8 +        * glplpx01.c
     3.9 +        A bug (it_cnt) in routine reset_parms was fixed.
    3.10 +        Thanks to Ali Baharev <ali.baharev@gmail.com> for report.
    3.11 +
    3.12 +        * glpmpl03.c
    3.13 +        A bug (print "text\") was fixed.
    3.14 +        Thanks to Xypron <xypron.glpk@gmx.de> for report.
    3.15 +
    3.16 +        * glpsql.c
    3.17 +        A precision bug was fixed.
    3.18 +        Thanks to Xypron <xypron.glpk@gmx.de>.
    3.19 +
    3.20 +        * glpk.tex
    3.21 +        Some typos were corrected.
    3.22 +        Thanks to Robbie Morrison <robbie@actrix.co.nz>.
    3.23 +
    3.24 +Thu Jun 03 12:00:00 2010 Andrew Makhorin <mao@gnu.org>
    3.25 +
    3.26 +        * GLPK 4.44 (29:0:29) has been released
    3.27 +
    3.28 +        * glpapi14.c glpmpl.h glpmpl01.c glpmpl03.c glpmpl04.c
    3.29 +        Implemented suffixes for variables and constraints.
    3.30 +
    3.31 +        * glpmpl06.c
    3.32 +        Made changes to allow comment records in CSV files.
    3.33 +
    3.34 +        * glpapi17.c
    3.35 +        Added and documented new API routine glp_cpp to solve Critical
    3.36 +        Path Problem.
    3.37 +
    3.38 +Sat Feb 20 12:00:00 2010 Andrew Makhorin <mao@gnu.org>
    3.39 +
    3.40 +        * GLPK 4.43 (28:0:28) has been released
    3.41 +
    3.42 +        * glplib.h, glplib.c, glpenv.h, glpenv.c
    3.43 +        The module glpenv was split into two modules glpenv and glplib.
    3.44 +
    3.45 +        * glpenv01.c, glpenv03.c, glpenv04.c, glpenv06.c
    3.46 +        The following new API routines were added and documented:
    3.47 +        glp_init_env, glp_free_env, glp_open_tee, glp_close_tee,
    3.48 +        glp_error (macro), glp_difftime.
    3.49 +
    3.50 +        * glpapi16.c
    3.51 +        New API routine glp_top_sort (topological sorting of ayclic
    3.52 +        digraph) was added and documented.
    3.53 +
    3.54 +        * glpapi17.c
    3.55 +        A serious bug was fixed in the routine glp_asn_prob_hall.
    3.56 +
    3.57 +        * glpnpp05.c
    3.58 +        A bug was fixed in the LP/MIP preprocessor (hidden covering
    3.59 +        inequalities).
    3.60 +
    3.61 +        * glpsql.c
    3.62 +        Some improvements were made in the table driver (NULL data).
    3.63 +        Thanks to Xypron <xypron.glpk@gmx.de> for contribution.
    3.64 +
    3.65 +        * configure.ac
    3.66 +        Changes were made to use .dylib rather than .so under Mac OS.
    3.67 +        Thanks to Noli Sicad <nsicad@gmail.com> for testing
    3.68 +
    3.69 +Wed Jan 13 12:00:00 2010 Andrew Makhorin <mao@gnu.org>
    3.70 +
    3.71 +        * GLPK 4.42 (27:0:27) has been released
    3.72 +
    3.73 +        * glpapi01.c, glpapi11.c, glpapi12.c, glpdmx.c
    3.74 +        The following new API routines were added and documented:
    3.75 +        glp_check_dup (check for duplicate elements in sparse matrix);
    3.76 +        glp_sort_matrix (sort elements of the constraint matrix);
    3.77 +        glp_read_prob (read problem data in GLPK format);
    3.78 +        glp_write_prob (write problem data in GLPK format);
    3.79 +        glp_analyze_bound (analyze active bound of non-basic variable);
    3.80 +        glp_analyze_coef (analyze obj. coefficient at basic variable);
    3.81 +        glp_print_ranges (print sensitivity analysis report; replaces
    3.82 +        lpx_print_sens_bnds).
    3.83 +
    3.84 +        * glpapi20.c
    3.85 +        New command-line options were added to glpsol:
    3.86 +        --glp (read problem data in GLPK format);
    3.87 +        --wglp (write problem data in GLPK format);
    3.88 +        --lp (replaces --cpxlp);
    3.89 +        --wlp (replaces --wcpxlp);
    3.90 +        --ranges (print sensitivity analysis report).
    3.91 +
    3.92 +        * glpapi06.c
    3.93 +        In the routine glp_init_smcp default value of the parameter
    3.94 +        out_frq was changed to 500 (it was 200).
    3.95 +
    3.96 +        * glpipp.h, glpipp01.c, glpipp02.c
    3.97 +        The old MIP preprocessor module was removed.
    3.98 +
    3.99 +        * glpapi09.c
   3.100 +        Now the MIP solver uses the new MIP preprocessor (NPP).
   3.101 +
   3.102 +        * glplpx03.c
   3.103 +        lpx_write_opb was disabled due to replacing IPP with NPP.
   3.104 +
   3.105 +        * glpnet09.c
   3.106 +        Kellerman's heuristic to cover edges by cliques was added.
   3.107 +
   3.108 +        * glplib08.c
   3.109 +        Recognition of special filenames "/dev/stdin", "/dev/stdout",
   3.110 +        and "/dev/stderr" was added.
   3.111 +
   3.112 +        * glpk.tex
   3.113 +        Chapter "Graph and network routines" was carried out from the
   3.114 +        reference manual as a separate document.
   3.115 +
   3.116 +Mon Dec 21 12:00:00 2009 Andrew Makhorin <mao@gnu.org>
   3.117 +
   3.118 +        * GLPK 4.41 (26:0:26) has been released
   3.119 +
   3.120 +        * glpapi12.c
   3.121 +        The following new API routines were added:
   3.122 +        glp_transform_row (replaces lpx_transform_row);
   3.123 +        glp_transform_col (replaces lpx_transform_col);
   3.124 +        glp_prim_rtest (replaces lpx_prim_ratio_test);
   3.125 +        glp_dual_rtest (replaces lpx_dual_ratio_test).
   3.126 +        Note that values returned by glp_prim_rtest and glp_dual_rtest
   3.127 +        differ from the ones retutned by the deprecated routines.
   3.128 +
   3.129 +        * glpnpp*.*
   3.130 +        The LP/MIP preprocessor was essentially re-implemented.
   3.131 +
   3.132 +        * glpios03.c
   3.133 +        The feature to remove inactive cuts from the active subproblem
   3.134 +        was implemented.
   3.135 +
   3.136 +        * glpios11.c
   3.137 +        The feature processing cuts stored in the cut pool was improved
   3.138 +        (now it uses estimation of objective degradation).
   3.139 +
   3.140 +        * glpscg.*
   3.141 +        Obsolete implemetation of the conflict graph was removed.
   3.142 +
   3.143 +        * glpmpl.h, glpmpl03.c, glpmpl04.c
   3.144 +        FILE was replaced by XFILE to allow using GLPK I/O routines.
   3.145 +
   3.146 +        * glpsql.c, examples/sql, doc/tables.tex
   3.147 +        The SQL table driver was changed to allow multiple arguments
   3.148 +        separated by semicolon in SQL statements. Thanks to Xypron
   3.149 +        <xypron.glpk@gmx.de>.
   3.150 +
   3.151 +        * glpk.h, glpapi14.c
   3.152 +        New API routine glp_time was added (not documented yet).
   3.153 +
   3.154 +        * glpapi20.c
   3.155 +        Two new options were added to glpsol: --seed value (initialize
   3.156 +        pseudo-random number generator used in MathProg model with
   3.157 +        specified seed value), and --ini filename (use as initial basis
   3.158 +        previously saved with -w option).
   3.159 +
   3.160 +        * examples/xyacfs.mod
   3.161 +        Thanks to Nigel Galloway <nigel_galloway@operamail.com> for
   3.162 +        contribution.
   3.163 +
   3.164 +        * examples/dbf/*.*
   3.165 +        Thanks to Noli Sicad <nsicad@gmail.com> for contribution.
   3.166 +
   3.167 +        * w32/*.*, w64/*.*
   3.168 +        Scripts to build GLPK with Microsoft Visual Studio 2010 were
   3.169 +        added. Thanks to Xypron <xypron.glpk@gmx.de> for contribution
   3.170 +        and testing.
   3.171 +
   3.172 +Tue Nov 03 12:00:00 2009 Andrew Makhorin <mao@gnu.org>
   3.173 +
   3.174 +        * GLPK 4.40 (25:0:25) has been released
   3.175 +
   3.176 +        * glpdmx.c
   3.177 +        Two new API routines were added:
   3.178 +        glp_read_ccdata (read graph in DIMACS clique/coloring format);
   3.179 +        glp_write_ccdata (write graph in DIMACS clique/coloring format).
   3.180 +        Also an example file examples/sample.col was added.
   3.181 +
   3.182 +        * glpapi19.c, glpnet08.c
   3.183 +        New API routine glp_wclique_exact was added. It is intended to
   3.184 +        find a maximum weight clique with the exact algorithm developed
   3.185 +        by Prof. P. Ostergard.
   3.186 +
   3.187 +        * glpnpp02.c
   3.188 +        A bug was fixed in the LP preprocessor (routine npp_empty_col).
   3.189 +        Thanks to Stefan Vigerske <stefan@math.hu-berlin.de> for the
   3.190 +        bug report.
   3.191 +
   3.192 +        * glpios10.c
   3.193 +        A bug was fixed and some improvements were made in the FPUMP
   3.194 +        heuristic module. Thanks to Xypron <xypron.glpk@gmx.de>.
   3.195 +
   3.196 +        * glpapi12.c
   3.197 +        A bug was fixed in the API routine glp_warm_up (dual
   3.198 +        feasibility test was incorrect in maximization case). Thanks to
   3.199 +        Uday Venkatadri <Uday.Venkatadri@dal.ca> for the bug report.
   3.200 +
   3.201 +        * glpapi16.c
   3.202 +        Two new API routines were added:
   3.203 +        glp_del_vertices (remove vertices from graph);
   3.204 +        glp_del_arc (remove arc from graph).
   3.205 +
   3.206 +        * glpios09.c
   3.207 +        The hybrid pseudocost branching heuristic was included in the
   3.208 +        MIP solver. It is available on API level (iocp.br_tech should
   3.209 +        be set to GLP_BR_PCH) and in the stand-alone solver glpsol
   3.210 +        (via the command-line option --pcost). This heuristic may be
   3.211 +        useful on solving hard MIP instances.
   3.212 +
   3.213 +        * glpios03.c
   3.214 +        The branching heuristic by Driebeck and Tomlin (used in the
   3.215 +        MIP solver by default) was changed to switch to branching on
   3.216 +        most fractional variable if an lower bound of degradation of
   3.217 +        the objective is close to zero for all branching candidates.
   3.218 +
   3.219 +Sun Jul 26 12:00:00 2009 Andrew Makhorin <mao@mai2.rcnet.ru>
   3.220 +
   3.221 +        * GLPK 4.39 (24:0:24) has been released
   3.222 +
   3.223 +        * glpsdf.c
   3.224 +        New API routines to read plain data files were added.
   3.225 +
   3.226 +        * glpcpx.h, glpini.h, glpscl.h
   3.227 +        These headers were removed.
   3.228 +
   3.229 +        * glpcpx.c
   3.230 +        API routines glp_read_lp and glp_write_lp to read/write files
   3.231 +        in CPLEX LP format were re-implemented. Now glp_write_lp
   3.232 +        correctly writes double-bounded (ranged) rows by introducing
   3.233 +        slack variables rather than by duplicating the rows. The data
   3.234 +        structure glp_cpxcp and routine glp_init_cpxcp were added.
   3.235 +
   3.236 +        * amd/*
   3.237 +        The 'xfree(NULL)' bug was fixed in the AMD routines. Thanks to
   3.238 +        Niels Klitgord <niels@bu.edu> for the bug report.
   3.239 +
   3.240 +        * glpapi16.c
   3.241 +        New API routines glp_set_vertex_name, glp_create_v_index,
   3.242 +        glp_find_vertex, and glp_delete_v_index were added.
   3.243 +
   3.244 +        * glpdmx.c
   3.245 +        New API routines glp_read_asnprob, glp_write_asnprob,
   3.246 +        glp_read_ccformat, and glp_write_ccformat were added (the two
   3.247 +        latter routines are not documented yet).
   3.248 +
   3.249 +        * glpapi18.c
   3.250 +        New API routines glp_check_asnprob, glp_asnprob_lp,
   3.251 +        glp_asnprob_okalg, and glp_asnprob_hall were added.
   3.252 +
   3.253 +        * glpini01.c, glpini02.c
   3.254 +        The message "Crashing..." was changed to "Constructing initial
   3.255 +        basis..." due to suggestion by Thomas Kahle <tom111@gmx.de>.
   3.256 +
   3.257 +        * glpapi14.c
   3.258 +        New API routines glp_printf, glp_vprintf, glp_malloc,
   3.259 +        glp_calloc, glp_free, and glp_assert were added.
   3.260 +
   3.261 +        * glplpp.h, glplpp01.c, glplpp02.c
   3.262 +        Old LP presolver routines were removed. Now glp_simplex uses
   3.263 +        new preprocessing routines (see glpnpp).
   3.264 +
   3.265 +        * glpapi12.c
   3.266 +        New API routine glp_warm_up was added; it replaces the routine
   3.267 +        lpx_warm_up.
   3.268 +
   3.269 +Sat May 02 12:00:00 2009 Andrew Makhorin <mao@mai2.rcnet.ru>
   3.270 +
   3.271 +        * GLPK 4.38 (23:0:23) has been released
   3.272 +
   3.273 +        * glpmps.c
   3.274 +        API routines to read/write MPS files were re-implemented.
   3.275 +
   3.276 +        * glpspx02.c
   3.277 +        Some improvements were made in the dual simplex routine.
   3.278 +
   3.279 +        * glpk.h
   3.280 +        New structure glp_iptcp was added.
   3.281 +
   3.282 +        * glpnpp.h, glpnpp01.c, glpnpp02.c
   3.283 +        New LP/MIP preprocessor. Currently it includes only some basic
   3.284 +        routines and used only in the interior-point solver.
   3.285 +
   3.286 +        * glpapi08.c
   3.287 +        API routine glp_interior was replaced by an improved version
   3.288 +        (new LP/MIP preprocessor, new ordering algorithms).
   3.289 +
   3.290 +        New API routine glp_init_iptcp was added.
   3.291 +
   3.292 +        API routine glp_ipt_status may return two new statuses due to
   3.293 +        changes in glp_interior.
   3.294 +
   3.295 +        * glpsol.c
   3.296 +        New command-line options were added (ordering algorithm used in
   3.297 +        the interior-point solver).
   3.298 +
   3.299 +        * amd/*.*, colamd/*.*
   3.300 +        Two external software modules AMD and COLAMD/SYMAMD used in the
   3.301 +        interior-point solver were included in the distribution.
   3.302 +
   3.303 +        For details see amd/README and colamd/README.
   3.304 +
   3.305 +        * glpnet03.c, glpnet04.c, glpnet05.c
   3.306 +        A minor bug was fixed (_G => G_). Thanks to Nelson H. F. Beebe
   3.307 +        <beebe@math.utah.edu> for bug report.
   3.308 +
   3.309 +Sun Mar 29 12:00:00 2009 Andrew Makhorin <mao@mai2.rcnet.ru>
   3.310 +
   3.311 +        * GLPK 4.37 (22:0:22) has been released
   3.312 +
   3.313 +        * glpk.h
   3.314 +        iocp.fp_heur was added to enable/disable fpump heuristic.
   3.315 +
   3.316 +        * glpios10.c
   3.317 +        ios_feas_pump was added (feasibility pump heuristic).
   3.318 +
   3.319 +        * glpsol.c
   3.320 +        --fpump command-line option was added.
   3.321 +
   3.322 +        * glpsds.c
   3.323 +        Plain data set routines were added to facilitate reading plain
   3.324 +        data in application programs. Currently these routines are not
   3.325 +        in API, though declared in glpk.h.
   3.326 +
   3.327 +        * glpapi08.c
   3.328 +        A bug was fixed in the internal routine restore. (Due to this
   3.329 +        bug dual solution components were computed incorrectly if the
   3.330 +        problem was scaled.)
   3.331 +
   3.332 +        * glpapi10.c, glpapi11.c
   3.333 +        The following new API routines were added:
   3.334 +        glp_print_sol (replaces lpx_print_sol);
   3.335 +        glp_print_ipt (replaces lpx_print_ips);
   3.336 +        glp_print_mip (replaces lpx_print_mip);
   3.337 +        _glp_check_kkt (replaces lpx_check_kkt, lpx_check_int).
   3.338 +        Now the routine lpx_print_prob (deprecated) is equivalent to
   3.339 +        the routine glp_write_lp.
   3.340 +
   3.341 +        * glpapi18.c, glpapi19.c
   3.342 +        The following new API routines were added:
   3.343 +        glp_read_graph (read graph from plain text file);
   3.344 +        glp_write_graph (write graph to plain text file);
   3.345 +        glp_weak_comp (find all weakly connected components);
   3.346 +        glp_strong_comp (find all strongly connected components).
   3.347 +
   3.348 +        * configure.ac, Makefile.am
   3.349 +        Changes were made: (a) to allow using autoreconf/autoheader;
   3.350 +        (b) to allow building glpk in a directory other than its source
   3.351 +        directory. Thanks to Marco Atzeri <marco_atzeri@yahoo.it> for
   3.352 +        bug report.
   3.353 +
   3.354 +        * examples/shiftcover.mod
   3.355 +        An example model in MathProg was added.
   3.356 +        Thanks to Larry D'Agostino <Larry.D'Agostino@gmacrescap.com>
   3.357 +        for contribution.
   3.358 +
   3.359 +Fri Feb 06 12:00:00 2009 Andrew Makhorin <mao@mai2.rcnet.ru>
   3.360 +
   3.361 +        * GLPK 4.36 (21:0:21) has been released
   3.362 +
   3.363 +        * glpnet06.c, glpnet07.c, glpapi19.c
   3.364 +        The following new API routines were added:
   3.365 +        glp_mincost_okalg     find minimum-cost flow with out-of-kilter
   3.366 +                              algorithm
   3.367 +        glp_maxflow_ffalg     find maximal flow with Ford-Fulkerson
   3.368 +                              algorithm
   3.369 +
   3.370 +        * glpsol.c
   3.371 +        Two new command-line options were added:
   3.372 +        --mincost             read min-cost flow data in DIMACS format
   3.373 +        --maxflow             read maximum flow data in DIMACS format
   3.374 +
   3.375 +        * doc/glpk.*
   3.376 +        New edition of the reference manual was included.
   3.377 +
   3.378 +        * glpk.h
   3.379 +        Duplicate symbols were removed to allow using swig.
   3.380 +        Thanks to Kelly Westbrooks <kellywestbrooks@yahoo.com> and
   3.381 +        Nigel Galloway <nigel_galloway@operamail.com> for suggestion.
   3.382 +
   3.383 +        * glpcpx.c
   3.384 +        A minor defect was fixed in the routine glp_write_lp.
   3.385 +        Thanks to Sebastien Briais <sbriais@free.fr> for bug report.
   3.386 +
   3.387 +        * glpsql.c
   3.388 +        A minor bug was fixed. Thanks to Xypron <xypron.glpk@gmx.de>
   3.389 +        for patch.
   3.390 +
   3.391 +        * examples/hashi.mod, examples/shikaku.mod
   3.392 +        Two example models in MathProg were added. Thanks to Sebastian
   3.393 +        Nowozin <nowozin@gmail.com> for contribution.
   3.394 +
   3.395 +        * examples/qfit.mod, examples/yacfs.mod
   3.396 +        Two example models in MathProg were added. Thanks to Nigel
   3.397 +        Galloway <nigel_galloway@operamail.com> for contribution.
   3.398 +
   3.399 +Fri Jan 09 12:00:00 2009 Andrew Makhorin <mao@mai2.rcnet.ru>
   3.400 +
   3.401 +        * GLPK 4.35 (20:0:20) has been released
   3.402 +
   3.403 +        * glpk.h, glpapi.c, glpnet.c
   3.404 +        The following new API routines were added:
   3.405 +        glp_create_graph      create graph
   3.406 +        glp_set_graph_name    assign (change) graph name
   3.407 +        glp_add_vertices      add new vertices to graph
   3.408 +        glp_add_arc           add new arc to graph
   3.409 +        glp_erase_graph       erase graph content
   3.410 +        glp_delete_graph      delete graph
   3.411 +        glp_read_mincost      read minimum cost flow problem data in
   3.412 +                              DIMACS format
   3.413 +        glp_write_mincost     write minimum cost flow problem data in
   3.414 +                              DIMACS format
   3.415 +        glp_mincost_lp        convert minimum cost flow problem to LP
   3.416 +        glp_netgen            Klingman's network problem generator
   3.417 +        glp_gridgen           grid-like network problem generator
   3.418 +        glp_read_maxflow      read maximum flow problem data in DIMACS
   3.419 +                              format
   3.420 +        glp_write_maxflow     write maximum flow problem data in DIMACS
   3.421 +                              format
   3.422 +        glp_maxflow_lp        convert maximum flow problem to LP
   3.423 +        glp_rmfgen            Goldfarb's maximum flow problem generator
   3.424 +
   3.425 +        * doc/glpk.*
   3.426 +        New edition of the reference manual was included.
   3.427 +
   3.428 +        * examples/sample.min, examples/sample.max
   3.429 +        Two example data files in DIMACS format were added.
   3.430 +
   3.431 +        * glplib04.c
   3.432 +        The statement "if (c = '\n') fflush(stdout)" was added to the
   3.433 +        internal routine xputc to provide "real-time" terminal output.
   3.434 +        Thanks to Luiz Bettoni <bettoni@cpgei.ct.utfpr.edu.br> for
   3.435 +        suggestion.
   3.436 +
   3.437 +        * glpmpl05.c
   3.438 +        A minor bug was fixed in the internal routine mpl_fn_time2str.
   3.439 +        Thanks to Stefan Vigerske <stefan@vigerske.de> for bug report.
   3.440 +
   3.441 +        * w32/makefile, w64/makefile
   3.442 +        The flag -O2 (/O2) was added to some makefiles.
   3.443 +
   3.444 +Thu Dec 04 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
   3.445 +
   3.446 +        * GLPK 4.34 (19:0:19) has been released
   3.447 +
   3.448 +        * src/glpios03.c
   3.449 +        A bug was fixed in the internal routine branch_on. Thanks to
   3.450 +        Nigel Galloway <nigel_galloway@operamail.com> for bug report.
   3.451 +
   3.452 +        * src/glpmpl05.c
   3.453 +        Three new MathProg functions were included:
   3.454 +        gmtime    obtaining current calendar time
   3.455 +        str2time  converting character string to calendar time
   3.456 +        time2str  converting calendar time to character string
   3.457 +        Thanks to Xypron <xypron.glpk@gmx.de>.
   3.458 +
   3.459 +        * doc/glpk.*, doc/gmpl.*
   3.460 +        A new edition of the GLPK reference manual and GNU MathProg
   3.461 +        language description were included.
   3.462 +
   3.463 +Thu Oct 30 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
   3.464 +
   3.465 +        * GLPK 4.33 (18:0:18) has been released
   3.466 +
   3.467 +        * glpapi*.*
   3.468 +        The following new API routines were added:
   3.469 +        glp_copy_prob         copy problem object content
   3.470 +        glp_exact             solve LP in exact arithmetic
   3.471 +                              (makes lpx_exact deprecated)
   3.472 +        glp_get_unbnd_ray     determine variable causing unboundedness
   3.473 +                              (makes lpx_get_ray_info deprecated)
   3.474 +        glp_interior          solve LP with interior-point method
   3.475 +                              (makes lpx_interior deprecated)
   3.476 +
   3.477 +        * glpapi*.*
   3.478 +        The following new API routines for processing models written in
   3.479 +        the GNU Mathprog language were added to the package:
   3.480 +        glp_mpl_alloc_wksp    allocate the translator workspace
   3.481 +        glp_mpl_read_model    read and translate model section
   3.482 +        glp_mpl_read_data     read and translate data section
   3.483 +        glp_mpl_generate      generate the model
   3.484 +        glp_mpl_build_prob    build LP/MIP instance from the model
   3.485 +        glp_mpl_postsolve     postsolve the model
   3.486 +        glp_mpl_free_wksp     deallocate the translator workspace
   3.487 +        (These routines make lpx_read_model deprecated.)
   3.488 +
   3.489 +        * src/glpapi17.c, examples/glpsol.c
   3.490 +        The stand-alone solver glpsol was re-implemented with new API
   3.491 +        routines.
   3.492 +
   3.493 +        * src/glpsql.c
   3.494 +        Some bugs were fixed in the SQL table driver. Thanks to Xypron
   3.495 +        <xypron.glpk@gmx.de>.
   3.496 +
   3.497 +        * examples/cplex/*.*
   3.498 +        A crude implementation of CPLEX-like interface to GLPK API was
   3.499 +        added to the package. See examples/cplex/README.
   3.500 +
   3.501 +Fri Oct 03 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
   3.502 +
   3.503 +        * GLPK 4.32 (17:0:17) has been released
   3.504 +
   3.505 +        * glpmpl01.c
   3.506 +        A bug was fixed. Due to this bug iterated expressions having
   3.507 +        an indexing expression whose dummy indices are bound to some
   3.508 +        values, i.e. like sum{(i+1,j,k-1) in E} x[i,j,k] are evaluated
   3.509 +        incorrectly. Namely, current value of such expressions is not
   3.510 +        invalidated when corresponding dummy indices (like i and k in
   3.511 +        the example above) are changed, that erroneously results in the
   3.512 +        same value evaluated for the first time.
   3.513 +
   3.514 +        * glpios03.c
   3.515 +        Euclidean reduction of the local objective bound was added in
   3.516 +        the routine glpios03.c.
   3.517 +
   3.518 +        * glpapi11.c
   3.519 +        The following new branch-and-cut API routines were added:
   3.520 +        glp_ios_row_attr      determine additional row attributes;
   3.521 +        glp_ios_pool_size     determine current size of the cut pool;
   3.522 +        glp_ios_add_row       add constraint to the cut pool;
   3.523 +        glp_ios_del_row       delete constraint from the cut pool;
   3.524 +        glp_ios_clear_pool    delete all constraints from the cut pool.
   3.525 +
   3.526 +        * glpapi08.c
   3.527 +        The following new features were included in the branch-and-cut
   3.528 +        solver (the API routine glp_intopt):
   3.529 +        MIP presolver;
   3.530 +        mixed cover cut generator;
   3.531 +        clique cut generator.
   3.532 +        Due to the MIP presolver glp_intopt may additionally return
   3.533 +        GLP_ENOPFS and GLP_ENODFS, if primal or dual infeasibility of
   3.534 +        LP relaxation is detected by the presolver. Also the return
   3.535 +        code GLP_EMIPGAP was introduced to correctly indicate that the
   3.536 +        mip gap tolerance is reached.
   3.537 +
   3.538 +        * glplpx01.c
   3.539 +        Now the obsolete API routines lpx_integer and lpx_intopt are
   3.540 +        completely superseded by the API routine glp_intopt that makes
   3.541 +        them deprecated.
   3.542 +
   3.543 +        * glpmpl05.c
   3.544 +        Now the table driver name "iODBC" can be specified as "ODBC".
   3.545 +
   3.546 +        * glpmpl03.c
   3.547 +        A bug fixed in the routine free_dca.
   3.548 +        Thanks to Xypron <xypron.glpk@gmx.de>.
   3.549 +
   3.550 +        * glpsql.c
   3.551 +        A bug was fixed in the SQL table driver.
   3.552 +        Thanks to Xypron <xypron.glpk@gmx.de>.
   3.553 +
   3.554 +        * examples/glpsol.c
   3.555 +        Changes were made to allow multiple MathProg data files.
   3.556 +
   3.557 +        * doc/glpk.*
   3.558 +        A new edition of the GLPK reference manual was included.
   3.559 +
   3.560 +        * doc/tables.*
   3.561 +        A new edition of the supplement "Using data tables in the GNU
   3.562 +        MathProg language" was included.
   3.563 +
   3.564 +Tue Sep 02 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
   3.565 +
   3.566 +        * GLPK 4.31 (16:0:16) has been released
   3.567 +
   3.568 +        * glpspx.h, glpspx01.c, glpspx02.c, glpapi06.c
   3.569 +        The dual simplex solver (spx_dual_opt) was replaced by a new
   3.570 +        implementation of the two-phase dual simplex method (spx_dual).
   3.571 +        Old simplex method routines (spx_prim_opt, spx_prim_feas, and
   3.572 +        spx_dual_opt) were removed from the package.
   3.573 +
   3.574 +        * glpk.h, glpscl.h, glpscl.c, glpapi04.c
   3.575 +        New API routine glp_scale_prob was added. It replaces routine
   3.576 +        lpx_scale_prob which is deprecated.
   3.577 +
   3.578 +        * glpk.h, glpini.h, glpini01.c, glpini02.c, glpapi05.c
   3.579 +        New API routines glp_std_basis, glp_adv_basis, glp_cpx_basis
   3.580 +        were added. They replace routines lpx_std_basis, lpx_adv_basis,
   3.581 +        lpx_cpx_basis which are deprecated.
   3.582 +
   3.583 +        * glpdmp.c
   3.584 +        8-byte data alignment was added to the module (sufficient for
   3.585 +        both ILP32 and LP64 environments).
   3.586 +
   3.587 +        * glplib07.c
   3.588 +        16-byte data alignment was added to the module to provide
   3.589 +        compatibility with LP64 environment (8-byte is not sufficient
   3.590 +        due to jmp_buf; thanks to Xypron for investigation).
   3.591 +
   3.592 +        * glplpx16.c
   3.593 +        New version of the routine lpx_write_pb was added. Thanks to
   3.594 +        Oscar Gustafsson <oscarg@isy.liu.se> for the contribution.
   3.595 +
   3.596 +        * w32/VC9, w64/VC9
   3.597 +        Makefiles and batch files were added to build GLPK under 32-
   3.598 +        and 64-bit Windows with Microsoft Visual Studio Express 2008.
   3.599 +        Thanks to Heinrich Schuchardt <heinrich.schuchardt@gmx.de> for
   3.600 +        the contribution and testing.
   3.601 +
   3.602 +        * w32/DM, w32/OWC
   3.603 +        Makefiles and batch files were added to build GLPK with Digital
   3.604 +        Mars C/C++ 8.50 and Open Watcom C/C++ 1.6 (32-bit Windows).
   3.605 +
   3.606 +Wed Aug 13 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
   3.607 +
   3.608 +        * GLPK 4.30 (15:0:15) has been released
   3.609 +
   3.610 +        * glpspx.h, glpspx03.c, glpapi06.c
   3.611 +        The primal simplex solver (spx_prim_opt, spx_prim_feas) was
   3.612 +        replaced by a new implementation (spx_primal), which currently
   3.613 +        provides the same features as the old version.
   3.614 +
   3.615 +        * glpmpl01.c, glpmpl03.c
   3.616 +        Some changes were made in the MathProg translator to allow <,
   3.617 +        <=, >=, and > on comparing symbolic values. Thanks to Heinrich
   3.618 +        Schuchardt <heinrich.schuchardt@gmx.de> for patches.
   3.619 +
   3.620 +        * glplpx10.c
   3.621 +        Internal routine set_d_eps in the exact LP solver was changed
   3.622 +        to prevent approximation errors in case of integral data.
   3.623 +        Thanks to Markus Pilz <pilz@cs.uni-bonn.de> for bug report.
   3.624 +
   3.625 +XXX XXX XX 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
   3.626 +
   3.627 +        * GLPK 4.29 (14:0:14) has been released
   3.628 +
   3.629 +        * configure.ac
   3.630 +        The configure script was changed to disable optional features
   3.631 +        by default. For details see file INSTALL.
   3.632 +
   3.633 +        * glpipp02.c
   3.634 +        A bug was fixed in the internal routine reduce_bounds. Thanks
   3.635 +        to Anne-Laurence Putz <anne-laurence.putz@eurodecision.com> for
   3.636 +        the bug report.
   3.637 +
   3.638 +        * glpapi01.c
   3.639 +        New API routine glp_erase_prob was added.
   3.640 +
   3.641 +        * glpapi13.c
   3.642 +        New API routines glp_read_mps and glp_write_mps were added.
   3.643 +        They replace API routines lpx_read_mps, lpx_read_freemps,
   3.644 +        lpx_write_mps, and lpx_write_freemps, which are deprecated.
   3.645 +
   3.646 +        * glpapi14.c
   3.647 +        New API routines glp_read_lp and glp_write_lp were added. They
   3.648 +        replace API routines lpx_read_cpxlp and lpx_write_cpxlp, which
   3.649 +        are deprecated.
   3.650 +
   3.651 +        * glpsql.c
   3.652 +        Minor bug was fixed. Thanks to Xypron <xypron.glpk@gmx.de> for
   3.653 +        the bug report.
   3.654 +
   3.655 +Tue Mar 25 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
   3.656 +
   3.657 +        * GLPK 4.28 (13:0:13) has been released
   3.658 +
   3.659 +        * glplib.h, glplib.c
   3.660 +        Three wrapper routines xdlopen, xdlsym, and xdlclose, which
   3.661 +        provide the shared library support, were added. A particular
   3.662 +        version of these routines depends on the option --enable-dl
   3.663 +        passed to the configure script (see file INSTALL for details).
   3.664 +        Thanks to Rafael Laboissiere <rafael@debian.org> for useful
   3.665 +        advices concerning the shared library support.
   3.666 +
   3.667 +        * glpsql.c
   3.668 +        A static linking to iODBC and MySQL libraries used in the
   3.669 +        MathProg table drivers was replaced by a dynamic linking to
   3.670 +        corresponding shared libraries.
   3.671 +        Many thanks to Heinrich Schuchardt <heinrich.schuchardt@gmx.de>
   3.672 +        for the contribution and to Vijay Patil <vijay.patil@gmail.com>
   3.673 +        for testing this feature under Windows XP.
   3.674 +
   3.675 +        * glpgmp.h, glpgmp.c
   3.676 +        A bug (which appeared only on 64-bit platforms) was fixed.
   3.677 +        Thanks to Axel Simon <Axel.Simon@ens.fr> for the bug report.
   3.678 +
   3.679 +        * glpapi.c
   3.680 +        A bug was fixed in the api routine glp_add_cols. (If the basis
   3.681 +        is valid, adding column keeps it valid, however, col->bind was
   3.682 +        set to -1 rather to 0.)
   3.683 +        Thanks to Cedric[FR] <fox2113@wanadoo.fr> for the bug report.
   3.684 +
   3.685 +        * glplib.c
   3.686 +        64-bit unsigned int type glp_ulong and corresponding routines
   3.687 +        were replaced by 64-bit signed int type xlong_t.
   3.688 +
   3.689 +        * glpk.h, glpapi.c
   3.690 +        The type glp_ulong was replaced by glp_long. This affects only
   3.691 +        the api routine glp_mem_usage.
   3.692 +
   3.693 +        * glplib.c
   3.694 +        Compressed data file support was added. This feature requires
   3.695 +        the zlib data compression libraries and allows compressing and
   3.696 +        decompressing .gz files "on the fly".
   3.697 +
   3.698 +        * glpcli.h, glpcli.c
   3.699 +        Command-line interface routines were added. (This feature is
   3.700 +        incomplete so far.)
   3.701 +
   3.702 +Sun Mar 02 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
   3.703 +
   3.704 +        * GLPK 4.27 (12:0:12) has been released
   3.705 +
   3.706 +        * glpsql.h, glpsql.c
   3.707 +        Two MathProg table drivers for iODBC and MySQL contributed by
   3.708 +        Heinrich Schuchardt <heinrich.schuchardt@gmx.de> were added to
   3.709 +        the package.
   3.710 +
   3.711 +        * glpmpl05.c
   3.712 +        Mathprog table driver for xBASE was added to the package.
   3.713 +
   3.714 +        * glpmpl03.c
   3.715 +        A minor was fixed in the MathProg translator (if some field
   3.716 +        specified in the table statement is missing in corresponding
   3.717 +        input table, the bug causes abnormal termination). Thanks to
   3.718 +        Heinrich Schuchardt <heinrich.schuchardt@gmx.de> for the bug
   3.719 +        report.
   3.720 +
   3.721 +        * glpmpl.h, glpmpl.c
   3.722 +        STRING data type was replaced by plain character strings.
   3.723 +
   3.724 +Sun Feb 17 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
   3.725 +
   3.726 +        * GLPK 4.26 (11:0:11) has been released
   3.727 +
   3.728 +        * glpmpl.h, glpmpl01.c, glpmpl03.c, glpmpl05.c
   3.729 +        The table statement was implemented. Description of this new
   3.730 +        feature is given in file doc/tables.txt.
   3.731 +
   3.732 +        * glpios03.c
   3.733 +        A bug causing zero divide error on computing euclidean norm of
   3.734 +        the cut coefficient vector was fixed.
   3.735 +
   3.736 +Wed Dec 19 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
   3.737 +
   3.738 +        * GLPK 4.25 (10:0:10) has been released
   3.739 +
   3.740 +        * glpapi10.c
   3.741 +        Routines lpx_eval_tab_row and lpx_eval_tab_col were replaced by
   3.742 +        glp_eval_tab_row and glp_eval_tab_col.
   3.743 +
   3.744 +        * glpios03.c, glpios05.c
   3.745 +        Gomory's mixed integer cuts were implemented.
   3.746 +
   3.747 +        * glpscs.h, glpscs.c
   3.748 +        Segmented character string routines are no longer used and were
   3.749 +        removed from the package.
   3.750 +
   3.751 +Wed Nov 21 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
   3.752 +
   3.753 +        * GLPK 4.24 (9:0:9) has been released
   3.754 +
   3.755 +        * src/glplpx16.c
   3.756 +        A bug was fixed in the routine lpx_write_cpxlp. If a variable
   3.757 +        x has upper bound and no lower bound, it should appear in the
   3.758 +        bounds section as "-inf <= x <= u", not as "x <= u". Thanks to
   3.759 +        Enric Rodriguez <erodri@lsi.upc.edu> for the bug report.
   3.760 +
   3.761 +        * src/glpios03.c, src/glpios04.c, src/glpios05.c
   3.762 +        MIR (mixed integer rounding) cuts were implemented.
   3.763 +
   3.764 +Sun Oct 28 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
   3.765 +
   3.766 +        * GLPK 4.23 (8:0:8) has been released
   3.767 +
   3.768 +        * src/glplib05.c, configure.ac
   3.769 +        Check for vsnprintf was added.
   3.770 +
   3.771 +        * include/glppds.h, src/glppds.c
   3.772 +        A module to scan plain data was added.
   3.773 +
   3.774 +        * src/glpapi09.c
   3.775 +        The following new API routines were added:
   3.776 +        glp_read_sol    read basic solution from text file;
   3.777 +        glp_write_sol   write basic solution to text file;
   3.778 +        glp_read_ipt    read interior-point solution from text file;
   3.779 +        glp_write_ipt   write interior-point solution to text file;
   3.780 +        glp_read_mip    read MIP solution from text file;
   3.781 +        glp_write_mip   write MIP solution to text file.
   3.782 +
   3.783 +        * src/glpapi12.c
   3.784 +        Advanced API routine glp_free_env was added.
   3.785 +
   3.786 +        * examples/glpsol.c
   3.787 +        The following three command-line options were added:
   3.788 +        --mipgap tol    set relative MIP gap tolerance
   3.789 +        -r filename     read solution from filename
   3.790 +        -w filename     write solution to filename
   3.791 +
   3.792 +Wed Sep 19 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
   3.793 +
   3.794 +        * GLPK 4.22 (7:0:7) has been released
   3.795 +
   3.796 +        * src/glpios02.c
   3.797 +        A bug was fixed in the MIP preprocessor (ios_preprocess_node).
   3.798 +        Thanks to Roberto Bagnara <bagnara@cs.unipr.it> (Department of
   3.799 +        Mathematics, University of Parma, Italy) for the bug report.
   3.800 +
   3.801 +        * src/glpios02.c
   3.802 +        A bug was fixed in the MIP preprocessor (col_implied_bounds),
   3.803 +        due to which constraint coefficients with small magnitude could
   3.804 +        lead to wrong implied bounds of structural variables.
   3.805 +
   3.806 +        * src/glpipp02.c
   3.807 +        A similar bug was fixed in the routine reduce_bounds.
   3.808 +
   3.809 +        * src/glpapi01.c
   3.810 +        A bug was fixed in the routines glp_set_mat_row and
   3.811 +        glp_set_mat_col. (The bug appeared due to incorrect removing
   3.812 +        zero elements from the row/column lists.)
   3.813 +
   3.814 +        * src/glplpx14.c
   3.815 +        A bug was fixed in the API routines lpx_read_mps and
   3.816 +        lpx_read_freemps, due to which bounds of type LI specified in
   3.817 +        BOUNDS section were incorrectly processed.
   3.818 +
   3.819 +        * src/glplib05.c
   3.820 +        A call to standard function vsprintf was replaced by a call to
   3.821 +        vsnprintf for security reasons. Many thanks to Peter T. Breuer
   3.822 +        <ptb@inv.it.uc3m.es> and Rafael Laboissiere <rafael@debian.org>.
   3.823 +
   3.824 +Tue Aug 28 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
   3.825 +
   3.826 +        * GLPK 4.21 (6:0:6) has been released
   3.827 +
   3.828 +        * glpscg.h, glpscg.c
   3.829 +        Routines to maintain sparse cliqued graph were added.
   3.830 +
   3.831 +        * glpios02.c
   3.832 +        MIP preprocessing routines were added.
   3.833 +
   3.834 +        * glpk.h, glpios.h, glpios03.c
   3.835 +        New reasons for calling the callback routine were introduced
   3.836 +        in the MIP solver.
   3.837 +
   3.838 +        * glpapi08.c
   3.839 +        Default backtracking strategy was changed to best local bound.
   3.840 +
   3.841 +        * glpapi11.c
   3.842 +        New API routine glp_term_out to enable/disable terminal output
   3.843 +        was added.
   3.844 +
   3.845 +        * glprng.h, glprng02.c
   3.846 +        Two routines to generate uniformly distributed pseudo-random
   3.847 +        floating-point numbers were added.
   3.848 +
   3.849 +Thu Jul 26 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
   3.850 +
   3.851 +        * GLPK 4.20 (5:0:5) has been released
   3.852 +
   3.853 +        * glpk.h, glpapi08.c
   3.854 +        The routine lpx_integer was replaced by an equivalent routine
   3.855 +        glp_intopt. Also new API routine glp_init_iocp was added.
   3.856 +
   3.857 +        * glpiet.h, glpiet.c
   3.858 +        Routines implementing the implicit enumeration tree are
   3.859 +        no longer used and therefore were removed from the package.
   3.860 +
   3.861 +        * glpios.h, glpios01.c, glpios02, glpios03
   3.862 +        Routines implementing the integer optimization suite being
   3.863 +        replaced by a new version were removed from the package.
   3.864 +
   3.865 +        * glpmip.h, glpmip01.c, glpmip02.c
   3.866 +
   3.867 +        Routines implementing the B&B method being replaced by a new
   3.868 +        version were removed from the package.
   3.869 +
   3.870 +        * glpios.h, glpios01.c, glpios02.c
   3.871 +
   3.872 +        Routines implementing a new version of the integer optimization
   3.873 +        suite (IOS) based on the B&B method were added to the package.
   3.874 +
   3.875 +        * glpk.h, glpapi10.c
   3.876 +        Branch-and-bound interface routines were added to the package.
   3.877 +
   3.878 +        * examples/tspsol.c
   3.879 +        The TSP solver based on old version of the integer optimization
   3.880 +        suite is no more supported and was removed from the package.
   3.881 +
   3.882 +        * glpipp02.c
   3.883 +        An error in the routine reduce_bounds was fixed; thanks to
   3.884 +        Graham Rockwell <bionomicron@gmail.com> for the bug report.
   3.885 +
   3.886 +        * glpk.latex
   3.887 +        A new edition of the reference manual was included.
   3.888 +
   3.889 +Thu Jul 05 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
   3.890 +
   3.891 +        * GLPK 4.19 (4:0:4) has been released
   3.892 +
   3.893 +        The principal change is upgrading to GPLv3.
   3.894 +
   3.895 +        * glpapi01.c
   3.896 +        A serious bug in the routine glp_del_cols was fixed; thanks to
   3.897 +        Cedric[FR] <fox2113@wanadoo.fr> for the bug report. The bug
   3.898 +        appeared because on deleting non-basic columns the basis header
   3.899 +        remained valid, however, contained invalid (old) column ordinal
   3.900 +        numbers.
   3.901 +
   3.902 +        * glpapi10.c
   3.903 +        A new advanced API routine glp_mem_limit was added.
   3.904 +
   3.905 +        * glplpx01.c
   3.906 +        The case GLP_EBOUND was added to the routine lpx_simplex.
   3.907 +        Thanks to Cameron Kellough <Cameron.Kellough@sri.com> for the
   3.908 +        bug report.
   3.909 +
   3.910 +        * glplpx19.c
   3.911 +        An API routine lpx_write_pb to write the problem instance in
   3.912 +        OPB (pseudo boolean) format format was added. Thanks to Oscar
   3.913 +        Gustafsson <oscarg@isy.liu.se> for the contribution.
   3.914 +
   3.915 +        * glpsol.c
   3.916 +        Two new options --wpb and --wnpb were added to glpsol to write
   3.917 +        the problem instance in OPB format.
   3.918 +
   3.919 +Mon Jun 25 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
   3.920 +
   3.921 +        * GLPK 4.18 (3:0:3) has been released
   3.922 +
   3.923 +        * glplib.h
   3.924 +        Type names ulong_t and uldiv_t were changed to glp_ulong and
   3.925 +        glp_uldiv to avoid conflicts with standard type names on some
   3.926 +        platforms. Thanks to Boris Wirtz <Boris.Wirtz@uni-oldenburg.de>
   3.927 +        for the bug report.
   3.928 +
   3.929 +        * glpbfd.*, glpfhv.*, glplpf.*
   3.930 +        LP basis factorization routines were made tidy.
   3.931 +
   3.932 +        * glpk.h, glpapi04.c
   3.933 +        The following API routines were added:
   3.934 +        glp_set_rii, glp_set_sjj, glp_get_rii, glp_get_sjj.
   3.935 +
   3.936 +        * glpk.h, glpapi06.c
   3.937 +        The routine lpx_simplex was replaced by an equivalent routine
   3.938 +        glp_simplex. Also new API routine glp_init_smcp was added.
   3.939 +
   3.940 +        * glpk.h, glpapi09.c
   3.941 +        The following advanced API routines were added:
   3.942 +        glp_bf_exists, glp_factorize, glp_bf_updated, glp_get_bfcp,
   3.943 +        glp_set_bfcp, glp_get_bhead, glp_get_row_bind, glp_get_col_bind,
   3.944 +        glp_ftran, glp_btran.
   3.945 +
   3.946 +        * glpk.latex
   3.947 +        A new edition of the reference manual was included.
   3.948 +
   3.949 +        * examples/dea.mod, examples/food.mod, examples/food2.mod
   3.950 +        Three examples in the MathProg language were added.
   3.951 +        Thanks to Sebastian Nowozin <nowozin@gmail.com>.
   3.952 +
   3.953 +Sat May 26 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
   3.954 +
   3.955 +        * GLPK 4.17 (2:0:2) has been released
   3.956 +
   3.957 +        * glpdmp.h, glpdmp.c
   3.958 +        Memory pool routines were replaced by a new version.
   3.959 +
   3.960 +        * glpscs.h, glpscs.c
   3.961 +        Segmented string routines were replaced by a new version.
   3.962 +
   3.963 +        * glplpx08.c, glplpx09.c
   3.964 +        Now the MIP problem may have no integer columns.
   3.965 +
   3.966 +        * glpapi01.c
   3.967 +        The routines glp_set_mat_row, glp_set_mat_col, and glp_load_mat
   3.968 +        were modified to allow zero elements (which are not stored in
   3.969 +        the constraint matrix).
   3.970 +
   3.971 +        * glpscf.h, glpscf.c
   3.972 +        Schur complement factorization routines were implemented.
   3.973 +
   3.974 +        * glplpf.h, glplpf.c
   3.975 +        LP basis factorization routines based on LU-factorization and
   3.976 +        Schur complement were implemented.
   3.977 +
   3.978 +        * glplpx02.c, glplpx03.c
   3.979 +        New control parameter LPX_K_BFTYPE was introduced to choose the
   3.980 +        basis factorization type used by the simplex method routines.
   3.981 +
   3.982 +        * glpsol.c
   3.983 +        Three new command-line options were added to choose the basis
   3.984 +        factorization type used by the simplex method routines: --luf,
   3.985 +        --cbg, and --cgr.
   3.986 +
   3.987 +        * glpk.latex
   3.988 +        A new edition of the reference manual was included.
   3.989 +
   3.990 +Sat May 05 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
   3.991 +
   3.992 +        * GLPK 4.16 (1:0:1) has been released
   3.993 +
   3.994 +        * glpk.h, glpapi.c, glplpx01.c, glplpx02.c
   3.995 +        Names of a number basic api routines were changed and now have
   3.996 +        the prefix 'glp_'. To keep backward compatibility these routines
   3.997 +        are also available via their old names prefixed with 'lpx_'.
   3.998 +
   3.999 +        * glplpx19.c
  3.1000 +        Three new api routines were added: glp_version, glp_term_hook,
  3.1001 +        and glp_mem_usage.
  3.1002 +
  3.1003 +        * glpk.latex, gmpl.texi
  3.1004 +        A new edition of the reference manuals was included.
  3.1005 +
  3.1006 +        * lpglpk40.c
  3.1007 +        This example program is no longer supported and therefore was
  3.1008 +        removed from the package.
  3.1009 +
  3.1010 +Sun Feb 18 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.1011 +
  3.1012 +        * GLPK 4.15 (0:0:0) has been released
  3.1013 +
  3.1014 +        * configure.ac, Makefile.am
  3.1015 +        Autotools specification files were changed to use GNU Libtool
  3.1016 +        that allows building the static as well as shared GLPK library.
  3.1017 +        Thanks to Rafael Laboissiere <rafael@debian.org>.
  3.1018 +
  3.1019 +Mon Feb 05 08:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.1020 +
  3.1021 +        * GLPK 4.14 has been released
  3.1022 +        Now GLPK conforms to ILP32, LLP64, and LP64 programming models
  3.1023 +        (the latter seems to be the ultimate choice regarding 64-bit
  3.1024 +        architectures). Note that GLPK itself is a 32-bit application,
  3.1025 +        and the conformity only means that the package works correctly
  3.1026 +        on all these arenae. Nevertheless, on 64-bit platforms it is
  3.1027 +        possible to use more than 4GB of memory, if necessary.
  3.1028 +
  3.1029 +        * Makefile
  3.1030 +        Starting from this release only the header glpk.h is needed to
  3.1031 +        be installed.
  3.1032 +
  3.1033 +        * glplib01.c
  3.1034 +        Two routines bigmul and bigdiv which performs multiplication
  3.1035 +        and division of unsigned integers of arbitrary precision were
  3.1036 +        added.
  3.1037 +
  3.1038 +        * glplib02.c
  3.1039 +        A set of 64-bit arithmetic routines were added.
  3.1040 +
  3.1041 +        * glplib04.c
  3.1042 +        Some low-level library routines were improved and renamed.
  3.1043 +
  3.1044 +        * glpcfg.h
  3.1045 +        The macro GLP_TM_SPEC were introduced to specify a version of
  3.1046 +        the time routine depending on the host environment.
  3.1047 +
  3.1048 +Mon Nov 13 12:00:00 2006 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.1049 +
  3.1050 +        * GLPK 4.13 has been released
  3.1051 +
  3.1052 +        * configure.in
  3.1053 +        '-lm' bug was fixed.
  3.1054 +
  3.1055 +        * glpbfx.h, glpbfx.c
  3.1056 +        Basis factorization interface routines based on exact (bignum)
  3.1057 +        arithmetic were implemented.
  3.1058 +
  3.1059 +        * glpssx.h, glpssx1.c, glpssx2.c
  3.1060 +        Simplex method routines based on exact (bignum) arithmetic were
  3.1061 +        implemented.
  3.1062 +
  3.1063 +        * glplpx6e.c
  3.1064 +        The routine lpx_exact, which is an easy-to-use driver to the
  3.1065 +        exact simplex method, was added.
  3.1066 +
  3.1067 +        * glpsol.c
  3.1068 +        Two command-line options were added: '--exact' and '--xcheck'.
  3.1069 +
  3.1070 +Wed Nov 08 12:00:00 2006 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.1071 +
  3.1072 +        * GLPK 4.12 has been released
  3.1073 +
  3.1074 +        * glpcfg.h
  3.1075 +        The package configuration file was added.
  3.1076 +
  3.1077 +        * glplib2.c
  3.1078 +        Alternative version of the routines umalloc, ucalloc, and ufree
  3.1079 +        was provided. It does not limit the amount of allocated memory
  3.1080 +        to INT_MAX bytes and therefore can be used on platforms where
  3.1081 +        sizeof(void *) > sizeof(int). To enable this version one should
  3.1082 +        define the preprocessor variable GLP_HUGE_MEM.
  3.1083 +
  3.1084 +        * glprng.c
  3.1085 +        The routine rng_create_rand was changed to initialize the
  3.1086 +        generator using seed = 1, not 0, to conform ISO C requirements.
  3.1087 +
  3.1088 +        * glpgmp.h, glpgmp.c
  3.1089 +        A set of bignum arithmetic routines implementing operations on
  3.1090 +        integers and rationals was added. These routines are compatible
  3.1091 +        with the GNU MP library.
  3.1092 +
  3.1093 +        NOTE: To attain a much better performance it is recommended to
  3.1094 +        use, if possible, the original GNU MP library rather than the
  3.1095 +        GLPK version, by defining the preprocessor variable GLP_USE_GMP.
  3.1096 +
  3.1097 +        * glplux.h, glplux.c
  3.1098 +        A tentative implementation of sparse LU-factorization based on
  3.1099 +        exact (bignum) arithmetic was added.
  3.1100 +
  3.1101 +        * glpssx.h, glpssx.c
  3.1102 +        A tentative implementation of some simplex method routines based
  3.1103 +        on exact (bignum) arithmetic was added.
  3.1104 +
  3.1105 +        * glplpx6f.c
  3.1106 +        A preliminary implementation of the routine lpx_exact_check was
  3.1107 +        added. This routine checks the current basis for primal and dual
  3.1108 +        feasibility using exact (bignum) arithmetic.
  3.1109 +
  3.1110 +        * examples/glpsol.c
  3.1111 +        The command-line option '--xcheck' was introduced to check the
  3.1112 +        current basis for feasibility using exact (bignum) arithmetic.
  3.1113 +
  3.1114 +Tue Jul 25 12:00:00 2006 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.1115 +
  3.1116 +        * GLPK 4.11 has been released.
  3.1117 +
  3.1118 +        * include/glpbfi.h, src/glpbfi.c
  3.1119 +        Basis factorization interface routines were added.
  3.1120 +
  3.1121 +        * include/glpluf.h, src/glpluf1.c
  3.1122 +        Hypersparse solution routines were added.
  3.1123 +
  3.1124 +        * include/glpinv.h, src/glpinv1.c
  3.1125 +        Hypersparse solution routines (fake version) were added.
  3.1126 +
  3.1127 +        * include/glpmpl.h, src/glpmpl.c
  3.1128 +        Built-in functions card, length, and substr were implemented.
  3.1129 +        Output redirection in the printf statement was implemented.
  3.1130 +
  3.1131 +        * examples/graph.mod, examples/crypto.mod
  3.1132 +        Two example models illustrating new features of the modeling
  3.1133 +        language were included.
  3.1134 +
  3.1135 +Thu May 11 12:00:00 2006 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.1136 +
  3.1137 +        * GLPK 4.10 has been released.
  3.1138 +
  3.1139 +        * src/glplpx8a.c
  3.1140 +        A fragment was added to the routines lpx_read_mps and
  3.1141 +        lpx_read_freemps to accept LI bound type (it is similar to LO,
  3.1142 +        however, additionally marks the column as integer).
  3.1143 +
  3.1144 +        * include/glpbfi.h, src/glpbfi.c
  3.1145 +        The module glpbfi which implements the basis factorization
  3.1146 +        interface (BFI) was added.
  3.1147 +
  3.1148 +        * src/glplpx7a.c
  3.1149 +        The routine lpx_cover_cut to generate mixed cover cuts was
  3.1150 +        added.
  3.1151 +
  3.1152 +        * src/glplpx7b.c
  3.1153 +        The routine lpx_clique_cut to generate clique cuts and related
  3.1154 +        routines to maintain the conflict graph were added.
  3.1155 +
  3.1156 +        * include/glplpx.h, src/glplpx5.c
  3.1157 +        The routine lpx_cpx_basis implementing Bixby's algorithm to
  3.1158 +        construct an initial LP basis was added.
  3.1159 +
  3.1160 +        * examples/glpsol.c
  3.1161 +        Command-line option '--bib' was added which allows building
  3.1162 +        an initial LP basis using Bixby's algorithm.
  3.1163 +        Default command-line option '--mps' was changed to '--freemps'.
  3.1164 +
  3.1165 +        * examples/cf12a.mod, examples/cf12b.mod
  3.1166 +        Two examples in MathProg (curve fitting problem) were added.
  3.1167 +        Thanks to Dr. Harley Mackenzie <hjm@hardsoftware.com>.
  3.1168 +
  3.1169 +Tue Jan 17 12:00:00 2006 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.1170 +
  3.1171 +        * GLPK 4.9 has been released.
  3.1172 +
  3.1173 +        * glpipp.h, glpipp1.c, glpipp2.c
  3.1174 +        A MIP presolver were implemented (currently incomplete). It is
  3.1175 +        used internally in the routine lpx_intopt (see below).
  3.1176 +
  3.1177 +        * glplpx6d.c, glplpx7a.c
  3.1178 +        An advanced branch-and-bound solver (the routine lpx_intopt)
  3.1179 +        were implemented.
  3.1180 +
  3.1181 +        * glplpx6c.c
  3.1182 +        The routine lpx_check_int to check MIP feasibility conditions
  3.1183 +        was added.
  3.1184 +
  3.1185 +        * glplpx8a.c
  3.1186 +        The routine lpx_print_mip was changed to print MIP feasibility
  3.1187 +        conditions.
  3.1188 +
  3.1189 +        * glpmpl.h, glpmpl1.c, glpmpl3.c
  3.1190 +        The built-in functions sin, cos, atan, and atan2 were added to
  3.1191 +        the MathProg language.
  3.1192 +
  3.1193 +        * doc/lang.*
  3.1194 +        Some typos were fixed.
  3.1195 +        Thanks to Minh Ha Duong <haduong@centre-cired.fr> (CIRED, CNRS).
  3.1196 +
  3.1197 +Wed Jan 12 12:00:00 2005 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.1198 +
  3.1199 +        * GLPK 4.8 has been released.
  3.1200 +
  3.1201 +        * glpspx.h, glpspx1.c, glpspx2.c, glplpx6a.c
  3.1202 +        Simplex method routines were changed due to a new format of the
  3.1203 +        constraint matrix.
  3.1204 +
  3.1205 +        * glpmat.h, glpmat.c
  3.1206 +        Sparse matrix routines were re-implemented using storage-by-rows
  3.1207 +        format.
  3.1208 +
  3.1209 +        * glpipm.h, glpipm.c, glplpx6b.c
  3.1210 +        Interior-point method routines were changed due to a new format
  3.1211 +        of sparse matrices.
  3.1212 +
  3.1213 +        * glpchol.h, glpchol.c
  3.1214 +        Old version of Cholesky factorization routines being replaced by
  3.1215 +        a new one (see glpmat.c) was removed from the package.
  3.1216 +
  3.1217 +        * glplpx8c.c
  3.1218 +        Minor bug was fixed in api routine lpx_read_cpxlp.
  3.1219 +
  3.1220 +Mon Aug 23 12:00:00 2004 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.1221 +
  3.1222 +        * GLPK 4.7 has been released.
  3.1223 +
  3.1224 +        * glplpx.h, glplpx1.c
  3.1225 +        New core API routines were added (but not documented yet):
  3.1226 +        lpx_order_matrix, lpx_create_index, lpx_find_row, lpx_find_col,
  3.1227 +        lpx_delete_index.
  3.1228 +
  3.1229 +        * glplpx8a.c
  3.1230 +        API routine lpx_read_mps was re-implemented, and two new API
  3.1231 +        routines lpx_read_freemps and lpx_write_freemps were added to
  3.1232 +        support free MPS format.
  3.1233 +
  3.1234 +        * glplpx8c.c
  3.1235 +        Two API routines lpx_read_cpxlp and lpx_write_cpxlp (formerly
  3.1236 +        named lpx_read_lpt and lpx_write_lpt) were re-implemented.
  3.1237 +
  3.1238 +        * glpmps.h, glpmps.c
  3.1239 +        This module formerly used in lpx_read_mps was removed from the
  3.1240 +        package.
  3.1241 +
  3.1242 +        * glplpt.h, glplpt.c
  3.1243 +        This module formerly used in lpx_read_lpt was removed from the
  3.1244 +        package.
  3.1245 +
  3.1246 +        * glpmip.h, glpmip1.h, glpmip2.h
  3.1247 +        New MIP routines mip_best_node and mip_relative_gap were added
  3.1248 +        due to suggestion of Brady Hunsaker <hunsaker@engr.pitt.edu>.
  3.1249 +
  3.1250 +        * glpsol.c
  3.1251 +        The following new command-options were added:
  3.1252 +        --freemps  to read problem data in free MPS format
  3.1253 +        --wfreemps to write problem data in free MPS format
  3.1254 +        --cpxlp    to read problem data in CPLEX LP format
  3.1255 +        --wcpxlp   to write problem data in CPLEX LP format
  3.1256 +        --bas      to read LP basis from a text file in MPS format
  3.1257 +        --wbas     to write LP basis to a text file in MPS format
  3.1258 +        --mostf    to use "most fractional" branching heuristic
  3.1259 +        --bestb    to use "best bound" backtracking heuristic
  3.1260 +
  3.1261 +        * contrib/deli/*.*
  3.1262 +        GLPK Delphi interface module was temporarily removed from the
  3.1263 +        distribution due to licensing problems.
  3.1264 +
  3.1265 +        * contrib/glpkmex/*.*
  3.1266 +        GLPK Matlab interface module was temporarily removed from the
  3.1267 +        distribution due to licensing problems.
  3.1268 +
  3.1269 +        * contrib/jni/*.*
  3.1270 +        GLPK Java interface module was temporarily removed from the
  3.1271 +        distribution due to licensing problems.
  3.1272 +
  3.1273 +Wed Aug 04 12:00:00 2004 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.1274 +
  3.1275 +        * GLPK 4.6 has been released.
  3.1276 +
  3.1277 +        * glpmpl.h, glpmpl1.c, glpmpl2.c, glpmpl3.c, glpmpl4.c
  3.1278 +        Three new statements were implemented in the GNU MathProg
  3.1279 +        language: solve, printf, and for. Also some bugs were fixed.
  3.1280 +
  3.1281 +        * glplpx.h, glplpx8e.c
  3.1282 +        Two API routines were added: lpx_read_prob and lpx_write_prob,
  3.1283 +        which allow reading and writing problem data in GNU LP format.
  3.1284 +
  3.1285 +        * glpsol.c
  3.1286 +        Three new command-line options were added: --glp (to read
  3.1287 +        problem data in GNU LP format), --wglp (to write problem data
  3.1288 +        in GNU LP format), and --name (to change problem name).
  3.1289 +
  3.1290 +        * glprng.h, glprng.c
  3.1291 +        A portable pseudo-random number generator was implemented as a
  3.1292 +        separate module.
  3.1293 +
  3.1294 +        * glplib4.c
  3.1295 +        The old implementation of a pseudo-random number generator was
  3.1296 +        removed from the package.
  3.1297 +
  3.1298 +        * doc/lang.*, doc/refman.*
  3.1299 +        New edition of the GLPK documentation was included.
  3.1300 +
  3.1301 +        * contrib/glpkmex/*.*
  3.1302 +        A new version of GLPKMEX was included in the distribution. For
  3.1303 +        more details see contrib/glpkmex/ChangeLog.
  3.1304 +
  3.1305 +Mon Jul 19 12:00:00 2004 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.1306 +
  3.1307 +        * GLPK 4.5 has been released.
  3.1308 +
  3.1309 +        * glpmip.h, glpmip1.c, glpmip2.c, glplpx6c.c
  3.1310 +        New implementation of the branch-and-bound method was added.
  3.1311 +        It replaces the old implementation, which was removed from the
  3.1312 +        package.
  3.1313 +
  3.1314 +        * glpies.h, glpies1.c, glpies2.c, glpies3.c
  3.1315 +        Modules used in the old implementation of the branch-and-bound
  3.1316 +        method were removed from the package.
  3.1317 +
  3.1318 +        * glplib2.c
  3.1319 +        Now if the preprocessor variable GLPHUGEMEM is defined, other
  3.1320 +        version of the routines umalloc, ucalloc, and ufree is used on
  3.1321 +        compiling the package. This allows avoiding memory allocation
  3.1322 +        problems on platforms where sizeof(void *) > sizeof(int), for
  3.1323 +        example, where addresses are 64-bit while integers are 32-bit.
  3.1324 +        The modification was made due to a bug report provided by Karel
  3.1325 +        Zimmermann <kzimm@diamant.jouy.inra.fr> and Christophe Caron
  3.1326 +        <caron@diamant.jouy.inra.fr>.
  3.1327 +
  3.1328 +Sat Jan 17 12:00:00 2004 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.1329 +
  3.1330 +        * GLPK 4.4 has been released.
  3.1331 +
  3.1332 +        * glplpx.h, glplpx*.c
  3.1333 +        All API routines were re-implemented using new data structures.
  3.1334 +        Some new API routines were added and some existing API routines
  3.1335 +        became obsolete as shown below:
  3.1336 +
  3.1337 +        Obsolete API routine   Equivalent new API routine
  3.1338 +        lpx_check_name         (no more supported)
  3.1339 +        lpx_set_obj_c0         lpx_set_obj_coef
  3.1340 +        lpx_set_row_coef       (no more supported)
  3.1341 +        lpx_set_col_coef       lpx_set_obj_coef
  3.1342 +        lpx_load_mat           (no more supported)
  3.1343 +        lpx_load_mat3          lpx_load_matrix
  3.1344 +        lpx_unmark_all         (no more supported)
  3.1345 +        lpx_mark_row           (no more supported)
  3.1346 +        lpx_mark_col           (no more supported)
  3.1347 +        lpx_clear_mat          (no more supported)
  3.1348 +        lpx_del_items          lpx_del_rows, lpx_del_cols
  3.1349 +        lpx_get_row_bnds       lpx_get_row_type, lpx_get_row_lb,
  3.1350 +                               lpx_get_row_ub
  3.1351 +        lpx_get_col_bnds       lpx_get_col_type, lpx_get_col_lb,
  3.1352 +                               lpx_get_col_ub
  3.1353 +        lpx_get_obj_c0         lpx_get_obj_coef
  3.1354 +        lpx_get_row_coef       (no more supported)
  3.1355 +        lpx_get_col_coef       lpx_get_obj_coef
  3.1356 +        lpx_get_row_mark       (no more supported)
  3.1357 +        lpx_get_col_mark       (no more supported)
  3.1358 +        lpx_get_row_info       lpx_get_row_stat, lpx_get_row_prim,
  3.1359 +                               lpx_get_row_dual
  3.1360 +        lpx_get_col_info       lpx_get_col_stat, lpx_get_col_prim,
  3.1361 +                               lpx_get_col_dual
  3.1362 +        lpx_get_ips_stat       lpx_ipt_status
  3.1363 +        lpx_get_ips_row        lpx_ipt_row_prim, lpx_ipt_row_dual
  3.1364 +        lpx_get_ips_col        lpx_ipt_col_prim, lpx_ipt_col_dual
  3.1365 +        lpx_get_ips_obj        lpx_ipt_obj_val
  3.1366 +        lpx_get_mip_stat       lpx_mip_status
  3.1367 +        lpx_get_mip_row        lpx_mip_row_val
  3.1368 +        lpx_get_mip_col        lpx_mip_col_val
  3.1369 +        lpx_get_mip_obj        lpx_mip_obj_val
  3.1370 +
  3.1371 +        Obsolete API routines were kept for backward compatibility,
  3.1372 +        however, they will be removed in the future.
  3.1373 +
  3.1374 +        * doc/refman.*
  3.1375 +        New edition of the GLPK reference manual containing description
  3.1376 +        of all new API routines was included.
  3.1377 +
  3.1378 +        * contrib/glpkmex/*.*
  3.1379 +        GLPKMEX, a Matlab MEX interface to GLPK package, contributed by
  3.1380 +        Nicolo Giorgetti <giorgetti@dii.unisi.it> was included.
  3.1381 +
  3.1382 +        * doc/GLPK_FAQ.txt
  3.1383 +        GLPK FAQ contributed by Harley Mackenzie <hjm@bigpond.com> was
  3.1384 +        included.
  3.1385 +
  3.1386 +Fri Dec 12 12:00:00 2003 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.1387 +
  3.1388 +        * GLPK 4.3 has been released.
  3.1389 +
  3.1390 +        * configure.in
  3.1391 +        The bug, due to which the standard math library is not linked on
  3.1392 +        some platforms, was fixed.
  3.1393 +
  3.1394 +        * glpmpl3.c
  3.1395 +        The bug (0 ** y) was fixed in the routine fp_power.
  3.1396 +
  3.1397 +        * glpmpl.h, glpmpl1.c, glpmpl3.c
  3.1398 +        Some new built-in functions (round, trunc, Irand224, Uniform01,
  3.1399 +        Uniform, Normal01, Normal) were added to the MathProg language.
  3.1400 +
  3.1401 +        * glpmpl1.c
  3.1402 +        The MathProg syntax was changed to allow writing 'subj to'.
  3.1403 +
  3.1404 +        * glplpx.h, glplpx1.c, glplpx2.c
  3.1405 +        The new api routine lpx_get_ray_info was added.
  3.1406 +
  3.1407 +        * glplpx8a.c
  3.1408 +        The api routine lpx_print_sol was changed to print the number of
  3.1409 +        non-basic variable, which causes primal unboundness.
  3.1410 +
  3.1411 +        * glpmps.c
  3.1412 +        The code was changed to avoid errors on compiling the package on
  3.1413 +        Mac OS X. Thanks to Andre Girard <andre@inrs-emt.uquebec.ca> for
  3.1414 +        the bug report.
  3.1415 +
  3.1416 +        * doc/lang.*, doc/refman.*
  3.1417 +        Several typos were fixed and some new material was added in the
  3.1418 +        glpk documentation.
  3.1419 +
  3.1420 +Fri Nov 14 12:00:00 2003 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.1421 +
  3.1422 +        * GLPK 4.2 has been released.
  3.1423 +
  3.1424 +        * glpiet.h, glpiet.c, glpios.h, glpios1.c, glpios2.c, glpios3.c
  3.1425 +        A preliminary implementation of the Integer Optimization Suite
  3.1426 +        (IOS) was included in the package. Eventually IOS will replace
  3.1427 +        the Implicit Enumeration Suite (IES).
  3.1428 +
  3.1429 +        * glplpx.h, glplpx6d.c
  3.1430 +        A dummy version of the integer optimization routine lpx_intopt
  3.1431 +        was included in the package. Later this routine will replace the
  3.1432 +        routine lpx_integer.
  3.1433 +
  3.1434 +        * examples/glpsol.c
  3.1435 +        A new command-line option --int-opt was added to the solver to
  3.1436 +        call lpx_intopt rather than lpx_integer.
  3.1437 +
  3.1438 +        * glpbcs.h, glpbcs1.c, glpbcs2.c
  3.1439 +        Being replaced by IOS routines (see above) the Branch-and-Cut
  3.1440 +        Framework (BCS) routines were removed from the package.
  3.1441 +
  3.1442 +        * examples/tspsol.c
  3.1443 +        Stand-alone Symmetric TSP solver was completely re-programmed
  3.1444 +        using IOS routines.
  3.1445 +
  3.1446 +        * glplib.h, glplib2.c, glplib4.c
  3.1447 +        The random-number generator was implemented. It is based on the
  3.1448 +        module GB_FLIB from the Stanford GraphBase originally developed
  3.1449 +        by Donald Knuth.
  3.1450 +
  3.1451 +        * glphbsm.c, glplpx8a.c, glpmps.c
  3.1452 +        All calls to fopen/fclose were replaced by corresponding calls
  3.1453 +        to ufopen/ufclose due to bug reports provided by Morten Welinder
  3.1454 +        <terra@gnu.org> and <jpark@sfwmd.gov>.
  3.1455 +
  3.1456 +        * glpmps.c
  3.1457 +        The code was made re-entrant.
  3.1458 +
  3.1459 +        * glplpx8b.c
  3.1460 +        API routine lpx_print_sens_bnds for bounds sensitivity analysis
  3.1461 +        contributed by Brady Hunsaker <hunsaker@engr.pitt.edu> was added
  3.1462 +        to the package. This feature is also available in glpsol via the
  3.1463 +        command-line option --bounds.
  3.1464 +
  3.1465 +        * contrib/jni/*.*
  3.1466 +        New version of GLPK JNI (Java Native Interface) contributed by
  3.1467 +        Chris Rosebrugh <cpr@pobox.com> was added to the package.
  3.1468 +
  3.1469 +        * contrib/deli/*.*
  3.1470 +        GLPK DELI (Delphi Interface) contributed by Ivo van Baren
  3.1471 +        <i.van.baren@freeler.nl> was added to the package.
  3.1472 +
  3.1473 +        * glplpx3.c
  3.1474 +        Default method to scale the problem was changed to equilibration
  3.1475 +        scaling (lp->scale = 1 in lpx_reset_parms).
  3.1476 +
  3.1477 +        * glplpx6a.c
  3.1478 +        Two minor (non-critical) typos were fixed due to report provided
  3.1479 +        by Andrew Hamilton-Wright <andrewhw@ieee.org>.
  3.1480 +
  3.1481 +        * glplpp2.c
  3.1482 +        An untested case (line 941) had been tested due to bug report
  3.1483 +        provided by Jiri Spitz <jiri.spitz@telecom.cz>.
  3.1484 +
  3.1485 +        * w32bc5.mak, w32vc6.mak, w32vc6d.mak, d32dmc.mak
  3.1486 +        Several makefiles were added to allow building GLPK library for
  3.1487 +        some non-GNU 32-bit platforms.
  3.1488 +
  3.1489 +Sat Aug 23 12:00:00 2003 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.1490 +
  3.1491 +        * GLPK 4.1 has been released.
  3.1492 +
  3.1493 +        * glpmpl1.c, glpmpl3.c
  3.1494 +        Some bugs were fixed in the MathProg translator due to the bug
  3.1495 +        reports provided by Giles Thompson <gwpt1@cus.cam.ac.uk>:
  3.1496 +        conditional set expressions were incorrectly parsed;
  3.1497 +        dimen attribute was not set by default when a set was used
  3.1498 +        recursively in its own declaration;
  3.1499 +        logical expressions ... in if ... then ... else ... did not
  3.1500 +        work;
  3.1501 +        displaying set expressions did not free memory allocated for
  3.1502 +        temporary results.
  3.1503 +
  3.1504 +        * glpmpl3.c (reduce_terms)
  3.1505 +        Implementation of summation of linear forms over domain was
  3.1506 +        improved to reduce complexity of that operation from O(n*n) to
  3.1507 +        O(n*log n). The improvement was made due to a report provided
  3.1508 +        by Sebastien de Menten <sdementen@hotmail.com>.
  3.1509 +
  3.1510 +        * glplpx6a.c (line 1056), glpmip1.c (line 641)
  3.1511 +        Two minor bugs were fixed due to the bug report provided by
  3.1512 +        Kendall Demaree <kendal.demaree@verizon.net>.
  3.1513 +
  3.1514 +        * glplpx.h, glplpx6a.c
  3.1515 +        The method of one artificial variable implemented in the routine
  3.1516 +        lpx_prim_art and used on the phase I in the glpk simplex solver
  3.1517 +        has a serious defect: for some lp instances it erroneously
  3.1518 +        reports that the problem has no primal feasible solution. This
  3.1519 +        error appears when the column of the artificial variable, which
  3.1520 +        enters the basis to make it primal feasible, has large
  3.1521 +        constraint coefficients, that leads to small reduced costs of
  3.1522 +        non-basic variables and premature termination of the search,
  3.1523 +        i.e. to wrong conclusion that the problem has no primal feasible
  3.1524 +        solution. To avoid this defect the routine lpx_prim_feas was
  3.1525 +        included. It implements the method of implicit artifical
  3.1526 +        variables (based on minimization of the sum of infeasibilities),
  3.1527 +        which is a bit slower but much more robust. The routine
  3.1528 +        lpx_prim_feas having the same functionality now is used instead
  3.1529 +        the routine lpx_prim_art.
  3.1530 +
  3.1531 +        * glpinv.h, glpinv.c
  3.1532 +        The test used in the routine inv_update to detect low accuracy
  3.1533 +        after updating LU-factorization of the basis matrix was replaced
  3.1534 +        by a new, more robust test.
  3.1535 +
  3.1536 +        * glplpx6c.c
  3.1537 +        Selecting an active node to be solved next in the routine
  3.1538 +        btrack_bestp was changed. Now, if any integer feasible solution
  3.1539 +        has not been found yet, the routine chooses an active node which
  3.1540 +        has the minimal sum of integer infeasibilities.
  3.1541 +
  3.1542 +        * glpmip.h, glpmip1.c
  3.1543 +        The additional flag int_obj was included in the structure
  3.1544 +        MIPTREE used by the branch-and-bound. This flag is set in the
  3.1545 +        routine mip_create_tree and used in the routine is_better. It
  3.1546 +        means that the objective is integral, i.e. depends only on
  3.1547 +        integer variables with integer objective coefficients. The test
  3.1548 +        used in the routine check_integrality was also replaced by a
  3.1549 +        new, more reasonable one.
  3.1550 +
  3.1551 +        * glplpx1.c
  3.1552 +        A minor bug was fixed in the routine lpx_check_name.
  3.1553 +
  3.1554 +        * glpmpl.h, glpmpl4.c, glplpx8d.c
  3.1555 +        The flag skip_data was added to the parameter list of the
  3.1556 +        routine mpl_read_model. If this flag is set, the data section
  3.1557 +        in the model file is ignored. Corresponding change was made in
  3.1558 +        the routine lpx_read_model. Now, if both model and data files
  3.1559 +        are specified, the data section in the model file is ignored.
  3.1560 +
  3.1561 +        * glplpx8c.c
  3.1562 +        A minor bug (wrong format used for writing free columns) in the
  3.1563 +        routine lpx_write_lpt was fixed due to the bug report provided
  3.1564 +        by Bernhard Schmidt <schmidt@math.uni-augsburg.de>
  3.1565 +
  3.1566 +        * sample/glpsol.c
  3.1567 +        The command-line parameter --tmlim, which allows limiting the
  3.1568 +        solution time, was added.
  3.1569 +
  3.1570 +        * doc/lang.*, doc/refman.*
  3.1571 +        New edition of the GLPK documentation was included.
  3.1572 +
  3.1573 +        * java-binding/*.*
  3.1574 +        New version of the GLPK JNI (Java Native Interface) package was
  3.1575 +        included in the distribution.
  3.1576 +
  3.1577 +        * sample/lpglpk40.c
  3.1578 +        A non-trivial example was added. It allows using GLPK as a base
  3.1579 +        LP solver for Concorde, a program for solving Traveling Salesman
  3.1580 +        Problem (TSP). For details see comments in lpglpk40.c.
  3.1581 +
  3.1582 +        * sample/*.mod
  3.1583 +        Some examples of LP and MIP models written in GNU MathProg were
  3.1584 +        added.
  3.1585 +
  3.1586 +Tue May 06 12:00:00 2003 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.1587 +
  3.1588 +        * GLPK 4.0 has been released.
  3.1589 +
  3.1590 +        * glpmpl.h, glpmpl1.c, glpmpl2.c, glpmpl3.c, glpmpl4.c
  3.1591 +        The model translator for the GNU MathProg modeling language was
  3.1592 +        implemented and included in the package.
  3.1593 +
  3.1594 +        * glplpx.h, glplpx8d.c
  3.1595 +        The api routine lpx_read_model, which is an interface to the
  3.1596 +        MathProg translator, was included in the package.
  3.1597 +
  3.1598 +        * glplpx.h, glplpx8a.c
  3.1599 +        The api routine lpx_print_prob for writing LP/MIP problem data
  3.1600 +        in plain text format was included in the package.
  3.1601 +
  3.1602 +        * sample/glpsol.c
  3.1603 +        New version of the GLPK stand-alone LP/MIP solver that supports
  3.1604 +        the GNU MathProg modeling language was implemented.
  3.1605 +
  3.1606 +        * doc/lang.latex, doc/lang.dvi, doc/lang.ps
  3.1607 +        The document "GLPK: Modeling Language GNU MathProg" was included
  3.1608 +        in the package.
  3.1609 +
  3.1610 +        * doc/refman.latex, doc/refman.dvi, doc/refman.ps
  3.1611 +        New edition of the GLPK Reference Manual was included in the
  3.1612 +        package.
  3.1613 +
  3.1614 +        * glplpx8c.c
  3.1615 +        A bug in the api routine lpx_write_lpt was fixed. Due to that
  3.1616 +        bug an addressing error occured in the routine if the objective
  3.1617 +        function has the non-zero constant term.
  3.1618 +
  3.1619 +        * glplan.h, glplan1.c, glplan2.c, glplan3.c, glplan4.c,
  3.1620 +        * glplan5.c, glplan6.c, glplan7.c, glplan8.c, glplpx8b.c
  3.1621 +        All modules of the translator for the GLPK/L modeling language
  3.1622 +        were removed from the package, because GLPK/L being completely
  3.1623 +        superseded by GNU MathProg is no more supported.
  3.1624 +
  3.1625 +Tue Mar 25 12:00:00 2003 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.1626 +
  3.1627 +        * GLPK 3.3 has been released.
  3.1628 +
  3.1629 +        * glplpp.h, glplpp1.c, glplpp2.c
  3.1630 +        An implementation of the built-in LP presolver was added to the
  3.1631 +        package.
  3.1632 +
  3.1633 +        * glplpx.h
  3.1634 +        The flag presol was added to the structure LPX. This flag tells
  3.1635 +        the lpx_simplex whether the built-in LP presolver should be used
  3.1636 +        or not. By default this flag is off. Also three macros (namely
  3.1637 +        LPX_E_NOPFS, LPX_E_NODFS, and LPX_K_PRESOL) that concern using
  3.1638 +        the LP presolver were introduced.
  3.1639 +
  3.1640 +        * glplpx3.c, glplpx6a.c
  3.1641 +        These modules was changed to use the built-in LP presolver.
  3.1642 +
  3.1643 +        * sample/glpsol.c
  3.1644 +        Command line options --presol and --nopresol that concern using
  3.1645 +        the LP presolver were added to the stand-alone LP/MIP solver.
  3.1646 +
  3.1647 +        * glplan1.c
  3.1648 +        This module was changed to allow declaring sets like A[1:10] in
  3.1649 +        the models written in the GLPK/L modeling language.
  3.1650 +
  3.1651 +        * doc/refman.latex, doc/lang.latex
  3.1652 +        New editions of the documents "GLPK User's Guide" and "GLPK/L
  3.1653 +        Modeling Language" were included in the distribution.
  3.1654 +
  3.1655 +        * java-binding/*.*
  3.1656 +        The package GLPK JNI (Java Native Interface) implementing Java
  3.1657 +        binding for GLPK was included in the distribution. This package
  3.1658 +        was developed and programmed by Yuri Victorovich <yuri@gjt.org>.
  3.1659 +
  3.1660 +Tue Feb 18 12:00:00 2003 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.1661 +
  3.1662 +        * GLPK 3.2.4 has been released.
  3.1663 +
  3.1664 +        * glplpx6b.c
  3.1665 +        The code was changed to allow auxiliary variables have non-zero
  3.1666 +        objective coefficients.
  3.1667 +
  3.1668 +        Also a minor bug was fixed (the constant term was not considered
  3.1669 +        on displaying the objective function value).
  3.1670 +
  3.1671 +        * sample/glpsol.c
  3.1672 +        The code was changed to fix a bug (the command-line option 'bfs'
  3.1673 +        was not recognized). The bug was fixed due to report provided by
  3.1674 +        Olivier <odwl@skynet.be>.
  3.1675 +
  3.1676 +        * glplpt.c
  3.1677 +        The code was changed to fix a bug (binary variables were treated
  3.1678 +        erroneously as integer ones).
  3.1679 +
  3.1680 +        * glplpx6b.c
  3.1681 +        The code was changed to fix a bug (variables that have no lower
  3.1682 +        bounds were incorrectly processed on converting to the standard
  3.1683 +        formulation). The bug was fixed due to report kindly provided by
  3.1684 +        Kjell Eikland <kjell.eikland@broadpark.no>.
  3.1685 +
  3.1686 +Mon Nov 11 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.1687 +
  3.1688 +        * GLPK 3.2.3 has been released.
  3.1689 +
  3.1690 +        * glpmip.h, glpmip1.c
  3.1691 +        A preliminary implementation of the branch-and-bound driver
  3.1692 +        based on the implicit enumeration suite (glpies) was added to
  3.1693 +        the package. This module is not documented yet.
  3.1694 +
  3.1695 +        * glplpx6c.c
  3.1696 +        A new implementation of the api routine lpx_integer which now
  3.1697 +        is based on the b&b driver (see glpmip above) was included in
  3.1698 +        the package. This new implementation has exactly the same
  3.1699 +        functionality as the old version and therefore all changes are
  3.1700 +        transparent to the api user.
  3.1701 +
  3.1702 +        * glpbbm.h, glpbbm.c
  3.1703 +        * glprsm.h, glprsm1.c, glprsm2.c
  3.1704 +        * glplp.h, glplp.c
  3.1705 +        These modules were removed from the package, because they were
  3.1706 +        used only in the old version of the routine lpx_integer, which
  3.1707 +        was replaced by the new version (see glplpx6c above).
  3.1708 +
  3.1709 +        * glplpx.h, glplpx6a.c
  3.1710 +        The api routine lpx_check_kkt was included in the package and
  3.1711 +        its description was added in the reference manual. This routine
  3.1712 +        allows checking Karush-Kuhn-Tucker optimality conditions for an
  3.1713 +        LP solution.
  3.1714 +
  3.1715 +        * glplpx.h, glplpx8a.c
  3.1716 +        Now the api routine lpx_print_sol also prints information about
  3.1717 +        "solution quality" obtained via the api routine lpx_check_kkt.
  3.1718 +
  3.1719 +        * glplpx.h, glplpx8a.c
  3.1720 +        New api routines lpx_read_bas and lpx_write_bas were included
  3.1721 +        in the package and documented. The routine lpx_write_bas allows
  3.1722 +        writing a current basis from an LP object to a text file in the
  3.1723 +        MPS format. The routine lpx_read_bas allows reading a basis
  3.1724 +        prepared in the MPS format from a text file into an LP object.
  3.1725 +
  3.1726 +        * glplpt.c
  3.1727 +        The parsing routine which reads LP problem data prepared in the
  3.1728 +        CPLEX LP format was modified to allow specifying lower bounds
  3.1729 +        of variables also in the form 'variable >= lower bound' (in the
  3.1730 +        bounds section). This modification was made due to a notice
  3.1731 +        provided by Ivan Luzzi <iluzzi@libero.it>.
  3.1732 +
  3.1733 +        * glplpx.h, glplpx8c.c
  3.1734 +        The api routine lpx_write_lpt which allows writing LP problem
  3.1735 +        data from an LP object to a text file using the CPLEX LP format
  3.1736 +        was included in the package and documented.
  3.1737 +
  3.1738 +        * glplpx.h, glplpx3.c
  3.1739 +        The control parameter LPX_K_LPTORIG that affects the behavior
  3.1740 +        of the api routine lpx_write_lpt was introduced.
  3.1741 +
  3.1742 +        * glplan6.c
  3.1743 +        The semantics of the language GLPK/L was changed to allow
  3.1744 +        selection in case when not all mute letters of a predicate (the
  3.1745 +        operand that follows the keyword 'where') are presented in a
  3.1746 +        parameter (the operand that precedes the keyword 'where'), i.e.
  3.1747 +        to allow writing something like this:
  3.1748 +            y[j] := sum(i, x[i] where p[i,j]);
  3.1749 +        The paragraph "Selection" in the langauge description (page 25)
  3.1750 +        was also correspondingly changed. This change of the language
  3.1751 +        semantics was undertaken due to a notice provided by Peter Lee
  3.1752 +        <plee@kinggee.com.au>.
  3.1753 +
  3.1754 +        * sample/hwd.lpm
  3.1755 +        A nice example of LP model written in GLPK/L and contributed by
  3.1756 +        Peter Lee <plee@kinggee.com.au> was included in the package.
  3.1757 +
  3.1758 +        * glplpx6b.c
  3.1759 +        The api routine lpx_interior was modified: a) to compute dual
  3.1760 +        values for all structural as well as auxiliary variables; b) to
  3.1761 +        allow specifying non-zero objective coefficients at auxiliary
  3.1762 +        variables.
  3.1763 +
  3.1764 +        * sample/glpsol.c
  3.1765 +        Three new command-line options were added to the solver, which
  3.1766 +        are: --plain, --orig, and --wrlpt.
  3.1767 +
  3.1768 +Mon Oct 14 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.1769 +
  3.1770 +        * GLPK 3.2.2 has been released.
  3.1771 +
  3.1772 +        * glplpt.h, glplpt.c
  3.1773 +        A module that reads LP/MIP problem data in CPLEX LP format was
  3.1774 +        implemented.
  3.1775 +
  3.1776 +        * glplpx8c.c
  3.1777 +        An api routine lpx_read_lpt that reads LP/MIP problem data in
  3.1778 +        CPLEX LP format was implemented.
  3.1779 +
  3.1780 +        * sample/glpsol.c, sample/plan.lpt
  3.1781 +        A new command-line option '--lpt' that allows reading LP/MIP
  3.1782 +        problem data in CPLEX LP format was added to the solver.
  3.1783 +
  3.1784 +        * doc/refman.latex, doc/refman.dvi, doc/refman.ps
  3.1785 +        A new edition of the Reference Manual was included.
  3.1786 +
  3.1787 +        * source/*.c
  3.1788 +        Casting to (unsigned char) was added in some calls to the
  3.1789 +        classification functions (isalpha, etc.). The bug was fixed due
  3.1790 +        to report provided by Morten Welinder <terra@diku.dk>.
  3.1791 +
  3.1792 +        * glplpx8a.c
  3.1793 +        The local routine mps_numb used in the routine lpx_write_mps
  3.1794 +        was modified to correctly format floating-point numbers that
  3.1795 +        have two digits in the decimal exponent. The bug was fixed due
  3.1796 +        to report provided by Vlahos Kiriakos <Kiriakos.Vlahos@gs.com>.
  3.1797 +
  3.1798 +        * glplan.h, glplan1.c, ..., glplan8.c
  3.1799 +        Several serious bugs were fixed in the language processor due
  3.1800 +        to reports provided by <NORBERT.PIOTROWSKI@LHSYSTEMS.COM>:
  3.1801 +        (a) a static search tree used to find sparse array elements was
  3.1802 +        sometimes overwritten that caused the message 'assertion failed'
  3.1803 +        to appear; the bug was fixed by creating separate search trees
  3.1804 +        in parsing routines; (b) a variable declared using the
  3.1805 +        predicate-controlled variable declaration statement had wrong
  3.1806 +        order of domain sets, because the variable array was built as
  3.1807 +        a copy of the predicate array; the bug was fixed by using the
  3.1808 +        internal routine transpose that coordinates mute letters (and
  3.1809 +        therefore domain sets) on copying sparse arrays; (c) sometimes
  3.1810 +        assignment statements like x[#a,#b,#c] := ... was incorrectly
  3.1811 +        processed; the bug was fixed by including an appropriate check
  3.1812 +        into the internal routine assign_stmt.
  3.1813 +
  3.1814 +        * glp_simplex.c
  3.1815 +        An additional check to see if all lower bounds are not greater
  3.1816 +        than corresponding upper bounds was included in the routine to
  3.1817 +        prevent wrong results to appear. Such incorrectness sometimes
  3.1818 +        was not detected, namely, when variables with such bounds were
  3.1819 +        non-basic and never entered the basis.
  3.1820 +
  3.1821 +        * glpspx1.c
  3.1822 +        Maximal number of simplex iterations before reinversion was
  3.1823 +        decreased from 100 to 50. This allowed to improve accuracy and,
  3.1824 +        that is more important, to reduce the solution time for many
  3.1825 +        serial lp problems approximately 1.5--2 times.
  3.1826 +
  3.1827 +        * glpspx2.c
  3.1828 +        A check to see if all elements in the column chosen to enter
  3.1829 +        the basis are close to zero in the routine spx_prim_chuzr was
  3.1830 +        temporarily removed because this check gave wrong conclusion in
  3.1831 +        case when the corresponding non-basic variable had zero column
  3.1832 +        in the constraint matrix. An analogous check to see if all
  3.1833 +        elements in the row chosen to leave the basis are close to zero
  3.1834 +        in the routine spx_dual_chuzc was also temporarily removed on
  3.1835 +        the same reason. The bug was fixed due to reports provided by
  3.1836 +        Flavio Keidi Miyazawa <fkm@ic.unicamp.br> and Vlahos Kiriakos
  3.1837 +        <Kiriakos.Vlahos@gs.com>.
  3.1838 +
  3.1839 +Mon Aug 12 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.1840 +
  3.1841 +        * GLPK 3.2.1 has been released.
  3.1842 +
  3.1843 +        * glpbcs.h, glpbcs1.c, glpbcs2.c
  3.1844 +        * glpies.h, glpies1.c, glpies2.c, glpies3.c
  3.1845 +        A preliminary implementation of the branch-and-cut framework
  3.1846 +        was included in the package.
  3.1847 +
  3.1848 +        * doc/brcut.txt
  3.1849 +        The document "GLPK: A Preliminary Implementation of the
  3.1850 +        Branch-And-Cut Framework" was included in the distribution.
  3.1851 +
  3.1852 +        * sample/tspsol.c
  3.1853 +        An illustrative program for solving symmetric TSP based on the
  3.1854 +        branch-and-cut method was included in the package.
  3.1855 +
  3.1856 +        * glpdmp.h, glpdmp.c
  3.1857 +        A new, re-enterable version of routines for managing dynamic
  3.1858 +        memory pools was included in the package.
  3.1859 +
  3.1860 +        * glpavl.h, glpavl.c
  3.1861 +        A new, re-enterable version of routines for managing AVL search
  3.1862 +        trees was included in the package.
  3.1863 +
  3.1864 +        * glplib.h, glplib2.c
  3.1865 +        Two new low-level routines ufopen and ufclose were included in
  3.1866 +        the package.
  3.1867 +
  3.1868 +        * glplpx.h, glplpx7.c
  3.1869 +        The following new api routines were added: lpx_eval_activity,
  3.1870 +        lpx_eval_red_cost, lpx_reduce_form, lpx_mixed_gomory.
  3.1871 +
  3.1872 +        * glptsp.h, glptsp.c
  3.1873 +        A module for reading TSP data using TSPLIB format was included
  3.1874 +        in the package.
  3.1875 +
  3.1876 +Mon Jul 15 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.1877 +
  3.1878 +        * GLPK 3.2 has been released.
  3.1879 +
  3.1880 +        * glplpx.h, glplpx1.c, glplpx2.c
  3.1881 +        The identifier 'class' (used as a member name in the structure
  3.1882 +        LPX and as an argument name in the routine lpx_set_class) was
  3.1883 +        changed to 'clss' in order to avoid conflicts with C++ reserved
  3.1884 +        words.
  3.1885 +
  3.1886 +        * glpk.h, glplpx.h, glplpx1.c, glplpx2.c, glplpx6a.c,
  3.1887 +        * glplpx6b.c, glplpx6c.c, glplpx7.c, glplpx8.c
  3.1888 +        The following new api routines were added: lpx_set_obj_name,
  3.1889 +        lpx_get_obj_name, lpx_get_row_mark, lpx_get_col_mark,
  3.1890 +        lpx_transform_row, lpx_transform_col, lpx_prim_ratio_test,
  3.1891 +        lpx_dual_ratio_test, lpx_interior, lpx_get_ips_stat,
  3.1892 +        lpx_get_ips_row, lpx_get_ips_col, lpx_get_ips_obj, lpx_read_lpm,
  3.1893 +        lpx_write_mps, lpx_print_ips.
  3.1894 +
  3.1895 +        * glpsol.c
  3.1896 +        The solver was completely re-programmed using new api routines.
  3.1897 +
  3.1898 +        * lang.latex, lang.dvi, lang.ps
  3.1899 +        New edition of the document "GLPK: Modeling Language GLPK/L"
  3.1900 +        was included in the distribution.
  3.1901 +
  3.1902 +        * refman.latex, refman.dvi, refman.ps
  3.1903 +        New edition of the document "GLPK: Reference Manual" (which
  3.1904 +        contains descriptions of all new api routines) was included in
  3.1905 +        the distribution.
  3.1906 +
  3.1907 +        * glpapi.h, glpapi1.c, glpapi2.c, glpapi3.c, glpapi4.c
  3.1908 +        These files (which contain old api routines) were removed from
  3.1909 +        the package.
  3.1910 +
  3.1911 +        * glpipm1.c, glpipm2.c
  3.1912 +        The file glpipm1.c was renamed to glpipm.c. The file glpipm2.c
  3.1913 +        was used only by old api routines and therefore was removed from
  3.1914 +        the package.
  3.1915 +
  3.1916 +        * language.texinfo
  3.1917 +        Old version of the document "GLPK: Modeling Language GLPK/L" was
  3.1918 +        removed from the distribution.
  3.1919 +
  3.1920 +Mon May 27 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.1921 +
  3.1922 +        * GLPK 3.1 has been released.
  3.1923 +
  3.1924 +        * glplpx.h, glplpx1.c, glplpx2.c, glplpx3.c, glplpx4.c,
  3.1925 +        * glplpx5.c, glplpx6.c, glplpx7.c, glplpx8.c
  3.1926 +        A preliminary implementation of new API routines was completed.
  3.1927 +
  3.1928 +        * refman.latex, refman.dvi, refman.ps
  3.1929 +        A draft edition of the document "GLPK Reference Manual", which
  3.1930 +        describes new API routines, was included.
  3.1931 +
  3.1932 +        * glplib3.c
  3.1933 +        A bug in measuring long time intervals was fixed up.
  3.1934 +
  3.1935 +        * glprsm3.c
  3.1936 +        This module contains some obsolete routines not longer used and
  3.1937 +        therefore it was removed from the package (into the subdirectory
  3.1938 +        'oldsrc').
  3.1939 +
  3.1940 +        * glprsm.h
  3.1941 +        Some declarations related to the module 'glprsm3.c' (see above)
  3.1942 +        were removed.
  3.1943 +
  3.1944 +        * guide.texinfo
  3.1945 +        The document "GLPK User's Guide" describing old API routines was
  3.1946 +        removed from the package (into the subdirectory 'oldsrc').
  3.1947 +
  3.1948 +        * newapi.txt
  3.1949 +        The document "New GLPK API Routines" was removed at all, because
  3.1950 +        it is superseded by the new reference manual (see above).
  3.1951 +
  3.1952 +Mon May 13 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.1953 +
  3.1954 +        * GLPK 3.0.8 has been released.
  3.1955 +
  3.1956 +        * glplpx.h, glplpx1.c, glplpx2.c, glplpx3.c, glplpx4.c,
  3.1957 +        * glplpx5.c, glplpx6.c, glplpx7.c
  3.1958 +        A preliminary (currently incomplete) implementation of new api
  3.1959 +        routines was included.
  3.1960 +
  3.1961 +        * sample/newsamp.c
  3.1962 +        A sample program for the new api routines was included.
  3.1963 +
  3.1964 +        * newapi.txt
  3.1965 +        A draft of the document "New GLPK API Routines" was included.
  3.1966 +
  3.1967 +        * glpapi2.c, glpapi5.c, glpapi6.c
  3.1968 +        These modules (which contain the api routines glp_call_rsm1,
  3.1969 +        glp_simplex1, glp_pivot_in, glp_pivot_out) were removed from the
  3.1970 +        package (to the subdirectory 'oldsrc') since these routines are
  3.1971 +        functionally superseded by the new api routines.
  3.1972 +
  3.1973 +        * glpk.h, glpapi2.c, glpapi3.c, glpapi4.c
  3.1974 +        The api routines glp_simplex2, glp_call_ipm1, glp_call_bbm1 were
  3.1975 +        renamed to glp_simplex, glp_interior, glp_integer, respectively.
  3.1976 +
  3.1977 +        * sample/glpsol.c
  3.1978 +        Some command-line options (which got obsolete due to the recent
  3.1979 +        changes in api) were excluded.
  3.1980 +
  3.1981 +        * doc/guide.texinfo
  3.1982 +        New edition of the document "GLPK User's Guide" was included in
  3.1983 +        the distribution to reflect the changes in some api routines.
  3.1984 +
  3.1985 +        * doc/libref.texinfo
  3.1986 +        This document was removed from the package (to the subdirectory
  3.1987 +        'oldsrc') since it describes the library routines, most of which
  3.1988 +        got obsolete and no longer used.
  3.1989 +
  3.1990 +        * Makefile.in
  3.1991 +        A minor bug was fixed up due to bug report from Hans Schwengeler
  3.1992 +        <Hans.Schwengeler@unibas.ch>.
  3.1993 +
  3.1994 +Mon Apr 22 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.1995 +
  3.1996 +        * GLPK 3.0.7 has been released.
  3.1997 +
  3.1998 +        * glpduff.h, glpduff.c, glpspx.h, glpspx1.c, glpspx2.c,
  3.1999 +        * glpapi7.c
  3.2000 +        These modules were replaced by a new implementation of the
  3.2001 +        simplex method and therefore they were removed from the package
  3.2002 +        (however they still can be found in the subdirectory 'oldsrc').
  3.2003 +
  3.2004 +        * glprsm1.c
  3.2005 +        The routine crash_aa was replaced by a new implementation and
  3.2006 +        therefore it was removed from the file 'glprsm1.c'.
  3.2007 +
  3.2008 +        * glplpx.h, glplpx.c, glpspx.h, glpspx1.c, glpspx2.c, glpspx3.c,
  3.2009 +        * glpspx4.c, glpapi7.c
  3.2010 +        New (currently incomplete) implementation of the simplex method
  3.2011 +        components was included in the package.
  3.2012 +
  3.2013 +Thu Mar 28 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.2014 +
  3.2015 +        * GLPK 3.0.6 has been released.
  3.2016 +
  3.2017 +        * glpluf.h, glpluf.c, glpinv.h, glpinv.c
  3.2018 +        New version of LU-factorization and basis maintenance routines
  3.2019 +        (based on Forrest-Tomlin updating technique) was implemented.
  3.2020 +
  3.2021 +        * glpeta.h, glpeta.c, glpfhv.h, glpfhv.c, glpgel.h, glpgel.c,
  3.2022 +        * glppfi.h, glppfi.c, glprfi.h, glprfi.c
  3.2023 +        These routines implement some other forms of the basis matrix.
  3.2024 +        Now they became obsolete being functionally superseded by the
  3.2025 +        new version of basis maintenance routines (see above) and were
  3.2026 +        removed from the package (however they still can be found in the
  3.2027 +        subdirectory 'oldsrc').
  3.2028 +
  3.2029 +        * glpbbm.c, glprsm.h, glprsm1.h, glprsm2.h, glpspx.h, glpspx2.c,
  3.2030 +        * glprsm2.c, glpsol.c
  3.2031 +        Necessary changes were made in order to use the new version of
  3.2032 +        basis maintenance routines.
  3.2033 +
  3.2034 +Tue Jan 29 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.2035 +
  3.2036 +        * GLPK 3.0.5 has been released.
  3.2037 +        Structure of the package was re-organized in order to simplify
  3.2038 +        its maintenance.
  3.2039 +
  3.2040 +        * doc/guide.texinfo
  3.2041 +        New edition of the document "GLPK User's Guide" was included in
  3.2042 +        the distribution. Now the document includes descriptions of some
  3.2043 +        additional API routines recently added to the package.
  3.2044 +
  3.2045 +        * doc/newapi.txt
  3.2046 +        The document "Additional GLPK API Routines" was removed from the
  3.2047 +        distribution, because the corresponding material was included in
  3.2048 +        the user's guide (see above).
  3.2049 +
  3.2050 +Mon Dec 10 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.2051 +
  3.2052 +        * GLPK 3.0.4 has been released.
  3.2053 +
  3.2054 +        * glpspx.h, glpspx1.c, glpspx2.c, glpapi/glp_simplex2.h
  3.2055 +        A new, more efficient version of the two-phase primal simplex
  3.2056 +        method was implemented (advanced initial basis, projected
  3.2057 +        steepest edge, recursive computations of solution components).
  3.2058 +
  3.2059 +        * glpapi/glp_call_bbm1.c
  3.2060 +        Now LP relaxation can be solved either using rsm1_driver(), or
  3.2061 +        using glp_simplex2(). The choice is controlled by the parameter
  3.2062 +        'meth' (a member of struct bbm1).
  3.2063 +
  3.2064 +        * sample/glpsol.c
  3.2065 +        The new implementation of the simplex method is now used by
  3.2066 +        default. The old version is available via --old-sim option.
  3.2067 +
  3.2068 +        * glpmat/gm_scaling.c
  3.2069 +        Now this routine displays only two lines: an initial "quality"
  3.2070 +        and a final "quality".
  3.2071 +
  3.2072 +        * glplp/prepro_lp.c
  3.2073 +        Identifiers 'fmin' and 'fmax' renamed to 'f_min' and 'f_max' in
  3.2074 +        order to avoid conflict with <math.h>. The bug was fixed due to
  3.2075 +        report provided by Sami Farin <sfarin@ratol.fi>.
  3.2076 +
  3.2077 +Wed Oct 03 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.2078 +
  3.2079 +        * GLPK 3.0.3 has been released.
  3.2080 +
  3.2081 +        * glprsm/harris_row.c, glprsm/harris_col.c
  3.2082 +        The relative tolerance used on the first pass of the two-pass
  3.2083 +        ratio test was replaced by the absolute tolerance.
  3.2084 +
  3.2085 +        * glprsm/rsm_primal.c, glprsm/rsm_feas.c, glprsm/rsm_dual.c
  3.2086 +        The absolute tolerance passed to the two-pass ratio test routine
  3.2087 +        was decaresed (for both primal and dual simplex).
  3.2088 +
  3.2089 +        These changes were made in order to improve numerical stability
  3.2090 +        of the simplex method.
  3.2091 +
  3.2092 +        * glprsm/glp_call_rsm1.c, glprsm/glp_call_bbm1.c,
  3.2093 +        * glprsm/glp_simplex1, glprsm/glp_pivoting.c
  3.2094 +        Default form of the inverse was changed from RFI to AFI.
  3.2095 +
  3.2096 +Mon Sep 24 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.2097 +
  3.2098 +        * GLPK 3.0.2 has been released.
  3.2099 +
  3.2100 +        * glpfhv.h, glpfhv.c
  3.2101 +        New version of the basis maintaining routines was implemented.
  3.2102 +        These routines, which are based on so called FHV-factorization
  3.2103 +        (a variety of LU-factorization) and Gustavson's data structures,
  3.2104 +        perform the main operations on the basis matrix faster at the
  3.2105 +        expense of some worsening numerical accuracy.
  3.2106 +
  3.2107 +        * glprsm.h, glprsm/afi.c
  3.2108 +        The routines, which implement AFI (Advanced Form of the
  3.2109 +        Inverse) based on FHV-factorization, were added to the package.
  3.2110 +        This new form is available via the parameter form = 3 (on API
  3.2111 +        level) or via the option --afi (in GLPSOL solver).
  3.2112 +
  3.2113 +        * EFI was renamed to PFI
  3.2114 +        In order to correct terminology the acronym EFI (Elimination
  3.2115 +        Form of the Inverse) was replaced by PFI (Product Form of the
  3.2116 +        Inverse) everywhere in the source code and the documentation.
  3.2117 +
  3.2118 +        * glpset/umalloc.c, glpset/ucalloc.c
  3.2119 +        * glpset/get_atom.c, glpset/get_atomv.c
  3.2120 +        These memory management routines were changed in order *not* to
  3.2121 +        clear allocated memory blocks by binary zeros.
  3.2122 +
  3.2123 +Wed Aug 01 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.2124 +
  3.2125 +        * GLPK 3.0.1 has been released.
  3.2126 +
  3.2127 +        * glpapi/old_api.c, glplp/extract_lp.c, store_lpsol.c
  3.2128 +        Old API routines were deleted from the package.
  3.2129 +
  3.2130 +        * include/glpk.h, include/glpapi.h, include/glplp.h
  3.2131 +        Specifications of old API routines and data structures were
  3.2132 +        removed from the headers.
  3.2133 +
  3.2134 +        * sample/glpsol.c
  3.2135 +        New version of the stand-alone solver GLPSOL that now uses new
  3.2136 +        API routines was implemented.
  3.2137 +
  3.2138 +        * glpapi/glp_set_row_fctr.c, glpapi/glp_set_col_fctr.c,
  3.2139 +        * glpapi/glp_get_row_fctr.c, glpapi/glp_get_col_fctr.c,
  3.2140 +        * glpapi/glp_scale_prob.c
  3.2141 +        Scaling routines were added.
  3.2142 +
  3.2143 +        * glpapi/glp_write_mps.c
  3.2144 +        The routine for writing problem data in MPS format was added.
  3.2145 +
  3.2146 +        * glpapi/glp_simplex1.c
  3.2147 +        Comprehensive driver to the simplex method was added.
  3.2148 +
  3.2149 +        * glpapi/glp_pivoting.c
  3.2150 +        The routines glp_pivot_in() and glp_pivot_out() intended for
  3.2151 +        basis maintaining were added.
  3.2152 +
  3.2153 +        * glprsm/create_rsm.c, glprsm/delete_rsm.c, glprsm/scale_rsm.c,
  3.2154 +        * glprsm/build_basis.c
  3.2155 +        Additional low level routines related to the simplex method
  3.2156 +        were added.
  3.2157 +
  3.2158 +        * glpk.h, glpapi.h, glprsm.h
  3.2159 +        Additional specifications for new routines and data structures
  3.2160 +        were added.
  3.2161 +
  3.2162 +        * sample/lpglpk30.c
  3.2163 +        A non-trivial example was added. It allows using GLPK as a base
  3.2164 +        LP solver for Concorde, a program for solving Traveling Salesman
  3.2165 +        Problem (TSP). For details see comments in 'lpglpk30.c'.
  3.2166 +
  3.2167 +        * doc/newapi.txt
  3.2168 +        The document "Additional GLPK API Routines" that describes some
  3.2169 +        new API routines was included.
  3.2170 +
  3.2171 +Thu Jul 19 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.2172 +
  3.2173 +        * GLPK 3.0 has been released.
  3.2174 +
  3.2175 +        Now GLPK is provided with new API, which is intended for using
  3.2176 +        the package in more complex algorithmic schemes.
  3.2177 +
  3.2178 +        * glpapi/old_api.c
  3.2179 +        All routines related to old API were gathered in one file named
  3.2180 +        'old_api.c'.
  3.2181 +
  3.2182 +        * glpapi/*.c
  3.2183 +        These routines that implement new API were added to the package.
  3.2184 +
  3.2185 +        * include/glpk.h, include/glpapi.h
  3.2186 +        Specifications of new API routines and data structures were
  3.2187 +        added to these headers. Specifications of old API routines and
  3.2188 +        data structures were locked by #ifdef GLP_OLD_API directive.
  3.2189 +
  3.2190 +        * doc/guide.texinfo
  3.2191 +        New edition of the document "GLPK User's Guide" that correspond
  3.2192 +        to new API was included.
  3.2193 +
  3.2194 +Thu Jun 14 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.2195 +
  3.2196 +        * GLPK 2.4.1 has been released.
  3.2197 +
  3.2198 +        * doc/glpk_ml.texinfo
  3.2199 +        The new document "Modeling Language GLPK/L" was included.
  3.2200 +
  3.2201 +        * doc/glpk_ug.texinfo
  3.2202 +        New edition of the document "GLPK User's Guide" was included.
  3.2203 +
  3.2204 +        * doc/language.txt
  3.2205 +        The preliminary document "GLPK/L Modeling Language: A Brief
  3.2206 +        description" was removed from the distribution, because it has
  3.2207 +        been replaced by the new document "Modeling Language GLPK/L".
  3.2208 +
  3.2209 +        * glplang/l_spar.c
  3.2210 +        The routine comparison() was re-programmed in order to
  3.2211 +        implement the relation operation as specified in the language
  3.2212 +        description.
  3.2213 +
  3.2214 +        * glpmip.h, glpmip/*.c
  3.2215 +        The partition 'glpmip' was renamed to 'glpbbm'.
  3.2216 +
  3.2217 +Thu May 10 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.2218 +
  3.2219 +        * GLPK 2.4 has been released.
  3.2220 +
  3.2221 +        Now GLPK includes an implementation of a preliminary version of
  3.2222 +        the GLPK/L modeling language.
  3.2223 +
  3.2224 +        * glplang.h, glplang/*.c
  3.2225 +        The header 'glplang.h' and a set of routines that implements
  3.2226 +        the GLPK/L language processor (the partition 'glplang') were
  3.2227 +        added to the package.
  3.2228 +
  3.2229 +        * doc/language.txt
  3.2230 +        The document "GLPK/L Modeling Language: A Brief Description
  3.2231 +        (Supplement to GLPK User's Guide)" in plain text format was
  3.2232 +        included in the package (see the file 'language.txt' in the
  3.2233 +        subdirectory 'doc' of the distribution).
  3.2234 +
  3.2235 +        * ex/model1.lpm, ex/model2.lpm
  3.2236 +        Two examples of model descriptions written in GLPK/L were added
  3.2237 +        to the package.
  3.2238 +
  3.2239 +        * sample/glpsol.c
  3.2240 +        This program was modified in order: a) to allow processing
  3.2241 +        model description written in GLPK/L; b) to allow solving pure
  3.2242 +        LP problem using the interior point method.
  3.2243 +
  3.2244 +        * sample/glpipm.c
  3.2245 +        This program was removed from the package, because its function
  3.2246 +        was passed to the GLPSOL solver.
  3.2247 +
  3.2248 +        * Makefile.in
  3.2249 +        This file was changed in order to install the GLPSOL solver
  3.2250 +        executable.
  3.2251 +
  3.2252 +Mon Apr 09 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.2253 +
  3.2254 +        * GLPK 2.3 has been released.
  3.2255 +
  3.2256 +        * glpmip.h, glpmip/*.c
  3.2257 +        These routines (that implement the branch-and-bound method) were
  3.2258 +        re-programmed in order to improve robustness of implementation.
  3.2259 +        In particular, heuristic routines were carried out from the main
  3.2260 +        driver routine.
  3.2261 +
  3.2262 +        Additional GLPK API routines were documented.
  3.2263 +
  3.2264 +        New edition of the document "GLPK User's Guide" was included in
  3.2265 +        the package.
  3.2266 +
  3.2267 +        The preliminary document "Mixed Integer Programming Using GLPK
  3.2268 +        Version 2.2 (Supplement to GLPK User's Guide)" was removed from
  3.2269 +        the package, because this material was included in GLPK User's
  3.2270 +        Guide.
  3.2271 +
  3.2272 +Thu Mar 15 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.2273 +
  3.2274 +        * GLPK 2.2 has been released.
  3.2275 +
  3.2276 +        Now GLPK includes a tentative implementation of the
  3.2277 +        branch-and-bound procedure based on the dual simplex method for
  3.2278 +        mixed integer linear programming (MIP).
  3.2279 +
  3.2280 +        The preliminary document "Mixed Integer Programming Using GLPK
  3.2281 +        Version 2.2 (Supplement to GLPK User's Guide)" was included into
  3.2282 +        the package in plain text format (see the file 'mip.txt' in the
  3.2283 +        subdirectory 'doc' of the distribution).
  3.2284 +
  3.2285 +        * glpmip.h, glpmip/*.c, glpapi/glp_integer.c
  3.2286 +        These routines (that implement the branch-and-bound method) were
  3.2287 +        added to the package.
  3.2288 +
  3.2289 +        * sample/glpsol.c
  3.2290 +        This program was modified in order to allow solving LP and MIP
  3.2291 +        problems.
  3.2292 +
  3.2293 +        * glprsm/rsm_primal.c, glprsm/rsm_dual.c, glprsm/rsm_feas.c,
  3.2294 +        * glprsm/rsm1_driver.c
  3.2295 +        These routines (which are drivers to basic components of the
  3.2296 +        revised simplex method) were added to the package.
  3.2297 +
  3.2298 +Mon Feb 19 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.2299 +
  3.2300 +        * GLPK 2.1 has been released.
  3.2301 +
  3.2302 +        * glprsm.h, glprsm/*.c
  3.2303 +        These routines (that implement components of the revised simplex
  3.2304 +        method) were re-programmed and documented.
  3.2305 +
  3.2306 +        The document "GLPK Implementation of the Revised Simplex Method"
  3.2307 +        was included into the package.
  3.2308 +
  3.2309 +Thu Jan 25 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.2310 +
  3.2311 +        * GLPK 2.0 has been released.
  3.2312 +
  3.2313 +        Now GLPK includes a tentative implementation of the primal-dual
  3.2314 +        interior point method for large-scale linear programming (for
  3.2315 +        more details see the file `NEWS' in the distribution). A number
  3.2316 +        of routines related to the interior point method were added to
  3.2317 +        the package.
  3.2318 +
  3.2319 +        * insist.c
  3.2320 +        The routine `insist' and the macro of the same name were
  3.2321 +        introduced into the package in order to replace the standard
  3.2322 +        macro `assert'. Some routines require the expression specified
  3.2323 +        in the `assert' macro to be evaluated, but compiling the package
  3.2324 +        with NDEBUG option prevents from that. This bug was fixed due to
  3.2325 +        bug report provided by Peter A. Huegler <phuegler@bsco.com>.
  3.2326 +
  3.2327 +        * Makefile.in
  3.2328 +        Minor bug was fixed due to a patch provided by Alexandre Oliva
  3.2329 +        <oliva@lsd.ic.unicamp.br>.
  3.2330 +
  3.2331 +Wed Jan 10 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.2332 +
  3.2333 +        * GLPK 1.1.2 has been released.
  3.2334 +
  3.2335 +        * umalloc.c, ufree.c, create_pool.c, get_atom.c, get_atomv.c
  3.2336 +        These routines were changed in order to fix a bug due to
  3.2337 +        report provided by Andrew Hood <ajhood@fl.net.au>. Because of
  3.2338 +        this bug data alignment error occured on the Sparc computer.
  3.2339 +
  3.2340 +Tue Dec 14 12:00:00 2000 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.2341 +
  3.2342 +        * GLPK 1.1.1 has been released.
  3.2343 +
  3.2344 +        Minor bug was fixed in `Makefile.in'.
  3.2345 +
  3.2346 +        GLPK Library Reference was included.
  3.2347 +
  3.2348 +Mon Nov 27 12:00:00 2000 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.2349 +
  3.2350 +        * GLPK 1.1 has been released.
  3.2351 +
  3.2352 +        Minor changes were made in order to co-ordinate GLPK routines
  3.2353 +        and their descriptions.
  3.2354 +
  3.2355 +        GLPK User's Guide was included.
  3.2356 +
  3.2357 +Fri Oct 20 12:00:00 2000 Andrew Makhorin <mao@mai2.rcnet.ru>
  3.2358 +
  3.2359 +        * GLPK 1.0 has been released.
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/INSTALL	Mon Dec 06 13:09:21 2010 +0100
     4.3 @@ -0,0 +1,209 @@
     4.4 +INSTALLING GLPK ON YOUR COMPUTER
     4.5 +********************************
     4.6 +
     4.7 +Unpacking the distribution file
     4.8 +-------------------------------
     4.9 +The GLPK package (like all other GNU software) is distributed in the
    4.10 +form of a packed archive. It is one file named `glpk-X.Y.tar.gz', where
    4.11 +`X' is the major version number and `Y' is the minor version number;
    4.12 +for example, the archive name might be `glpk-4.15.tar.gz'.
    4.13 +
    4.14 +In order to prepare the distribution for installation you should:
    4.15 +
    4.16 +1. Copy the GLPK distribution file to a working directory.
    4.17 +
    4.18 +2. Unpack the distribution file with the following command:
    4.19 +
    4.20 +      gzip -d glpk-X.Y.tar.gz
    4.21 +
    4.22 +   After unpacking the distribution file is automatically renamed to
    4.23 +   `glpk-X.Y.tar'.
    4.24 +
    4.25 +3. Unarchive the distribution file with the following command:
    4.26 +
    4.27 +      tar -x < glpk-X.Y.tar
    4.28 +
    4.29 +   It automatically creates the subdirectory `glpk-X.Y' containing the
    4.30 +   GLPK distribution.
    4.31 +
    4.32 +Configuring the package
    4.33 +-----------------------
    4.34 +After unpacking and unarchiving the GLPK distribution you should
    4.35 +configure the package, i.e. automatically tune it for your platform.
    4.36 +
    4.37 +Normally, you should just `cd' to the directory `glpk-X.Y' and run the
    4.38 +`configure' script, e.g.
    4.39 +
    4.40 +      ./configure
    4.41 +
    4.42 +The `configure' shell script attempts to guess correct values for
    4.43 +various system-dependent variables used during compilation. It uses
    4.44 +those values to create a `Makefile' in each directory of the package.
    4.45 +It also creates file `config.h' containing platform-dependent
    4.46 +definitions. Finally, it creates a shell script `config.status' that
    4.47 +you can run in the future to recreate the current configuration, a file
    4.48 +`config.cache' that saves the results of its tests to speed up
    4.49 +reconfiguring, and a file `config.log' containing compiler output
    4.50 +(useful mainly for debugging `configure').
    4.51 +
    4.52 +Running `configure' takes about a few seconds. While it is running, it
    4.53 +displays some messages that tell you what it is doing. If you don't want
    4.54 +to see the messages, run `configure' with its standard output redirected
    4.55 +to `dev/null'; for example, `./configure > /dev/null'.
    4.56 +
    4.57 +By default both static and shared versions of the GLPK library will be
    4.58 +compiled. Compilation of the shared librariy can be turned off by
    4.59 +specifying the `--disable-shared' option to `configure', e.g.
    4.60 +
    4.61 +      ./configure --disable-shared
    4.62 +
    4.63 +If you encounter problems building the library try using the above
    4.64 +option, because some platforms do not support shared libraries.
    4.65 +
    4.66 +The GLPK package has some optional features listed below. By default
    4.67 +all these features are disabled. To enable a feature the corresponding
    4.68 +option should be passed to the configure script.
    4.69 +
    4.70 +--with-gmp           Enable using the GNU MP bignum library
    4.71 +
    4.72 +   This feature allows the exact simplex solver to use the GNU MP
    4.73 +   bignum library. If it is disabled, the exact simplex solver uses the
    4.74 +   GLPK bignum module, which provides the same functionality as GNU MP,
    4.75 +   however, it is much less efficient.
    4.76 +
    4.77 +   For details about the GNU MP bignum library see its web page at
    4.78 +   <http://gmplib.org/>.
    4.79 +
    4.80 +--with-zlib          Enable using the zlib data compression library
    4.81 +
    4.82 +   This feature allows GLPK API routines and the stand-alone solver to
    4.83 +   read and write compressed data files performing compression and
    4.84 +   decompression "on the fly" (compressed data files are recognized by
    4.85 +   suffix `.gz' in the file name). It may be useful in case of large
    4.86 +   MPS files to save the disk space.
    4.87 +
    4.88 +   For details about the zlib compression library see its web page at
    4.89 +   <http://www.zlib.net/>.
    4.90 +
    4.91 +--enable-dl          The same as --enable-dl=ltdl
    4.92 +--enable-dl=ltdl     Enable shared library support (GNU)
    4.93 +--enable-dl=dlfcn    Enable shared library support (POSIX)
    4.94 +
    4.95 +   Currently this feature is only needed to provide dynamic linking to
    4.96 +   ODBC and MySQL shared libraries (see below).
    4.97 +
    4.98 +   For details about the GNU shared library support see the manual at
    4.99 +   <http://www.gnu.org/software/libtool/manual/>.
   4.100 +
   4.101 +--enable-odbc        Enable using ODBC table driver (libiodbc)
   4.102 +--enable-odbc=unix   Enable using ODBC table driver (libodbc)
   4.103 +
   4.104 +   This feature allows transmitting data between MathProg model objects
   4.105 +   and relational databases accessed through ODBC.
   4.106 +
   4.107 +   For more details about this feature see the supplement "Using Data
   4.108 +   Tables in the GNU MathProg Modeling Language" (doc/tables.*).
   4.109 +
   4.110 +--enable-mysql       Enable using MySQL table driver (libmysql)
   4.111 +
   4.112 +   This feature allows transmitting data between MathProg model objects
   4.113 +   and MySQL relational databases.
   4.114 +
   4.115 +   For more details about this feature see the supplement "Using Data
   4.116 +   Tables in the GNU MathProg Modeling Language" (doc/tables.*).
   4.117 +
   4.118 +Compiling the package
   4.119 +---------------------
   4.120 +Normally, you can compile (build) the package by typing the command:
   4.121 +
   4.122 +      make
   4.123 +
   4.124 +It reads `Makefile' generated by `configure' and performs all necessary
   4.125 +jobs.
   4.126 +
   4.127 +If you want, you can override the `make' variables CFLAGS and LDFLAGS
   4.128 +like this:
   4.129 +
   4.130 +      make CFLAGS=-O2 LDFLAGS=-s
   4.131 +
   4.132 +To compile the package in a different directory from the one containing
   4.133 +the source code, you must use a version of `make' that supports `VPATH'
   4.134 +variable, such as GNU `make'. `cd' to the directory where you want the
   4.135 +object files and executables to go and run the `configure' script.
   4.136 +`configure' automatically checks for the source code in the directory
   4.137 +that `configure' is in and in `..'. If for some reason `configure' is
   4.138 +not in the source code directory that you are configuring, then it will
   4.139 +report that it can't find the source code. In that case, run `configure'
   4.140 +with the option `--srcdir=DIR', where DIR is the directory that contains
   4.141 +the source code.
   4.142 +
   4.143 +Some systems require unusual options for compilation or linking that
   4.144 +the `configure' script does not know about. You can give `configure'
   4.145 +initial values for variables by setting them in the environment. Using
   4.146 +a Bourne-compatible shell, you can do that on the command line like
   4.147 +this:
   4.148 +
   4.149 +      CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
   4.150 +
   4.151 +Or on systems that have the `env' program, you can do it like this:
   4.152 +
   4.153 +      env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
   4.154 +
   4.155 +Here are the `make' variables that you might want to override with
   4.156 +environment variables when running `configure'.
   4.157 +
   4.158 +For these variables, any value given in the environment overrides the
   4.159 +value that `configure' would choose:
   4.160 +
   4.161 +CC:      C compiler program. The default is `cc'.
   4.162 +
   4.163 +INSTALL: Program used to install files. The default value is `install'
   4.164 +         if you have it, otherwise `cp'.
   4.165 +
   4.166 +For these variables, any value given in the environment is added to the
   4.167 +value that `configure' chooses:
   4.168 +
   4.169 +DEFS:    Configuration options, in the form `-Dfoo -Dbar ...'.
   4.170 +
   4.171 +LIBS:    Libraries to link with, in the form `-lfoo -lbar ...'.
   4.172 +
   4.173 +Checking the package
   4.174 +--------------------
   4.175 +To check the package, i.e. to run some tests included in the package,
   4.176 +you can use the following command:
   4.177 +
   4.178 +      make check
   4.179 +
   4.180 +Installing the package
   4.181 +----------------------
   4.182 +Normally, to install the GLPK package you should type the following
   4.183 +command:
   4.184 +
   4.185 +      make install
   4.186 +
   4.187 +By default, `make install' will install the package's files in
   4.188 +`usr/local/bin', `usr/local/lib', etc. You can specify an installation
   4.189 +prefix other than `/usr/local' by giving `configure' the option
   4.190 +`--prefix=PATH'. Alternately, you can do so by consistently giving a
   4.191 +value for the `prefix' variable when you run `make', e.g.
   4.192 +
   4.193 +      make prefix=/usr/gnu
   4.194 +      make prefix=/usr/gnu install
   4.195 +
   4.196 +After installing you can remove the program binaries and object files
   4.197 +from the source directory by typing `make clean'. To remove all files
   4.198 +that `configure' created (`Makefile', `config.status', etc.), just type
   4.199 +`make distclean'.
   4.200 +
   4.201 +The file `configure.ac' is used to create `configure' by a program
   4.202 +called `autoconf'. You only need it if you want to remake `configure'
   4.203 +using a newer version of `autoconf'.
   4.204 +
   4.205 +Uninstalling the package
   4.206 +------------------------
   4.207 +To uninstall the GLPK package, i.e. to remove all the package's files
   4.208 +from the system places, you can use the following command:
   4.209 +
   4.210 +      make uninstall
   4.211 +
   4.212 +========================================================================
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/Makefile.am	Mon Dec 06 13:09:21 2010 +0100
     5.3 @@ -0,0 +1,7 @@
     5.4 +## Process this file with automake to produce Makefile.in ##
     5.5 +
     5.6 +ACLOCAL_AMFLAGS=-I m4
     5.7 +
     5.8 +SUBDIRS = include src examples
     5.9 +
    5.10 +## eof ##
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/Makefile_MMIX	Mon Dec 06 13:09:21 2010 +0100
     6.3 @@ -0,0 +1,149 @@
     6.4 +# Build GLPK for MMIX with GCC cross-compiler
     6.5 +
     6.6 +#**********************************************************************#
     6.7 +# You can use this Makefile to build GLPK with GCC cross-compiler for  #
     6.8 +# MMIX. No configuring is needed.                                      #
     6.9 +#                                                                      #
    6.10 +# MMIX is a 64-bit RISC computer for the third millennium designed by  #
    6.11 +# Prof. Donald Knuth. For details see:                                 #
    6.12 +#                                                                      #
    6.13 +# http://www-cs-faculty.stanford.edu/~knuth/mmix.html                  #
    6.14 +# http://en.wikipedia.org/wiki/MMIX                                    #
    6.15 +# http://www.malgil.com/mmix                                           #
    6.16 +#                                                                      #
    6.17 +# The GNU MMIX compiler tool-suite (GCC backend, binutils, and newlib) #
    6.18 +# was developed by Hans-Peter Nilsson. You may follow his instructions #
    6.19 +# to build and install the MMIX tools; see:                            #
    6.20 +#                                                                      #
    6.21 +# http://bitrange.com/mmix/install.html                                #
    6.22 +#**********************************************************************#
    6.23 +
    6.24 +GCC = mmix-gcc
    6.25 +AR = mmix-ar
    6.26 +MMIX = mmix
    6.27 +CFLAGS = -O2
    6.28 +
    6.29 +OBJSET = \
    6.30 +src/glpapi01.o \
    6.31 +src/glpapi02.o \
    6.32 +src/glpapi03.o \
    6.33 +src/glpapi04.o \
    6.34 +src/glpapi05.o \
    6.35 +src/glpapi06.o \
    6.36 +src/glpapi07.o \
    6.37 +src/glpapi08.o \
    6.38 +src/glpapi09.o \
    6.39 +src/glpapi10.o \
    6.40 +src/glpapi11.o \
    6.41 +src/glpapi12.o \
    6.42 +src/glpapi13.o \
    6.43 +src/glpapi14.o \
    6.44 +src/glpapi15.o \
    6.45 +src/glpapi16.o \
    6.46 +src/glpapi17.o \
    6.47 +src/glpapi18.o \
    6.48 +src/glpapi19.o \
    6.49 +src/glpavl.o \
    6.50 +src/glpbfd.o \
    6.51 +src/glpbfx.o \
    6.52 +src/glpcpx.o \
    6.53 +src/glpdmp.o \
    6.54 +src/glpdmx.o \
    6.55 +src/glpenv01.o \
    6.56 +src/glpenv02.o \
    6.57 +src/glpenv03.o \
    6.58 +src/glpenv04.o \
    6.59 +src/glpenv05.o \
    6.60 +src/glpenv06.o \
    6.61 +src/glpenv07.o \
    6.62 +src/glpenv08.o \
    6.63 +src/glpfhv.o \
    6.64 +src/glpgmp.o \
    6.65 +src/glphbm.o \
    6.66 +src/glpini01.o \
    6.67 +src/glpini02.o \
    6.68 +src/glpios01.o \
    6.69 +src/glpios02.o \
    6.70 +src/glpios03.o \
    6.71 +src/glpios04.o \
    6.72 +src/glpios05.o \
    6.73 +src/glpios06.o \
    6.74 +src/glpios07.o \
    6.75 +src/glpios08.o \
    6.76 +src/glpios09.o \
    6.77 +src/glpios10.o \
    6.78 +src/glpios11.o \
    6.79 +src/glpios12.o \
    6.80 +src/glpipm.o \
    6.81 +src/glplib01.o \
    6.82 +src/glplib02.o \
    6.83 +src/glplib03.o \
    6.84 +src/glplpf.o \
    6.85 +src/glplpx01.o \
    6.86 +src/glplpx02.o \
    6.87 +src/glplpx03.o \
    6.88 +src/glpluf.o \
    6.89 +src/glplux.o \
    6.90 +src/glpmat.o \
    6.91 +src/glpmpl01.o \
    6.92 +src/glpmpl02.o \
    6.93 +src/glpmpl03.o \
    6.94 +src/glpmpl04.o \
    6.95 +src/glpmpl05.o \
    6.96 +src/glpmpl06.o \
    6.97 +src/glpmps.o \
    6.98 +src/glpnet01.o \
    6.99 +src/glpnet02.o \
   6.100 +src/glpnet03.o \
   6.101 +src/glpnet04.o \
   6.102 +src/glpnet05.o \
   6.103 +src/glpnet06.o \
   6.104 +src/glpnet07.o \
   6.105 +src/glpnet08.o \
   6.106 +src/glpnet09.o \
   6.107 +src/glpnpp01.o \
   6.108 +src/glpnpp02.o \
   6.109 +src/glpnpp03.o \
   6.110 +src/glpnpp04.o \
   6.111 +src/glpnpp05.o \
   6.112 +src/glpqmd.o \
   6.113 +src/glprgr.o \
   6.114 +src/glprng01.o \
   6.115 +src/glprng02.o \
   6.116 +src/glpscf.o \
   6.117 +src/glpscl.o \
   6.118 +src/glpsdf.o \
   6.119 +src/glpspm.o \
   6.120 +src/glpspx01.o \
   6.121 +src/glpspx02.o \
   6.122 +src/glpsql.o \
   6.123 +src/glpssx01.o \
   6.124 +src/glpssx02.o \
   6.125 +src/glptsp.o \
   6.126 +src/amd/amd_1.o \
   6.127 +src/amd/amd_2.o \
   6.128 +src/amd/amd_aat.o \
   6.129 +src/amd/amd_control.o \
   6.130 +src/amd/amd_defaults.o \
   6.131 +src/amd/amd_dump.o \
   6.132 +src/amd/amd_info.o \
   6.133 +src/amd/amd_order.o \
   6.134 +src/amd/amd_post_tree.o \
   6.135 +src/amd/amd_postorder.o \
   6.136 +src/amd/amd_preprocess.o \
   6.137 +src/amd/amd_valid.o \
   6.138 +src/colamd/colamd.o
   6.139 +
   6.140 +.c.o:
   6.141 +	$(GCC) $(CFLAGS) -Iinclude -Isrc -o $@ -c $<
   6.142 +
   6.143 +all: libglpk.a glpsol.mmo
   6.144 +
   6.145 +libglpk.a: $(OBJSET)
   6.146 +	$(AR) cru libglpk.a $(OBJSET)
   6.147 +
   6.148 +glpsol.mmo: examples/glpsol.o libglpk.a
   6.149 +	$(GCC) $(CFLAGS) -o glpsol.mmo examples/glpsol.o libglpk.a -lm
   6.150 +
   6.151 +check: glpsol.mmo
   6.152 +	$(MMIX) glpsol.mmo --mps examples/plan.mps
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/NEWS	Mon Dec 06 13:09:21 2010 +0100
     7.3 @@ -0,0 +1,1532 @@
     7.4 +GLPK 4.45 (release date: Dec 05, 2010)
     7.5 +
     7.6 +        This is a bug-fix release.
     7.7 +
     7.8 +        Several bugs/typos were fixed. Thanks to
     7.9 +        Xypron <xypron.glpk@gmx.de>,
    7.10 +        Robbie Morrison <robbie@actrix.co.nz>, and
    7.11 +        Ali Baharev <ali.baharev@gmail.com> for reports.
    7.12 +
    7.13 +        Some glpk documents was re-formatted and merged into a single
    7.14 +        document. Now the glpk documentation consists of the following
    7.15 +        three main documents (all included in the distribution):
    7.16 +
    7.17 +        GLPK: Reference Manual
    7.18 +
    7.19 +        GLPK: Graph and Network Routines
    7.20 +
    7.21 +        Modeling Language GNU MathProg: Language Reference
    7.22 +
    7.23 +GLPK 4.44 (release date: Jun 03, 2010)
    7.24 +
    7.25 +        The following suffixes for variables and constraints were
    7.26 +        implemented in the MathProg language:
    7.27 +
    7.28 +        .lb     (lower bound),
    7.29 +        .ub     (upper bound),
    7.30 +        .status (status in the solution),
    7.31 +        .val    (primal value), and
    7.32 +        .dual   (dual value).
    7.33 +
    7.34 +        Thanks to Xypron <xypron.glpk@gmx.de> for draft implementation
    7.35 +        and testing.
    7.36 +
    7.37 +        Now the MathProg language allows comment records (marked by
    7.38 +        '#' in the very first position) in CSV data files read with the
    7.39 +        table statements. Note that the comment records may appear only
    7.40 +        in the beginning of a CSV data file.
    7.41 +
    7.42 +        The API routine glp_cpp to solve the Critical Path Problem was
    7.43 +        added and documented.
    7.44 +
    7.45 +GLPK 4.43 (release date: Feb 20, 2010)
    7.46 +
    7.47 +        This is a maintainer release.
    7.48 +
    7.49 +        `configure.ac' was changed to allow building the package under
    7.50 +        Mac OS and Darwin with ODBC support.
    7.51 +        Thanks to Xypron <xypron.glpk@gmx.de> for suggestions and Noli
    7.52 +        Sicad <nsicad@gmail.com> for testing.
    7.53 +
    7.54 +        The SQL table driver was improved to process NULL data. Thanks
    7.55 +        to Xypron <xypron.glpk@gmx.de>.
    7.56 +
    7.57 +        Some bugs were fixed in the LP/MIP preprocessor.
    7.58 +
    7.59 +GLPK 4.42 (release date: Jan 13, 2010)
    7.60 +
    7.61 +        The following new API routines were added:
    7.62 +
    7.63 +        glp_check_dup         check for duplicate elements in sparse
    7.64 +                              matrix
    7.65 +        glp_sort_matrix       sort elements of the constraint matrix
    7.66 +        glp_read_prob         read problem data in GLPK format
    7.67 +        glp_write_prob        write problem data in GLPK format
    7.68 +        glp_analyze_bound     analyze active bound of non-basic variable
    7.69 +        glp_analyze_coef      analyze objective coefficient at basic
    7.70 +                              variable
    7.71 +        glp_print_ranges      print sensitivity analysis report (this
    7.72 +                              routine replaces lpx_print_sens_bnds and
    7.73 +                              makes it deprecated)
    7.74 +
    7.75 +        For description of these new routines and the GLPK LP/MIP
    7.76 +        format see a new edition of the reference manual included in
    7.77 +        the distribution. (Chapter "Graph and network API routines" was
    7.78 +        carried out from the main reference manual and included in the
    7.79 +        distribution as a separate document.)
    7.80 +
    7.81 +        The following new command-line options were added to the stand-
    7.82 +        alone solver glpsol:
    7.83 +        --glp filename        read problem data in GLPK format
    7.84 +        --wglp filename       write problem data in GLPK format
    7.85 +        --ranges filename     print sensitivity analysis report (this
    7.86 +                              option replaces --bounds)
    7.87 +
    7.88 +        Now all GLPK routines performing file I/O support special
    7.89 +        filenames "/dev/stdin", "/dev/stdout", and "/dev/stderr", which
    7.90 +        can be specified in the same way as regular filenames. This
    7.91 +        feature is plaform-independent.
    7.92 +
    7.93 +GLPK 4.41 (release date: Dec 21, 2009)
    7.94 +
    7.95 +        The following new API routies were added:
    7.96 +
    7.97 +        glp_transform_row     transform explicitly specified row
    7.98 +        glp_transform_col     transform explicitly specified column
    7.99 +        glp_prim_rtest        perform primal ratio test
   7.100 +        glp_dual_rtest        perform dual ratio test
   7.101 +
   7.102 +        For description of these new routines see a new edition of the
   7.103 +        reference manual included in the distribution.
   7.104 +
   7.105 +        The following API routines are deprecated: lpx_transform_row,
   7.106 +        lpx_transform_col, lpx_prim_ratio_test, lpx_dual_ratio_test.
   7.107 +
   7.108 +        Some improvements were made in the MIP solver (glp_intopt).
   7.109 +
   7.110 +        The SQL table driver used to read/write data in MathProg models
   7.111 +        was changed to allow multiple arguments separated by semicolon
   7.112 +        in SQL statements. Thanks to Xypron <xypron.glpk@gmx.de>.
   7.113 +
   7.114 +        Two new options were added to the glpsol stand-alone solver:
   7.115 +        --seed value (to initialize the pseudo-random number generator
   7.116 +        used in MathProg models with specified value), and
   7.117 +        --ini filename (to use a basis previously saved with -w option
   7.118 +        as an initial basis on solving similar LP's).
   7.119 +
   7.120 +        Two new MathProg example models were included. Thanks to
   7.121 +        Nigel Galloway <nigel_galloway@operamail.com> and Noli Sicad
   7.122 +        <nsicad@gmail.com> for contribution.
   7.123 +
   7.124 +        Scripts to build GLPK with Microsoft Visual Studio 2010 for
   7.125 +        both 32-bit and 64-bit Windows were included. Thanks to Xypron
   7.126 +        <xypron.glpk@gmx.de> for contribution and testing.
   7.127 +
   7.128 +GLPK 4.40 (release date: Nov 03, 2009)
   7.129 +
   7.130 +        The following new API routines were added:
   7.131 +
   7.132 +        glp_del_vertices      remove vertices from graph
   7.133 +        glp_del_arc           remove arc from graph
   7.134 +        glp_wclique_exact     find maximum weight clique with the exact
   7.135 +                              algorithm developed by Prof. P. Ostergard
   7.136 +        glp_read_ccdata       read graph in DIMACS clique/coloring
   7.137 +                              format
   7.138 +        glp_write_ccdata      write graph in DIMACS clique/coloring
   7.139 +                              format
   7.140 +
   7.141 +        For description of these new routines see a new edition of the
   7.142 +        reference manual included in the distribution.
   7.143 +
   7.144 +        The hybrid pseudocost branching heuristic was included in the
   7.145 +        MIP solver. It is available on API level (iocp.br_tech should
   7.146 +        be set to GLP_BR_PCH) and in the stand-alone solver glpsol
   7.147 +        (via the command-line option --pcost). This heuristic may be
   7.148 +        useful on solving hard MIP instances.
   7.149 +
   7.150 +        The branching heuristic by Driebeck and Tomlin (used in the
   7.151 +        MIP solver by default) was changed to switch to branching on
   7.152 +        most fractional variable if an lower bound of degradation of
   7.153 +        the objective is close to zero for all branching candidates.
   7.154 +
   7.155 +        A bug was fixed in the LP preprocessor (routine npp_empty_col).
   7.156 +        Thanks to Stefan Vigerske <stefan@math.hu-berlin.de> for the
   7.157 +        bug report.
   7.158 +
   7.159 +        A bug was fixed and some improvements were made in the FPUMP
   7.160 +        heuristic module. Thanks to Xypron <xypron.glpk@gmx.de>.
   7.161 +
   7.162 +        A bug was fixed in the API routine glp_warm_up (dual
   7.163 +        feasibility test was incorrect in maximization case). Thanks to
   7.164 +        Uday Venkatadri <Uday.Venkatadri@dal.ca> for the bug report.
   7.165 +
   7.166 +GLPK 4.39 (release date: Jul 26, 2009)
   7.167 +
   7.168 +        The following new API routines were added:
   7.169 +
   7.170 +        glp_warm_up           "warm up" LP basis
   7.171 +        glp_set_vertex_name   assign (change) vertex name
   7.172 +        glp_create_v_index    create vertex name index
   7.173 +        glp_find_vertex       find vertex by its name
   7.174 +        glp_delete_v_index    delete vertex name index
   7.175 +        glp_read_asnprob      read assignment problem data in DIMACS
   7.176 +                              format
   7.177 +        glp_write_asnprob     write assignment problem data in DIMACS
   7.178 +                              format
   7.179 +        glp_check_asnprob     check correctness of assignment problem
   7.180 +                              data
   7.181 +        glp_asnprob_lp        convert assignment problem to LP
   7.182 +        glp_asnprob_okalg     solve assignment problem with the
   7.183 +                              out-of-kilter algorithm
   7.184 +        glp_asnprob_hall      find bipartite matching of maxumum
   7.185 +                              cardinality with Hall's algorithm
   7.186 +
   7.187 +        Also were added some API routines to read plain data files.
   7.188 +
   7.189 +        The API routines glp_read_lp and glp_write_lp to read/write
   7.190 +        files in CPLEX LP format were re-implemented. Now glp_write_lp
   7.191 +        correctly writes double-bounded (ranged) rows by introducing
   7.192 +        slack variables rather than by duplicating the rows.
   7.193 +
   7.194 +        For description of these new routines see a new edition of the
   7.195 +        reference manual included in the distribution.
   7.196 +
   7.197 +        The 'xfree(NULL)' bug was fixed in the AMD routines. Thanks to
   7.198 +        Niels Klitgord <niels@bu.edu> for bug report.
   7.199 +
   7.200 +        The message "Crashing..." was changed to "Constructing initial
   7.201 +        basis..." due to suggestion by Thomas Kahle <tom111@gmx.de>.
   7.202 +
   7.203 +        Some typos were corrected in glpsol output messages. Thanks to
   7.204 +        Xypron <xypron.glpk@gmx.de> for patch.
   7.205 +
   7.206 +GLPK 4.38 (release date: May 02, 2009)
   7.207 +
   7.208 +        API routines glp_read_mps and glp_write_mps were improved.
   7.209 +
   7.210 +        Some improvements were made in the dual simplex routines.
   7.211 +
   7.212 +        Two external software modules AMD and COLAMD were included in
   7.213 +        the distribution (for more details please see src/amd/README
   7.214 +        and src/colamd/README). Now they are used in the interior-point
   7.215 +        solver to reorder the matrix prior to Cholesky factorization.
   7.216 +
   7.217 +        API routine glp_ipt_status may return two new statuses due to
   7.218 +        changes in the routine glp_interior. For details please see the
   7.219 +        reference manual included in the distribution.
   7.220 +
   7.221 +        A minor bug was fixed in the graph/network routines. Thanks to
   7.222 +        Nelson H. F. Beebe <beebe@math.utah.edu> for bug report.
   7.223 +
   7.224 +GLPK 4.37 (release date: Mar 29, 2009)
   7.225 +
   7.226 +        The 0-1 Feasibility Pump heuristic was included in the GLPK
   7.227 +        integer optimizer glp_intopt. On API level the heuristic can be
   7.228 +        enabled by setting the parameter fp_heur in glp_iocp to GLP_ON.
   7.229 +        This feature is also available in the solver glpsol through
   7.230 +        command-line option '--fpump'. For more details please see the
   7.231 +        reference manual included in the distribution.
   7.232 +
   7.233 +        The following new API routines were added:
   7.234 +
   7.235 +        glp_print_sol         write basic solution in printable format
   7.236 +        glp_print_ipt         write interior-point solution in printable
   7.237 +                              format
   7.238 +        glp_print_mip         write MIP solution in printable format
   7.239 +        glp_read_graph        read (di)graph from plain text file
   7.240 +        glp_write_graph       write (di)graph to plain text file
   7.241 +        glp_weak_comp         find all weakly connected components
   7.242 +        glp_strong_comp       find all strongly connected components
   7.243 +
   7.244 +        The following API routines are deprecated: lpx_print_sol,
   7.245 +        lpx_print_ips, lpx_print_mip, lpx_print_prob (the latter is
   7.246 +        equivalent to glp_write_lp).
   7.247 +
   7.248 +        A bug was fixed in the interior-point solver (glp_interior) to
   7.249 +        correctly compute dual solution components when the problem is
   7.250 +        scaled.
   7.251 +
   7.252 +        The files configure.ac and Makefile.am were changed:
   7.253 +        (a) to allow using autoreconf/autoheader;
   7.254 +        (b) to allow building the package in a directory other than its
   7.255 +            source directory.
   7.256 +        Thanks to Marco Atzeri <marco_atzeri@yahoo.it> for bug report.
   7.257 +
   7.258 +        An example model in the GNU MathProg language was added.
   7.259 +        Thanks to Larry D'Agostino <Larry.D'Agostino@gmacrescap.com> for
   7.260 +        contribution.
   7.261 +
   7.262 +GLPK 4.36 (release date: Feb 06, 2009)
   7.263 +
   7.264 +        The following new API routines were added to the package:
   7.265 +
   7.266 +        glp_mincost_okalg     find minimum-cost flow with out-of-kilter
   7.267 +                              algorithm
   7.268 +        glp_maxflow_ffalg     find maximal flow with Ford-Fulkerson
   7.269 +                              algorithm
   7.270 +
   7.271 +        For detailed description of these new routines and related data
   7.272 +        structures see chapter "Graph and Network API Routines" in a new
   7.273 +        edition of the reference manual included in the distribution.
   7.274 +
   7.275 +        The following two new command-line options were added to the
   7.276 +        solver glpsol:
   7.277 +
   7.278 +        --mincost             read min-cost flow data in DIMACS format
   7.279 +        --maxflow             read maximum flow data in DIMACS format
   7.280 +
   7.281 +        Duplicate symbols in the header glpk.h were removed to allow
   7.282 +        using swig.
   7.283 +        Thanks to Kelly Westbrooks <kellywestbrooks@yahoo.com> and
   7.284 +        Nigel Galloway <nigel_galloway@operamail.com> for suggestion.
   7.285 +
   7.286 +        A minor defect was fixed in the routine glp_write_lp.
   7.287 +        Thanks to Sebastien Briais <sbriais@free.fr> for bug report.
   7.288 +
   7.289 +        A minor bug was fixed in the SQL module.
   7.290 +        Thanks to Xypron <xypron.glpk@gmx.de> for patch.
   7.291 +
   7.292 +        Some new example models in the GNU MathProg modeling language
   7.293 +        were added. Thanks to Sebastian Nowozin <nowozin@gmail.com> and
   7.294 +        Nigel Galloway <nigel_galloway@operamail.com> for contribution.
   7.295 +
   7.296 +GLPK 4.35 (release date: Jan 09, 2009)
   7.297 +
   7.298 +        The following new API routines were added to the package:
   7.299 +
   7.300 +        glp_create_graph      create graph
   7.301 +        glp_set_graph_name    assign (change) graph name
   7.302 +        glp_add_vertices      add new vertices to graph
   7.303 +        glp_add_arc           add new arc to graph
   7.304 +        glp_erase_graph       erase graph content
   7.305 +        glp_delete_graph      delete graph
   7.306 +        glp_read_mincost      read minimum cost flow problem data in
   7.307 +                              DIMACS format
   7.308 +        glp_write_mincost     write minimum cost flow problem data in
   7.309 +                              DIMACS format
   7.310 +        glp_mincost_lp        convert minimum cost flow problem to LP
   7.311 +        glp_netgen            Klingman's network problem generator
   7.312 +        glp_gridgen           grid-like network problem generator
   7.313 +        glp_read_maxflow      read maximum flow problem data in DIMACS
   7.314 +                              format
   7.315 +        glp_write_maxflow     write maximum flow problem data in DIMACS
   7.316 +                              format
   7.317 +        glp_maxflow_lp        convert maximum flow problem to LP
   7.318 +        glp_rmfgen            Goldfarb's maximum flow problem generator
   7.319 +
   7.320 +        For detailed description of these new routines and related data
   7.321 +        structures see chapter "Graph and Network API Routines" in a new
   7.322 +        edition of the reference manual included in the distribution.
   7.323 +
   7.324 +        A minor change were made in the internal routine xputc. Thanks
   7.325 +        to Luiz Bettoni <bettoni@cpgei.ct.utfpr.edu.br> for suggestion.
   7.326 +
   7.327 +        A minor bug was fixed in the internal routine mpl_fn_time2str.
   7.328 +        Thanks to Stefan Vigerske <stefan@vigerske.de> for bug report.
   7.329 +
   7.330 +GLPK 4.34 (release date: Dec 04, 2008)
   7.331 +
   7.332 +        The GNU MathProg modeling language was supplemented with three
   7.333 +        new built-in functions:
   7.334 +
   7.335 +        gmtime    obtaining current calendar time
   7.336 +        str2time  converting character string to calendar time
   7.337 +        time2str  converting calendar time to character string
   7.338 +
   7.339 +        (Thanks to Xypron <xypron.glpk@gmx.de>.)
   7.340 +
   7.341 +        For detailed description of these functions see Appendix A in
   7.342 +        the document "Modeling Language GNU MathProg", a new edition of
   7.343 +        which was included in the distribution.
   7.344 +
   7.345 +        A bug was fixed in the MIP solver. Thanks to Nigel Galloway
   7.346 +        <nigel_galloway@operamail.com> for bug report.
   7.347 +
   7.348 +        A new makefile was added to build the GLPK DLL with Microsoft
   7.349 +        Visual Studio Express 2008 for 64-bit Windows. Thanks to Xypron
   7.350 +        <xypron.glpk@gmx.de> for contribution and testing.
   7.351 +
   7.352 +GLPK 4.33 (release date: Oct 30, 2008)
   7.353 +
   7.354 +        The following new API routines were added to the package:
   7.355 +        glp_copy_prob         copy problem object content
   7.356 +        glp_exact             solve LP in exact arithmetic
   7.357 +                              (makes lpx_exact deprecated)
   7.358 +        glp_get_unbnd_ray     determine variable causing unboundedness
   7.359 +                              (makes lpx_get_ray_info deprecated)
   7.360 +        glp_interior          solve LP with interior-point method
   7.361 +                              (makes lpx_interior deprecated)
   7.362 +
   7.363 +        The following new API routines for processing models written in
   7.364 +        the GNU Mathprog language were added to the package:
   7.365 +        glp_mpl_alloc_wksp    allocate the translator workspace
   7.366 +        glp_mpl_read_model    read and translate model section
   7.367 +        glp_mpl_read_data     read and translate data section
   7.368 +        glp_mpl_generate      generate the model
   7.369 +        glp_mpl_build_prob    build LP/MIP instance from the model
   7.370 +        glp_mpl_postsolve     postsolve the model
   7.371 +        glp_mpl_free_wksp     deallocate the translator workspace
   7.372 +        (These routines make lpx_read_model deprecated.)
   7.373 +
   7.374 +        For description of all these new API routines see the reference
   7.375 +        manual included in the distribution.
   7.376 +
   7.377 +        A crude implementation of CPLEX-like interface to GLPK API was
   7.378 +        added to the package. Currently it allows using GLPK as a core
   7.379 +        LP solver for Concorde, a well known computer code for solving
   7.380 +        the symmetric TSP. For details see examples/cplex/README.
   7.381 +
   7.382 +        Some bugs were fixed in the SQL table driver. Thanks to Xypron
   7.383 +        <xypron.glpk@gmx.de>.
   7.384 +
   7.385 +GLPK 4.32 (release date: Oct 03, 2008)
   7.386 +
   7.387 +        The following new features were included in the MIP solver
   7.388 +        (the API routine glp_intopt):
   7.389 +
   7.390 +        *  MIP presolver
   7.391 +        *  mixed cover cut generator
   7.392 +        *  clique cut generator
   7.393 +        *  Euclidean reduction of the objective value
   7.394 +
   7.395 +        Due to changes the routine glp_intopt may additionally return
   7.396 +        GLP_ENOPFS, GLP_ENODFS, and GLP_EMIPGAP.
   7.397 +
   7.398 +        The API routines lpx_integer are lpx_intopt are deprecated,
   7.399 +        since they are completely superseded by glp_intopt.
   7.400 +
   7.401 +        The following new branch-and-cut API routines were added:
   7.402 +        glp_ios_row_attr      determine additional row attributes
   7.403 +        glp_ios_pool_size     determine current size of the cut pool
   7.404 +        glp_ios_add_row       add constraint to the cut pool
   7.405 +        glp_ios_del_row       delete constraint from the cut pool
   7.406 +        glp_ios_clear_pool    delete all constraints from the cut pool
   7.407 +
   7.408 +        For description of these new routines see the reference manual
   7.409 +        included in the distribution.
   7.410 +
   7.411 +        The stand-alone solver glpsol was changed to allow multiple
   7.412 +        data files.
   7.413 +
   7.414 +        A new edition of the supplement "Using Data Tables in the GNU
   7.415 +        MathProg Modeling Language" was included.
   7.416 +
   7.417 +        As usual, some bugs were fixed (in the MathProg translator).
   7.418 +        Thanks to Xypron <xypron.glpk@gmx.de>.
   7.419 +
   7.420 +GLPK 4.31 (release date: Sep 02, 2008)
   7.421 +
   7.422 +        The core LP solver based on the dual simplex method was
   7.423 +        re-implemented and now it provides both phases I and II.
   7.424 +
   7.425 +        The following new API routines were added:
   7.426 +        glp_scale_prob  automatic scaling of problem data
   7.427 +        glp_std_basis   construct standard initial LP basis
   7.428 +        glp_adv_basis   construct advanced initial LP basis
   7.429 +        glp_cpx_basis   construct Bixby's initial LP basis
   7.430 +
   7.431 +        For description of these new routines see the reference manual
   7.432 +        included in the distribution.
   7.433 +
   7.434 +        The following API routines are deprecated:
   7.435 +        lpx_scale_prob, lpx_std_basis, lpx_adv_basis, lpx_cpx_basis.
   7.436 +
   7.437 +        Necessary changes were made in memory allocation routines to
   7.438 +        resolve portability issues for 64-bit platforms.
   7.439 +
   7.440 +        New version of the routine lpx_write_pb to write problem data
   7.441 +        in OPB (pseudo boolean format) was added to the package. Thanks
   7.442 +        to Oscar Gustafsson <oscarg@isy.liu.se> for the contribution.
   7.443 +
   7.444 +        Two new makefiles were added to build the package for 32- and
   7.445 +        64-bit Windows with Microsoft Visual Studio Express 2008.
   7.446 +        Thanks to Heinrich Schuchardt <heinrich.schuchardt@gmx.de> (aka
   7.447 +        Xypron) for the contribution and testing.
   7.448 +
   7.449 +        Two new makefiles were added to build the package with Digital
   7.450 +        Mars C/C++ 8.50 and Open Watcom C/C++ 1.6 (for 32-bit Windows).
   7.451 +
   7.452 +GLPK 4.30 (release date: Aug 13, 2008)
   7.453 +
   7.454 +        The core LP solver based on the primal simplex method was
   7.455 +        re-implemented to allow its further improvements. Currently the
   7.456 +        new version provides the same features as the old one, however,
   7.457 +        it is a bit faster and more numerically stable.
   7.458 +
   7.459 +        Some changes were made in the MathProg translator to allow <,
   7.460 +        <=, >=, and > on comparing symbolic values. Thanks to Heinrich
   7.461 +        Schuchardt <heinrich.schuchardt@gmx.de> for patches.
   7.462 +
   7.463 +        Internal routine set_d_eps in the exact LP solver was changed
   7.464 +        to prevent approximation errors in case of integral data.
   7.465 +        Thanks to Markus Pilz <pilz@cs.uni-bonn.de> for bug report.
   7.466 +
   7.467 +GLPK 4.29 (release date: Jul 06, 2008)
   7.468 +
   7.469 +        The configure script was changed to disable all optional
   7.470 +        features by default. For details please see file INSTALL.
   7.471 +
   7.472 +        The following new API routines were added:
   7.473 +        glp_erase_prob  erase problem object content
   7.474 +        glp_read_mps    read problem data in MPS format
   7.475 +        glp_write_mps   write problem data in MPS format
   7.476 +        glp_read_lp     read problem data in CPLEX LP format
   7.477 +        glp_write_lp    write problem data in CPLEX LP format
   7.478 +
   7.479 +        For description of these new routines see the reference manual
   7.480 +        included in the distribution.
   7.481 +
   7.482 +        The following API routines are deprecated:
   7.483 +        lpx_read_mps, lpx_read_freemps, lpx_write_mps,
   7.484 +        lpx_write_freemps, lpx_read_cpxlp, and lpx_write_cpxlp.
   7.485 +
   7.486 +        Two bugs were fixed. Thanks to
   7.487 +        Anne-Laurence Putz <anne-laurence.putz@eurodecision.com> and
   7.488 +        Xypron <xypron.glpk@gmx.de> for bug report.
   7.489 +
   7.490 +GLPK 4.28 (release date: Mar 25, 2008)
   7.491 +
   7.492 +        The iODBC and MySQL table drivers, which allows transmitting
   7.493 +        data between MathProg model objects and relational databases,
   7.494 +        were re-implemented to replace a static linking by a dynamic
   7.495 +        linking to corresponding shared libraries.
   7.496 +        Many thanks to Heinrich Schuchardt <heinrich.schuchardt@gmx.de>
   7.497 +        for the contribution, Rafael Laboissiere <rafael@debian.org>
   7.498 +        for useful advices concerning the shared library support under
   7.499 +        GNU/Linux, and Vijay Patil <vijay.patil@gmail.com> for testing
   7.500 +        this feature under Windows XP.
   7.501 +
   7.502 +        A new optional feature was added to the package. This feature
   7.503 +        is based on the zlib data compression library and allows GLPK
   7.504 +        API routines and the stand-alone solver to read and write
   7.505 +        compressed data files performing compression/decompression "on
   7.506 +        the fly" (compressed data files are recognized by suffix `.gz'
   7.507 +        in the file name). It may be useful in case of large MPS files
   7.508 +        to save the disk space (up to ten times).
   7.509 +
   7.510 +        The `configure' script was re-implemented. Now it supports the
   7.511 +        following specific options:
   7.512 +
   7.513 +        --with-gmp           Enable using the GNU MP bignum library
   7.514 +        --without-gmp        Disable using the GNU MP bignum library
   7.515 +        --with-zlib          Enable using the zlib data compression
   7.516 +                             library
   7.517 +        --without-zlib       Disable using the zlib data compression
   7.518 +                             library
   7.519 +        --enable-dl          Enable shared library support (auto check)
   7.520 +        --enable-dl=ltdl     Enable shared library support (GNU)
   7.521 +        --enable-dl=dlfcn    Enable shared library support (POSIX)
   7.522 +        --disable-dl         Disable shared library support
   7.523 +        --enable-odbc        Enable using ODBC table driver
   7.524 +        --disable-odbc       Disable using ODBC table driver
   7.525 +        --enable-mysql       Enable using MySQL table driver
   7.526 +        --disable-mysql      Disable using MySQL table driver
   7.527 +
   7.528 +        For more details please see file INSTALL.
   7.529 +
   7.530 +GLPK 4.27 (release date: Mar 02, 2008)
   7.531 +
   7.532 +        Three new table drivers were added to the MathProg translator:
   7.533 +
   7.534 +        xBASE built-in table driver, which allows reading and writing
   7.535 +        data in .dbf format (only C and N fields are supported);
   7.536 +
   7.537 +        MySQL table driver, which provides connection to a MySQL
   7.538 +        database;
   7.539 +
   7.540 +        iODBC table driver, which provides connection to a database
   7.541 +        through ODBC.
   7.542 +
   7.543 +        The MySQL and iODBC table drivers were contributed to GLPK by
   7.544 +        Heinrich Schuchardt <heinrich.schuchardt@gmx.de>.
   7.545 +
   7.546 +        The table driver is a program module which allows transmitting
   7.547 +        data between MathProg model objects and external data tables.
   7.548 +
   7.549 +        For detailed description of the table statement and table
   7.550 +        drivers see the document "Using Data Tables in the GNU MathProg
   7.551 +        Modeling Language" (file doc/tables.txt) included in the
   7.552 +        distribution. Some examples which demonstrate using MySQL and
   7.553 +        iODBC table drivers can be found in subdirectory examples/sql.
   7.554 +
   7.555 +GLPK 4.26 (release date: Feb 17, 2008)
   7.556 +
   7.557 +        The table statement was implemented in the GNU MathProg
   7.558 +        modeling language. This new feature allows reading data from
   7.559 +        external tables into model objects such as sets and parameters
   7.560 +        as well as writing results of computations to external tables.
   7.561 +
   7.562 +        A table is a (unordered) set of records, where each record
   7.563 +        consists of the same number of fields, and each field is
   7.564 +        provided with a unique symbolic name called the field name.
   7.565 +
   7.566 +        Currently the GLPK package has the only built-in table driver,
   7.567 +        which supports tables in the CSV (comma-separated values) file
   7.568 +        format. This format is very simple and supported by almost all
   7.569 +        spreadsheets and database management systems.
   7.570 +
   7.571 +        Detailed description of the table statement and CSV format can
   7.572 +        be found in file doc/tables.txt, included in the distribution.
   7.573 +
   7.574 +GLPK 4.25 (release date: Dec 19, 2007)
   7.575 +
   7.576 +        A tentative implementation of Gomory's mixed integer cuts was
   7.577 +        included in the branch-and-cut solver. To enable generating
   7.578 +        Gomory's cuts the control parameter gmi_cuts passed to the
   7.579 +        routine glp_intopt should be set to GLP_ON. This feature is
   7.580 +        also available in the solver glpsol through command-line option
   7.581 +        '--gomory'. For more details please see the reference manual
   7.582 +        included in the distribution.
   7.583 +
   7.584 +GLPK 4.24 (release date: Nov 21, 2007)
   7.585 +
   7.586 +        A tentative implementation of MIR (mixed integer rounding) cuts
   7.587 +        was included in the MIP solver. To enable generating MIR cuts
   7.588 +        the control parameter mir_cuts passed to the routine glp_intopt
   7.589 +        should be set to GLP_ON. This feature is also available in the
   7.590 +        stand-alone solver glpsol via command-line option '--mir'. For
   7.591 +        more details please see the reference manual included in the
   7.592 +        distribution.
   7.593 +
   7.594 +        The implementation is mainly based on the following two papers:
   7.595 +
   7.596 +        1. H. Marchand and L. A. Wolsey. Aggregation and mixed integer
   7.597 +           rounding to solve MIPs. CORE discussion paper 9839, CORE,
   7.598 +           Universite catholique de Louvain, June 1998.
   7.599 +
   7.600 +        2. G. Andreello, A. Caprara, and M. Fischetti. Embedding cuts
   7.601 +           in a Branch&Cut framework. Preliminary draft, October 2003.
   7.602 +
   7.603 +        MIR cuts can be generated on any level of the search tree that
   7.604 +        makes the GLPK MIP solver to be a real branch-and-cut solver.
   7.605 +
   7.606 +        A bug was fixed in the routine lpx_write_cpxlp. If a variable
   7.607 +        x has upper bound and no lower bound, it should appear in the
   7.608 +        bounds section as "-inf <= x <= u", not as "x <= u". Thanks to
   7.609 +        Enric Rodriguez <erodri@lsi.upc.edu> for the bug report.
   7.610 +
   7.611 +GLPK 4.23 (release date: Oct 28, 2007)
   7.612 +
   7.613 +        The following new API routines were added:
   7.614 +
   7.615 +        glp_read_sol    read basic solution from text file
   7.616 +        glp_write_sol   write basic solution to text file
   7.617 +        glp_read_ipt    read interior-point solution from text file
   7.618 +        glp_write_ipt   write interior-point solution to text file
   7.619 +        glp_read_mip    read MIP solution from text file
   7.620 +        glp_write_mip   write MIP solution to text file
   7.621 +
   7.622 +        For description of these routines and corresponding file
   7.623 +        formats see Chapter "API Routines", Section "Utility routines"
   7.624 +        in the reference manual included in the distribution.
   7.625 +
   7.626 +        Advanced API routine glp_free_env was added. It may be used by
   7.627 +        the application program to free all resources allocated by GLPK
   7.628 +        routines.
   7.629 +
   7.630 +        The following three new command-line options were added to the
   7.631 +        solver glpsol:
   7.632 +
   7.633 +        --mipgap tol    set relative MIP gap tolerance
   7.634 +        -r filename     read solution from filename
   7.635 +        -w filename     write solution to filename
   7.636 +
   7.637 +GLPK 4.22 (release date: Sep 19, 2007)
   7.638 +
   7.639 +        This is a maintainer release.
   7.640 +
   7.641 +        A bug was fixed in the MIP preprocessor (ios_preprocess_node).
   7.642 +        Thanks to Roberto Bagnara <bagnara@cs.unipr.it> (Department of
   7.643 +        Mathematics, University of Parma, Italy) for the bug report.
   7.644 +
   7.645 +        A bug was fixed in the MIP preprocessor (col_implied_bounds),
   7.646 +        due to which constraint coefficients with small magnitude could
   7.647 +        lead to wrong implied bounds of structural variables.
   7.648 +
   7.649 +        A similar bug was fixed in the routine reduce_bounds.
   7.650 +
   7.651 +        A bug was fixed in the routines glp_set_mat_row and
   7.652 +        glp_set_mat_col. (The bug appeared due to incorrect removing
   7.653 +        zero elements from the row/column lists.)
   7.654 +
   7.655 +        A bug was fixed in the API routines lpx_read_mps and
   7.656 +        lpx_read_freemps, due to which bounds of type LI specified in
   7.657 +        BOUNDS section were incorrectly processed.
   7.658 +
   7.659 +        A call to standard function vsprintf was replaced by a call to
   7.660 +        vsnprintf for security reasons. Many thanks to Peter T. Breuer
   7.661 +        <ptb@inv.it.uc3m.es> and Rafael Laboissiere <rafael@debian.org>.
   7.662 +
   7.663 +GLPK 4.21 (release date: Aug 28, 2007)
   7.664 +
   7.665 +        Additional reasons for calling the callback routine used in the
   7.666 +        MIP solver (glp_intopt) were introduced. Currently the following
   7.667 +        reasons are supported:
   7.668 +
   7.669 +        * request for subproblem selection
   7.670 +        * request for preprocessing
   7.671 +        * request for row generation
   7.672 +        * request for heuristic solution
   7.673 +        * request for cut generation
   7.674 +        * request for branching
   7.675 +        * better integer solution found
   7.676 +
   7.677 +        A basic preprocessing component used to improve subproblem
   7.678 +        formulations by tightening bounds of variables was included in
   7.679 +        the MIP solver. Depending on the control parameter pp_tech
   7.680 +        passed to the routine glp_intopt the preprocessing can be
   7.681 +        performed either on the root level or on all levels (default)
   7.682 +        or can be disabled.
   7.683 +
   7.684 +        Backtracking heuristic used by default in the MIP solver was
   7.685 +        changed to the "best local bound".
   7.686 +
   7.687 +        For more details see Chapter "Advanced API routines", Section
   7.688 +        "Branch-and-bound interface routines" in a new edition of the
   7.689 +        reference manual included in the distribution.
   7.690 +
   7.691 +GLPK 4.20 (release date: Jul 26, 2007)
   7.692 +
   7.693 +        API routine lpx_integer was replaced by API routine glp_intopt,
   7.694 +        which provides equivalent functionality and additionally allows
   7.695 +        the application to control the solution process by means of the
   7.696 +        user-written callback routine, which is called by the solver at
   7.697 +        various points of the branch-and-bound algorithm. Besides, the
   7.698 +        new MIP solver allows generating "lazy" constraints and cutting
   7.699 +        planes on all levels of the branch-and-bound tree, not only on
   7.700 +        the root level. The routine lpx_integer is also still available
   7.701 +        for the backward compatibility.
   7.702 +
   7.703 +        The following new advanced API routines, which may be called
   7.704 +        from the B&B callback routine, were included in the package:
   7.705 +
   7.706 +        glp_ios_reason     determine reason for calling callback
   7.707 +                           routine
   7.708 +        glp_ios_get_prob   access the problem object
   7.709 +        glp_ios_tree_size  determine size of the branch-and-bound tree
   7.710 +        glp_ios_curr_node  determine current active subproblem
   7.711 +        glp_ios_next_node  determine next active subproblem
   7.712 +        glp_ios_prev_node  determine previous active subproblem
   7.713 +        glp_ios_up_node    determine parent subproblem
   7.714 +        glp_ios_node_level determine subproblem level
   7.715 +        glp_ios_node_bound determine subproblem local bound
   7.716 +        glp_ios_mip_gap    compute relative MIP gap
   7.717 +        glp_ios_heur_sol   provide solution found by heuristic
   7.718 +        glp_ios_terminate  terminate the solution process
   7.719 +
   7.720 +        For description of these routines see Chapter "Advanced API
   7.721 +        routines", Section "Branch-and-bound interface routines" in a
   7.722 +        new edition of the reference manual, which was included in the
   7.723 +        distribution.
   7.724 +
   7.725 +        Old version of the integer optimization suite (IOS) as well as
   7.726 +        TSP solver tspsol based on it are no longer supported and were
   7.727 +        removed from the package.
   7.728 +
   7.729 +        A minor error in the MIP presolver was fixed; thanks to Graham
   7.730 +        Rockwell <bionomicron@gmail.com> for the bug report.
   7.731 +
   7.732 +GLPK 4.19 (release date: Jul 05, 2007)
   7.733 +
   7.734 +        The principal change is upgrading to GPLv3.
   7.735 +
   7.736 +        A serious bug in the routine glp_del_cols was fixed; thanks to
   7.737 +        Cedric[FR] <fox2113@wanadoo.fr> for the bug report. The bug
   7.738 +        appeared because on deleting non-basic columns the basis header
   7.739 +        remained valid, however, contained invalid (old) column ordinal
   7.740 +        numbers.
   7.741 +
   7.742 +        A new advanced API routine glp_mem_limit was added.
   7.743 +
   7.744 +        The case GLP_EBOUND was added to the routine lpx_simplex.
   7.745 +        Thanks to Cameron Kellough <Cameron.Kellough@sri.com> for the
   7.746 +        bug report.
   7.747 +
   7.748 +        An API routine lpx_write_pb to write the problem instance in
   7.749 +        OPB (pseudo boolean) format format was added. Thanks to Oscar
   7.750 +        Gustafsson <oscarg@isy.liu.se> for the contribution.
   7.751 +
   7.752 +        Two new options --wpb and --wnpb were added to glpsol to write
   7.753 +        the problem instance in OPB format.
   7.754 +
   7.755 +GLPK 4.18 (release date: Jun 25, 2007)
   7.756 +
   7.757 +        The following new API routines were added:
   7.758 +
   7.759 +        glp_set_rii        set (change) row scale factor
   7.760 +        glp_set_sjj        set (change) column scale factor
   7.761 +        glp_get_rii        retrieve row scale factor
   7.762 +        glp_get_sjj        retrieve column scale factor
   7.763 +        glp_simplex        solve LP problem with the simplex method
   7.764 +                           (this routine replaces lpx_simplex, which is
   7.765 +                           also available for backward compatibility)
   7.766 +        glp_init_smcp      initialize simplex method control params
   7.767 +        glp_bf_exists      check if the basis factorization exists
   7.768 +        glp_factorize      compute the basis factorization
   7.769 +        glp_bf_updated     check if the basis factorization has been
   7.770 +                           updated
   7.771 +        glp_get_bfcp       retrieve basis factorization control params
   7.772 +        glp_set_bfcp       change basis factorization control params
   7.773 +        glp_get_bhead      retrieve the basis header information
   7.774 +        glp_get_row_bind   retrieve row index in the basis header
   7.775 +        glp_get_col_bind   retrieve column index in the basis header
   7.776 +        glp_ftran          perform forward transformation
   7.777 +        glp_btran          perform backward transformation
   7.778 +
   7.779 +        For description of all these routines see a new edition of the
   7.780 +        reference manual included in the distribution.
   7.781 +
   7.782 +        Type names ulong_t and uldiv_t were changed to glp_ulong and
   7.783 +        glp_uldiv to avoid conflicts with standard type names on some
   7.784 +        platforms. Thanks to Boris Wirtz <Boris.Wirtz@uni-oldenburg.de>
   7.785 +        for the bug report.
   7.786 +
   7.787 +        Some new examples in the MathProg language were added. Thanks
   7.788 +        to Sebastian Nowozin <nowozin@gmail.com>.
   7.789 +
   7.790 +GLPK 4.17 (release date: May 26, 2007)
   7.791 +
   7.792 +        API routines glp_set_mat_row, glp_set_mat_col, and glp_load_mat
   7.793 +        were modified to allow zero constraint coefficients (which are
   7.794 +        not stored in the constraint matrix). Note that constraint
   7.795 +        coefficients with duplicate row/column indices are not allowed.
   7.796 +
   7.797 +        Another form of LP basis factorization was implemented in the
   7.798 +        package. It is based on LU-factorization of an initial basis
   7.799 +        and Schur complement to reflect changes in the basis. Currently
   7.800 +        the implementation is incomplete and provides only updating the
   7.801 +        factorization on replacing a column of the basis matrix. On API
   7.802 +        level the user can set the control parameter LPX_K_BFTYPE to
   7.803 +        choose between the folloiwng forms of LP basis factorization to
   7.804 +        be used in the simplex method routines:
   7.805 +        1) LU + Forrest-Tomlin update;
   7.806 +        2) LU + Schur complement + Bartels-Golub update;
   7.807 +        3) LU + Schur complement + Givens rotation update.
   7.808 +        The GLPK implementation is similar to LUSOL/LUMOD developed by
   7.809 +        Michael A. Saunders.
   7.810 +
   7.811 +        The user can choose the form of LP basis factorzation used by
   7.812 +        the simplex method routines by specifying the folloiwng options
   7.813 +        of glpsol: --luf, --cbg, --cgr.
   7.814 +
   7.815 +GLPK 4.16 (release date: May 05, 2007)
   7.816 +
   7.817 +        A number of basic GLPK API routines, which now are in the
   7.818 +        stable stable, were renamed to be prefixed with 'glp_'. Note
   7.819 +        that all these routines are available via their old names
   7.820 +        prefixed with 'lpx_' that keeps the downward compatibility with
   7.821 +        older versions of the package.
   7.822 +
   7.823 +        Three new GLPK API routines were added to the package:
   7.824 +        glp_version, glp_term_hook, and glp_mem_usage; for more details
   7.825 +        see a new edition of the GLPK reference manual included in the
   7.826 +        distribution. The routine glp_version reports the actual version
   7.827 +        of the GLPK library and also can be used (along with the header
   7.828 +        glpk.h) in Autotools specification files to check if the GLPK
   7.829 +        library has been installed.
   7.830 +
   7.831 +        The header glpk.h was changed to conform to C++ environment.
   7.832 +
   7.833 +GLPK 4.15 (release date: Feb 18, 2007)
   7.834 +
   7.835 +        Autotools specification files (configure.ac, Makefile.am) were
   7.836 +        changed to use GNU Libtool. This allows building the static as
   7.837 +        well as shared GLPK library.
   7.838 +
   7.839 +GLPK 4.14 (release date: Feb 05, 2007)
   7.840 +
   7.841 +        Now GLPK conforms to ILP32, LLP64, and LP64 programming models
   7.842 +        (the latter seems to be the ultimate choice regarding 64-bit
   7.843 +        architectures). Note that GLPK itself is a 32-bit application,
   7.844 +        and the conformity only means that the package works correctly
   7.845 +        on all these arenae. Nevertheless, on 64-bit platforms it is
   7.846 +        possible to use more than 4GB of memory, if necessary.
   7.847 +
   7.848 +GLPK 4.13 (release date: Nov 13, 2006)
   7.849 +
   7.850 +        A tentative implementation of the "exact" simplex method based
   7.851 +        on bignum (rational) arithmetic was included in the package.
   7.852 +
   7.853 +        On API level this new feature is available through the routine
   7.854 +        lpx_exact, which is similar to the routine lpx_simplex.
   7.855 +
   7.856 +        In the solver glpsol this feature is available through two new
   7.857 +        command-line options: --exact and --xcheck. If the '--exact'
   7.858 +        option is specified, glpsol solves LP instance using the exact
   7.859 +        simplex method; in case of MIP it is used to obtain optimal
   7.860 +        solution of LP relaxation. If the --xcheck option is specified,
   7.861 +        LP instance (or LP relaxation) is solved using the standard
   7.862 +        (floating-point) simplex method, however, then glpsol calls the
   7.863 +        exact simplex routine to make sure that the final LP basis is
   7.864 +        exactly optimal, and if it is not, to perform some additional
   7.865 +        simplex iterations in exact arithmetic.
   7.866 +
   7.867 +GLPK 4.12 (release date: Nov 08, 2006)
   7.868 +
   7.869 +        A tentative implementation of some simplex method routines
   7.870 +        based on exact (bignum) arithmetic was included in the package.
   7.871 +        Currently these routines provide computing LU-factorization of
   7.872 +        the basis matrix and computing components of basic solution.
   7.873 +
   7.874 +        These routines were used to implement a routine, which checks
   7.875 +        primal and dual feasibility of basic solution exactly, i.e. in
   7.876 +        rational numbers, without round-off errors. In glpsol this
   7.877 +        feature is available through the command-line option --xcheck.
   7.878 +
   7.879 +        GLPK has its own low-level routines implementing operations on
   7.880 +        integer and rational numbers that makes it independent on other
   7.881 +        software packages. However, to attain a much better performance
   7.882 +        it is highly recommended to install (before configuring GLPK)
   7.883 +        the GNU Multiple Precision Arithmetic Library (GMP). Using GMP
   7.884 +        makes computations 100-200 times faster.
   7.885 +
   7.886 +GLPK 4.11 (release date: Jul 25, 2006)
   7.887 +
   7.888 +        Three new built-in functions in the modeling language were
   7.889 +        implemented: card (cardinality of set), length (length of
   7.890 +        character string), and substr (substring of character string).
   7.891 +        Another improvement concerns the printf statement which now
   7.892 +        allows redirecting its output to a specified file. These new
   7.893 +        features are illustrated in example models crypto.mod and
   7.894 +        graph.mod included in the distribution. For more details see
   7.895 +        the document "Modeling Language GNU MathProg".
   7.896 +
   7.897 +        Four batch files (along with corresponding makefiles) were
   7.898 +        included in the distribution to simplify building GLPK under
   7.899 +        MS Windows; see them in subdirectory 'w32'.
   7.900 +
   7.901 +GLPK 4.10 (release date: May 11, 2006)
   7.902 +
   7.903 +        Cutting planes of two new classes were implemented: mixed cover
   7.904 +        cuts and clique cuts. On API level this feature can be enabled
   7.905 +        by setting control parameter LPX_K_USECUTS passed to the routine
   7.906 +        lpx_intopt. In glpsol this feature is available through the
   7.907 +        command-line options --cover and --clique. For more details see
   7.908 +        the reference manual.
   7.909 +
   7.910 +        Now the routines lpx_read_mps and lpx_read_freemps support LI
   7.911 +        bound type. It is similar to LO, however, indicates the column
   7.912 +        as of integer kind.
   7.913 +
   7.914 +GLPK 4.9 (release date: Jan 17, 2006)
   7.915 +
   7.916 +        An advanced MIP solver was implemented. It includes:
   7.917 +
   7.918 +        - basic presolving technique (removing free, singleton and
   7.919 +          redundant rows, improving bounds of columns, removing fixed
   7.920 +          columns, reducing constraint coefficents);
   7.921 +
   7.922 +        - generating cutting planes to improve LP relaxation (currently
   7.923 +          only Gomory's mixed integer cuts are implemented);
   7.924 +
   7.925 +        - using the branch-and-bound method to solve resultant MIP;
   7.926 +
   7.927 +        - recovering solution of the original MIP.
   7.928 +
   7.929 +        The solver is available on API level via the routine lpx_intopt
   7.930 +        (see the reference manual). It is similar to the routine
   7.931 +        lpx_integer, however, does not require initial solution of LP
   7.932 +        relaxation.
   7.933 +
   7.934 +        The solver is also available in the command-line utility glpsol
   7.935 +        via two options: --intopt (only presolving) and --cuts (assumes
   7.936 +        --intopt plus generating cuts).
   7.937 +
   7.938 +        Note that efficiency of the MIP solver strongly depends on the
   7.939 +        internal structure of the problem to be solved. For some hard
   7.940 +        instances it is very efficient, but for other instances it may
   7.941 +        be significantly worse than the standard branch-and-bound.
   7.942 +
   7.943 +        For some comparative benchmarks see doc/bench1.txt.
   7.944 +
   7.945 +        Well, what else...
   7.946 +
   7.947 +        Three built-in functions were added to MathProg: sin, cos, and
   7.948 +        atan (the latter allows one or two arguments).
   7.949 +
   7.950 +        Some bugs were fixed.
   7.951 +
   7.952 +        Several new examples in MathProg were included: color.mod
   7.953 +        (graph coloring problem), tsp.mod (traveling salesman problem),
   7.954 +        and pbn.mod (paint-by-numbers puzzle).
   7.955 +
   7.956 +GLPK 4.8 (release date: Jan 12, 2005)
   7.957 +
   7.958 +        Core simplex method and interior-point method routines were
   7.959 +        re-implemented and now they use a new, "storage-by-rows" sparse
   7.960 +        matrix format (unlike previous versions where linked lists were
   7.961 +        used to represent sparse matrices). For details see ChangeLog.
   7.962 +
   7.963 +        Also a minor bug was fixed in API routine lpx_read_cpxlp.
   7.964 +
   7.965 +GLPK 4.7 (release date: Aug 23, 2004)
   7.966 +
   7.967 +        Now GLPK supports free MPS format. Two new API routines
   7.968 +        lpx_read_freemps (to read problem data in free MPS format) and
   7.969 +        lpx_write_freemps (to write problem data in free MPS format)
   7.970 +        were added. This feature is also available in the solver glpsol
   7.971 +        via new command-line options --freemps and --wfreemps. For more
   7.972 +        details see the GLPK reference manual.
   7.973 +
   7.974 +        API routines lpx_read_cpxlp and lpx_write_cpxlp for reading and
   7.975 +        writing problem data in CPLEX LP format were re-implemented to
   7.976 +        allow long symbolic names (up to 255 characters).
   7.977 +
   7.978 +        The following three modules were temporarily removed from the
   7.979 +        GLPK distribution due to licensing problems: DELI (an interface
   7.980 +        module to Delphi), GLPKMEX (an interface module to Matlab), and
   7.981 +        JNI (an interface module to Java).
   7.982 +
   7.983 +GLPK 4.6 (release date: Aug 04, 2004)
   7.984 +
   7.985 +        Three new statements were implemented in the GNU MathProg
   7.986 +        language: solve, printf, and for. Their detailed description can
   7.987 +        be found in the GLPK documentation included in the distribution.
   7.988 +        (See also a sample model, examples/queens.mod, which illustrates
   7.989 +        using these new statements.)
   7.990 +
   7.991 +        Two new API routines were added to the package: lpx_read_prob
   7.992 +        and lpx_write_prob. They allow reading/writing problem data in
   7.993 +        GNU LP low-level text format.
   7.994 +
   7.995 +        Three new command-line options were implemented in the LP/MIP
   7.996 +        solver glpsol: --glp (to read problem data in GNU LP format),
   7.997 +        --wglp (to write problem data in GNU LP format), and --name (to
   7.998 +        change problem name). Now glpsol also supports processing models
   7.999 +        where the new statements (see above) are used.
  7.1000 +
  7.1001 +        A new version of GLPKMEX, a Matlab MEX interface to GLPK, was
  7.1002 +        included. For more details see contrib/glpkmex/ChangeLog.
  7.1003 +
  7.1004 +GLPK 4.5 (release date: Jul 19, 2004)
  7.1005 +
  7.1006 +        The branch-and-bound solver was completely re-implemented.
  7.1007 +
  7.1008 +        Some modifications were made in memory allocation routines that
  7.1009 +        allows using the package on 64-bit platforms.
  7.1010 +
  7.1011 +        For more details see ChangeLog.
  7.1012 +
  7.1013 +GLPK 4.4 (release date: Jan 17, 2004)
  7.1014 +
  7.1015 +        All API routines were re-implemented using new data structures.
  7.1016 +        The new implementation provides the same specifications and
  7.1017 +        functionality of API routines as the old one, however, it has
  7.1018 +        some important advantages, in particular:
  7.1019 +        * linked lists are used everywhere that allows creating and
  7.1020 +          modifying the problem object as efficiently as possible
  7.1021 +        * all data stored in the problem object are non-scaled (even if
  7.1022 +          the internal scaling is used) that prevents distortion of the
  7.1023 +          original problem data
  7.1024 +        * solution components obtained by the solver remain available
  7.1025 +          even if the problem object has been modified
  7.1026 +        * no solver-specific data are used in the new data structures
  7.1027 +          that allows attaching any external lp/mip solver using GLPK
  7.1028 +          API as an uniform interface
  7.1029 +        Note that some API routines became obsolete being replaced by
  7.1030 +        new, more convenient routines. These obsolete routines are kept
  7.1031 +        for backward compatibility, however, they will be removed in
  7.1032 +        the future. For more details please see ChangeLog and the GLPK
  7.1033 +        Reference Manual.
  7.1034 +
  7.1035 +        New edition of the GLPK Reference Manual was included in the
  7.1036 +        distribution.
  7.1037 +
  7.1038 +        GLPKMEX, a Matlab MEX interface to GLPK package, contributed by
  7.1039 +        Nicolo Giorgetti <giorgetti@dii.unisi.it> was included in the
  7.1040 +        distribution.
  7.1041 +
  7.1042 +        GLPK FAQ contributed by Harley Mackenzie <hjm@bigpond.com> was
  7.1043 +        included in the distribution.
  7.1044 +
  7.1045 +GLPK 4.3 (release date: Dec 12, 2003)
  7.1046 +
  7.1047 +        The bug, due to which the standard math library is not linked
  7.1048 +        on building the package on some platforms, was fixed.
  7.1049 +
  7.1050 +        The following new built-in functions were added to the MathProg
  7.1051 +        language: round, trunc, Irand224, Uniform01, Uniform, Normal01,
  7.1052 +        Normal. For details see the language description.
  7.1053 +
  7.1054 +        The MathProg syntax was changed to allow writing 'subj to' that
  7.1055 +        means 'subject to'.
  7.1056 +
  7.1057 +        The new api routine lpx_get_ray_info was added. It is intended
  7.1058 +        to determine which (non-basic) variable causes unboundness. For
  7.1059 +        details see the reference manual.
  7.1060 +
  7.1061 +        The module glpmps.c was changed to avoid compilation errors on
  7.1062 +        building the package on Mac OS X.
  7.1063 +
  7.1064 +        Several typos was fixed and some new material was added to the
  7.1065 +        GLPK documentation.
  7.1066 +
  7.1067 +GLPK 4.2 (release date: Nov 14, 2003)
  7.1068 +
  7.1069 +        A preliminary implementation of the Integer Optimization Suite
  7.1070 +        (IOS) was included in the package. The Branch-and-Cut Framework
  7.1071 +        being completely superseded by IOS was removed from the package.
  7.1072 +
  7.1073 +        New API routine lpx_print_sens_bnds intended for bounds
  7.1074 +        sensitivity analysis was contributed to GLPK by Brady Hunsaker
  7.1075 +        <hunsaker@engr.pitt.edu>. This function is also available in
  7.1076 +        the solver glpsol (via command-line option --bounds).
  7.1077 +
  7.1078 +        An improved version of GLPK JNI (Java Native Interface) was
  7.1079 +        contributed by Chris Rosebrugh <cpr@pobox.com>.
  7.1080 +
  7.1081 +        GLPK DELI (Delphi Interface) was contributed by Ivo van Baren
  7.1082 +        <i.van.baren@freeler.nl>.
  7.1083 +
  7.1084 +        Several makefiles were added to allow compiling GLPK on some
  7.1085 +        non-GNU 32-bit platforms:
  7.1086 +        * Windows single-threaded static library, Visual C++ 6.0
  7.1087 +        * Windows multi-threaded dynamic library, Visual C++ 6.0
  7.1088 +        * Windows single-threaded static library, Borland C++ 5.2
  7.1089 +        * DOS single-threaded static library, Digital Mars C++ 7.50
  7.1090 +
  7.1091 +        And, of course, some bugs were fixed.
  7.1092 +
  7.1093 +        For more details see ChangeLog.
  7.1094 +
  7.1095 +GLPK 4.1 (release date: Aug 23, 2003)
  7.1096 +
  7.1097 +        Some improvements were made in the lp/mip solver routines and
  7.1098 +        several bugs were fixed in the model translator.
  7.1099 +
  7.1100 +        For more details see ChangeLog.
  7.1101 +
  7.1102 +GLPK 4.0 (release date: May 06, 2003)
  7.1103 +
  7.1104 +        Now GLPK supports the GNU MathProg modeling language, which is
  7.1105 +        a subset of the AMPL modeling language.
  7.1106 +
  7.1107 +        The document "GLPK: Modeling Language GNU MathProg" included in
  7.1108 +        the distribution is a complete description of GNU MathProg. (See
  7.1109 +        the files lang.latex, lang.dvi, and lang.ps in the subdirectory
  7.1110 +        'doc'. See also some examples in the subdirectory 'sample'.)
  7.1111 +
  7.1112 +        New version of the solver glpsol, which supports models written
  7.1113 +        in GNU MathProg, was implemented. (Brief instructions how to use
  7.1114 +        glpsol can be found in the GNU MathProg documentation.)
  7.1115 +
  7.1116 +        The GLPK/L modeling language is no more supported. The reason is
  7.1117 +        that GNU MathProg being much more powerful completely supersedes
  7.1118 +        all features of GLPK/L.
  7.1119 +
  7.1120 +GLPK 3.3 (release date: Mar 25, 2003)
  7.1121 +
  7.1122 +        LP PRESOLVER
  7.1123 +        ------------
  7.1124 +
  7.1125 +        Now the routine lpx_simplex (which is a driver to the simplex
  7.1126 +        method for solving LP) is provided with the built-in LP
  7.1127 +        presolver, which is a program that transforms the original LP
  7.1128 +        problem to an equivalent LP problem, which may be easier for
  7.1129 +        solving with the simplex method than the original one. Once the
  7.1130 +        transformed LP has been solver, the presolver transforms its
  7.1131 +        basic solution back to a corresponding basic solution of the
  7.1132 +        original problem. For details about this feature please see the
  7.1133 +        GLPK reference manual.
  7.1134 +
  7.1135 +        Currently the LP presolver implements the following features:
  7.1136 +        * removing empty rows;
  7.1137 +        * removing empty columns;
  7.1138 +        * removing free rows;
  7.1139 +        * removing fixed columns;
  7.1140 +        * removing row singletons, which have the form of equations;
  7.1141 +        * removing row singletons, which have the form of inequalities;
  7.1142 +        * removing column singletons, which are implied slack variables;
  7.1143 +        * fixing and removing column singletons, which are implied free
  7.1144 +          variables;
  7.1145 +        * removing forcing rows that involves fixing and removing the
  7.1146 +          corresponding columns;
  7.1147 +        * checking for primal and dual infeasibilities.
  7.1148 +
  7.1149 +        The LP presolver is also used by default in the stand-alone
  7.1150 +        program glpsol. In order *not* to use it, the option --nopresol
  7.1151 +        should be specified in the command-line.
  7.1152 +
  7.1153 +        CHANGES IN GLPK/L
  7.1154 +        -----------------
  7.1155 +
  7.1156 +        The syntax and semantics of the GLPK/L modeling language was
  7.1157 +        changed to allow declaration of "interval" sets. This means that
  7.1158 +        now the user can declare a set, for example, as:
  7.1159 +
  7.1160 +           set task = [8:11];
  7.1161 +
  7.1162 +        that is exactly equivalent to the following declaration:
  7.1163 +
  7.1164 +           set task = (task_8, task_9, task_10, task_11);
  7.1165 +
  7.1166 +        For details see the language description.
  7.1167 +
  7.1168 +        JAVA INTERFACE
  7.1169 +        --------------
  7.1170 +
  7.1171 +        Now GLPK includes the package GLPK JNI (Java Native Interface)
  7.1172 +        that implements Java binding for GLPK. It allows Java programs
  7.1173 +        to utilize GLPK in solving LP and MIP problems. For details see
  7.1174 +        a brief user's guide in the subdirectory contrib/java-binding.
  7.1175 +        This package was developed and programmed by Yuri Victorovich
  7.1176 +        <yuri@gjt.org>, who contributed it to GLPK.
  7.1177 +
  7.1178 +GLPK 3.2.4 (release date: Feb 18, 2003)
  7.1179 +
  7.1180 +        This is a bug-fix release. For details see ChangeLog.
  7.1181 +
  7.1182 +GLPK 3.2.3 (release date: Nov 11, 2002)
  7.1183 +
  7.1184 +        A new implementation of the api routine lpx_integer which now
  7.1185 +        is based on the b&b driver (which is based on the implicit
  7.1186 +        enumeration suite) was included in the package. This new
  7.1187 +        implementation has exactly the same functionality as the old
  7.1188 +        version, so all changes are transparent to the api user.
  7.1189 +
  7.1190 +        Four new api routines were included in the package:
  7.1191 +        lpx_check_kkt checks Karush-Kuhn-Tucker optmality conditions;
  7.1192 +        lpx_read_bas reads predifined basis in MPS format;
  7.1193 +        lpx_write_bas writes current basis in MPS format;
  7.1194 +        lpx_write_lpt writes problem data in CPLEX LP format.
  7.1195 +
  7.1196 +        Also other minor improvements were made (for details see the
  7.1197 +        file 'ChangeLog').
  7.1198 +
  7.1199 +GLPK 3.2.2 (release date: Oct 14, 2002)
  7.1200 +
  7.1201 +        The api routine lpx_read_lpt was included in the package. It
  7.1202 +        is similar to the routine lpx_read_mps and intended to read
  7.1203 +        LP/MIP data prepared in CPLEX LP format. Description of this
  7.1204 +        format is given in the GLPK reference manual, a new edition of
  7.1205 +        which was also included in the distribution (see the files
  7.1206 +        'refman.latex', 'refman.dvi', 'refman.ps' in the subdirectory
  7.1207 +        'doc'). In order to use data files in CPLEX LP format with the
  7.1208 +        solver glpsol the option '--lpt' should be specified in the
  7.1209 +        command line.
  7.1210 +
  7.1211 +        Several bugs were fixed and some minor improvements were made
  7.1212 +        (for details see the file 'ChangeLog').
  7.1213 +
  7.1214 +GLPK 3.2.1 (release date: Aug 12, 2002)
  7.1215 +
  7.1216 +        Now GLPK includes a preliminary implementation of the
  7.1217 +        branch-and-cut framework, which is a set of data structures and
  7.1218 +        routines intended for developing branch-and-cut methods for
  7.1219 +        solving mixed-integer and combinatorial optimization problems.
  7.1220 +
  7.1221 +        Detailed decsription of the branch-and-cut framework is given in
  7.1222 +        the document "GLPK: A Preliminary Implementation of the
  7.1223 +        Branch-And-Cut Framework" included in the distribution (see the
  7.1224 +        file 'brcut.txt' in the subdirectory 'doc').
  7.1225 +
  7.1226 +        In order to illustrate how the GLPK branch-and-cut framework
  7.1227 +        can be used for solving a particular optimization problem there
  7.1228 +        is an example included in the package. This is a stand-alone
  7.1229 +        program, TSPSOL, which is intended for solving to optimality the
  7.1230 +        symmetric Traveling Salesman Problem (TSP), a classical problem
  7.1231 +        of the combinatorial optimization (see the file 'tspsol.c' in
  7.1232 +        the subdirectory 'sample').
  7.1233 +
  7.1234 +GLPK 3.2 (release date: Jul 15, 2002)
  7.1235 +
  7.1236 +        New edition of the document "GLPK: Reference Manual" was
  7.1237 +        included (see the files 'refman.latex', 'refman.dvi', and
  7.1238 +        'refman.ps' in the subdirectory 'doc').
  7.1239 +
  7.1240 +        New edition of the document "GLPK: Modeling Language GLPK/L" was
  7.1241 +        included (see the files 'lang.latex', 'lang.dvi', and 'lang.ps'
  7.1242 +        in the subdirectory 'doc').
  7.1243 +
  7.1244 +        The following new API routines were added to the package:
  7.1245 +
  7.1246 +        lpx_transform_row (transform explicitly specified row);
  7.1247 +        lpx_transform_col (transform explicitly specified column);
  7.1248 +        lpx_prim_ratio_test (perform primal ratio test);
  7.1249 +        lpx_dual_ratio_test (perform dual ratio test);
  7.1250 +        lpx_interior (solve LP problem using interior point method);
  7.1251 +        lpx_get_ips_stat (query status of interior point solution);
  7.1252 +        lpx_get_ips_row (obtain row interior point solution);
  7.1253 +        lpx_get_ips_col (obtain column interior point solution);
  7.1254 +        lpx_get_ips_obj (obtain interior point value of obj.func.);
  7.1255 +        lpx_read_lpm (read LP/MIP model written in GLPK/L);
  7.1256 +        lpx_write_mps (write problem data using MPS format);
  7.1257 +        lpx_print_ips (print interior point solution).
  7.1258 +
  7.1259 +        Detailed description of all these new API routines are given in
  7.1260 +        the new edition of the reference manual.
  7.1261 +
  7.1262 +        New version of the stand-alone solver glpsol (which is based on
  7.1263 +        the new API) was implemented.
  7.1264 +
  7.1265 +        So long as the new API (introduced in glpk 3.0) now provides
  7.1266 +        all the functions, which were provided by the old API, the old
  7.1267 +        API routines were removed from the package at all.
  7.1268 +
  7.1269 +GLPK 3.1 (release date: May 27, 2002)
  7.1270 +
  7.1271 +        A preliminary implementation of new API routines was completed
  7.1272 +        and included in the package.
  7.1273 +
  7.1274 +        These new API routines provide much more flexible interaction
  7.1275 +        between the application program, LP/MIP problem instances, and
  7.1276 +        solver routines. Based on completely changed data structures
  7.1277 +        they are, however, similar to the API routines and provide the
  7.1278 +        same functionality. Please note that three routines, namely,
  7.1279 +        solving LPs using interior point method, reading model written
  7.1280 +        in the GLPK/L modeling language, and writing problem data in
  7.1281 +        the MPS format, are not implemented in the new API, however,
  7.1282 +        these routines are planned to be implemented in the next version
  7.1283 +        of the package.
  7.1284 +
  7.1285 +        A description of the new API routines is given in the document
  7.1286 +        "GLPK Reference Manual", a draft edition of which is included
  7.1287 +        in the package (see the files 'refman.latex', 'refman.dvi', and
  7.1288 +        'refman.ps' in the subdirectory 'doc').
  7.1289 +
  7.1290 +        Although the old API routines are kept in the package, they are
  7.1291 +        no longer supported and will be removed in the future.
  7.1292 +
  7.1293 +GLPK 3.0.8 (release date: May 13, 2002)
  7.1294 +
  7.1295 +        A preliminary implementation of new API routines was included
  7.1296 +        in the package. These new API routines are intended to provide
  7.1297 +        much more flexible interaction between the application program,
  7.1298 +        LP/MIP problem and solver routines. See the document "New GLPK
  7.1299 +        API Routines" (the file 'newapi.txt' in the subdirectory 'doc')
  7.1300 +        also included in the package.
  7.1301 +
  7.1302 +        The api routines glp_simplex2, glp_call_ipm1, glp_call_bbm1 were
  7.1303 +        renamed, respectively, to glp_simplex, glp_interior, glp_integer
  7.1304 +        in order to reflect changes in implementation. The api routines
  7.1305 +        glp_call_rsm1, glp_simplex1, glp_pivot_in, glp_pivout_out were
  7.1306 +        removed from the package since they are completely supreseded by
  7.1307 +        the new API routines (however, these routines still can be found
  7.1308 +        in the subdirectory 'oldsrc'). Please consult a new edition of
  7.1309 +        the document "GLPK User's Guide" about all these changes in the
  7.1310 +        existing api routines.
  7.1311 +
  7.1312 +        The document "GLPK Library Reference" was removed from the
  7.1313 +        package (into the subdirectory 'oldsrc') since it describes the
  7.1314 +        obsolete library routines, most of which are no longer used.
  7.1315 +
  7.1316 +GLPK 3.0.7 (release date: Apr 22, 2002)
  7.1317 +
  7.1318 +        A new, more efficient implementation of the primal/dual simplex
  7.1319 +        method was included in the package. Due to some improvements the
  7.1320 +        simplex-based solver allows solving many LP problems faster and
  7.1321 +        provides more reliable results. Note that the new implementation
  7.1322 +        is currently incomplete and available only via the api routine
  7.1323 +        glp_simplex2.
  7.1324 +
  7.1325 +        All the changes are transparent on API level.
  7.1326 +
  7.1327 +GLPK 3.0.6 (release date: Mar 28, 2002)
  7.1328 +
  7.1329 +        New version of LU-factorization and basis maintenance routines
  7.1330 +        (based on Forrest-Tomlin updating technique) was implemented.
  7.1331 +        Since these new routines functionally supersede some routines
  7.1332 +        (which implement other forms of the basis matrix) and make them
  7.1333 +        obsolete, the latter were removed from the package (they still
  7.1334 +        can be found in the subdirectory 'oldsrc').
  7.1335 +
  7.1336 +        All the changes are transparent on API level.
  7.1337 +
  7.1338 +GLPK 3.0.5 (release date: Jan 29, 2002)
  7.1339 +
  7.1340 +        New edition of the document "GLPK User's Guide" was included in
  7.1341 +        the distribution. Now it describes all additional API routines,
  7.1342 +        which were recently added to the package.
  7.1343 +
  7.1344 +        Structure of the package was re-organized in order to make its
  7.1345 +        maintenance easier (all small files in the subdurectory 'source'
  7.1346 +        were merged in bigger units). These changes are transparent for
  7.1347 +        the user.
  7.1348 +
  7.1349 +GLPK 3.0.4 (release date: Dec 10, 2001)
  7.1350 +
  7.1351 +        A new, more efficient implementation of the two-phase primal
  7.1352 +        simplex method was included in the package. Due to some new
  7.1353 +        features (an advanced initial basis, projected steepest edge,
  7.1354 +        recursive updating values and reduced costs) the new LP solver
  7.1355 +        is faster and numerically more stable than the old one.
  7.1356 +
  7.1357 +        The new LP solver is available as API routine glp_simplex2 and
  7.1358 +        has the same purpose as API routine glp_call_rsm1. For detailed
  7.1359 +        specification see the file 'newapi.txt' in the directory 'doc'.
  7.1360 +
  7.1361 +        Now the new LP solver is also used by default to solve an
  7.1362 +        initial LP problem in the branch-and-bound routine glp_call_bbm1
  7.1363 +        instead the routine rsm1_driver. Note that the branch-and-bound
  7.1364 +        procedure itself is still based on rsm1_driver.
  7.1365 +
  7.1366 +        The new LP solver is also used as default solver in GLPSOL for
  7.1367 +        solving LP and MIP problems. In order to choose the old solver
  7.1368 +        the option '--old-sim' can be specified in the command line.
  7.1369 +
  7.1370 +GLPK 3.0.3 (release date: Oct 03, 2001)
  7.1371 +
  7.1372 +        Some minor changes were made in the simplex method routines in
  7.1373 +        order to improve numerical stability of the method.
  7.1374 +
  7.1375 +GLPK 3.0.2 (release date: Sep 24, 2001)
  7.1376 +
  7.1377 +        A new implementation of the basis maintaining routines was
  7.1378 +        included in the package. These routines, which are based on so
  7.1379 +        called FHV-factorization (a variety of LU-factorization) of the
  7.1380 +        basis matrix and Gustavson's data structures, allows performing
  7.1381 +        the main operations faster at the expense of some worsening
  7.1382 +        numerical accuracy.
  7.1383 +
  7.1384 +        AFI (Advanced Form of the Inverse), which is the form of the
  7.1385 +        basis matrix based on FHV-factorization, is available via the
  7.1386 +        parameter form = 3 (on API level) or via the option --afi (in
  7.1387 +        GLPSOL solver).
  7.1388 +
  7.1389 +GLPK 3.0.1 (release date: Aug 01, 2001)
  7.1390 +
  7.1391 +        Old GLPK API routines have been removed from the package.
  7.1392 +
  7.1393 +        New GLPK API routines were added:
  7.1394 +
  7.1395 +        - scaling routines;
  7.1396 +
  7.1397 +        - a routine for writing problem data in MPS format;
  7.1398 +
  7.1399 +        - a comprehensive driver to the simplex method;
  7.1400 +
  7.1401 +        - basis maintaining routines.
  7.1402 +
  7.1403 +        A description of the new API routines is given in the document
  7.1404 +        "Additional GLPK API Routines". This document is included into
  7.1405 +        the distribution in plain text format (see the file 'newapi.txt'
  7.1406 +        in the subdirectory 'doc').
  7.1407 +
  7.1408 +        Now the distribution includes a non-trivial example of using
  7.1409 +        GLPK as a base LP solver for Concorde, a well known program that
  7.1410 +        solves Traveling Salesman Problem (TSP). For further details see
  7.1411 +        comments in the file 'sample/lpglpk30.c'.
  7.1412 +
  7.1413 +GLPK 3.0 (release date: Jul 19, 2001)
  7.1414 +
  7.1415 +        Now GLPK is provided with new API, which being more flexible
  7.1416 +        can be used in more complex algorithmic schemes.
  7.1417 +
  7.1418 +        New edition of the document "GLPK User's Guide" is included in
  7.1419 +        the distribution. Now it completely corresponds to the new GLPK
  7.1420 +        API routines.
  7.1421 +
  7.1422 +        Old API routines are not removed yet from the package, however
  7.1423 +        they became obsolete and therefore should not be used. Since now
  7.1424 +        the header glpk.h corresponds to new API, in order to compile
  7.1425 +        existing programs that use old GLPK API routines the statement
  7.1426 +
  7.1427 +        #define GLP_OLD_API
  7.1428 +
  7.1429 +        should be inserted before the statement
  7.1430 +
  7.1431 +        #include "glpk.h"
  7.1432 +
  7.1433 +GLPK 2.4.1 (release date: Jun 14, 2001)
  7.1434 +
  7.1435 +        The document "Modeling language GLPK/L" is included into the
  7.1436 +        distribution in texinfo format.
  7.1437 +
  7.1438 +        New edition of the document "GLPK User's Guide" is included in
  7.1439 +        the distribution. Now it describes all additional API routines
  7.1440 +        which were recently added to the package.
  7.1441 +
  7.1442 +GLPK 2.4 (release date: May 10, 2001)
  7.1443 +
  7.1444 +        Now GLPK includes an implementation of a preliminary version
  7.1445 +        of the GLPK/L modeling language. This language is intended for
  7.1446 +        writing mathematcal programming models. The name GLPK/L is
  7.1447 +        derived from GNU Linear Programming Kit Language.
  7.1448 +
  7.1449 +        A brief description of the GLPK/L language is given in the
  7.1450 +        document "GLPK/L Modeling Language: A Brief Description". This
  7.1451 +        document is included into the distribution in plain text format
  7.1452 +        (see the file 'language.txt' in the subdirectory 'doc').
  7.1453 +
  7.1454 +        The language processor (which is a program that analyzes model
  7.1455 +        description written in GLPK/L and translates it to internal data
  7.1456 +        structures) is available as the GLPK API routine.
  7.1457 +
  7.1458 +        The stand-alone solver GLPSOL now is able: a) to process model
  7.1459 +        descriptions written in the GLPK/L language; b) to solve pure LP
  7.1460 +        problems using the interior point method (therefore the program
  7.1461 +        GLPIPM was removed from the package).
  7.1462 +
  7.1463 +GLPK 2.3 (release date: Apr 09, 2001)
  7.1464 +
  7.1465 +        New edition of the document "GLPK User's Guide" is included in
  7.1466 +        the distribution. Now it describes all additional API routines
  7.1467 +        which were recently added to the package.
  7.1468 +
  7.1469 +        The MIP solver was fully re-programmed in order to improve its
  7.1470 +        robustness and performance. In particular, a basis recovering
  7.1471 +        procedure was implemented (this procedure allows switching to
  7.1472 +        the primal simplex method in case when the dual simplex method
  7.1473 +        fails).
  7.1474 +
  7.1475 +GLPK 2.2 (release date: Mar 15, 2001)
  7.1476 +
  7.1477 +        Now GLPK includes a tentative implementation of the
  7.1478 +        branch-and-bound procedure based on the dual simplex method for
  7.1479 +        mixed integer linear programming (MIP).
  7.1480 +
  7.1481 +        Complete description of this new feature of the package is given
  7.1482 +        in the preliminary document "Mixed Integer Linear Programming
  7.1483 +        Using GLPK Version 2.2 (Supplement to GLPK User's Guide)". This
  7.1484 +        document is included into the distribution in plain text format
  7.1485 +        (see the file 'mip.txt' in the subdirectory 'doc').
  7.1486 +
  7.1487 +        The MIP solver (glp_integer) can be used as GLPK API routine in
  7.1488 +        the same way as the pure LP solver (glp_simplex).
  7.1489 +
  7.1490 +        The stand-alone program 'glpsol' is now able to solve LP as well
  7.1491 +        as MIP problems.
  7.1492 +
  7.1493 +        Note that the current version of GLPK MIP solver is based on
  7.1494 +        easiest heuristics for branching and backtrackng. Therefore the
  7.1495 +        solver is fit mainly for MIP problems which are not very hard
  7.1496 +        and have few integer variables.
  7.1497 +
  7.1498 +GLPK 2.1 (release date: Feb 19, 2001)
  7.1499 +
  7.1500 +        The document "GLPK Implementation of the Revised Simplex Method"
  7.1501 +        is included into the distribution. This document describes most
  7.1502 +        of routines related to the revised simplex method.
  7.1503 +
  7.1504 +GLPK 2.0 (release date: Jan 25, 2001)
  7.1505 +
  7.1506 +        Now GLPK includes a tentative implementation of the primal-dual
  7.1507 +        interior point method for large-scale linear programming.
  7.1508 +
  7.1509 +        The interior point solver can be used as GLPK API routine in the
  7.1510 +        same manner as the simplex method solver (glp_simplex):
  7.1511 +
  7.1512 +        ret = glp_interior();
  7.1513 +
  7.1514 +        Note that currently the interior point solver implemented in
  7.1515 +        GLPK doesn't include many important features, in particular:
  7.1516 +
  7.1517 +        * it can't process dense columns; therefore if the problem has
  7.1518 +          dense columns, the solving will be extremely inefficient;
  7.1519 +
  7.1520 +        * it has no special features against numerical unstability;
  7.1521 +          some problems may cause premature termination of the solving
  7.1522 +          when the matrix A*D*A' becomes ill-conditioned;
  7.1523 +
  7.1524 +        * it computes only values of primal (auxiliary and structural)
  7.1525 +          variables and doesn't compute values of dual variables (i.e.
  7.1526 +          reduced costs) which are just set to zero;
  7.1527 +
  7.1528 +        * it doesn't identify optimal basis corresponding to the found
  7.1529 +          interior point solution; all variables in the found solution
  7.1530 +          are just marked as basic variables.
  7.1531 +
  7.1532 +        GLPK also includes a stand-alone program 'glpipm' which is a
  7.1533 +        demo based on the interior point method. It may be used in the
  7.1534 +        same way as the program 'glpsol' that is based on the simplex
  7.1535 +        method.
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/README	Mon Dec 06 13:09:21 2010 +0100
     8.3 @@ -0,0 +1,39 @@
     8.4 +                                                     Olga K. gewidmet
     8.5 +
     8.6 +GLPK (GNU Linear Programming Kit) Version 4.45
     8.7 +
     8.8 +Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
     8.9 +2009, 2010 Andrew Makhorin, Department for Applied Informatics,
    8.10 +Moscow Aviation Institute, Moscow, Russia. All rights reserved.
    8.11 +E-mail: <mao@gnu.org>.
    8.12 +
    8.13 +GLPK is part of the GNU Project released under the aegis of GNU.
    8.14 +
    8.15 +GLPK is free software: you can redistribute it and/or modify it
    8.16 +under the terms of the GNU General Public License as published by the
    8.17 +Free Software Foundation, either version 3 of the License, or (at your
    8.18 +option) any later version.
    8.19 +
    8.20 +See the file COPYING for the GNU General Public License.
    8.21 +
    8.22 +See the file INSTALL for compilation and installation instructions.
    8.23 +
    8.24 +The GLPK package is a set of routines written in ANSI C and organized
    8.25 +in the form of a callable library. This package is intended for solving
    8.26 +large-scale linear programming (LP), mixed integer linear programming
    8.27 +(MIP), and other related problems.
    8.28 +
    8.29 +The GLPK package includes the following main components:
    8.30 +
    8.31 +* implementation of the simplex method;
    8.32 +* implementation of the exact simplex method based on bignum (rational)
    8.33 +  arithmetic;
    8.34 +* implementation of the primal-dual interior-point method;
    8.35 +* implementation of the branch-and-cut method;
    8.36 +* application program interface (API);
    8.37 +* GNU MathProg modeling language (a subset of AMPL);
    8.38 +* GLPSOL, a stand-alone LP/MIP solver.
    8.39 +
    8.40 +See GLPK webpage <http://www.gnu.org/software/glpk/glpk.html>.
    8.41 +
    8.42 +Please report bugs to <bug-glpk@gnu.org>.
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/THANKS	Mon Dec 06 13:09:21 2010 +0100
     9.3 @@ -0,0 +1,183 @@
     9.4 +Noli Sicad <nsicad@gmail.com> for testing glpk under Mac OS.
     9.5 +
     9.6 +Pietro Scionti <pietro.scionti@archinet.it> for report typos found in
     9.7 +the reference manual.
     9.8 +
     9.9 +Noli Sicad <nsicad@gmail.com> for example model in MathProg.
    9.10 +
    9.11 +Nigel Galloway <nigel_galloway@operamail.com> for example model in
    9.12 +MathProg.
    9.13 +
    9.14 +Xypron <xypron.glpk@gmx.de> for contribution and testing batch scripts
    9.15 +to build Glpk with MS Visual Studio 2010.
    9.16 +
    9.17 +Xypron <xypron.glpk@gmx.de> for improving the SQL table driver.
    9.18 +
    9.19 +Stefan Vigerske <stefan@math.hu-berlin.de> for bug report.
    9.20 +
    9.21 +Uday Venkatadri <Uday.Venkatadri@dal.ca> for bug report.
    9.22 +
    9.23 +Xypron <xypron.glpk@gmx.de> for bug fixing and some improvments in the
    9.24 +FPUMP module.
    9.25 +
    9.26 +Niels Klitgord <niels@bu.edu> for bug report.
    9.27 +
    9.28 +Thomas Kahle <tom111@gmx.de> for some suggestions.
    9.29 +
    9.30 +Jonathan Senning <Jonathan.Senning@gordon.edu> for bug report.
    9.31 +
    9.32 +Xypron <xypron.glpk@gmx.de> for testing GLPK on 64-bit platforms and
    9.33 +for maintaining Windows versions of the package.
    9.34 +
    9.35 +Nelson H. F. Beebe <beebe@math.utah.edu> for bug report.
    9.36 +
    9.37 +Larry D'Agostino <Larry.D'Agostino@gmacrescap.com> for example model in
    9.38 +MathProg.
    9.39 +
    9.40 +Marco Atzeri <marco_atzeri@yahoo.it> for bug report.
    9.41 +
    9.42 +Robert Wood <rgwood01@cox.net> for example model in MathProg.
    9.43 +
    9.44 +Sebastien Briais <sbriais@free.fr> for bug report.
    9.45 +
    9.46 +Kelly Westbrooks <kellywestbrooks@yahoo.com> for suggestions.
    9.47 +
    9.48 +Nigel Galloway <nigel_galloway@operamail.com> for example models in
    9.49 +MathProg.
    9.50 +
    9.51 +Xypron <xypron.glpk@gmx.de> for bug patch.
    9.52 +
    9.53 +Sebastian Nowozin <nowozin@gmail.com> for example models in MathProg.
    9.54 +
    9.55 +Stefan Vigerske <stefan@vigerske.de> for bug report.
    9.56 +
    9.57 +Luiz Bettoni <bettoni@cpgei.ct.utfpr.edu.br> for some suggestions.
    9.58 +
    9.59 +Nigel Galloway <nigel_galloway@operamail.com> for bug report.
    9.60 +
    9.61 +Peter Ingerfeld <peter.ingerfeld@mops-optimizer.com> for bug report.
    9.62 +
    9.63 +Heinrich Schuchardt <heinrich.schuchardt@gmx.de> for contribution of
    9.64 +makefiles and testing the package under 64-bit Windows. 
    9.65 +
    9.66 +Oscar Gustafsson <oscarg@isy.liu.se> for contribution of a new version
    9.67 +of the routine to write data in OPB (pseudo boolean) format.
    9.68 +
    9.69 +Heinrich Schuchardt <heinrich.schuchardt@gmx.de> for some patches for
    9.70 +the MathProg translator.
    9.71 +
    9.72 +Markus Pilz <pilz@cs.uni-bonn.de> for bug report.
    9.73 +
    9.74 +Anne-Laurence Putz <anne-laurence.putz@eurodecision.com> for bug
    9.75 +report.
    9.76 +
    9.77 +Robbie Morrison <robbie@actrix.co.nz> for correcting the glpk manual.
    9.78 +
    9.79 +Axel Simon <Axel.Simon@ens.fr> for bug report.
    9.80 +
    9.81 +Vijay Patil <vijay.patil@gmail.com> for testing the package under
    9.82 +Windows XP.
    9.83 +
    9.84 +Heinrich Schuchardt <heinrich.schuchardt@gmx.de> for contribution of
    9.85 +two MathProg table drivers for iODBC and MySQL.
    9.86 +
    9.87 +Rafael Laboissiere <rafael@debian.org> for useful advices concerning
    9.88 +shared library support under GNU/Linux.
    9.89 +
    9.90 +Nigel Galloway <Nigel_Galloway@operamail.com> for an example program
    9.91 +in C#.
    9.92 +
    9.93 +Enric Rodriguez <erodri@lsi.upc.edu> for bug report.
    9.94 +
    9.95 +Nigel Galloway <Nigel_Galloway@operamail.com> for an example MathProg
    9.96 +model.
    9.97 +
    9.98 +Roberto Bagnara <bagnara@cs.unipr.it> (Department of Mathematics,
    9.99 +University of Parma, Italy) for bug report.
   9.100 +
   9.101 +Peter T. Breuer <ptb@inv.it.uc3m.es> for bug report.
   9.102 +
   9.103 +Graham Rockwell <bionomicron@gmail.com> for bug report.
   9.104 +
   9.105 +Cedric[FR] <fox2113@wanadoo.fr> for bug report.
   9.106 +
   9.107 +Cameron Kellough <Cameron.Kellough@sri.com> for bug report.
   9.108 +
   9.109 +Oscar Gustafsson <oscarg@isy.liu.se> for contribution of a routine to
   9.110 +write data in OPB (pseudo boolean) format.
   9.111 +
   9.112 +Boris Wirtz <Boris.Wirtz@uni-oldenburg.de> for bug report.
   9.113 +
   9.114 +Sebastian Nowozin <nowozin@gmail.com> for three example MathProg
   9.115 +models.
   9.116 +
   9.117 +Rafael Laboissiere <rafael@debian.org> for useful advices concerning
   9.118 +shared library support.
   9.119 +
   9.120 +Dr. Harley Mackenzie <hjm@hardsoftware.com> for two example MathProg
   9.121 +models (curve fitting problem).
   9.122 +
   9.123 +Minh Ha Duong <haduong@centre-cired.fr> for fixing doc typos.
   9.124 +
   9.125 +Brady Hunsaker <hunsaker@engr.pitt.edu> for some suggestions concerning
   9.126 +MIP routines.
   9.127 +
   9.128 +Karel Zimmermann <kzimm@diamant.jouy.inra.fr> for bug report.
   9.129 +
   9.130 +Christophe Caron <caron@diamant.jouy.inra.fr> for bug report.
   9.131 +
   9.132 +Nicolo Giorgetti <giorgetti@dii.unisi.it> for contribution of GLPKMEX,
   9.133 +a Matlab MEX interface.
   9.134 +
   9.135 +Harley Mackenzie <hjm@bigpond.com> for contribution of GLPK FAQ.
   9.136 +
   9.137 +Andre Girard <andre@inrs-emt.uquebec.ca> for bug report.
   9.138 +
   9.139 +Morten Welinder <terra@gnu.org> for bug report.
   9.140 +
   9.141 +Brady Hunsaker <hunsaker@engr.pitt.edu> for contribution of a routine
   9.142 +for bounds sensitivity analysis.
   9.143 +
   9.144 +Chris Rosebrugh <cpr@pobox.com> for contribution of a new version of
   9.145 +GLPK JNI (Java Native Interface).
   9.146 +
   9.147 +Ivo van Baren <i.van.baren@freeler.nl> for contribution of GLPK DELI
   9.148 +(Delphi Interface).
   9.149 +
   9.150 +Andrew Hamilton-Wright <andrewhw@ieee.org> for bug report.
   9.151 +
   9.152 +Jiri Spitz <jiri.spitz@telecom.cz> for bug report.
   9.153 +
   9.154 +Giles Thompson <gwpt1@cus.cam.ac.uk> for bug report.
   9.155 +
   9.156 +Sebastien de Menten <sdementen@hotmail.com> for bug report.
   9.157 +
   9.158 +Kendall Demaree <kendal.demaree@verizon.net> for bug report.
   9.159 +
   9.160 +Bernhard Schmidt <schmidt@math.uni-augsburg.de> for bug report.
   9.161 +
   9.162 +Yuri Victorovich <yuri@gjt.org> for contribution of GLPK Java binding.
   9.163 +
   9.164 +Olivier <odwl@skynet.be> for bug report.
   9.165 +
   9.166 +Kjell Eikland <kjell.eikland@broadpark.no> for bug report.
   9.167 +
   9.168 +Ivan Luzzi <iluzzi@libero.it> for comments concerning CPLEX LP format.
   9.169 +
   9.170 +Peter Lee <plee@kinggee.com.au> for example LP model and bug report.
   9.171 +
   9.172 +Morten Welinder <terra@diku.dk> for bug report.
   9.173 +
   9.174 +Vlahos Kiriakos <Kiriakos.Vlahos@gs.com> for bug report.
   9.175 +
   9.176 +Flavio Keidi Miyazawa <fkm@ic.unicamp.br> for bug report.
   9.177 +
   9.178 +Hans Schwengeler <Hans.Schwengeler@unibas.ch> for bug report.
   9.179 +
   9.180 +Sami Farin <sfarin@ratol.fi> for bug report.
   9.181 +
   9.182 +Peter A. Huegler <phuegler@bsco.com> for bug report.
   9.183 +
   9.184 +Alexandre Oliva <oliva@lsd.ic.unicamp.br> for bug report.
   9.185 +
   9.186 +Andrew Hood <ajhood@fl.net.au> for bug report.
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/configure.ac	Mon Dec 06 13:09:21 2010 +0100
    10.3 @@ -0,0 +1,159 @@
    10.4 +dnl Process this file with autoconf to produce a configure script
    10.5 +
    10.6 +AC_INIT([GLPK], [4.45], [bug-glpk@gnu.org])
    10.7 +
    10.8 +AC_CONFIG_SRCDIR([include/glpk.h])
    10.9 +
   10.10 +AC_CONFIG_MACRO_DIR([m4])
   10.11 +
   10.12 +AM_INIT_AUTOMAKE
   10.13 +
   10.14 +AC_CONFIG_HEADERS([config.h])
   10.15 +
   10.16 +AC_ARG_WITH(gmp,
   10.17 +AC_HELP_STRING([--with-gmp],
   10.18 +   [use GNU MP bignum library [[default=no]]]),
   10.19 +   [case $withval in
   10.20 +      yes | no) ;;
   10.21 +      *) AC_MSG_ERROR([invalid value `$withval' for --with-gmp]);;
   10.22 +      esac],
   10.23 +   [with_gmp=no])
   10.24 +
   10.25 +AC_ARG_WITH(zlib,
   10.26 +AC_HELP_STRING([--with-zlib],
   10.27 +   [use zlib data compression library [[default=no]]]),
   10.28 +   [case $withval in
   10.29 +      yes | no) ;;
   10.30 +      *) AC_MSG_ERROR([invalid value `$withval' for --with-zlib]);;
   10.31 +      esac],
   10.32 +   [with_zlib=no])
   10.33 +
   10.34 +AC_ARG_ENABLE(dl,
   10.35 +AC_HELP_STRING([--enable-dl],
   10.36 +   [enable shared library support [[default=no]]]),
   10.37 +   [case $enableval in
   10.38 +      yes | ltdl | dlfcn | no) ;;
   10.39 +      *) AC_MSG_ERROR([invalid value `$enableval' for --enable-dl]);;
   10.40 +      esac],
   10.41 +   [enable_dl=no])
   10.42 +
   10.43 +AC_ARG_ENABLE(odbc,
   10.44 +AC_HELP_STRING([--enable-odbc],
   10.45 +   [enable MathProg ODBC support [[default=no]]]),
   10.46 +   [case $enableval in
   10.47 +      yes | unix | no) ;;
   10.48 +      *) AC_MSG_ERROR([invalid value `$enableval' for --enable-odbc]);;
   10.49 +      esac],
   10.50 +   [enable_odbc=no])
   10.51 +
   10.52 +AC_ARG_ENABLE(mysql,
   10.53 +AC_HELP_STRING([--enable-mysql],
   10.54 +   [enable MathProg MySQL support [[default=no]]]),
   10.55 +   [case $enableval in
   10.56 +      yes | no) ;;
   10.57 +      *) AC_MSG_ERROR([invalid value `$enableval' for --enable-mysql]);;
   10.58 +      esac],
   10.59 +   [enable_mysql=no])
   10.60 +
   10.61 +dnl Disable unnecessary libtool tests
   10.62 +define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])
   10.63 +define([AC_LIBTOOL_LANG_F77_CONFIG], [:])
   10.64 +define([AC_LIBTOOL_LANG_GCJ_CONFIG], [:])
   10.65 +
   10.66 +dnl Check for programs
   10.67 +AC_PROG_CC
   10.68 +AC_PROG_INSTALL
   10.69 +AC_PROG_LIBTOOL
   10.70 +
   10.71 +dnl Check for math library
   10.72 +AC_CHECK_LIB([m], [exp])
   10.73 +
   10.74 +dnl Check for <sys/time.h> header
   10.75 +AC_CHECK_HEADER([sys/time.h],
   10.76 +   AC_DEFINE([HAVE_SYS_TIME_H], [1], [N/A]))
   10.77 +
   10.78 +dnl Check for gettimeofday function
   10.79 +AC_CHECK_FUNC([gettimeofday],
   10.80 +   AC_DEFINE([HAVE_GETTIMEOFDAY], [1], [N/A]))
   10.81 +
   10.82 +AC_MSG_CHECKING([whether to use GNU MP bignum library])
   10.83 +if test "$with_gmp" = "yes"; then
   10.84 +   AC_MSG_RESULT([yes])
   10.85 +   AC_DEFINE([HAVE_GMP], [1], [N/A])
   10.86 +   LIBS="-lgmp $LIBS"
   10.87 +else
   10.88 +   AC_MSG_RESULT([no])
   10.89 +fi
   10.90 +
   10.91 +AC_MSG_CHECKING([whether to use zlib data compression library])
   10.92 +if test "$with_zlib" = "yes"; then
   10.93 +   AC_MSG_RESULT([yes])
   10.94 +   AC_DEFINE([HAVE_ZLIB], [1], [N/A])
   10.95 +   LIBS="-lz $LIBS"
   10.96 +else
   10.97 +   AC_MSG_RESULT([no])
   10.98 +fi
   10.99 +
  10.100 +AC_MSG_CHECKING([whether to enable shared library support])
  10.101 +if test "$enable_dl" = "yes"; then
  10.102 +   AC_MSG_RESULT([ltdl])
  10.103 +   AC_DEFINE([HAVE_LTDL], [1], [N/A])
  10.104 +   LIBS="-lltdl $LIBS"
  10.105 +elif test "$enable_dl" = "ltdl"; then
  10.106 +   AC_MSG_RESULT([ltdl])
  10.107 +   AC_DEFINE([HAVE_LTDL], [1], [N/A])
  10.108 +   LIBS="-lltdl $LIBS"
  10.109 +elif test "$enable_dl" = "dlfcn"; then
  10.110 +   AC_MSG_RESULT([dlfcn])
  10.111 +   AC_DEFINE([HAVE_DLFCN], [1], [N/A])
  10.112 +else
  10.113 +   AC_MSG_RESULT([no])
  10.114 +fi
  10.115 +
  10.116 +case $host_os in
  10.117 +   darwin* | macosx*)
  10.118 +      LIBIODBC="libiodbc.dylib"
  10.119 +      LIBODBC="libodbc.dylib"
  10.120 +      LIBMYSQL="libmysqlclient.dylib"
  10.121 +      ;;
  10.122 +   *)
  10.123 +      LIBIODBC="libiodbc.so"
  10.124 +      LIBODBC="libodbc.so"
  10.125 +      LIBMYSQL="libmysqlclient.so"
  10.126 +      ;;
  10.127 +esac
  10.128 +
  10.129 +AC_MSG_CHECKING([whether to enable MathProg ODBC support])
  10.130 +if test "$enable_odbc" = "yes"; then
  10.131 +   if test "$enable_dl" = "no"; then
  10.132 +      AC_MSG_ERROR([--enable-odbc requires --enable-dl])
  10.133 +   fi
  10.134 +   AC_MSG_RESULT([yes])
  10.135 +   AC_DEFINE_UNQUOTED([ODBC_DLNAME], ["$LIBIODBC"], [N/A])
  10.136 +elif test "$enable_odbc" = "unix"; then
  10.137 +   if test "$enable_dl" = "no"; then
  10.138 +      AC_MSG_ERROR([--enable-odbc requires --enable-dl])
  10.139 +   fi
  10.140 +   AC_MSG_RESULT([unix])
  10.141 +   AC_DEFINE_UNQUOTED([ODBC_DLNAME], ["$LIBODBC"], [N/A])
  10.142 +else
  10.143 +   AC_MSG_RESULT([no])
  10.144 +fi
  10.145 +
  10.146 +AC_MSG_CHECKING([whether to enable MathProg MySQL support])
  10.147 +if test "$enable_mysql" = "yes"; then
  10.148 +   if test "$enable_dl" = "no"; then
  10.149 +      AC_MSG_ERROR([--enable-mysql requires --enable-dl])
  10.150 +   fi
  10.151 +   AC_MSG_RESULT([yes])
  10.152 +   CPPFLAGS="-I/usr/include/mysql $CPPFLAGS"
  10.153 +   AC_DEFINE_UNQUOTED([MYSQL_DLNAME], ["$LIBMYSQL"], [N/A])
  10.154 +else
  10.155 +   AC_MSG_RESULT([no])
  10.156 +fi
  10.157 +
  10.158 +AC_CONFIG_FILES(
  10.159 +   [include/Makefile src/Makefile examples/Makefile Makefile])
  10.160 +AC_OUTPUT
  10.161 +
  10.162 +dnl eof
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/doc/glpk.tex	Mon Dec 06 13:09:21 2010 +0100
    11.3 @@ -0,0 +1,128 @@
    11.4 +%* glpk.tex *%
    11.5 +
    11.6 +%***********************************************************************
    11.7 +%  This code is part of GLPK (GNU Linear Programming Kit).
    11.8 +%
    11.9 +%  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
   11.10 +%  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
   11.11 +%  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
   11.12 +%  E-mail: <mao@gnu.org>.
   11.13 +%
   11.14 +%  GLPK is free software: you can redistribute it and/or modify it
   11.15 +%  under the terms of the GNU General Public License as published by
   11.16 +%  the Free Software Foundation, either version 3 of the License, or
   11.17 +%  (at your option) any later version.
   11.18 +%
   11.19 +%  GLPK is distributed in the hope that it will be useful, but WITHOUT
   11.20 +%  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   11.21 +%  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
   11.22 +%  License for more details.
   11.23 +%
   11.24 +%  You should have received a copy of the GNU General Public License
   11.25 +%  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
   11.26 +%***********************************************************************
   11.27 +
   11.28 +\documentclass[11pt]{report}
   11.29 +\usepackage{amssymb}
   11.30 +\usepackage{lscape}
   11.31 +\usepackage[dvipdfm,linktocpage,colorlinks,linkcolor=blue,
   11.32 +urlcolor=blue]{hyperref}
   11.33 +\usepackage[all]{xy}
   11.34 +
   11.35 +\renewcommand\contentsname{\sf\bfseries Contents}
   11.36 +\renewcommand\chaptername{\sf\bfseries Chapter}
   11.37 +\renewcommand\appendixname{\sf\bfseries Appendix}
   11.38 +
   11.39 +\begin{document}
   11.40 +
   11.41 +\thispagestyle{empty}
   11.42 +
   11.43 +\begin{center}
   11.44 +
   11.45 +\vspace*{1in}
   11.46 +
   11.47 +\begin{huge}
   11.48 +\sf\bfseries GNU Linear Programming Kit
   11.49 +\end{huge}
   11.50 +
   11.51 +\vspace{0.5in}
   11.52 +
   11.53 +\begin{LARGE}
   11.54 +\sf Reference Manual
   11.55 +\end{LARGE}
   11.56 +
   11.57 +\vspace{0.5in}
   11.58 +
   11.59 +\begin{LARGE}
   11.60 +\sf for GLPK Version 4.45
   11.61 +\end{LARGE}
   11.62 +
   11.63 +\vspace{0.5in}
   11.64 +\begin{Large}
   11.65 +\sf (DRAFT, December 2010)
   11.66 +\end{Large}
   11.67 +\end{center}
   11.68 +
   11.69 +\newpage
   11.70 +
   11.71 +\vspace*{1in}
   11.72 +
   11.73 +\vfill
   11.74 +
   11.75 +\noindent
   11.76 +The GLPK package is part of the GNU Project released under the aegis of
   11.77 +GNU.
   11.78 +
   11.79 +\medskip \noindent
   11.80 +Copyright \copyright{} 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
   11.81 +2008, 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
   11.82 +Moscow Aviation Institute, Moscow, Russia. All rights reserved.
   11.83 +
   11.84 +\medskip \noindent
   11.85 +Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
   11.86 +02110-1301, USA.
   11.87 +
   11.88 +\medskip \noindent
   11.89 +Permission is granted to make and distribute verbatim copies of this
   11.90 +manual provided the copyright notice and this permission notice are
   11.91 +preserved on all copies.
   11.92 +
   11.93 +\medskip \noindent
   11.94 +Permission is granted to copy and distribute modified versions of this
   11.95 +manual under the conditions for verbatim copying, provided also that the
   11.96 +entire resulting derived work is distributed under the terms of
   11.97 +a permission notice identical to this one.
   11.98 +
   11.99 +\medskip \noindent
  11.100 +Permission is granted to copy and distribute translations of this manual
  11.101 +into another language, under the above conditions for modified versions.
  11.102 +
  11.103 +\tableofcontents
  11.104 +
  11.105 +\include{glpk01}
  11.106 +
  11.107 +\include{glpk02}
  11.108 +
  11.109 +\include{glpk03}
  11.110 +
  11.111 +\include{glpk04}
  11.112 +
  11.113 +\include{glpk05}
  11.114 +
  11.115 +\include{glpk06}
  11.116 +
  11.117 +\appendix
  11.118 +
  11.119 +\include{glpk07}
  11.120 +
  11.121 +\include{glpk08}
  11.122 +
  11.123 +\include{glpk09}
  11.124 +
  11.125 +\include{glpk10}
  11.126 +
  11.127 +\include{glpk11}
  11.128 +
  11.129 +\include{glpk12}
  11.130 +
  11.131 +\end{document}
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/doc/glpk01.tex	Mon Dec 06 13:09:21 2010 +0100
    12.3 @@ -0,0 +1,348 @@
    12.4 +%* glpk01.tex *%
    12.5 +
    12.6 +\chapter{Introduction}
    12.7 +
    12.8 +GLPK (\underline{G}NU \underline{L}inear \underline{P}rogramming
    12.9 +\underline{K}it) is a set of routines written in the ANSI C programming
   12.10 +language and organized in the form of a callable library. It is intended
   12.11 +for solving linear programming (LP), mixed integer programming (MIP),
   12.12 +and other related problems.
   12.13 +
   12.14 +\section{LP problem}
   12.15 +\label{seclp}
   12.16 +
   12.17 +GLPK assumes the following formulation of {\it linear programming (LP)}
   12.18 +problem:
   12.19 +
   12.20 +\medskip
   12.21 +
   12.22 +\noindent
   12.23 +\hspace{.5in} minimize (or maximize)
   12.24 +$$z = c_1x_{m+1} + c_2x_{m+2} + \dots + c_nx_{m+n} + c_0 \eqno (1.1)$$
   12.25 +\hspace{.5in} subject to linear constraints
   12.26 +$$
   12.27 +\begin{array}{r@{\:}c@{\:}r@{\:}c@{\:}r@{\:}c@{\:}r}
   12.28 +x_1&=&a_{11}x_{m+1}&+&a_{12}x_{m+2}&+ \dots +&a_{1n}x_{m+n} \\
   12.29 +x_2&=&a_{21}x_{m+1}&+&a_{22}x_{m+2}&+ \dots +&a_{2n}x_{m+n} \\
   12.30 +\multicolumn{7}{c}
   12.31 +{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .} \\
   12.32 +x_m&=&a_{m1}x_{m+1}&+&a_{m2}x_{m+2}&+ \dots +&a_{mn}x_{m+n} \\
   12.33 +\end{array} \eqno (1.2)
   12.34 +$$
   12.35 +\hspace{.5in} and bounds of variables
   12.36 +$$
   12.37 +\begin{array}{r@{\:}c@{\:}c@{\:}c@{\:}l}
   12.38 +l_1&\leq&x_1&\leq&u_1 \\
   12.39 +l_2&\leq&x_2&\leq&u_2 \\
   12.40 +\multicolumn{5}{c}{.\ \ .\ \ .\ \ .\ \ .}\\
   12.41 +l_{m+n}&\leq&x_{m+n}&\leq&u_{m+n} \\
   12.42 +\end{array} \eqno (1.3)
   12.43 +$$
   12.44 +where: $x_1, x_2, \dots, x_m$ are auxiliary variables;
   12.45 +$x_{m+1}, x_{m+2}, \dots, x_{m+n}$ are\linebreak structural variables;
   12.46 +$z$ is the objective function;
   12.47 +$c_1, c_2, \dots, c_n$ are objective coefficients;
   12.48 +$c_0$ is the constant term (``shift'') of the objective function;
   12.49 +$a_{11}, a_{12}, \dots, a_{mn}$ are constraint coefficients;
   12.50 +$l_1, l_2, \dots, l_{m+n}$ are lower bounds of variables;
   12.51 +$u_1, u_2, \dots, u_{m+n}$ are upper bounds of variables.
   12.52 +
   12.53 +Auxiliary variables are also called {\it rows}, because they correspond
   12.54 +to rows of the constraint matrix (i.e. a matrix built of the constraint
   12.55 +coefficients). Similarly, structural variables are also called
   12.56 +{\it columns}, because they correspond to columns of the constraint
   12.57 +matrix.
   12.58 +
   12.59 +Bounds of variables can be finite as well as infinite. Besides, lower
   12.60 +and upper bounds can be equal to each other. Thus, the following types
   12.61 +of variables are possible:
   12.62 +\begin{center}
   12.63 +\begin{tabular}{r@{}c@{}ll}
   12.64 +\multicolumn{3}{c}{Bounds of variable} & Type of variable \\
   12.65 +\hline
   12.66 +$-\infty <$ &$\ x_k\ $& $< +\infty$ & Free (unbounded) variable \\
   12.67 +$l_k \leq$ &$\ x_k\ $& $< +\infty$  & Variable with lower bound \\
   12.68 +$-\infty <$ &$\ x_k\ $& $\leq u_k$  & Variable with upper bound \\
   12.69 +$l_k \leq$ &$\ x_k\ $& $\leq u_k$   & Double-bounded variable \\
   12.70 +$l_k =$ &$\ x_k\ $& $= u_k$         & Fixed variable \\
   12.71 +\end{tabular}
   12.72 +\end{center}
   12.73 +\noindent
   12.74 +Note that the types of variables shown above are applicable to
   12.75 +structural as well as to auxiliary variables.
   12.76 +
   12.77 +To solve the LP problem (1.1)---(1.3) is to find such values of all
   12.78 +structural and auxiliary variables, which:
   12.79 +
   12.80 +$\bullet$ satisfy to all the linear constraints (1.2), and
   12.81 +
   12.82 +$\bullet$ are within their bounds (1.3), and
   12.83 +
   12.84 +$\bullet$ provide the smallest (in case of minimization) or the largest
   12.85 +(in case of maximization) value of the objective function (1.1).
   12.86 +
   12.87 +\section{MIP problem}
   12.88 +
   12.89 +{\it Mixed integer linear programming (MIP)} problem is LP problem in
   12.90 +which some variables are additionally required to be integer.
   12.91 +
   12.92 +GLPK assumes that MIP problem has the same formulation as ordinary
   12.93 +(pure) LP problem (1.1)---(1.3), i.e. includes auxiliary and structural
   12.94 +variables, which may have lower and/or upper bounds. However, in case of
   12.95 +MIP problem some variables may be required to be integer. This
   12.96 +additional constraint means that a value of each {\it integer variable}
   12.97 +must be only integer number. (Should note that GLPK allows only
   12.98 +structural variables to be of integer kind.)
   12.99 +
  12.100 +\section{Using the package}
  12.101 +
  12.102 +\subsection{Brief example}
  12.103 +
  12.104 +In order to understand what GLPK is from the user's standpoint,
  12.105 +consider the following simple LP problem:
  12.106 +
  12.107 +\medskip
  12.108 +
  12.109 +\noindent
  12.110 +\hspace{.5in} maximize
  12.111 +$$z = 10 x_1 + 6 x_2 + 4 x_3$$
  12.112 +\hspace{.5in} subject to
  12.113 +$$
  12.114 +\begin{array}{r@{\:}c@{\:}r@{\:}c@{\:}r@{\:}c@{\:}r}
  12.115 +x_1 &+&x_2 &+&x_3 &\leq 100 \\
  12.116 +10 x_1 &+& 4 x_2 & +&5 x_3 & \leq 600 \\
  12.117 +2 x_1 &+& 2 x_2 & +& 6 x_3 & \leq 300 \\
  12.118 +\end{array}
  12.119 +$$
  12.120 +\hspace{.5in} where all variables are non-negative
  12.121 +$$x_1 \geq 0, \ x_2 \geq 0, \ x_3 \geq 0$$
  12.122 +
  12.123 +At first this LP problem should be transformed to the standard form
  12.124 +(1.1)---(1.3). This can be easily done by introducing auxiliary
  12.125 +variables, by one for each original inequality constraint. Thus, the
  12.126 +problem can be reformulated as follows:
  12.127 +
  12.128 +\medskip
  12.129 +
  12.130 +\noindent
  12.131 +\hspace{.5in} maximize
  12.132 +$$z = 10 x_1 + 6 x_2 + 4 x_3$$
  12.133 +\hspace{.5in} subject to
  12.134 +$$
  12.135 +\begin{array}{r@{\:}c@{\:}r@{\:}c@{\:}r@{\:}c@{\:}r}
  12.136 +p& = &x_1 &+&x_2 &+&x_3 \\
  12.137 +q& = &10 x_1 &+& 4 x_2 &+& 5 x_3 \\
  12.138 +r& = &2  x_1 &+& 2 x_2 &+& 6 x_3 \\
  12.139 +\end{array}
  12.140 +$$
  12.141 +\hspace{.5in} and bounds of variables
  12.142 +$$
  12.143 +\begin{array}{ccc}
  12.144 +\nonumber -\infty < p \leq 100 && 0 \leq x_1 < +\infty \\
  12.145 +\nonumber -\infty < q \leq 600 && 0 \leq x_2 < +\infty \\
  12.146 +\nonumber -\infty < r \leq 300 && 0 \leq x_3 < +\infty \\
  12.147 +\end{array}
  12.148 +$$
  12.149 +where $p, q, r$ are auxiliary variables (rows), and $x_1, x_2, x_3$ are
  12.150 +structural variables (columns).
  12.151 +
  12.152 +The example C program shown below uses GLPK API routines in order to
  12.153 +solve this LP problem.\footnote{If you just need to solve LP or MIP
  12.154 +instance, you may write it in MPS or CPLEX LP format and then use the
  12.155 +GLPK stand-alone solver to obtain a solution. This is much less
  12.156 +time-consuming than programming in C with GLPK API routines.}
  12.157 +
  12.158 +\newpage
  12.159 +
  12.160 +\begin{verbatim}
  12.161 +/* sample.c */
  12.162 +
  12.163 +#include <stdio.h>
  12.164 +#include <stdlib.h>
  12.165 +#include <glpk.h>
  12.166 +
  12.167 +int main(void)
  12.168 +{     glp_prob *lp;
  12.169 +      int ia[1+1000], ja[1+1000];
  12.170 +      double ar[1+1000], z, x1, x2, x3;
  12.171 +s1:   lp = glp_create_prob();
  12.172 +s2:   glp_set_prob_name(lp, "sample");
  12.173 +s3:   glp_set_obj_dir(lp, GLP_MAX);
  12.174 +s4:   glp_add_rows(lp, 3);
  12.175 +s5:   glp_set_row_name(lp, 1, "p");
  12.176 +s6:   glp_set_row_bnds(lp, 1, GLP_UP, 0.0, 100.0);
  12.177 +s7:   glp_set_row_name(lp, 2, "q");
  12.178 +s8:   glp_set_row_bnds(lp, 2, GLP_UP, 0.0, 600.0);
  12.179 +s9:   glp_set_row_name(lp, 3, "r");
  12.180 +s10:  glp_set_row_bnds(lp, 3, GLP_UP, 0.0, 300.0);
  12.181 +s11:  glp_add_cols(lp, 3);
  12.182 +s12:  glp_set_col_name(lp, 1, "x1");
  12.183 +s13:  glp_set_col_bnds(lp, 1, GLP_LO, 0.0, 0.0);
  12.184 +s14:  glp_set_obj_coef(lp, 1, 10.0);
  12.185 +s15:  glp_set_col_name(lp, 2, "x2");
  12.186 +s16:  glp_set_col_bnds(lp, 2, GLP_LO, 0.0, 0.0);
  12.187 +s17:  glp_set_obj_coef(lp, 2, 6.0);
  12.188 +s18:  glp_set_col_name(lp, 3, "x3");
  12.189 +s19:  glp_set_col_bnds(lp, 3, GLP_LO, 0.0, 0.0);
  12.190 +s20:  glp_set_obj_coef(lp, 3, 4.0);
  12.191 +s21:  ia[1] = 1, ja[1] = 1, ar[1] =  1.0; /* a[1,1] =  1 */
  12.192 +s22:  ia[2] = 1, ja[2] = 2, ar[2] =  1.0; /* a[1,2] =  1 */
  12.193 +s23:  ia[3] = 1, ja[3] = 3, ar[3] =  1.0; /* a[1,3] =  1 */
  12.194 +s24:  ia[4] = 2, ja[4] = 1, ar[4] = 10.0; /* a[2,1] = 10 */
  12.195 +s25:  ia[5] = 3, ja[5] = 1, ar[5] =  2.0; /* a[3,1] =  2 */
  12.196 +s26:  ia[6] = 2, ja[6] = 2, ar[6] =  4.0; /* a[2,2] =  4 */
  12.197 +s27:  ia[7] = 3, ja[7] = 2, ar[7] =  2.0; /* a[3,2] =  2 */
  12.198 +s28:  ia[8] = 2, ja[8] = 3, ar[8] =  5.0; /* a[2,3] =  5 */
  12.199 +s29:  ia[9] = 3, ja[9] = 3, ar[9] =  6.0; /* a[3,3] =  6 */
  12.200 +s30:  glp_load_matrix(lp, 9, ia, ja, ar);
  12.201 +s31:  glp_simplex(lp, NULL);
  12.202 +s32:  z = glp_get_obj_val(lp);
  12.203 +s33:  x1 = glp_get_col_prim(lp, 1);
  12.204 +s34:  x2 = glp_get_col_prim(lp, 2);
  12.205 +s35:  x3 = glp_get_col_prim(lp, 3);
  12.206 +s36:  printf("\nz = %g; x1 = %g; x2 = %g; x3 = %g\n",
  12.207 +         z, x1, x2, x3);
  12.208 +s37:  glp_delete_prob(lp);
  12.209 +      return 0;
  12.210 +}
  12.211 +
  12.212 +/* eof */
  12.213 +\end{verbatim}
  12.214 +
  12.215 +The statement \verb|s1| creates a problem object. Being created the
  12.216 +object is initially empty. The statement \verb|s2| assigns a symbolic
  12.217 +name to the problem object.
  12.218 +
  12.219 +The statement \verb|s3| calls the routine \verb|glp_set_obj_dir| in
  12.220 +order to set the optimization direction flag, where \verb|GLP_MAX| means
  12.221 +maximization.
  12.222 +
  12.223 +The statement \verb|s4| adds three rows to the problem object.
  12.224 +
  12.225 +The statement \verb|s5| assigns the symbolic name `\verb|p|' to the
  12.226 +first row, and the statement \verb|s6| sets the type and bounds of the
  12.227 +first row, where \verb|GLP_UP| means that the row has an upper bound.
  12.228 +The statements \verb|s7|, \verb|s8|, \verb|s9|, \verb|s10| are used in
  12.229 +the same way in order to assign the symbolic names `\verb|q|' and
  12.230 +`\verb|r|' to the second and third rows and set their types and bounds.
  12.231 +
  12.232 +The statement \verb|s11| adds three columns to the problem object.
  12.233 +
  12.234 +The statement \verb|s12| assigns the symbolic name `\verb|x1|' to the
  12.235 +first column, the statement \verb|s13| sets the type and bounds of the
  12.236 +first column, where \verb|GLP_LO| means that the column has an lower
  12.237 +bound, and the statement \verb|s14| sets the objective coefficient for
  12.238 +the first column. The statements \verb|s15|---\verb|s20| are used in the
  12.239 +same way in order to assign the symbolic names `\verb|x2|' and
  12.240 +`\verb|x3|' to the second and third columns and set their types, bounds,
  12.241 +and objective coefficients.
  12.242 +
  12.243 +The statements \verb|s21|---\verb|s29| prepare non-zero elements of the
  12.244 +constraint matrix (i.e. constraint coefficients). Row indices of each
  12.245 +element are stored in the array \verb|ia|, column indices are stored in
  12.246 +the array \verb|ja|, and numerical values of corresponding elements are
  12.247 +stored in the array \verb|ar|. Then the statement \verb|s30| calls
  12.248 +the routine \verb|glp_load_matrix|, which loads information from these
  12.249 +three arrays into the problem object.
  12.250 +
  12.251 +Now all data have been entered into the problem object, and therefore
  12.252 +the statement \verb|s31| calls the routine \verb|glp_simplex|, which is
  12.253 +a driver to the simplex method, in order to solve the LP problem. This
  12.254 +routine finds an optimal solution and stores all relevant information
  12.255 +back into the problem object.
  12.256 +
  12.257 +The statement \verb|s32| obtains a computed value of the objective
  12.258 +function, and the statements \verb|s33|---\verb|s35| obtain computed
  12.259 +values of structural variables (columns), which correspond to the
  12.260 +optimal basic solution found by the solver.
  12.261 +
  12.262 +The statement \verb|s36| writes the optimal solution to the standard
  12.263 +output. The printout may look like follows:
  12.264 +
  12.265 +{\footnotesize
  12.266 +\begin{verbatim}
  12.267 +*     0:   objval =   0.000000000e+00   infeas =   0.000000000e+00 (0)
  12.268 +*     2:   objval =   7.333333333e+02   infeas =   0.000000000e+00 (0)
  12.269 +OPTIMAL SOLUTION FOUND
  12.270 +
  12.271 +z = 733.333; x1 = 33.3333; x2 = 66.6667; x3 = 0
  12.272 +\end{verbatim}
  12.273 +
  12.274 +}
  12.275 +
  12.276 +Finally, the statement \verb|s37| calls the routine
  12.277 +\verb|glp_delete_prob|, which frees all the memory allocated to the
  12.278 +problem object.
  12.279 +
  12.280 +\subsection{Compiling}
  12.281 +
  12.282 +The GLPK package has the only header file \verb|glpk.h|, which should
  12.283 +be available on compiling a C (or C++) program using GLPK API routines.
  12.284 +
  12.285 +If the header file is installed in the default location
  12.286 +\verb|/usr/local/include|, the following typical command may be used to
  12.287 +compile, say, the example C program described above with the GNU C
  12.288 +compiler:
  12.289 +
  12.290 +\begin{verbatim}
  12.291 +   $ gcc -c sample.c
  12.292 +\end{verbatim}
  12.293 +
  12.294 +If \verb|glpk.h| is not in the default location, the corresponding
  12.295 +directory containing it should be made known to the C compiler through
  12.296 +\verb|-I| option, for example:
  12.297 +
  12.298 +\begin{verbatim}
  12.299 +   $ gcc -I/foo/bar/glpk-4.15/include -c sample.c
  12.300 +\end{verbatim}
  12.301 +
  12.302 +In any case the compilation results in an object file \verb|sample.o|.
  12.303 +
  12.304 +\subsection{Linking}
  12.305 +
  12.306 +The GLPK library is a single file \verb|libglpk.a|. (On systems which
  12.307 +support shared libraries there may be also a shared version of the
  12.308 +library \verb|libglpk.so|.)
  12.309 +
  12.310 +If the library is installed in the default
  12.311 +location \verb|/usr/local/lib|, the following typical command may be
  12.312 +used to link, say, the example C program described above against with
  12.313 +the library:
  12.314 +
  12.315 +\begin{verbatim}
  12.316 +   $ gcc sample.o -lglpk -lm
  12.317 +\end{verbatim}
  12.318 +
  12.319 +If the GLPK library is not in the default location, the corresponding
  12.320 +directory containing it should be made known to the linker through
  12.321 +\verb|-L| option, for example:
  12.322 +
  12.323 +\begin{verbatim}
  12.324 +   $ gcc -L/foo/bar/glpk-4.15 sample.o -lglpk -lm
  12.325 +\end{verbatim}
  12.326 +
  12.327 +Depending on configuration of the package linking against with the GLPK
  12.328 +library may require the following optional libraries:
  12.329 +
  12.330 +\bigskip
  12.331 +
  12.332 +\begin{tabular}{@{}ll}
  12.333 +\verb|-lgmp|  & the GNU MP bignum library; \\
  12.334 +\verb|-lz|    & the zlib data compression library; \\
  12.335 +\verb|-lltdl| & the GNU ltdl shared support library. \\
  12.336 +\end{tabular}
  12.337 +
  12.338 +\bigskip
  12.339 +
  12.340 +\noindent
  12.341 +in which case corresponding libraries should be also made known to the
  12.342 +linker, for example:
  12.343 +
  12.344 +\begin{verbatim}
  12.345 +   $ gcc sample.o -lglpk -lz -lltdl -lm
  12.346 +\end{verbatim}
  12.347 +
  12.348 +For more details about configuration options of the GLPK package see
  12.349 +Appendix \ref{install}, page \pageref{install}.
  12.350 +
  12.351 +%* eof *%
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/doc/glpk02.tex	Mon Dec 06 13:09:21 2010 +0100
    13.3 @@ -0,0 +1,3406 @@
    13.4 +%* glpk02.tex *%
    13.5 +
    13.6 +\chapter{Basic API Routines}
    13.7 +
    13.8 +This chapter describes GLPK API routines intended for using in
    13.9 +application programs.
   13.10 +
   13.11 +\subsubsection*{Library header}
   13.12 +
   13.13 +All GLPK API data types and routines are defined in the header file
   13.14 +\verb|glpk.h|. It should be included in all source files which use
   13.15 +GLPK API, either directly or indirectly through some other header file
   13.16 +as follows:
   13.17 +
   13.18 +\begin{verbatim}
   13.19 +   #include <glpk.h>
   13.20 +\end{verbatim}
   13.21 +
   13.22 +\subsubsection*{Error handling}
   13.23 +
   13.24 +If some GLPK API routine detects erroneous or incorrect data passed by
   13.25 +the application program, it writes appropriate diagnostic messages to
   13.26 +the terminal and then abnormally terminates the application program.
   13.27 +In most practical cases this allows to simplify programming by avoiding
   13.28 +numerous checks of return codes. Thus, in order to prevent crashing the
   13.29 +application program should check all data, which are suspected to be
   13.30 +incorrect, before calling GLPK API routines.
   13.31 +
   13.32 +Should note that this kind of error handling is used only in cases of
   13.33 +incorrect data passed by the application program. If, for example, the
   13.34 +application program calls some GLPK API routine to read data from an
   13.35 +input file and these data are incorrect, the GLPK API routine reports
   13.36 +about error in the usual way by means of the return code.
   13.37 +
   13.38 +\subsubsection*{Thread safety}
   13.39 +
   13.40 +Currently GLPK API routines are non-reentrant and therefore cannot be
   13.41 +used in multi-threaded programs.
   13.42 +
   13.43 +\subsubsection*{Array indexing}
   13.44 +
   13.45 +Normally all GLPK API routines start array indexing from 1, not from 0
   13.46 +(except the specially stipulated cases). This means, for example, that
   13.47 +if some vector $x$ of the length $n$ is passed as an array to some GLPK
   13.48 +API routine, the latter expects vector components to be placed in
   13.49 +locations \verb|x[1]|, \verb|x[2]|, \dots, \verb|x[n]|, and the location
   13.50 +\verb|x[0]| normally is not used.
   13.51 +
   13.52 +In order to avoid indexing errors it is most convenient and most
   13.53 +reliable to declare the array \verb|x| as follows:
   13.54 +
   13.55 +\begin{verbatim}
   13.56 +   double x[1+n];
   13.57 +\end{verbatim}
   13.58 +
   13.59 +\noindent
   13.60 +or to allocate it as follows:
   13.61 +
   13.62 +\begin{verbatim}
   13.63 +   double *x;
   13.64 +   . . .
   13.65 +   x = calloc(1+n, sizeof(double));
   13.66 +\end{verbatim}
   13.67 +
   13.68 +\noindent
   13.69 +In both cases one extra location \verb|x[0]| is reserved that allows
   13.70 +passing the array to GLPK routines in a usual way.
   13.71 +
   13.72 +\section{Problem object}
   13.73 +
   13.74 +All GLPK API routines deal with so called {\it problem object}, which
   13.75 +is a program object of type \verb|glp_prob| and intended to represent
   13.76 +a particular LP or MIP instance.
   13.77 +
   13.78 +The type \verb|glp_prob| is a data structure declared in the header
   13.79 +file \verb|glpk.h| as follows:
   13.80 +
   13.81 +\begin{verbatim}
   13.82 +   typedef struct { ... } glp_prob;
   13.83 +\end{verbatim}
   13.84 +
   13.85 +Problem objects (i.e. program objects of the \verb|glp_prob| type) are
   13.86 +allocated and managed internally by the GLPK API routines. The
   13.87 +application program should never use any members of the \verb|glp_prob|
   13.88 +structure directly and should deal only with pointers to these objects
   13.89 +(that is, \verb|glp_prob *| values).
   13.90 +
   13.91 +\pagebreak
   13.92 +
   13.93 +The problem object consists of five segments, which are:
   13.94 +
   13.95 +$\bullet$ problem segment,
   13.96 +
   13.97 +$\bullet$ basis segment,
   13.98 +
   13.99 +$\bullet$ interior point segment,
  13.100 +
  13.101 +$\bullet$ MIP segment, and
  13.102 +
  13.103 +$\bullet$ control parameters and statistics segment.
  13.104 +
  13.105 +\subsubsection*{Problem segment}
  13.106 +
  13.107 +The {\it problem segment} contains original LP/MIP data, which
  13.108 +corresponds to the problem formulation (1.1)---(1.3) (see Section
  13.109 +\ref{seclp}, page \pageref{seclp}). It includes the following
  13.110 +components:
  13.111 +
  13.112 +$\bullet$ rows (auxiliary variables),
  13.113 +
  13.114 +$\bullet$ columns (structural variables),
  13.115 +
  13.116 +$\bullet$ objective function, and
  13.117 +
  13.118 +$\bullet$ constraint matrix.
  13.119 +
  13.120 +Rows and columns have the same set of the following attributes:
  13.121 +
  13.122 +$\bullet$ ordinal number,
  13.123 +
  13.124 +$\bullet$ symbolic name (1 up to 255 arbitrary graphic characters),
  13.125 +
  13.126 +$\bullet$ type (free, lower bound, upper bound, double bound, fixed),
  13.127 +
  13.128 +$\bullet$ numerical values of lower and upper bounds,
  13.129 +
  13.130 +$\bullet$ scale factor.
  13.131 +
  13.132 +{\it Ordinal numbers} are intended for referencing rows and columns.
  13.133 +Row ordinal numbers are integers $1, 2, \dots, m$, and column ordinal
  13.134 +numbers are integers $1, 2, \dots, n$, where $m$ and $n$ are,
  13.135 +respectively, the current number of rows and columns in the problem
  13.136 +object.
  13.137 +
  13.138 +{\it Symbolic names} are intended for informational purposes. They also
  13.139 +can be used for referencing rows and columns.
  13.140 +
  13.141 +{\it Types and bounds} of rows (auxiliary variables) and columns
  13.142 +(structural variables) are explained above (see Section \ref{seclp},
  13.143 +page \pageref{seclp}).
  13.144 +
  13.145 +{\it Scale factors} are used internally for scaling rows and columns of
  13.146 +the constraint matrix.
  13.147 +
  13.148 +Information about the {\it objective function} includes numerical
  13.149 +values of objective coefficients and a flag, which defines the
  13.150 +optimization direction (i.e. minimization or maximization).
  13.151 +
  13.152 +The {\it constraint matrix} is a $m \times n$ rectangular matrix built
  13.153 +of constraint coefficients $a_{ij}$, which defines the system of linear
  13.154 +constraints (1.2) (see Section \ref{seclp}, page \pageref{seclp}). This
  13.155 +matrix is stored in the problem object in both row-wise and column-wise
  13.156 +sparse formats.
  13.157 +
  13.158 +Once the problem object has been created, the application program can
  13.159 +access and modify any components of the problem segment in arbitrary
  13.160 +order.
  13.161 +
  13.162 +\subsubsection*{Basis segment}
  13.163 +
  13.164 +The {\it basis segment} of the problem object keeps information related
  13.165 +to the current basic solution. It includes:
  13.166 +
  13.167 +$\bullet$ row and column statuses,
  13.168 +
  13.169 +$\bullet$ basic solution statuses,
  13.170 +
  13.171 +$\bullet$ factorization of the current basis matrix, and
  13.172 +
  13.173 +$\bullet$ basic solution components.
  13.174 +
  13.175 +The {\it row and column statuses} define which rows and columns are
  13.176 +basic and which are non-basic. These statuses may be assigned either by
  13.177 +the application program of by some API routines. Note that these
  13.178 +statuses are always defined independently on whether the corresponding
  13.179 +basis is valid or not.
  13.180 +
  13.181 +The {\it basic solution statuses} include the {\it primal status} and
  13.182 +the {\it dual status}, which are set by the simplex-based solver once
  13.183 +the problem has been solved. The primal status shows whether a primal
  13.184 +basic solution is feasible, infeasible, or undefined. The dual status
  13.185 +shows the same for a dual basic solution.
  13.186 +
  13.187 +The {\it factorization of the basis matrix} is some factorized form
  13.188 +(like LU-factorization) of the current basis matrix (defined by the
  13.189 +current row and column statuses). The factorization is used by the
  13.190 +simplex-based solver and kept when the solver terminates the search.
  13.191 +This feature allows efficiently reoptimizing the problem after some
  13.192 +modifications (for example, after changing some bounds or objective
  13.193 +coefficients). It also allows performing the post-optimal analysis (for
  13.194 +example, computing components of the simplex table, etc.).
  13.195 +
  13.196 +The {\it basic solution components} include primal and dual values of
  13.197 +all auxiliary and structural variables for the most recently obtained
  13.198 +basic solution.
  13.199 +
  13.200 +\subsubsection*{Interior point segment}
  13.201 +
  13.202 +The {\it interior point segment} is automatically allocated after the
  13.203 +problem has been solved using the interior point solver. It contains
  13.204 +interior point solution components, which include the solution status,
  13.205 +and primal and dual values of all auxiliary and structural variables.
  13.206 +
  13.207 +\subsubsection*{MIP segment}
  13.208 +
  13.209 +The {\it MIP segment} is used only for MIP problems. This segment
  13.210 +includes:
  13.211 +
  13.212 +$\bullet$ column kinds,
  13.213 +
  13.214 +$\bullet$ MIP solution status, and
  13.215 +
  13.216 +$\bullet$ MIP solution components.
  13.217 +
  13.218 +The {\it column kinds} define which columns (i.e. structural variables)
  13.219 +are integer and which are continuous.
  13.220 +
  13.221 +The {\it MIP solution status} is set by the MIP solver and shows whether
  13.222 +a MIP solution is integer optimal, integer feasible (non-optimal), or
  13.223 +undefined.
  13.224 +
  13.225 +The {\it MIP solution components} are computed by the MIP solver and
  13.226 +include primal values of all auxiliary and structural variables for the
  13.227 +most recently obtained MIP solution.
  13.228 +
  13.229 +Note that in case of MIP problem the basis segment corresponds to
  13.230 +the optimal solution of LP relaxation, which is also available to the
  13.231 +application program.
  13.232 +
  13.233 +Currently the search tree is not kept in the MIP segment. Therefore if
  13.234 +the search has been terminated, it cannot be continued.
  13.235 +
  13.236 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  13.237 +
  13.238 +\newpage
  13.239 +
  13.240 +\section{Problem creating and modifying routines}
  13.241 +
  13.242 +\subsection{glp\_create\_prob---create problem object}
  13.243 +
  13.244 +\subsubsection*{Synopsis}
  13.245 +
  13.246 +\begin{verbatim}
  13.247 +glp_prob *glp_create_prob(void);
  13.248 +\end{verbatim}
  13.249 +
  13.250 +\subsubsection*{Description}
  13.251 +
  13.252 +The routine \verb|glp_create_prob| creates a new problem object, which
  13.253 +initially is ``empty'', i.e. has no rows and columns.
  13.254 +
  13.255 +\subsubsection*{Returns}
  13.256 +
  13.257 +The routine returns a pointer to the created object, which should be
  13.258 +used in any subsequent operations on this object.
  13.259 +
  13.260 +\subsection{glp\_set\_prob\_name---assign (change) problem name}
  13.261 +
  13.262 +\subsubsection*{Synopsis}
  13.263 +
  13.264 +\begin{verbatim}
  13.265 +void glp_set_prob_name(glp_prob *lp, const char *name);
  13.266 +\end{verbatim}
  13.267 +
  13.268 +\subsubsection*{Description}
  13.269 +
  13.270 +The routine \verb|glp_set_prob_name| assigns a given symbolic
  13.271 +\verb|name| (1 up to 255 characters) to the specified problem object.
  13.272 +
  13.273 +If the parameter \verb|name| is \verb|NULL| or empty string, the routine
  13.274 +erases an existing symbolic name of the problem object.
  13.275 +
  13.276 +\subsection{glp\_set\_obj\_name---assign (change) objective function
  13.277 +name}
  13.278 +
  13.279 +\subsubsection*{Synopsis}
  13.280 +
  13.281 +\begin{verbatim}
  13.282 +void glp_set_obj_name(glp_prob *lp, const char *name);
  13.283 +\end{verbatim}
  13.284 +
  13.285 +\subsubsection*{Description}
  13.286 +
  13.287 +The routine \verb|glp_set_obj_name| assigns a given symbolic
  13.288 +\verb|name| (1 up to 255 characters) to the objective function of the
  13.289 +specified problem object.
  13.290 +
  13.291 +If the parameter \verb|name| is \verb|NULL| or empty string, the routine
  13.292 +erases an existing symbolic name of the objective function.
  13.293 +
  13.294 +\subsection{glp\_set\_obj\_dir---set (change) optimization direction\\
  13.295 +flag}
  13.296 +
  13.297 +\subsubsection*{Synopsis}
  13.298 +
  13.299 +\begin{verbatim}
  13.300 +void glp_set_obj_dir(glp_prob *lp, int dir);
  13.301 +\end{verbatim}
  13.302 +
  13.303 +\subsubsection*{Description}
  13.304 +
  13.305 +The routine \verb|glp_set_obj_dir| sets (changes) the optimization
  13.306 +direction flag (i.e. ``sense'' of the objective function) as specified
  13.307 +by the parameter \verb|dir|:
  13.308 +
  13.309 +\begin{tabular}{@{}ll}
  13.310 +\verb|GLP_MIN| & minimization; \\
  13.311 +\verb|GLP_MAX| & maximization. \\
  13.312 +\end{tabular}
  13.313 +
  13.314 +\noindent
  13.315 +(Note that by default the problem is minimization.)
  13.316 +
  13.317 +\subsection{glp\_add\_rows---add new rows to problem object}
  13.318 +
  13.319 +\subsubsection*{Synopsis}
  13.320 +
  13.321 +\begin{verbatim}
  13.322 +int glp_add_rows(glp_prob *lp, int nrs);
  13.323 +\end{verbatim}
  13.324 +
  13.325 +\subsubsection*{Description}
  13.326 +
  13.327 +The routine \verb|glp_add_rows| adds \verb|nrs| rows (constraints) to
  13.328 +the specified problem object. New rows are always added to the end of
  13.329 +the row list, so the ordinal numbers of existing rows are not changed.
  13.330 +
  13.331 +Being added each new row is initially free (unbounded) and has empty
  13.332 +list of the constraint coefficients.
  13.333 +
  13.334 +\subsubsection*{Returns}
  13.335 +
  13.336 +The routine \verb|glp_add_rows| returns the ordinal number of the first
  13.337 +new row added to the problem object.
  13.338 +
  13.339 +\newpage
  13.340 +
  13.341 +\subsection{glp\_add\_cols---add new columns to problem object}
  13.342 +
  13.343 +\subsubsection*{Synopsis}
  13.344 +
  13.345 +\begin{verbatim}
  13.346 +int glp_add_cols(glp_prob *lp, int ncs);
  13.347 +\end{verbatim}
  13.348 +
  13.349 +\subsubsection*{Description}
  13.350 +
  13.351 +The routine \verb|glp_add_cols| adds \verb|ncs| columns (structural
  13.352 +variables) to the specified problem object. New columns are always added
  13.353 +to the end of the column list, so the ordinal numbers of existing
  13.354 +columns are not changed.
  13.355 +
  13.356 +Being added each new column is initially fixed at zero and has empty
  13.357 +list of the constraint coefficients.
  13.358 +
  13.359 +\subsubsection*{Returns}
  13.360 +
  13.361 +The routine \verb|glp_add_cols| returns the ordinal number of the first
  13.362 +new column added to the problem object.
  13.363 +
  13.364 +\subsection{glp\_set\_row\_name---assign (change) row name}
  13.365 +
  13.366 +\subsubsection*{Synopsis}
  13.367 +
  13.368 +\begin{verbatim}
  13.369 +void glp_set_row_name(glp_prob *lp, int i, const char *name);
  13.370 +\end{verbatim}
  13.371 +
  13.372 +\subsubsection*{Description}
  13.373 +
  13.374 +The routine \verb|glp_set_row_name| assigns a given symbolic
  13.375 +\verb|name| (1 up to 255 characters) to \verb|i|-th row (auxiliary
  13.376 +variable) of the specified problem object.
  13.377 +
  13.378 +If the parameter \verb|name| is \verb|NULL| or empty string, the routine
  13.379 +erases an existing name of $i$-th row.
  13.380 +
  13.381 +\subsection{glp\_set\_col\_name---assign (change) column name}
  13.382 +
  13.383 +\subsubsection*{Synopsis}
  13.384 +
  13.385 +\begin{verbatim}
  13.386 +void glp_set_col_name(glp_prob *lp, int j, const char *name);
  13.387 +\end{verbatim}
  13.388 +
  13.389 +\subsubsection*{Description}
  13.390 +
  13.391 +The routine \verb|glp_set_col_name| assigns a given symbolic
  13.392 +\verb|name| (1 up to 255 characters) to \verb|j|-th column (structural
  13.393 +variable) of the specified problem object.
  13.394 +
  13.395 +If the parameter \verb|name| is \verb|NULL| or empty string, the routine
  13.396 +erases an existing name of $j$-th column.
  13.397 +
  13.398 +\subsection{glp\_set\_row\_bnds---set (change) row bounds}
  13.399 +
  13.400 +\subsubsection*{Synopsis}
  13.401 +
  13.402 +\begin{verbatim}
  13.403 +void glp_set_row_bnds(glp_prob *lp, int i, int type,
  13.404 +      double lb, double ub);
  13.405 +\end{verbatim}
  13.406 +
  13.407 +\subsubsection*{Description}
  13.408 +
  13.409 +The routine \verb|glp_set_row_bnds| sets (changes) the type and bounds
  13.410 +of \verb|i|-th row (auxiliary variable) of the specified problem object.
  13.411 +
  13.412 +The parameters \verb|type|, \verb|lb|, and \verb|ub| specify the type,
  13.413 +lower bound, and upper bound, respectively, as follows:
  13.414 +
  13.415 +\begin{center}
  13.416 +\begin{tabular}{cr@{}c@{}ll}
  13.417 +Type & \multicolumn{3}{c}{Bounds} & Comment \\
  13.418 +\hline
  13.419 +\verb|GLP_FR| & $-\infty <$ &$\ x\ $& $< +\infty$
  13.420 +   & Free (unbounded) variable \\
  13.421 +\verb|GLP_LO| & $lb \leq$ &$\ x\ $& $< +\infty$
  13.422 +   & Variable with lower bound \\
  13.423 +\verb|GLP_UP| & $-\infty <$ &$\ x\ $& $\leq ub$
  13.424 +   & Variable with upper bound \\
  13.425 +\verb|GLP_DB| & $lb \leq$ &$\ x\ $& $\leq ub$
  13.426 +   & Double-bounded variable \\
  13.427 +\verb|GLP_FX| & $lb =$ &$\ x\ $& $= ub$
  13.428 +   & Fixed variable \\
  13.429 +\end{tabular}
  13.430 +\end{center}
  13.431 +
  13.432 +\noindent
  13.433 +where $x$ is the auxiliary variable associated with $i$-th row.
  13.434 +
  13.435 +If the row has no lower bound, the parameter \verb|lb| is ignored. If
  13.436 +the row has no upper bound, the parameter \verb|ub| is ignored. If the
  13.437 +row is an equality constraint (i.e. the corresponding auxiliary variable
  13.438 +is of fixed type), only the parameter \verb|lb| is used while the
  13.439 +parameter \verb|ub| is ignored.
  13.440 +
  13.441 +Being added to the problem object each row is initially free, i.e. its
  13.442 +type is \verb|GLP_FR|.
  13.443 +
  13.444 +\newpage
  13.445 +
  13.446 +\subsection{glp\_set\_col\_bnds---set (change) column bounds}
  13.447 +
  13.448 +\subsubsection*{Synopsis}
  13.449 +
  13.450 +\begin{verbatim}
  13.451 +void glp_set_col_bnds(glp_prob *lp, int j, int type,
  13.452 +      double lb, double ub);
  13.453 +\end{verbatim}
  13.454 +
  13.455 +\subsubsection*{Description}
  13.456 +
  13.457 +The routine \verb|glp_set_col_bnds| sets (changes) the type and bounds
  13.458 +of \verb|j|-th column (structural variable) of the specified problem
  13.459 +object.
  13.460 +
  13.461 +The parameters \verb|type|, \verb|lb|, and \verb|ub| specify the type,
  13.462 +lower bound, and upper bound, respectively, as follows:
  13.463 +
  13.464 +\begin{center}
  13.465 +\begin{tabular}{cr@{}c@{}ll}
  13.466 +Type & \multicolumn{3}{c}{Bounds} & Comment \\
  13.467 +\hline
  13.468 +\verb|GLP_FR| & $-\infty <$ &$\ x\ $& $< +\infty$
  13.469 +   & Free (unbounded) variable \\
  13.470 +\verb|GLP_LO| & $lb \leq$ &$\ x\ $& $< +\infty$
  13.471 +   & Variable with lower bound \\
  13.472 +\verb|GLP_UP| & $-\infty <$ &$\ x\ $& $\leq ub$
  13.473 +   & Variable with upper bound \\
  13.474 +\verb|GLP_DB| & $lb \leq$ &$\ x\ $& $\leq ub$
  13.475 +   & Double-bounded variable \\
  13.476 +\verb|GLP_FX| & $lb =$ &$\ x\ $& $= ub$
  13.477 +   & Fixed variable \\
  13.478 +\end{tabular}
  13.479 +\end{center}
  13.480 +
  13.481 +\noindent
  13.482 +where $x$ is the structural variable associated with $j$-th column.
  13.483 +
  13.484 +If the column has no lower bound, the parameter \verb|lb| is ignored.
  13.485 +If the column has no upper bound, the parameter \verb|ub| is ignored.
  13.486 +If the column is of fixed type, only the parameter \verb|lb| is used
  13.487 +while the parameter \verb|ub| is ignored.
  13.488 +
  13.489 +Being added to the problem object each column is initially fixed at
  13.490 +zero, i.e. its type is \verb|GLP_FX| and both bounds are 0.
  13.491 +
  13.492 +\subsection{glp\_set\_obj\_coef---set (change) objective coefficient
  13.493 +or constant term}
  13.494 +
  13.495 +\subsubsection*{Synopsis}
  13.496 +
  13.497 +\begin{verbatim}
  13.498 +void glp_set_obj_coef(glp_prob *lp, int j, double coef);
  13.499 +\end{verbatim}
  13.500 +
  13.501 +\subsubsection*{Description}
  13.502 +
  13.503 +The routine \verb|glp_set_obj_coef| sets (changes) the objective
  13.504 +coefficient at \verb|j|-th column (structural variable). A new value of
  13.505 +the objective coefficient is specified by the parameter \verb|coef|.
  13.506 +
  13.507 +If the parameter \verb|j| is 0, the routine sets (changes) the constant
  13.508 +term (``shift'') of the objective function.
  13.509 +
  13.510 +\subsection{glp\_set\_mat\_row---set (replace) row of the constraint
  13.511 +matrix}
  13.512 +
  13.513 +\subsubsection*{Synopsis}
  13.514 +
  13.515 +\begin{verbatim}
  13.516 +void glp_set_mat_row(glp_prob *lp, int i, int len,
  13.517 +      const int ind[], const double val[]);
  13.518 +\end{verbatim}
  13.519 +
  13.520 +\subsubsection*{Description}
  13.521 +
  13.522 +The routine \verb|glp_set_mat_row| stores (replaces) the contents of
  13.523 +\verb|i|-th row of the constraint matrix of the specified problem
  13.524 +object.
  13.525 +
  13.526 +Column indices and numerical values of new row elements must be placed
  13.527 +in locations \verb|ind[1]|, \dots, \verb|ind[len]| and \verb|val[1]|,
  13.528 +\dots, \verb|val[len]|, respectively, where $0 \leq$ \verb|len| $\leq n$
  13.529 +is the new length of $i$-th row, $n$ is the current number of columns in
  13.530 +the problem object. Elements with identical column indices are not
  13.531 +allowed. Zero elements are allowed, but they are not stored in the
  13.532 +constraint matrix.
  13.533 +
  13.534 +If the parameter \verb|len| is 0, the parameters \verb|ind| and/or
  13.535 +\verb|val| can be specified as \verb|NULL|.
  13.536 +
  13.537 +\subsection{glp\_set\_mat\_col---set (replace) column of the
  13.538 +constr\-aint matrix}
  13.539 +
  13.540 +\subsubsection*{Synopsis}
  13.541 +
  13.542 +\begin{verbatim}
  13.543 +void glp_set_mat_col(glp_prob *lp, int j, int len,
  13.544 +      const int ind[], const double val[]);
  13.545 +\end{verbatim}
  13.546 +
  13.547 +\subsubsection*{Description}
  13.548 +
  13.549 +The routine \verb|glp_set_mat_col| stores (replaces) the contents of
  13.550 +\verb|j|-th column of the constraint matrix of the specified problem
  13.551 +object.
  13.552 +
  13.553 +Row indices and numerical values of new column elements must be placed
  13.554 +in locations \verb|ind[1]|, \dots, \verb|ind[len]| and \verb|val[1]|,
  13.555 +\dots, \verb|val[len]|, respectively, where $0 \leq$ \verb|len| $\leq m$
  13.556 +is the new length of $j$-th column, $m$ is the current number of rows in
  13.557 +the problem object. Elements with identical row indices are not allowed.
  13.558 +Zero elements are allowed, but they are not stored in the constraint
  13.559 +matrix.
  13.560 +
  13.561 +If the parameter \verb|len| is 0, the parameters \verb|ind| and/or
  13.562 +\verb|val| can be specified as \verb|NULL|.
  13.563 +
  13.564 +\subsection{glp\_load\_matrix---load (replace) the whole constraint
  13.565 +matrix}
  13.566 +
  13.567 +\subsubsection*{Synopsis}
  13.568 +
  13.569 +\begin{verbatim}
  13.570 +void glp_load_matrix(glp_prob *lp, int ne, const int ia[],
  13.571 +      const int ja[], const double ar[]);
  13.572 +\end{verbatim}
  13.573 +
  13.574 +\subsubsection*{Description}
  13.575 +
  13.576 +The routine \verb|glp_load_matrix| loads the constraint matrix passed
  13.577 +in  the arrays \verb|ia|, \verb|ja|, and \verb|ar| into the specified
  13.578 +problem object. Before loading the current contents of the constraint
  13.579 +matrix is destroyed.
  13.580 +
  13.581 +Constraint coefficients (elements of the constraint matrix) must be
  13.582 +specified as triplets (\verb|ia[k]|, \verb|ja[k]|, \verb|ar[k]|) for
  13.583 +$k=1,\dots,ne$, where \verb|ia[k]| is the row index, \verb|ja[k]| is
  13.584 +the column index, and \verb|ar[k]| is a numeric value of corresponding
  13.585 +constraint coefficient. The parameter \verb|ne| specifies the total
  13.586 +number of (non-zero) elements in the matrix to be loaded. Coefficients
  13.587 +with identical indices are not allowed. Zero coefficients are allowed,
  13.588 +however, they are not stored in the constraint matrix.
  13.589 +
  13.590 +If the parameter \verb|ne| is 0, the parameters \verb|ia|, \verb|ja|,
  13.591 +and/or \verb|ar| can be specified as \verb|NULL|.
  13.592 +
  13.593 +\subsection{glp\_check\_dup---check for duplicate elements in sparse
  13.594 +matrix}
  13.595 +
  13.596 +\subsubsection*{Synopsis}
  13.597 +
  13.598 +\begin{verbatim}
  13.599 +int glp_check_dup(int m, int n, int ne, const int ia[],
  13.600 +   const int ja[]);
  13.601 +\end{verbatim}
  13.602 +
  13.603 +\subsubsection*{Description}
  13.604 +
  13.605 +The routine \verb|glp_check_dup checks| for duplicate elements (that
  13.606 +is, elements with identical indices) in a sparse matrix specified in
  13.607 +the coordinate format.
  13.608 +
  13.609 +The parameters $m$ and $n$ specifies, respectively, the number of rows
  13.610 +and columns in the matrix, $m\geq 0$, $n\geq 0$.
  13.611 +
  13.612 +The parameter {\it ne} specifies the number of (structurally) non-zero
  13.613 +elements in the matrix, {\it ne} $\geq 0$.
  13.614 +
  13.615 +Elements of the matrix are specified as doublets $(ia[k],ja[k])$ for
  13.616 +$k=1,\dots,ne$, where $ia[k]$ is a row index, $ja[k]$ is a column index.
  13.617 +
  13.618 +The routine \verb|glp_check_dup| can be used prior to a call to the
  13.619 +routine \verb|glp_load_matrix| to check that the constraint matrix to
  13.620 +be loaded has no duplicate elements.
  13.621 +
  13.622 +\subsubsection*{Returns}
  13.623 +
  13.624 +The routine \verb|glp_check_dup| returns one of the following values:
  13.625 +
  13.626 +\noindent
  13.627 +\begin{tabular}{@{}r@{\ }c@{\ }l@{}}
  13.628 +0&---&the matrix has no duplicate elements;\\
  13.629 +$-k$&---&indices $ia[k]$ or/and $ja[k]$ are out of range;\\
  13.630 +$+k$&---&element $(ia[k],ja[k])$ is duplicate.\\
  13.631 +\end{tabular}
  13.632 +
  13.633 +\subsection{glp\_sort\_matrix---sort elements of the constraint matrix}
  13.634 +
  13.635 +\subsubsection*{Synopsis}
  13.636 +
  13.637 +\begin{verbatim}
  13.638 +void glp_sort_matrix(glp_prob *P);
  13.639 +\end{verbatim}
  13.640 +
  13.641 +\subsubsection*{Description}
  13.642 +
  13.643 +The routine \verb|glp_sort_matrix| sorts elements of the constraint
  13.644 +matrix rebuilding its row and column linked lists. On exit from the
  13.645 +routine the constraint matrix is not changed, however, elements in the
  13.646 +row linked lists become ordered by ascending column indices, and the
  13.647 +elements in the column linked lists become ordered by ascending row
  13.648 +indices.
  13.649 +
  13.650 +\subsection{glp\_del\_rows---delete rows from problem object}
  13.651 +
  13.652 +\subsubsection*{Synopsis}
  13.653 +
  13.654 +\begin{verbatim}
  13.655 +void glp_del_rows(glp_prob *lp, int nrs, const int num[]);
  13.656 +\end{verbatim}
  13.657 +
  13.658 +\subsubsection*{Description}
  13.659 +
  13.660 +The routine \verb|glp_del_rows| deletes rows from the specified problem
  13.661 +ob-\linebreak ject. Ordinal numbers of rows to be deleted should be
  13.662 +placed in locations \verb|num[1]|, \dots, \verb|num[nrs]|, where
  13.663 +${\tt nrs}>0$.
  13.664 +
  13.665 +Note that deleting rows involves changing ordinal numbers of other
  13.666 +rows remaining in the problem object. New ordinal numbers of the
  13.667 +remaining rows are assigned under the assumption that the original
  13.668 +order of rows is not changed. Let, for example, before deletion there
  13.669 +be five rows $a$, $b$, $c$, $d$, $e$ with ordinal numbers 1, 2, 3, 4, 5,
  13.670 +and let rows $b$ and $d$ have been deleted. Then after deletion the
  13.671 +remaining rows $a$, $c$, $e$ are assigned new oridinal numbers 1, 2, 3.
  13.672 +
  13.673 +\subsection{glp\_del\_cols---delete columns from problem object}
  13.674 +
  13.675 +\subsubsection*{Synopsis}
  13.676 +
  13.677 +\begin{verbatim}
  13.678 +void glp_del_cols(glp_prob *lp, int ncs, const int num[]);
  13.679 +\end{verbatim}
  13.680 +
  13.681 +\subsubsection*{Description}
  13.682 +
  13.683 +The routine \verb|glp_del_cols| deletes columns from the specified
  13.684 +problem object. Ordinal numbers of columns to be deleted should be
  13.685 +placed in locations \verb|num[1]|, \dots, \verb|num[ncs]|, where
  13.686 +${\tt ncs}>0$.
  13.687 +
  13.688 +Note that deleting columns involves changing ordinal numbers of other
  13.689 +columns remaining in the problem object. New ordinal numbers of the
  13.690 +remaining columns are assigned under the assumption that the original
  13.691 +order of columns is not changed. Let, for example, before deletion there
  13.692 +be six columns $p$, $q$, $r$, $s$, $t$, $u$ with ordinal numbers 1, 2,
  13.693 +3, 4, 5, 6, and let columns $p$, $q$, $s$ have been deleted. Then after
  13.694 +deletion the remaining columns $r$, $t$, $u$ are assigned new ordinal
  13.695 +numbers 1, 2, 3.
  13.696 +
  13.697 +\subsection{glp\_copy\_prob---copy problem object content}
  13.698 +
  13.699 +\subsubsection*{Synopsis}
  13.700 +
  13.701 +\begin{verbatim}
  13.702 +void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names);
  13.703 +\end{verbatim}
  13.704 +
  13.705 +\subsubsection*{Description}
  13.706 +
  13.707 +The routine \verb|glp_copy_prob| copies the content of the problem
  13.708 +object \verb|prob| to the problem object \verb|dest|.
  13.709 +
  13.710 +The parameter \verb|names| is a flag. If it is \verb|GLP_ON|,
  13.711 +the routine also copies all symbolic names; otherwise, if it is
  13.712 +\verb|GLP_OFF|, no symbolic names are copied.
  13.713 +
  13.714 +\newpage
  13.715 +
  13.716 +\subsection{glp\_erase\_prob---erase problem object content}
  13.717 +
  13.718 +\subsubsection*{Synopsis}
  13.719 +
  13.720 +\begin{verbatim}
  13.721 +void glp_erase_prob(glp_prob *lp);
  13.722 +\end{verbatim}
  13.723 +
  13.724 +\subsubsection*{Description}
  13.725 +
  13.726 +The routine \verb|glp_erase_prob| erases the content of the specified
  13.727 +problem object. The effect of this operation is the same as if the
  13.728 +problem object would be deleted with the routine \verb|glp_delete_prob|
  13.729 +and then created anew with the routine \verb|glp_create_prob|, with the
  13.730 +only exception that the handle (pointer) to the problem object remains
  13.731 +valid.
  13.732 +
  13.733 +\subsection{glp\_delete\_prob---delete problem object}
  13.734 +
  13.735 +\subsubsection*{Synopsis}
  13.736 +
  13.737 +\begin{verbatim}
  13.738 +void glp_delete_prob(glp_prob *lp);
  13.739 +\end{verbatim}
  13.740 +
  13.741 +\subsubsection*{Description}
  13.742 +
  13.743 +The routine \verb|glp_delete_prob| deletes a problem object, which the
  13.744 +parameter \verb|lp| points to, freeing all the memory allocated to this
  13.745 +object.
  13.746 +
  13.747 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  13.748 +
  13.749 +\newpage
  13.750 +
  13.751 +\section{Problem retrieving routines}
  13.752 +
  13.753 +\subsection{glp\_get\_prob\_name---retrieve problem name}
  13.754 +
  13.755 +\subsubsection*{Synopsis}
  13.756 +
  13.757 +\begin{verbatim}
  13.758 +const char *glp_get_prob_name(glp_prob *lp);
  13.759 +\end{verbatim}
  13.760 +
  13.761 +\subsubsection*{Returns}
  13.762 +
  13.763 +The routine \verb|glp_get_prob_name| returns a pointer to an internal
  13.764 +buffer, which contains symbolic name of the problem. However, if the
  13.765 +problem has no assigned name, the routine returns \verb|NULL|.
  13.766 +
  13.767 +\subsection{glp\_get\_obj\_name---retrieve objective function name}
  13.768 +
  13.769 +\subsubsection*{Synopsis}
  13.770 +
  13.771 +\begin{verbatim}
  13.772 +const char *glp_get_obj_name(glp_prob *lp);
  13.773 +\end{verbatim}
  13.774 +
  13.775 +\subsubsection*{Returns}
  13.776 +
  13.777 +The routine \verb|glp_get_obj_name| returns a pointer to an internal
  13.778 +buffer, which contains symbolic name assigned to the objective
  13.779 +function. However, if the objective function has no assigned name, the
  13.780 +routine returns \verb|NULL|.
  13.781 +
  13.782 +\subsection{glp\_get\_obj\_dir---retrieve optimization direction flag}
  13.783 +
  13.784 +\subsubsection*{Synopsis}
  13.785 +
  13.786 +\begin{verbatim}
  13.787 +int glp_get_obj_dir(glp_prob *lp);
  13.788 +\end{verbatim}
  13.789 +
  13.790 +\subsubsection*{Returns}
  13.791 +
  13.792 +The routine \verb|glp_get_obj_dir| returns the optimization direction
  13.793 +flag (i.e. ``sense'' of the objective function):
  13.794 +
  13.795 +\begin{tabular}{@{}ll}
  13.796 +\verb|GLP_MIN| & minimization; \\
  13.797 +\verb|GLP_MAX| & maximization. \\
  13.798 +\end{tabular}
  13.799 +
  13.800 +\pagebreak
  13.801 +
  13.802 +\subsection{glp\_get\_num\_rows---retrieve number of rows}
  13.803 +
  13.804 +\subsubsection*{Synopsis}
  13.805 +
  13.806 +\begin{verbatim}
  13.807 +int glp_get_num_rows(glp_prob *lp);
  13.808 +\end{verbatim}
  13.809 +
  13.810 +\subsubsection*{Returns}
  13.811 +
  13.812 +The routine \verb|glp_get_num_rows| returns the current number of rows
  13.813 +in the specified problem object.
  13.814 +
  13.815 +\subsection{glp\_get\_num\_cols---retrieve number of columns}
  13.816 +
  13.817 +\subsubsection*{Synopsis}
  13.818 +
  13.819 +\begin{verbatim}
  13.820 +int glp_get_num_cols(glp_prob *lp);
  13.821 +\end{verbatim}
  13.822 +
  13.823 +\subsubsection*{Returns}
  13.824 +
  13.825 +The routine \verb|glp_get_num_cols| returns the current number of
  13.826 +columns the specified problem object.
  13.827 +
  13.828 +\subsection{glp\_get\_row\_name---retrieve row name}
  13.829 +
  13.830 +\subsubsection*{Synopsis}
  13.831 +
  13.832 +\begin{verbatim}
  13.833 +const char *glp_get_row_name(glp_prob *lp, int i);
  13.834 +\end{verbatim}
  13.835 +
  13.836 +\subsubsection*{Returns}
  13.837 +
  13.838 +The routine \verb|glp_get_row_name| returns a pointer to an internal
  13.839 +buffer, which contains a symbolic name assigned to \verb|i|-th row.
  13.840 +However, if the row has no assigned name, the routine returns
  13.841 +\verb|NULL|.
  13.842 +
  13.843 +\subsection{glp\_get\_col\_name---retrieve column name}
  13.844 +
  13.845 +\subsubsection*{Synopsis}
  13.846 +
  13.847 +\begin{verbatim}
  13.848 +const char *glp_get_col_name(glp_prob *lp, int j);
  13.849 +\end{verbatim}
  13.850 +
  13.851 +\subsubsection*{Returns}
  13.852 +
  13.853 +The routine \verb|glp_get_col_name| returns a pointer to an internal
  13.854 +buffer, which contains a symbolic name assigned to \verb|j|-th column.
  13.855 +However, if the column has no assigned name, the routine returns
  13.856 +\verb|NULL|.
  13.857 +
  13.858 +\subsection{glp\_get\_row\_type---retrieve row type}
  13.859 +
  13.860 +\subsubsection*{Synopsis}
  13.861 +
  13.862 +\begin{verbatim}
  13.863 +int glp_get_row_type(glp_prob *lp, int i);
  13.864 +\end{verbatim}
  13.865 +
  13.866 +\subsubsection*{Returns}
  13.867 +
  13.868 +The routine \verb|glp_get_row_type| returns the type of \verb|i|-th
  13.869 +row, i.e. the type of corresponding auxiliary variable, as follows:
  13.870 +
  13.871 +\begin{tabular}{@{}ll}
  13.872 +\verb|GLP_FR| & free (unbounded) variable; \\
  13.873 +\verb|GLP_LO| & variable with lower bound; \\
  13.874 +\verb|GLP_UP| & variable with upper bound; \\
  13.875 +\verb|GLP_DB| & double-bounded variable; \\
  13.876 +\verb|GLP_FX| & fixed variable. \\
  13.877 +\end{tabular}
  13.878 +
  13.879 +\subsection{glp\_get\_row\_lb---retrieve row lower bound}
  13.880 +
  13.881 +\subsubsection*{Synopsis}
  13.882 +
  13.883 +\begin{verbatim}
  13.884 +double glp_get_row_lb(glp_prob *lp, int i);
  13.885 +\end{verbatim}
  13.886 +
  13.887 +\subsubsection*{Returns}
  13.888 +
  13.889 +The routine \verb|glp_get_row_lb| returns the lower bound of
  13.890 +\verb|i|-th row, i.e. the lower bound of corresponding auxiliary
  13.891 +variable. However, if the row has no lower bound, the routine returns
  13.892 +\verb|-DBL_MAX|.
  13.893 +
  13.894 +\subsection{glp\_get\_row\_ub---retrieve row upper bound}
  13.895 +
  13.896 +\subsubsection*{Synopsis}
  13.897 +
  13.898 +\begin{verbatim}
  13.899 +double glp_get_row_ub(glp_prob *lp, int i);
  13.900 +\end{verbatim}
  13.901 +
  13.902 +\subsubsection*{Returns}
  13.903 +
  13.904 +The routine \verb|glp_get_row_ub| returns the upper bound of
  13.905 +\verb|i|-th row, i.e. the upper bound of corresponding auxiliary
  13.906 +variable. However, if the row has no upper bound, the routine returns
  13.907 +\verb|+DBL_MAX|.
  13.908 +
  13.909 +\subsection{glp\_get\_col\_type---retrieve column type}
  13.910 +
  13.911 +\subsubsection*{Synopsis}
  13.912 +
  13.913 +\begin{verbatim}
  13.914 +int glp_get_col_type(glp_prob *lp, int j);
  13.915 +\end{verbatim}
  13.916 +
  13.917 +\subsubsection*{Returns}
  13.918 +
  13.919 +The routine \verb|glp_get_col_type| returns the type of \verb|j|-th
  13.920 +column, i.e. the type of corresponding structural variable, as follows:
  13.921 +
  13.922 +\begin{tabular}{@{}ll}
  13.923 +\verb|GLP_FR| & free (unbounded) variable; \\
  13.924 +\verb|GLP_LO| & variable with lower bound; \\
  13.925 +\verb|GLP_UP| & variable with upper bound; \\
  13.926 +\verb|GLP_DB| & double-bounded variable; \\
  13.927 +\verb|GLP_FX| & fixed variable. \\
  13.928 +\end{tabular}
  13.929 +
  13.930 +\subsection{glp\_get\_col\_lb---retrieve column lower bound}
  13.931 +
  13.932 +\subsubsection*{Synopsis}
  13.933 +
  13.934 +\begin{verbatim}
  13.935 +double glp_get_col_lb(glp_prob *lp, int j);
  13.936 +\end{verbatim}
  13.937 +
  13.938 +\subsubsection*{Returns}
  13.939 +
  13.940 +The routine \verb|glp_get_col_lb| returns the lower bound of
  13.941 +\verb|j|-th column, i.e. the lower bound of corresponding structural
  13.942 +variable. However, if the column has no lower bound, the routine returns
  13.943 +\verb|-DBL_MAX|.
  13.944 +
  13.945 +\subsection{glp\_get\_col\_ub---retrieve column upper bound}
  13.946 +
  13.947 +\subsubsection*{Synopsis}
  13.948 +
  13.949 +\begin{verbatim}
  13.950 +double glp_get_col_ub(glp_prob *lp, int j);
  13.951 +\end{verbatim}
  13.952 +
  13.953 +\subsubsection*{Returns}
  13.954 +
  13.955 +The routine \verb|glp_get_col_ub| returns the upper bound of
  13.956 +\verb|j|-th column, i.e. the upper bound of corresponding structural
  13.957 +variable. However, if the column has no upper bound, the routine returns
  13.958 +\verb|+DBL_MAX|.
  13.959 +
  13.960 +\subsection{glp\_get\_obj\_coef---retrieve objective coefficient or\\
  13.961 +constant term}
  13.962 +
  13.963 +\subsubsection*{Synopsis}
  13.964 +
  13.965 +\begin{verbatim}
  13.966 +double glp_get_obj_coef(glp_prob *lp, int j);
  13.967 +\end{verbatim}
  13.968 +
  13.969 +\subsubsection*{Returns}
  13.970 +
  13.971 +The routine \verb|glp_get_obj_coef| returns the objective coefficient
  13.972 +at \verb|j|-th structural variable (column).
  13.973 +
  13.974 +If the parameter \verb|j| is 0, the routine returns the constant term
  13.975 +(``shift'') of the objective function.
  13.976 +
  13.977 +\subsection{glp\_get\_num\_nz---retrieve number of constraint
  13.978 +coefficients}
  13.979 +
  13.980 +\subsubsection*{Synopsis}
  13.981 +
  13.982 +\begin{verbatim}
  13.983 +int glp_get_num_nz(glp_prob *lp);
  13.984 +\end{verbatim}
  13.985 +
  13.986 +\subsubsection*{Returns}
  13.987 +
  13.988 +The routine \verb|glp_get_num_nz| returns the number of non-zero
  13.989 +elements in the constraint matrix of the specified problem object.
  13.990 +
  13.991 +\subsection{glp\_get\_mat\_row---retrieve row of the constraint
  13.992 +matrix}
  13.993 +
  13.994 +\subsubsection*{Synopsis}
  13.995 +
  13.996 +\begin{verbatim}
  13.997 +int glp_get_mat_row(glp_prob *lp, int i, int ind[],
  13.998 +      double val[]);
  13.999 +\end{verbatim}
 13.1000 +
 13.1001 +\subsubsection*{Description}
 13.1002 +
 13.1003 +The routine \verb|glp_get_mat_row| scans (non-zero) elements of
 13.1004 +\verb|i|-th row of the constraint matrix of the specified problem object
 13.1005 +and stores their column indices and numeric values to locations
 13.1006 +\verb|ind[1]|, \dots, \verb|ind[len]| and \verb|val[1]|, \dots,
 13.1007 +\verb|val[len]|, respectively, where $0\leq{\tt len}\leq n$ is the
 13.1008 +number of elements in $i$-th row, $n$ is the number of columns.
 13.1009 +
 13.1010 +The parameter \verb|ind| and/or \verb|val| can be specified as
 13.1011 +\verb|NULL|, in which case corresponding information is not stored.
 13.1012 +
 13.1013 +\subsubsection*{Returns}
 13.1014 +
 13.1015 +The routine \verb|glp_get_mat_row| returns the length \verb|len|, i.e.
 13.1016 +the number of (non-zero) elements in \verb|i|-th row.
 13.1017 +
 13.1018 +\subsection{glp\_get\_mat\_col---retrieve column of the constraint\\
 13.1019 +matrix}
 13.1020 +
 13.1021 +\subsubsection*{Synopsis}
 13.1022 +
 13.1023 +\begin{verbatim}
 13.1024 +int glp_get_mat_col(glp_prob *lp, int j, int ind[],
 13.1025 +      double val[]);
 13.1026 +\end{verbatim}
 13.1027 +
 13.1028 +\subsubsection*{Description}
 13.1029 +
 13.1030 +The routine \verb|glp_get_mat_col| scans (non-zero) elements of
 13.1031 +\verb|j|-th column of the constraint matrix of the specified problem
 13.1032 +object and stores their row indices and numeric values to locations
 13.1033 +\verb|ind[1]|, \dots, \verb|ind[len]| and \verb|val[1]|, \dots,
 13.1034 +\verb|val[len]|, respectively, where $0\leq{\tt len}\leq m$ is the
 13.1035 +number of elements in $j$-th column, $m$ is the number of rows.
 13.1036 +
 13.1037 +The parameter \verb|ind| and/or \verb|val| can be specified as
 13.1038 +\verb|NULL|, in which case corresponding information is not stored.
 13.1039 +
 13.1040 +\subsubsection*{Returns}
 13.1041 +
 13.1042 +The routine \verb|glp_get_mat_col| returns the length \verb|len|, i.e.
 13.1043 +the number of (non-zero) elements in \verb|j|-th column.
 13.1044 +
 13.1045 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 13.1046 +
 13.1047 +\newpage
 13.1048 +
 13.1049 +\section{Row and column searching routines}
 13.1050 +
 13.1051 +\subsection{glp\_create\_index---create the name index}
 13.1052 +
 13.1053 +\subsubsection*{Synopsis}
 13.1054 +
 13.1055 +\begin{verbatim}
 13.1056 +void glp_create_index(glp_prob *lp);
 13.1057 +\end{verbatim}
 13.1058 +
 13.1059 +\subsubsection*{Description}
 13.1060 +
 13.1061 +The routine \verb|glp_create_index| creates the name index for the
 13.1062 +specified problem object. The name index is an auxiliary data structure,
 13.1063 +which is intended to quickly (i.e. for logarithmic time) find rows and
 13.1064 +columns by their names.
 13.1065 +
 13.1066 +This routine can be called at any time. If the name index already
 13.1067 +exists, the routine does nothing.
 13.1068 +
 13.1069 +\subsection{glp\_find\_row---find row by its name}
 13.1070 +
 13.1071 +\subsubsection*{Synopsis}
 13.1072 +
 13.1073 +\begin{verbatim}
 13.1074 +int glp_find_row(glp_prob *lp, const char *name);
 13.1075 +\end{verbatim}
 13.1076 +
 13.1077 +\subsubsection*{Returns}
 13.1078 +
 13.1079 +The routine \verb|glp_find_row| returns the ordinal number of a row,
 13.1080 +which is assigned (by the routine \verb|glp_set_row_name|) the specified
 13.1081 +symbolic \verb|name|. If no such row exists, the routine returns 0.
 13.1082 +
 13.1083 +\subsection{glp\_find\_col---find column by its name}
 13.1084 +
 13.1085 +\subsubsection*{Synopsis}
 13.1086 +
 13.1087 +\begin{verbatim}
 13.1088 +int glp_find_col(glp_prob *lp, const char *name);
 13.1089 +\end{verbatim}
 13.1090 +
 13.1091 +\subsubsection*{Returns}
 13.1092 +
 13.1093 +The routine \verb|glp_find_col| returns the ordinal number of a column,
 13.1094 +which is assigned (by the routine \verb|glp_set_col_name|) the specified
 13.1095 +symbolic \verb|name|. If no such column exists, the routine returns 0.
 13.1096 +
 13.1097 +\subsection{glp\_delete\_index---delete the name index}
 13.1098 +
 13.1099 +\subsubsection*{Synopsis}
 13.1100 +
 13.1101 +\begin{verbatim}
 13.1102 +void glp_delete_index(glp_prob *lp);
 13.1103 +\end{verbatim}
 13.1104 +
 13.1105 +\subsubsection*{Description}
 13.1106 +
 13.1107 +The routine \verb|glp_delete_index| deletes the name index previously
 13.1108 +created by the routine \verb|glp_create_index| and frees the memory
 13.1109 +allocated to this auxiliary data structure.
 13.1110 +
 13.1111 +This routine can be called at any time. If the name index does not
 13.1112 +exist, the routine does nothing.
 13.1113 +
 13.1114 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 13.1115 +
 13.1116 +\newpage
 13.1117 +
 13.1118 +\section{Problem scaling routines}
 13.1119 +
 13.1120 +\subsection{Background}
 13.1121 +
 13.1122 +In GLPK the {\it scaling} means a linear transformation applied to the
 13.1123 +constraint matrix to improve its numerical properties.\footnote{In many
 13.1124 +cases a proper scaling allows making the constraint matrix to be better
 13.1125 +conditioned, i.e. decreasing its condition number, that makes
 13.1126 +computations numerically more stable.}
 13.1127 +
 13.1128 +The main equality is the following:
 13.1129 +$$\widetilde{A}=RAS,\eqno(2.1)$$
 13.1130 +where $A=(a_{ij})$ is the original constraint matrix, $R=(r_{ii})>0$ is
 13.1131 +a diagonal matrix used to scale rows (constraints), $S=(s_{jj})>0$ is a
 13.1132 +diagonal matrix used to scale columns (variables), $\widetilde{A}$ is
 13.1133 +the scaled constraint matrix.
 13.1134 +
 13.1135 +From (2.1) it follows that in the {\it scaled} problem instance each
 13.1136 +original constraint coefficient $a_{ij}$ is replaced by corresponding
 13.1137 +scaled constraint coefficient:
 13.1138 +$$\widetilde{a}_{ij}=r_{ii}a_{ij}s_{jj}.\eqno(2.2)$$
 13.1139 +
 13.1140 +Note that the scaling is performed internally and therefore
 13.1141 +transparently to the user. This means that on API level the user always
 13.1142 +deal with unscaled data.
 13.1143 +
 13.1144 +Scale factors $r_{ii}$ and $s_{jj}$ can be set or changed at any time
 13.1145 +either directly by the application program in a problem specific way
 13.1146 +(with the routines \verb|glp_set_rii| and \verb|glp_set_sjj|), or by
 13.1147 +some API routines intended for automatic scaling.
 13.1148 +
 13.1149 +\subsection{glp\_set\_rii---set (change) row scale factor}
 13.1150 +
 13.1151 +\subsubsection*{Synopsis}
 13.1152 +
 13.1153 +\begin{verbatim}
 13.1154 +void glp_set_rii(glp_prob *lp, int i, double rii);
 13.1155 +\end{verbatim}
 13.1156 +
 13.1157 +\subsubsection*{Description}
 13.1158 +
 13.1159 +The routine \verb|glp_set_rii| sets (changes) the scale factor $r_{ii}$
 13.1160 +for $i$-th row of the specified problem object.
 13.1161 +
 13.1162 +\subsection{glp\_set\_sjj---set (change) column scale factor}
 13.1163 +
 13.1164 +\subsubsection*{Synopsis}
 13.1165 +
 13.1166 +\begin{verbatim}
 13.1167 +void glp_set_sjj(glp_prob *lp, int j, double sjj);
 13.1168 +\end{verbatim}
 13.1169 +
 13.1170 +\subsubsection*{Description}
 13.1171 +
 13.1172 +The routine \verb|glp_set_sjj| sets (changes) the scale factor $s_{jj}$
 13.1173 +for $j$-th column of the specified problem object.
 13.1174 +
 13.1175 +\subsection{glp\_get\_rii---retrieve row scale factor}
 13.1176 +
 13.1177 +\subsubsection*{Synopsis}
 13.1178 +
 13.1179 +\begin{verbatim}
 13.1180 +double glp_get_rii(glp_prob *lp, int i);
 13.1181 +\end{verbatim}
 13.1182 +
 13.1183 +\subsubsection*{Returns}
 13.1184 +
 13.1185 +The routine \verb|glp_get_rii| returns current scale factor $r_{ii}$ for
 13.1186 +$i$-th row of the specified problem object.
 13.1187 +
 13.1188 +\subsection{glp\_get\_sjj---retrieve column scale factor}
 13.1189 +
 13.1190 +\subsubsection*{Synopsis}
 13.1191 +
 13.1192 +\begin{verbatim}
 13.1193 +double glp_get_sjj(glp_prob *lp, int j);
 13.1194 +\end{verbatim}
 13.1195 +
 13.1196 +\subsubsection*{Returns}
 13.1197 +
 13.1198 +The routine \verb|glp_get_sjj| returns current scale factor $s_{jj}$ for
 13.1199 +$j$-th column of the specified problem object.
 13.1200 +
 13.1201 +\subsection{glp\_scale\_prob---scale problem data}
 13.1202 +
 13.1203 +\subsubsection*{Synopsis}
 13.1204 +
 13.1205 +\begin{verbatim}
 13.1206 +void glp_scale_prob(glp_prob *lp, int flags);
 13.1207 +\end{verbatim}
 13.1208 +
 13.1209 +\subsubsection*{Description}
 13.1210 +
 13.1211 +The routine \verb|glp_scale_prob| performs automatic scaling of problem
 13.1212 +data for the specified problem object.
 13.1213 +
 13.1214 +The parameter \verb|flags| specifies scaling options used by the
 13.1215 +routine. The options can be combined with the bitwise OR operator and
 13.1216 +may be the following:
 13.1217 +
 13.1218 +\begin{tabular}{@{}ll}
 13.1219 +\verb|GLP_SF_GM| & perform geometric mean scaling;\\
 13.1220 +\verb|GLP_SF_EQ| & perform equilibration scaling;\\
 13.1221 +\verb|GLP_SF_2N| & round scale factors to nearest power of two;\\
 13.1222 +\verb|GLP_SF_SKIP| & skip scaling, if the problem is well scaled.\\
 13.1223 +\end{tabular}
 13.1224 +
 13.1225 +The parameter \verb|flags| may be specified as \verb|GLP_SF_AUTO|, in
 13.1226 +which case the routine chooses the scaling options automatically.
 13.1227 +
 13.1228 +\subsection{glp\_unscale\_prob---unscale problem data}
 13.1229 +
 13.1230 +\subsubsection*{Synopsis}
 13.1231 +
 13.1232 +\begin{verbatim}
 13.1233 +void glp_unscale_prob(glp_prob *lp);
 13.1234 +\end{verbatim}
 13.1235 +
 13.1236 +The routine \verb|glp_unscale_prob| performs unscaling of problem data
 13.1237 +for the specified problem object.
 13.1238 +
 13.1239 +``Unscaling'' means replacing the current scaling matrices $R$ and $S$
 13.1240 +by unity matrices that cancels the scaling effect.
 13.1241 +
 13.1242 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 13.1243 +
 13.1244 +\newpage
 13.1245 +
 13.1246 +\section{LP basis constructing routines}
 13.1247 +
 13.1248 +\subsection{Background}
 13.1249 +
 13.1250 +To start the search the simplex method needs a valid initial basis. In
 13.1251 +GLPK the basis is completely defined by a set of {\it statuses} assigned
 13.1252 +to {\it all} (auxiliary and structural) variables, where the status may
 13.1253 +be one of the following:
 13.1254 +
 13.1255 +\begin{tabular}{@{}ll}
 13.1256 +\verb|GLP_BS| & basic variable;\\
 13.1257 +\verb|GLP_NL| & non-basic variable having active lower bound;\\
 13.1258 +\verb|GLP_NU| & non-basic variable having active upper bound;\\
 13.1259 +\verb|GLP_NF| & non-basic free variable;\\
 13.1260 +\verb|GLP_NS| & non-basic fixed variable.\\
 13.1261 +\end{tabular}
 13.1262 +
 13.1263 +The basis is {\it valid}, if the basis matrix, which is a matrix built
 13.1264 +of columns of the augmented constraint matrix $(I\:|-A)$ corresponding
 13.1265 +to basic variables, is non-singular. This, in particular, means that
 13.1266 +the number of basic variables must be the same as the number of rows in
 13.1267 +the problem object. (For more details see Section \ref{lpbasis}, page
 13.1268 +\pageref{lpbasis}.)
 13.1269 +
 13.1270 +Any initial basis may be constructed (or restored) with the API
 13.1271 +routines \verb|glp_set_row_stat| and \verb|glp_set_col_stat| by
 13.1272 +assigning appropriate statuses to auxiliary and structural variables.
 13.1273 +Another way to construct an initial basis is to use API routines like
 13.1274 +\verb|glp_adv_basis|, which implement so called
 13.1275 +{\it crashing}.\footnote{This term is from early linear programming
 13.1276 +systems and means a heuristic to construct a valid initial basis.} Note
 13.1277 +that on normal exit the simplex solver remains the basis valid, so in
 13.1278 +case of reoptimization there is no need to construct an initial basis
 13.1279 +from scratch.
 13.1280 +
 13.1281 +\subsection{glp\_set\_row\_stat---set (change) row status}
 13.1282 +
 13.1283 +\subsubsection*{Synopsis}
 13.1284 +
 13.1285 +\begin{verbatim}
 13.1286 +void glp_set_row_stat(glp_prob *lp, int i, int stat);
 13.1287 +\end{verbatim}
 13.1288 +
 13.1289 +\subsubsection*{Description}
 13.1290 +
 13.1291 +The routine \verb|glp_set_row_stat| sets (changes) the current status
 13.1292 +of \verb|i|-th row (auxiliary variable) as specified by the parameter
 13.1293 +\verb|stat|:
 13.1294 +
 13.1295 +\begin{tabular}{@{}lp{104.2mm}@{}}
 13.1296 +\verb|GLP_BS| & make the row basic (make the constraint inactive); \\
 13.1297 +\verb|GLP_NL| & make the row non-basic (make the constraint active); \\
 13.1298 +\end{tabular}
 13.1299 +
 13.1300 +\newpage
 13.1301 +
 13.1302 +\begin{tabular}{@{}lp{104.2mm}@{}}
 13.1303 +\verb|GLP_NU| & make the row non-basic and set it to the upper bound;
 13.1304 +   if the row is not double-bounded, this status is equivalent to
 13.1305 +   \verb|GLP_NL| (only in the case of this routine); \\
 13.1306 +\verb|GLP_NF| & the same as \verb|GLP_NL| (only in the case of this
 13.1307 +   routine); \\
 13.1308 +\verb|GLP_NS| & the same as \verb|GLP_NL| (only in the case of this
 13.1309 +   routine). \\
 13.1310 +\end{tabular}
 13.1311 +
 13.1312 +\subsection{glp\_set\_col\_stat---set (change) column status}
 13.1313 +
 13.1314 +\subsubsection*{Synopsis}
 13.1315 +
 13.1316 +\begin{verbatim}
 13.1317 +void glp_set_col_stat(glp_prob *lp, int j, int stat);
 13.1318 +\end{verbatim}
 13.1319 +
 13.1320 +\subsubsection*{Description}
 13.1321 +
 13.1322 +The routine \verb|glp_set_col_stat sets| (changes) the current status
 13.1323 +of \verb|j|-th column (structural variable) as specified by the
 13.1324 +parameter \verb|stat|:
 13.1325 +
 13.1326 +\begin{tabular}{@{}lp{104.2mm}@{}}
 13.1327 +\verb|GLP_BS| & make the column basic; \\
 13.1328 +\verb|GLP_NL| & make the column non-basic; \\
 13.1329 +\verb|GLP_NU| & make the column non-basic and set it to the upper
 13.1330 +   bound; if the column is not double-bounded, this status is equivalent
 13.1331 +   to \verb|GLP_NL| (only in the case of this routine); \\
 13.1332 +\verb|GLP_NF| & the same as \verb|GLP_NL| (only in the case of this
 13.1333 +   routine); \\
 13.1334 +\verb|GLP_NS| & the same as \verb|GLP_NL| (only in the case of this
 13.1335 +   routine).
 13.1336 +\end{tabular}
 13.1337 +
 13.1338 +\subsection{glp\_std\_basis---construct standard initial LP basis}
 13.1339 +
 13.1340 +\subsubsection*{Synopsis}
 13.1341 +
 13.1342 +\begin{verbatim}
 13.1343 +void glp_std_basis(glp_prob *lp);
 13.1344 +\end{verbatim}
 13.1345 +
 13.1346 +\subsubsection*{Description}
 13.1347 +
 13.1348 +The routine \verb|glp_std_basis| constructs the ``standard'' (trivial)
 13.1349 +initial LP basis for the specified problem object.
 13.1350 +
 13.1351 +In the ``standard'' LP basis all auxiliary variables (rows) are basic,
 13.1352 +and all structural variables (columns) are non-basic (so the
 13.1353 +corresponding basis matrix is unity).
 13.1354 +
 13.1355 +\newpage
 13.1356 +
 13.1357 +\subsection{glp\_adv\_basis---construct advanced initial LP basis}
 13.1358 +
 13.1359 +\subsubsection*{Synopsis}
 13.1360 +
 13.1361 +\begin{verbatim}
 13.1362 +void glp_adv_basis(glp_prob *lp, int flags);
 13.1363 +\end{verbatim}
 13.1364 +
 13.1365 +\subsubsection*{Description}
 13.1366 +
 13.1367 +The routine \verb|glp_adv_basis| constructs an advanced initial LP
 13.1368 +basis for the specified problem object.
 13.1369 +
 13.1370 +The parameter \verb|flags| is reserved for use in the future and must
 13.1371 +be specified as zero.
 13.1372 +
 13.1373 +In order to construct the advanced initial LP basis the routine does
 13.1374 +the following:
 13.1375 +
 13.1376 +1) includes in the basis all non-fixed auxiliary variables;
 13.1377 +
 13.1378 +2) includes in the basis as many non-fixed structural variables as
 13.1379 +possible keeping the triangular form of the basis matrix;
 13.1380 +
 13.1381 +3) includes in the basis appropriate (fixed) auxiliary variables to
 13.1382 +complete the basis.
 13.1383 +
 13.1384 +As a result the initial LP basis has as few fixed variables as possible
 13.1385 +and the corresponding basis matrix is triangular.
 13.1386 +
 13.1387 +\subsection{glp\_cpx\_basis---construct Bixby's initial LP basis}
 13.1388 +
 13.1389 +\subsubsection*{Synopsis}
 13.1390 +
 13.1391 +\begin{verbatim}
 13.1392 +void glp_cpx_basis(glp_prob *lp);
 13.1393 +\end{verbatim}
 13.1394 +
 13.1395 +\subsubsection*{Description}
 13.1396 +
 13.1397 +The routine \verb|glp_cpx_basis| constructs an initial basis for the
 13.1398 +specified problem object with the algorithm proposed by
 13.1399 +R.~Bixby.\footnote{Robert E. Bixby, ``Implementing the Simplex Method:
 13.1400 +The Initial Basis.'' ORSA Journal on Computing, Vol. 4, No. 3, 1992,
 13.1401 +pp. 267-84.}
 13.1402 +
 13.1403 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 13.1404 +
 13.1405 +\newpage
 13.1406 +
 13.1407 +\section{Simplex method routines}
 13.1408 +
 13.1409 +The {\it simplex method} is a well known efficient numerical procedure
 13.1410 +to solve LP problems.
 13.1411 +
 13.1412 +On each iteration the simplex method transforms the original system of
 13.1413 +equaility constraints (1.2) resolving them through different sets of
 13.1414 +variables to an equivalent system called {\it the simplex table} (or
 13.1415 +sometimes {\it the simplex tableau}), which has the following form:
 13.1416 +$$
 13.1417 +\begin{array}{r@{\:}c@{\:}r@{\:}c@{\:}r@{\:}c@{\:}r}
 13.1418 +z&=&d_1(x_N)_1&+&d_2(x_N)_2&+ \dots +&d_n(x_N)_n \\
 13.1419 +(x_B)_1&=&\xi_{11}(x_N)_1& +& \xi_{12}(x_N)_2& + \dots +&
 13.1420 +   \xi_{1n}(x_N)_n \\
 13.1421 +(x_B)_2&=& \xi_{21}(x_N)_1& +& \xi_{22}(x_N)_2& + \dots +&
 13.1422 +   \xi_{2n}(x_N)_n \\
 13.1423 +\multicolumn{7}{c}
 13.1424 +{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .} \\
 13.1425 +(x_B)_m&=&\xi_{m1}(x_N)_1& +& \xi_{m2}(x_N)_2& + \dots +&
 13.1426 +   \xi_{mn}(x_N)_n \\
 13.1427 +\end{array} \eqno (2.3)
 13.1428 +$$
 13.1429 +where: $(x_B)_1, (x_B)_2, \dots, (x_B)_m$ are basic variables;
 13.1430 +$(x_N)_1, (x_N)_2, \dots, (x_N)_n$ are non-basic variables;
 13.1431 +$d_1, d_2, \dots, d_n$ are reduced costs;
 13.1432 +$\xi_{11}, \xi_{12}, \dots, \xi_{mn}$ are coefficients of the
 13.1433 +simplex table. (May note that the original LP problem (1.1)---(1.3) also
 13.1434 +has the form of a simplex table, where all equalities are resolved
 13.1435 +through auxiliary variables.)
 13.1436 +
 13.1437 +From the linear programming theory it is known that if an optimal
 13.1438 +solution of the LP problem (1.1)---(1.3) exists, it can always be
 13.1439 +written in the form (2.3), where non-basic variables are set on their
 13.1440 +bounds while values of the objective function and basic variables are
 13.1441 +determined by the corresponding equalities of the simplex table.
 13.1442 +
 13.1443 +A set of values of all basic and non-basic variables determined by the
 13.1444 +simplex table is called {\it basic solution}. If all basic variables are
 13.1445 +within their bounds, the basic solution is called {\it (primal)
 13.1446 +feasible}, otherwise it is called {\it (primal) infeasible}. A feasible
 13.1447 +basic solution, which provides a smallest (in case of minimization) or
 13.1448 +a largest (in case of maximization) value of the objective function is
 13.1449 +called {\it optimal}. Therefore, for solving LP problem the simplex
 13.1450 +method tries to find its optimal basic solution.
 13.1451 +
 13.1452 +Primal feasibility of some basic solution may be stated by simple
 13.1453 +checking if all basic variables are within their bounds. Basic solution
 13.1454 +is optimal if additionally the following optimality conditions are
 13.1455 +satisfied for all non-basic variables:
 13.1456 +\begin{center}
 13.1457 +\begin{tabular}{lcc}
 13.1458 +Status of $(x_N)_j$ & Minimization & Maximization \\
 13.1459 +\hline
 13.1460 +$(x_N)_j$ is free & $d_j = 0$ & $d_j = 0$ \\
 13.1461 +$(x_N)_j$ is on its lower bound & $d_j \geq 0$ & $d_j \leq 0$ \\
 13.1462 +$(x_N)_j$ is on its upper bound & $d_j \leq 0$ & $d_j \geq 0$ \\
 13.1463 +\end{tabular}
 13.1464 +\end{center}
 13.1465 +In other words, basic solution is optimal if there is no non-basic
 13.1466 +variable, which changing in the feasible direction (i.e. increasing if
 13.1467 +it is free or on its lower bound, or decreasing if it is free or on its
 13.1468 +upper bound) can improve (i.e. decrease in case of minimization or
 13.1469 +increase in case of maximization) the objective function.
 13.1470 +
 13.1471 +If all non-basic variables satisfy to the optimality conditions shown
 13.1472 +above (independently on whether basic variables are within their bounds
 13.1473 +or not), the basic solution is called {\it dual feasible}, otherwise it
 13.1474 +is called {\it dual infeasible}.
 13.1475 +
 13.1476 +It may happen that some LP problem has no primal feasible solution due
 13.1477 +to incorrect formulation---this means that its constraints conflict
 13.1478 +with each other. It also may happen that some LP problem has unbounded
 13.1479 +solution again due to incorrect formulation---this means that some
 13.1480 +non-basic variable can improve the objective function, i.e. the
 13.1481 +optimality conditions are violated, and at the same time this variable
 13.1482 +can infinitely change in the feasible direction meeting no resistance
 13.1483 +from basic variables. (May note that in the latter case the LP problem
 13.1484 +has no dual feasible solution.)
 13.1485 +
 13.1486 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 13.1487 +
 13.1488 +\subsection{glp\_simplex---solve LP problem with the primal or dual
 13.1489 +simplex method}
 13.1490 +
 13.1491 +\subsubsection*{Synopsis}
 13.1492 +
 13.1493 +\begin{verbatim}
 13.1494 +int glp_simplex(glp_prob *lp, const glp_smcp *parm);
 13.1495 +\end{verbatim}
 13.1496 +
 13.1497 +\subsubsection*{Description}
 13.1498 +
 13.1499 +The routine \verb|glp_simplex| is a driver to the LP solver based on
 13.1500 +the simplex method. This routine retrieves problem data from the
 13.1501 +specified problem object, calls the solver to solve the problem
 13.1502 +instance, and stores results of computations back into the problem
 13.1503 +object.
 13.1504 +
 13.1505 +The simplex solver has a set of control parameters. Values of the
 13.1506 +control parameters can be passed in the structure \verb|glp_smcp|,
 13.1507 +which the parameter \verb|parm| points to. For detailed description of
 13.1508 +this structure see paragraph ``Control parameters'' below.
 13.1509 +Before specifying some control parameters the application program
 13.1510 +should initialize the structure \verb|glp_smcp| by default values of
 13.1511 +all control parameters using the routine \verb|glp_init_smcp| (see the
 13.1512 +next subsection). This is needed for backward compatibility, because in
 13.1513 +the future there may appear new members in the structure
 13.1514 +\verb|glp_smcp|.
 13.1515 +
 13.1516 +The parameter \verb|parm| can be specified as \verb|NULL|, in which
 13.1517 +case the solver uses default settings.
 13.1518 +
 13.1519 +\subsubsection*{Returns}
 13.1520 +
 13.1521 +\def\arraystretch{1}
 13.1522 +
 13.1523 +\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
 13.1524 +0 & The LP problem instance has been successfully solved. (This code
 13.1525 +does {\it not} necessarily mean that the solver has found optimal
 13.1526 +solution. It only means that the solution process was successful.) \\
 13.1527 +\verb|GLP_EBADB| & Unable to start the search, because the initial basis
 13.1528 +specified in the problem object is invalid---the number of basic
 13.1529 +(auxiliary and structural) variables is not the same as the number of
 13.1530 +rows in the problem object.\\
 13.1531 +\verb|GLP_ESING| & Unable to start the search, because the basis matrix
 13.1532 +corresponding to the initial basis is singular within the working
 13.1533 +precision.\\
 13.1534 +\verb|GLP_ECOND| & Unable to start the search, because the basis matrix
 13.1535 +corresponding to the initial basis is ill-conditioned, i.e. its
 13.1536 +condition number is too large.\\
 13.1537 +\verb|GLP_EBOUND| & Unable to start the search, because some
 13.1538 +double-bounded (auxiliary or structural) variables have incorrect
 13.1539 +bounds.\\
 13.1540 +\verb|GLP_EFAIL| & The search was prematurely terminated due to the
 13.1541 +solver failure.\\
 13.1542 +\verb|GLP_EOBJLL| & The search was prematurely terminated, because the
 13.1543 +objective function being maximized has reached its lower limit and
 13.1544 +continues decreasing (the dual simplex only).\\
 13.1545 +\verb|GLP_EOBJUL| & The search was prematurely terminated, because the
 13.1546 +objective function being minimized has reached its upper limit and
 13.1547 +continues increasing (the dual simplex only).\\
 13.1548 +\verb|GLP_EITLIM| & The search was prematurely terminated, because the
 13.1549 +simplex iteration limit has been exceeded.\\
 13.1550 +\verb|GLP_ETMLIM| & The search was prematurely terminated, because the
 13.1551 +time limit has been exceeded.\\
 13.1552 +\verb|GLP_ENOPFS| & The LP problem instance has no primal feasible
 13.1553 +solution (only if the LP presolver is used).\\
 13.1554 +\verb|GLP_ENODFS| & The LP problem instance has no dual feasible
 13.1555 +solution (only if the LP presolver is used).\\
 13.1556 +\end{tabular}
 13.1557 +
 13.1558 +\subsubsection*{Built-in LP presolver}
 13.1559 +
 13.1560 +The simplex solver has {\it built-in LP presolver}. It is a subprogram
 13.1561 +that transforms the original LP problem specified in the problem object
 13.1562 +to an equivalent LP problem, which may be easier for solving with the
 13.1563 +simplex method than the original one. This is attained mainly due to
 13.1564 +reducing the problem size and improving its numeric properties (for
 13.1565 +example, by removing some inactive constraints or by fixing some
 13.1566 +non-basic variables). Once the transformed LP problem has been solved,
 13.1567 +the presolver transforms its basic solution back to the corresponding
 13.1568 +basic solution of the original problem.
 13.1569 +
 13.1570 +Presolving is an optional feature of the routine \verb|glp_simplex|,
 13.1571 +and by default it is disabled. In order to enable the LP presolver the
 13.1572 +control parameter \verb|presolve| should be set to \verb|GLP_ON| (see
 13.1573 +paragraph ``Control parameters'' below). Presolving may be used when
 13.1574 +the problem instance is solved for the first time. However, on
 13.1575 +performing re-optimization the presolver should be disabled.
 13.1576 +
 13.1577 +The presolving procedure is transparent to the API user in the sense
 13.1578 +that all necessary processing is performed internally, and a basic
 13.1579 +solution of the original problem recovered by the presolver is the same
 13.1580 +as if it were computed directly, i.e. without presolving.
 13.1581 +
 13.1582 +Note that the presolver is able to recover only optimal solutions. If
 13.1583 +a computed solution is infeasible or non-optimal, the corresponding
 13.1584 +solution of the original problem cannot be recovered and therefore
 13.1585 +remains undefined. If you need to know a basic solution even if it is
 13.1586 +infeasible or non-optimal, the presolver should be disabled.
 13.1587 +
 13.1588 +\subsubsection*{Terminal output}
 13.1589 +
 13.1590 +Solving large problem instances may take a long time, so the solver
 13.1591 +reports some information about the current basic solution, which is sent
 13.1592 +to the terminal. This information has the following format:
 13.1593 +
 13.1594 +\begin{verbatim}
 13.1595 +nnn:  obj = xxx  infeas = yyy (ddd)
 13.1596 +\end{verbatim}
 13.1597 +
 13.1598 +\noindent
 13.1599 +where: `\verb|nnn|' is the iteration number, `\verb|xxx|' is the
 13.1600 +current value of the objective function (it is is unscaled and has
 13.1601 +correct sign); `\verb|yyy|' is the current sum of primal or dual
 13.1602 +infeasibilities (it is scaled and therefore may be used only for visual
 13.1603 +estimating), `\verb|ddd|' is the current number of fixed basic
 13.1604 +variables.
 13.1605 +
 13.1606 +The symbol preceding the iteration number indicates which phase of the
 13.1607 +simplex method is in effect:
 13.1608 +
 13.1609 +{\it Blank} means that the solver is searching for primal feasible
 13.1610 +solution using the primal simplex or for dual feasible solution using
 13.1611 +the dual simplex;
 13.1612 +
 13.1613 +{\it Asterisk} (\verb|*|) means that the solver is searching for
 13.1614 +optimal solution using the primal simplex;
 13.1615 +
 13.1616 +{\it Vertical dash} (\verb/|/) means that the solver is searching for
 13.1617 +optimal solution using the dual simplex.
 13.1618 +
 13.1619 +\subsubsection*{Control parameters}
 13.1620 +
 13.1621 +This paragraph describes all control parameters currently used in the
 13.1622 +simplex solver. Symbolic names of control parameters are names of
 13.1623 +corresponding members in the structure \verb|glp_smcp|.
 13.1624 +
 13.1625 +\medskip
 13.1626 +
 13.1627 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.1628 +\multicolumn{2}{@{}l}{{\tt int msg\_lev} (default: {\tt GLP\_MSG\_ALL})}
 13.1629 +\\
 13.1630 +&Message level for terminal output:\\
 13.1631 +&\verb|GLP_MSG_OFF|---no output;\\
 13.1632 +&\verb|GLP_MSG_ERR|---error and warning messages only;\\
 13.1633 +&\verb|GLP_MSG_ON |---normal output;\\
 13.1634 +&\verb|GLP_MSG_ALL|---full output (including informational messages).
 13.1635 +\\
 13.1636 +\end{tabular}
 13.1637 +
 13.1638 +\medskip
 13.1639 +
 13.1640 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.1641 +\multicolumn{2}{@{}l}{{\tt int meth} (default: {\tt GLP\_PRIMAL})}
 13.1642 +\\
 13.1643 +&Simplex method option:\\
 13.1644 +&\verb|GLP_PRIMAL|---use two-phase primal simplex;\\
 13.1645 +&\verb|GLP_DUAL  |---use two-phase dual simplex;\\
 13.1646 +&\verb|GLP_DUALP |---use two-phase dual simplex, and if it fails,
 13.1647 +switch to the\\
 13.1648 +&\verb|            |$\:$ primal simplex.\\
 13.1649 +\end{tabular}
 13.1650 +
 13.1651 +\medskip
 13.1652 +
 13.1653 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.1654 +\multicolumn{2}{@{}l}{{\tt int pricing} (default: {\tt GLP\_PT\_PSE})}
 13.1655 +\\
 13.1656 +&Pricing technique:\\
 13.1657 +&\verb|GLP_PT_STD|---standard (textbook);\\
 13.1658 +&\verb|GLP_PT_PSE|---projected steepest edge.\\
 13.1659 +\end{tabular}
 13.1660 +
 13.1661 +\medskip
 13.1662 +
 13.1663 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.1664 +\multicolumn{2}{@{}l}{{\tt int r\_test} (default: {\tt GLP\_RT\_HAR})}
 13.1665 +\\
 13.1666 +&Ratio test technique:\\
 13.1667 +&\verb|GLP_RT_STD|---standard (textbook);\\
 13.1668 +&\verb|GLP_RT_HAR|---Harris' two-pass ratio test.\\
 13.1669 +\end{tabular}
 13.1670 +
 13.1671 +\medskip
 13.1672 +
 13.1673 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.1674 +\multicolumn{2}{@{}l}{{\tt double tol\_bnd} (default: {\tt 1e-7})}
 13.1675 +\\
 13.1676 +&Tolerance used to check if the basic solution is primal feasible.
 13.1677 +(Do not change this parameter without detailed understanding its
 13.1678 +purpose.)\\
 13.1679 +\end{tabular}
 13.1680 +
 13.1681 +\medskip
 13.1682 +
 13.1683 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.1684 +\multicolumn{2}{@{}l}{{\tt double tol\_dj} (default: {\tt 1e-7})}
 13.1685 +\\
 13.1686 +&Tolerance used to check if the basic solution is dual feasible.
 13.1687 +(Do not change this parameter without detailed understanding its
 13.1688 +purpose.)\\
 13.1689 +\end{tabular}
 13.1690 +
 13.1691 +\medskip
 13.1692 +
 13.1693 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.1694 +\multicolumn{2}{@{}l}{{\tt double tol\_piv} (default: {\tt 1e-10})}
 13.1695 +\\
 13.1696 +&Tolerance used to choose eligble pivotal elements of the simplex table.
 13.1697 +(Do not change this parameter without detailed understanding its
 13.1698 +purpose.)\\
 13.1699 +\end{tabular}
 13.1700 +
 13.1701 +\medskip
 13.1702 +
 13.1703 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.1704 +\multicolumn{2}{@{}l}{{\tt double obj\_ll} (default: {\tt -DBL\_MAX})}
 13.1705 +\\
 13.1706 +&Lower limit of the objective function. If the objective function
 13.1707 +reaches this limit and continues decreasing, the solver terminates the
 13.1708 +search. (Used in the dual simplex only.)\\
 13.1709 +\end{tabular}
 13.1710 +
 13.1711 +\medskip
 13.1712 +
 13.1713 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.1714 +\multicolumn{2}{@{}l}{{\tt double obj\_ul} (default: {\tt +DBL\_MAX})}
 13.1715 +\\
 13.1716 +&Upper limit of the objective function. If the objective function
 13.1717 +reaches this limit and continues increasing, the solver terminates the
 13.1718 +search. (Used in the dual simplex only.)\\
 13.1719 +\end{tabular}
 13.1720 +
 13.1721 +\medskip
 13.1722 +
 13.1723 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.1724 +\multicolumn{2}{@{}l}{{\tt int it\_lim} (default: {\tt INT\_MAX})}
 13.1725 +\\
 13.1726 +&Simplex iteration limit.\\
 13.1727 +\end{tabular}
 13.1728 +
 13.1729 +\medskip
 13.1730 +
 13.1731 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.1732 +\multicolumn{2}{@{}l}{{\tt int tm\_lim} (default: {\tt INT\_MAX})}
 13.1733 +\\
 13.1734 +&Searching time limit, in milliseconds.\\
 13.1735 +\end{tabular}
 13.1736 +
 13.1737 +\medskip
 13.1738 +
 13.1739 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.1740 +\multicolumn{2}{@{}l}{{\tt int out\_frq} (default: {\tt 500})}
 13.1741 +\\
 13.1742 +&Output frequency, in iterations. This parameter specifies how
 13.1743 +frequently the solver sends information about the solution process to
 13.1744 +the terminal.\\
 13.1745 +\end{tabular}
 13.1746 +
 13.1747 +\medskip
 13.1748 +
 13.1749 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.1750 +\multicolumn{2}{@{}l}{{\tt int out\_dly} (default: {\tt 0})}
 13.1751 +\\
 13.1752 +&Output delay, in milliseconds. This parameter specifies how long the
 13.1753 +solver should delay sending information about the solution process to
 13.1754 +the terminal.\\
 13.1755 +\end{tabular}
 13.1756 +
 13.1757 +\medskip
 13.1758 +
 13.1759 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.1760 +\multicolumn{2}{@{}l}{{\tt int presolve} (default: {\tt GLP\_OFF})}
 13.1761 +\\
 13.1762 +&LP presolver option:\\
 13.1763 +&\verb|GLP_ON |---enable using the LP presolver;\\
 13.1764 +&\verb|GLP_OFF|---disable using the LP presolver.\\
 13.1765 +\end{tabular}
 13.1766 +
 13.1767 +\subsubsection*{Example 1}
 13.1768 +
 13.1769 +The following main program reads LP problem instance in fixed MPS
 13.1770 +format from file \verb|25fv47.mps|,\footnote{This instance in fixed MPS
 13.1771 +format can be found in the Netlib LP collection; see
 13.1772 +{\tt ftp://ftp.netlib.org/lp/data/}.} constructs an advanced initial
 13.1773 +basis, solves the instance with the primal simplex method (by default),
 13.1774 +and writes the solution to file \verb|25fv47.txt|.
 13.1775 +
 13.1776 +\newpage
 13.1777 +
 13.1778 +\begin{footnotesize}
 13.1779 +\begin{verbatim}
 13.1780 +/* spxsamp1.c */
 13.1781 +
 13.1782 +#include <stdio.h>
 13.1783 +#include <stdlib.h>
 13.1784 +#include <glpk.h>
 13.1785 +
 13.1786 +int main(void)
 13.1787 +{     glp_prob *P;
 13.1788 +      P = glp_create_prob();
 13.1789 +      glp_read_mps(P, GLP_MPS_DECK, NULL, "25fv47.mps");
 13.1790 +      glp_adv_basis(P, 0);
 13.1791 +      glp_simplex(P, NULL);
 13.1792 +      glp_print_sol(P, "25fv47.txt");
 13.1793 +      glp_delete_prob(P);
 13.1794 +      return 0;
 13.1795 +}
 13.1796 +
 13.1797 +/* eof */
 13.1798 +\end{verbatim}
 13.1799 +\end{footnotesize}
 13.1800 +
 13.1801 +\noindent
 13.1802 +Below here is shown the terminal output from this example program.
 13.1803 +
 13.1804 +\begin{footnotesize}
 13.1805 +\begin{verbatim}
 13.1806 +Reading problem data from `25fv47.mps'...
 13.1807 +Problem: 25FV47
 13.1808 +Objective: R0000
 13.1809 +822 rows, 1571 columns, 11127 non-zeros
 13.1810 +6919 records were read
 13.1811 +Crashing...
 13.1812 +Size of triangular part = 799
 13.1813 +      0: obj =   1.627307307e+04  infeas =  5.194e+04 (23)
 13.1814 +    200: obj =   1.474901610e+04  infeas =  1.233e+04 (19)
 13.1815 +    400: obj =   1.343909995e+04  infeas =  3.648e+03 (13)
 13.1816 +    600: obj =   1.756052217e+04  infeas =  4.179e+02 (7)
 13.1817 +*   775: obj =   1.789251591e+04  infeas =  4.982e-14 (1)
 13.1818 +*   800: obj =   1.663354510e+04  infeas =  2.857e-14 (1)
 13.1819 +*  1000: obj =   1.024935068e+04  infeas =  1.958e-12 (1)
 13.1820 +*  1200: obj =   7.860174791e+03  infeas =  2.810e-29 (1)
 13.1821 +*  1400: obj =   6.642378184e+03  infeas =  2.036e-16 (1)
 13.1822 +*  1600: obj =   6.037014568e+03  infeas =  0.000e+00 (1)
 13.1823 +*  1800: obj =   5.662171307e+03  infeas =  6.447e-15 (1)
 13.1824 +*  2000: obj =   5.528146165e+03  infeas =  9.764e-13 (1)
 13.1825 +*  2125: obj =   5.501845888e+03  infeas =  0.000e+00 (1)
 13.1826 +OPTIMAL SOLUTION FOUND
 13.1827 +Writing basic solution to `25fv47.txt'...
 13.1828 +\end{verbatim}
 13.1829 +\end{footnotesize}
 13.1830 +
 13.1831 +\newpage
 13.1832 +
 13.1833 +\subsubsection*{Example 2}
 13.1834 +
 13.1835 +The following main program solves the same LP problem instance as in
 13.1836 +Example 1 above, however, it uses the dual simplex method, which starts
 13.1837 +from the standard initial basis.
 13.1838 +
 13.1839 +\begin{footnotesize}
 13.1840 +\begin{verbatim}
 13.1841 +/* spxsamp2.c */
 13.1842 +
 13.1843 +#include <stdio.h>
 13.1844 +#include <stdlib.h>
 13.1845 +#include <glpk.h>
 13.1846 +
 13.1847 +int main(void)
 13.1848 +{     glp_prob *P;
 13.1849 +      glp_smcp parm;
 13.1850 +      P = glp_create_prob();
 13.1851 +      glp_read_mps(P, GLP_MPS_DECK, NULL, "25fv47.mps");
 13.1852 +      glp_init_smcp(&parm);
 13.1853 +      parm.meth = GLP_DUAL;
 13.1854 +      glp_simplex(P, &parm);
 13.1855 +      glp_print_sol(P, "25fv47.txt");
 13.1856 +      glp_delete_prob(P);
 13.1857 +      return 0;
 13.1858 +}
 13.1859 +
 13.1860 +/* eof */
 13.1861 +\end{verbatim}
 13.1862 +\end{footnotesize}
 13.1863 +
 13.1864 +\noindent
 13.1865 +Below here is shown the terminal output from this example program.
 13.1866 +
 13.1867 +\begin{footnotesize}
 13.1868 +\begin{verbatim}
 13.1869 +Reading problem data from `25fv47.mps'...
 13.1870 +Problem: 25FV47
 13.1871 +Objective: R0000
 13.1872 +822 rows, 1571 columns, 11127 non-zeros
 13.1873 +6919 records were read
 13.1874 +      0:                          infeas =  1.223e+03 (516)
 13.1875 +    200:                          infeas =  7.000e+00 (471)
 13.1876 +    240:                          infeas =  1.106e-14 (461)
 13.1877 +|   400: obj =  -5.394267152e+03  infeas =  5.571e-16 (391)
 13.1878 +|   600: obj =  -4.586395752e+03  infeas =  1.389e-15 (340)
 13.1879 +|   800: obj =  -4.158268146e+03  infeas =  1.640e-15 (264)
 13.1880 +|  1000: obj =  -3.725320045e+03  infeas =  5.181e-15 (245)
 13.1881 +|  1200: obj =  -3.104802163e+03  infeas =  1.019e-14 (210)
 13.1882 +|  1400: obj =  -2.584190499e+03  infeas =  8.865e-15 (178)
 13.1883 +|  1600: obj =  -2.073852927e+03  infeas =  7.867e-15 (142)
 13.1884 +|  1800: obj =  -1.164037407e+03  infeas =  8.792e-15 (109)
 13.1885 +|  2000: obj =  -4.370590250e+02  infeas =  2.591e-14 (85)
 13.1886 +|  2200: obj =   1.068240144e+03  infeas =  1.025e-13 (70)
 13.1887 +|  2400: obj =   1.607481126e+03  infeas =  3.272e-14 (67)
 13.1888 +|  2600: obj =   3.038230551e+03  infeas =  4.850e-14 (52)
 13.1889 +|  2800: obj =   4.316238187e+03  infeas =  2.622e-14 (36)
 13.1890 +|  3000: obj =   5.443842629e+03  infeas =  3.976e-15 (11)
 13.1891 +|  3060: obj =   5.501845888e+03  infeas =  8.806e-15 (2)
 13.1892 +OPTIMAL SOLUTION FOUND
 13.1893 +Writing basic solution to `25fv47.txt'...
 13.1894 +\end{verbatim}
 13.1895 +\end{footnotesize}
 13.1896 +
 13.1897 +\subsection{glp\_exact---solve LP problem in exact arithmetic}
 13.1898 +
 13.1899 +\subsubsection*{Synopsis}
 13.1900 +
 13.1901 +\begin{verbatim}
 13.1902 +int glp_exact(glp_prob *lp, const glp_smcp *parm);
 13.1903 +\end{verbatim}
 13.1904 +
 13.1905 +\subsubsection*{Description}
 13.1906 +
 13.1907 +The routine \verb|glp_exact| is a tentative implementation of the
 13.1908 +primal two-phase simplex method based on exact (rational) arithmetic.
 13.1909 +It is similar to the routine \verb|glp_simplex|, however, for all
 13.1910 +internal computations it uses arithmetic of rational numbers, which is
 13.1911 +exact in mathematical sense, i.e. free of round-off errors unlike
 13.1912 +floating-point arithmetic.
 13.1913 +
 13.1914 +Note that the routine \verb|glp_exact| uses only two control parameters
 13.1915 +passed in the structure \verb|glp_smcp|, namely, \verb|it_lim| and
 13.1916 +\verb|tm_lim|.
 13.1917 +
 13.1918 +\subsubsection*{Returns}
 13.1919 +
 13.1920 +\def\arraystretch{1}
 13.1921 +
 13.1922 +\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
 13.1923 +0 & The LP problem instance has been successfully solved. (This code
 13.1924 +does {\it not} necessarily mean that the solver has found optimal
 13.1925 +solution. It only means that the solution process was successful.) \\
 13.1926 +\verb|GLP_EBADB| & Unable to start the search, because the initial basis
 13.1927 +specified in the problem object is invalid---the number of basic
 13.1928 +(auxiliary and structural) variables is not the same as the number of
 13.1929 +rows in the problem object.\\
 13.1930 +\verb|GLP_ESING| & Unable to start the search, because the basis matrix
 13.1931 +corresponding to the initial basis is exactly singular.\\
 13.1932 +\verb|GLP_EBOUND| & Unable to start the search, because some
 13.1933 +double-bounded (auxiliary or structural) variables have incorrect
 13.1934 +bounds.\\
 13.1935 +\verb|GLP_EFAIL| & The problem instance has no rows/columns.\\
 13.1936 +\verb|GLP_EITLIM| & The search was prematurely terminated, because the
 13.1937 +simplex iteration limit has been exceeded.\\
 13.1938 +\verb|GLP_ETMLIM| & The search was prematurely terminated, because the
 13.1939 +time limit has been exceeded.\\
 13.1940 +\end{tabular}
 13.1941 +
 13.1942 +\subsubsection*{Comments}
 13.1943 +
 13.1944 +Computations in exact arithmetic are very time consuming, so solving
 13.1945 +LP problem with the routine \verb|glp_exact| from the very beginning is
 13.1946 +not a good idea. It is much better at first to find an optimal basis
 13.1947 +with the routine \verb|glp_simplex| and only then to call
 13.1948 +\verb|glp_exact|, in which case only a few simplex iterations need to
 13.1949 +be performed in exact arithmetic.
 13.1950 +
 13.1951 +\subsection{glp\_init\_smcp---initialize simplex solver control
 13.1952 +parameters}
 13.1953 +
 13.1954 +\subsubsection*{Synopsis}
 13.1955 +
 13.1956 +\begin{verbatim}
 13.1957 +int glp_init_smcp(glp_smcp *parm);
 13.1958 +\end{verbatim}
 13.1959 +
 13.1960 +\subsubsection*{Description}
 13.1961 +
 13.1962 +The routine \verb|glp_init_smcp| initializes control parameters, which
 13.1963 +are used by the simplex solver, with default values.
 13.1964 +
 13.1965 +Default values of the control parameters are stored in a \verb|glp_smcp|
 13.1966 +structure, which the parameter \verb|parm| points to.
 13.1967 +
 13.1968 +\subsection{glp\_get\_status---determine generic status of basic
 13.1969 +solution}
 13.1970 +
 13.1971 +\subsubsection*{Synopsis}
 13.1972 +
 13.1973 +\begin{verbatim}
 13.1974 +int glp_get_status(glp_prob *lp);
 13.1975 +\end{verbatim}
 13.1976 +
 13.1977 +\subsubsection*{Returns}
 13.1978 +
 13.1979 +The routine \verb|glp_get_status| reports the generic status of the
 13.1980 +current basic solution for the specified problem object as follows:
 13.1981 +
 13.1982 +\begin{tabular}{@{}ll}
 13.1983 +\verb|GLP_OPT|    & solution is optimal; \\
 13.1984 +\verb|GLP_FEAS|   & solution is feasible; \\
 13.1985 +\verb|GLP_INFEAS| & solution is infeasible; \\
 13.1986 +\verb|GLP_NOFEAS| & problem has no feasible solution; \\
 13.1987 +\verb|GLP_UNBND|  & problem has unbounded solution; \\
 13.1988 +\verb|GLP_UNDEF|  & solution is undefined. \\
 13.1989 +\end{tabular}
 13.1990 +
 13.1991 +More detailed information about the status of basic solution can be
 13.1992 +retrieved with the routines \verb|glp_get_prim_stat| and
 13.1993 +\verb|glp_get_dual_stat|.
 13.1994 +
 13.1995 +\newpage
 13.1996 +
 13.1997 +\subsection{glp\_get\_prim\_stat---retrieve status of primal basic
 13.1998 +solution}
 13.1999 +
 13.2000 +\subsubsection*{Synopsis}
 13.2001 +
 13.2002 +\begin{verbatim}
 13.2003 +int glp_get_prim_stat(glp_prob *lp);
 13.2004 +\end{verbatim}
 13.2005 +
 13.2006 +\subsubsection*{Returns}
 13.2007 +
 13.2008 +The routine \verb|glp_get_prim_stat| reports the status of the primal
 13.2009 +basic solution for the specified problem object as follows:
 13.2010 +
 13.2011 +\begin{tabular}{@{}ll}
 13.2012 +\verb|GLP_UNDEF|  & primal solution is undefined; \\
 13.2013 +\verb|GLP_FEAS|   & primal solution is feasible; \\
 13.2014 +\verb|GLP_INFEAS| & primal solution is infeasible; \\
 13.2015 +\verb|GLP_NOFEAS| & no primal feasible solution exists. \\
 13.2016 +\end{tabular}
 13.2017 +
 13.2018 +\subsection{glp\_get\_dual\_stat---retrieve status of dual basic
 13.2019 +solution}
 13.2020 +
 13.2021 +\subsubsection*{Synopsis}
 13.2022 +
 13.2023 +\begin{verbatim}
 13.2024 +int glp_get_dual_stat(glp_prob *lp);
 13.2025 +\end{verbatim}
 13.2026 +
 13.2027 +\subsubsection*{Returns}
 13.2028 +
 13.2029 +The routine \verb|glp_get_dual_stat| reports the status of the dual
 13.2030 +basic solution for the specified problem object as follows:
 13.2031 +
 13.2032 +\begin{tabular}{@{}ll}
 13.2033 +\verb|GLP_UNDEF|  & dual solution is undefined; \\
 13.2034 +\verb|GLP_FEAS|   & dual solution is feasible; \\
 13.2035 +\verb|GLP_INFEAS| & dual solution is infeasible; \\
 13.2036 +\verb|GLP_NOFEAS| & no dual feasible solution exists. \\
 13.2037 +\end{tabular}
 13.2038 +
 13.2039 +\subsection{glp\_get\_obj\_val---retrieve objective value}
 13.2040 +
 13.2041 +\subsubsection*{Synopsis}
 13.2042 +
 13.2043 +\begin{verbatim}
 13.2044 +double glp_get_obj_val(glp_prob *lp);
 13.2045 +\end{verbatim}
 13.2046 +
 13.2047 +\subsubsection*{Returns}
 13.2048 +
 13.2049 +The routine \verb|glp_get_obj_val| returns current value of the
 13.2050 +objective function.
 13.2051 +
 13.2052 +\subsection{glp\_get\_row\_stat---retrieve row status}
 13.2053 +
 13.2054 +\subsubsection*{Synopsis}
 13.2055 +
 13.2056 +\begin{verbatim}
 13.2057 +int glp_get_row_stat(glp_prob *lp, int i);
 13.2058 +\end{verbatim}
 13.2059 +
 13.2060 +\subsubsection*{Returns}
 13.2061 +
 13.2062 +The routine \verb|glp_get_row_stat| returns current status assigned to
 13.2063 +the auxiliary variable associated with \verb|i|-th row as follows:
 13.2064 +
 13.2065 +\begin{tabular}{@{}ll}
 13.2066 +\verb|GLP_BS| & basic variable; \\
 13.2067 +\verb|GLP_NL| & non-basic variable on its lower bound; \\
 13.2068 +\verb|GLP_NU| & non-basic variable on its upper bound; \\
 13.2069 +\verb|GLP_NF| & non-basic free (unbounded) variable; \\
 13.2070 +\verb|GLP_NS| & non-basic fixed variable. \\
 13.2071 +\end{tabular}
 13.2072 +
 13.2073 +\subsection{glp\_get\_row\_prim---retrieve row primal value}
 13.2074 +
 13.2075 +\subsubsection*{Synopsis}
 13.2076 +
 13.2077 +\begin{verbatim}
 13.2078 +double glp_get_row_prim(glp_prob *lp, int i);
 13.2079 +\end{verbatim}
 13.2080 +
 13.2081 +\subsubsection*{Returns}
 13.2082 +
 13.2083 +The routine \verb|glp_get_row_prim| returns primal value of the
 13.2084 +auxiliary variable associated with \verb|i|-th row.
 13.2085 +
 13.2086 +\subsection{glp\_get\_row\_dual---retrieve row dual value}
 13.2087 +
 13.2088 +\subsubsection*{Synopsis}
 13.2089 +
 13.2090 +\begin{verbatim}
 13.2091 +double glp_get_row_dual(glp_prob *lp, int i);
 13.2092 +\end{verbatim}
 13.2093 +
 13.2094 +\subsubsection*{Returns}
 13.2095 +
 13.2096 +The routine \verb|glp_get_row_dual| returns dual value (i.e. reduced
 13.2097 +cost) of the auxiliary variable associated with \verb|i|-th row.
 13.2098 +
 13.2099 +\newpage
 13.2100 +
 13.2101 +\subsection{glp\_get\_col\_stat---retrieve column status}
 13.2102 +
 13.2103 +\subsubsection*{Synopsis}
 13.2104 +
 13.2105 +\begin{verbatim}
 13.2106 +int glp_get_col_stat(glp_prob *lp, int j);
 13.2107 +\end{verbatim}
 13.2108 +
 13.2109 +\subsubsection*{Returns}
 13.2110 +
 13.2111 +The routine \verb|glp_get_col_stat| returns current status assigned to
 13.2112 +the structural variable associated with \verb|j|-th column as follows:
 13.2113 +
 13.2114 +\begin{tabular}{@{}ll}
 13.2115 +\verb|GLP_BS| & basic variable; \\
 13.2116 +\verb|GLP_NL| & non-basic variable on its lower bound; \\
 13.2117 +\verb|GLP_NU| & non-basic variable on its upper bound; \\
 13.2118 +\verb|GLP_NF| & non-basic free (unbounded) variable; \\
 13.2119 +\verb|GLP_NS| & non-basic fixed variable. \\
 13.2120 +\end{tabular}
 13.2121 +
 13.2122 +\subsection{glp\_get\_col\_prim---retrieve column primal value}
 13.2123 +
 13.2124 +\subsubsection*{Synopsis}
 13.2125 +
 13.2126 +\begin{verbatim}
 13.2127 +double glp_get_col_prim(glp_prob *lp, int j);
 13.2128 +\end{verbatim}
 13.2129 +
 13.2130 +\subsubsection*{Returns}
 13.2131 +
 13.2132 +The routine \verb|glp_get_col_prim| returns primal value of the
 13.2133 +structural variable associated with \verb|j|-th column.
 13.2134 +
 13.2135 +\subsection{glp\_get\_col\_dual---retrieve column dual value}
 13.2136 +
 13.2137 +\subsubsection*{Synopsis}
 13.2138 +
 13.2139 +\begin{verbatim}
 13.2140 +double glp_get_col_dual(glp_prob *lp, int j);
 13.2141 +\end{verbatim}
 13.2142 +
 13.2143 +\subsubsection*{Returns}
 13.2144 +
 13.2145 +The routine \verb|glp_get_col_dual| returns dual value (i.e. reduced
 13.2146 +cost) of the structural variable associated with \verb|j|-th column.
 13.2147 +
 13.2148 +\newpage
 13.2149 +
 13.2150 +\subsection{glp\_get\_unbnd\_ray---determine variable causing\\
 13.2151 +unboundedness}
 13.2152 +
 13.2153 +\subsubsection*{Synopsis}
 13.2154 +
 13.2155 +\begin{verbatim}
 13.2156 +int glp_get_unbnd_ray(glp_prob *lp);
 13.2157 +\end{verbatim}
 13.2158 +
 13.2159 +\subsubsection*{Returns}
 13.2160 +
 13.2161 +The routine \verb|glp_get_unbnd_ray| returns the number $k$ of
 13.2162 +a variable, which causes primal or dual unboundedness.
 13.2163 +If $1\leq k\leq m$, it is $k$-th auxiliary variable, and if
 13.2164 +$m+1\leq k\leq m+n$, it is $(k-m)$-th structural variable, where $m$ is
 13.2165 +the number of rows, $n$ is the number of columns in the problem object.
 13.2166 +If such variable is not defined, the routine returns 0.
 13.2167 +
 13.2168 +\subsubsection*{Comments}
 13.2169 +
 13.2170 +If it is not exactly known which version of the simplex solver
 13.2171 +detected unboundedness, i.e. whether the unboundedness is primal or
 13.2172 +dual, it is sufficient to check the status of the variable
 13.2173 +with the routine \verb|glp_get_row_stat| or \verb|glp_get_col_stat|.
 13.2174 +If the variable is non-basic, the unboundedness is primal, otherwise,
 13.2175 +if the variable is basic, the unboundedness is dual (the latter case
 13.2176 +means that the problem has no primal feasible dolution).
 13.2177 +
 13.2178 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 13.2179 +
 13.2180 +\newpage
 13.2181 +
 13.2182 +\section{Interior-point method routines}
 13.2183 +
 13.2184 +{\it Interior-point methods} (also known as {\it barrier methods}) are
 13.2185 +more modern and powerful numerical methods for large-scale linear
 13.2186 +programming. Such methods are especially efficient for very sparse LP
 13.2187 +problems and allow solving such problems much faster than the simplex
 13.2188 +method.
 13.2189 +
 13.2190 +In brief, the GLPK interior-point solver works as follows.
 13.2191 +
 13.2192 +At first, the solver transforms the original LP to a {\it working} LP
 13.2193 +in the standard format:
 13.2194 +
 13.2195 +\medskip
 13.2196 +
 13.2197 +\noindent
 13.2198 +\hspace{.5in} minimize
 13.2199 +$$z = c_1x_{m+1} + c_2x_{m+2} + \dots + c_nx_{m+n} + c_0 \eqno (2.4)$$
 13.2200 +\hspace{.5in} subject to linear constraints
 13.2201 +$$
 13.2202 +\begin{array}{r@{\:}c@{\:}r@{\:}c@{\:}r@{\:}c@{\:}l}
 13.2203 +a_{11}x_{m+1}&+&a_{12}x_{m+2}&+ \dots +&a_{1n}x_{m+n}&=&b_1 \\
 13.2204 +a_{21}x_{m+1}&+&a_{22}x_{m+2}&+ \dots +&a_{2n}x_{m+n}&=&b_2 \\
 13.2205 +\multicolumn{7}{c}
 13.2206 +{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .} \\
 13.2207 +a_{m1}x_{m+1}&+&a_{m2}x_{m+2}&+ \dots +&a_{mn}x_{m+n}&=&b_m \\
 13.2208 +\end{array} \eqno (2.5)
 13.2209 +$$
 13.2210 +\hspace{.5in} and non-negative variables
 13.2211 +$$x_1\geq 0,\ \ x_2\geq 0,\ \ \dots,\ \ x_n\geq 0 \eqno(2.6)$$
 13.2212 +where: $z$ is the objective function; $x_1$, \dots, $x_n$ are variables;
 13.2213 +$c_1$, \dots, $c_n$ are objective coefficients; $c_0$ is a constant term
 13.2214 +of the objective function;\linebreak $a_{11}$, \dots, $a_{mn}$ are
 13.2215 +constraint coefficients; $b_1$, \dots, $b_m$ are right-hand sides.
 13.2216 +
 13.2217 +Using vector and matrix notations the working LP (2.4)---(2.6) can be
 13.2218 +written as follows:
 13.2219 +$$z=c^Tx+c_0\ \rightarrow\ \min,\eqno(2.7)$$
 13.2220 +$$Ax=b,\eqno(2.8)$$
 13.2221 +$$x\geq 0,\eqno(2.9)$$
 13.2222 +where: $x=(x_j)$ is $n$-vector of variables, $c=(c_j)$ is $n$-vector of
 13.2223 +objective coefficients, $A=(a_{ij})$ is $m\times n$-matrix of
 13.2224 +constraint coefficients, and $b=(b_i)$ is $m$-vector of right-hand
 13.2225 +sides.
 13.2226 +
 13.2227 +Karush--Kuhn--Tucker optimality conditions for LP (2.7)---(2.9) are the
 13.2228 +following:
 13.2229 +
 13.2230 +\newpage
 13.2231 +
 13.2232 +$$Ax=b,\eqno(2.10)$$
 13.2233 +$$A^T\pi+\lambda=c,\eqno(2.11)$$
 13.2234 +$$\lambda^Tx=0,\eqno(2.12)$$
 13.2235 +$$x\geq 0,\ \ \lambda\geq 0,\eqno(2.13)$$
 13.2236 +where: $\pi$ is $m$-vector of Lagrange multipliers (dual variables) for
 13.2237 +equality constraints (2.8), $\lambda$ is $n$-vector of Lagrange
 13.2238 +multipliers (dual variables) for non-negativity constraints (2.9),
 13.2239 +(2.10) is the primal feasibility condition, (2.11) is the dual
 13.2240 +feasibility condition, (2.12) is the primal-dual complementarity
 13.2241 +condition, and (2.13) is the non-negativity conditions.
 13.2242 +
 13.2243 +The main idea of the primal-dual interior-point method is based on
 13.2244 +finding a point in the primal-dual space (i.e. in the space of all
 13.2245 +primal and dual variables $x$, $\pi$, and $\lambda$), which satisfies
 13.2246 +to all optimality conditions (2.10)---(2.13). Obviously, $x$-component
 13.2247 +of such point then provides an optimal solution to the working LP
 13.2248 +(2.7)---(2.9).
 13.2249 +
 13.2250 +To find the optimal point $(x^*,\pi^*,\lambda^*)$ the interior-point
 13.2251 +method attempts to solve the system of equations (2.10)---(2.12), which
 13.2252 +is closed in the sense that the number of variables $x_j$, $\pi_i$, and
 13.2253 +$\lambda_j$ and the number equations are the same and equal to $m+2n$.
 13.2254 +Due to condition (2.12) this system of equations is non-linear, so it
 13.2255 +can be solved with a version of {\it Newton's method} provided with
 13.2256 +additional rules to keep the current point within the positive orthant
 13.2257 +as required by the non-negativity conditions (2.13).
 13.2258 +
 13.2259 +Finally, once the optimal point $(x^*,\pi^*,\lambda^*)$ has been found,
 13.2260 +the solver performs inverse transformations to recover corresponding
 13.2261 +solution to the original LP passed to the solver from the application
 13.2262 +program.
 13.2263 +
 13.2264 +\subsection{glp\_interior---solve LP problem with the interior-point
 13.2265 +method}
 13.2266 +
 13.2267 +\subsubsection*{Synopsis}
 13.2268 +
 13.2269 +\begin{verbatim}
 13.2270 +int glp_interior(glp_prob *P, const glp_iptcp *parm);
 13.2271 +\end{verbatim}
 13.2272 +
 13.2273 +\subsubsection*{Description}
 13.2274 +
 13.2275 +The routine \verb|glp_interior| is a driver to the LP solver based on
 13.2276 +the primal-dual interior-point method. This routine retrieves problem
 13.2277 +data from the specified problem object, calls the solver to solve the
 13.2278 +problem instance, and stores results of computations back into the
 13.2279 +problem object.
 13.2280 +
 13.2281 +The interior-point solver has a set of control parameters. Values of
 13.2282 +the control parameters can be passed in the structure \verb|glp_iptcp|,
 13.2283 +which the parameter \verb|parm| points to. For detailed description of
 13.2284 +this structure see paragraph ``Control parameters'' below. Before
 13.2285 +specifying some control parameters the application program should
 13.2286 +initialize the structure \verb|glp_iptcp| by default values of all
 13.2287 +control parameters using the routine \verb|glp_init_iptcp| (see the
 13.2288 +next subsection). This is needed for backward compatibility, because in
 13.2289 +the future there may appear new members in the structure
 13.2290 +\verb|glp_iptcp|.
 13.2291 +
 13.2292 +The parameter \verb|parm| can be specified as \verb|NULL|, in which
 13.2293 +case the solver uses default settings.
 13.2294 +
 13.2295 +\subsubsection*{Returns}
 13.2296 +
 13.2297 +\def\arraystretch{1}
 13.2298 +
 13.2299 +\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
 13.2300 +0 & The LP problem instance has been successfully solved. (This code
 13.2301 +does {\it not} necessarily mean that the solver has found optimal
 13.2302 +solution. It only means that the solution process was successful.) \\
 13.2303 +\verb|GLP_EFAIL| & The problem has no rows/columns.\\
 13.2304 +\verb|GLP_ENOCVG| & Very slow convergence or divergence.\\
 13.2305 +\verb|GLP_EITLIM| & Iteration limit exceeded.\\
 13.2306 +\verb|GLP_EINSTAB| & Numerical instability on solving Newtonian
 13.2307 +system.\\
 13.2308 +\end{tabular}
 13.2309 +
 13.2310 +\subsubsection*{Comments}
 13.2311 +
 13.2312 +The routine \verb|glp_interior| implements an easy version of
 13.2313 +the primal-dual interior-point method based on Mehrotra's
 13.2314 +technique.\footnote{S. Mehrotra. On the implementation of a primal-dual
 13.2315 +interior point method. SIAM J. on Optim., 2(4), pp. 575-601, 1992.}
 13.2316 +
 13.2317 +Note that currently the GLPK interior-point solver does not include
 13.2318 +many important features, in particular:
 13.2319 +
 13.2320 +$\bullet$ it is not able to process dense columns. Thus, if the
 13.2321 +constraint matrix of the LP problem has dense columns, the solving
 13.2322 +process may be inefficient;
 13.2323 +
 13.2324 +$\bullet$ it has no features against numerical instability. For some
 13.2325 +LP problems premature termination may happen if the matrix $ADA^T$
 13.2326 +becomes singular or ill-conditioned;
 13.2327 +
 13.2328 +$\bullet$ it is not able to identify the optimal basis, which
 13.2329 +corresponds to the interior-point solution found.
 13.2330 +
 13.2331 +\newpage
 13.2332 +
 13.2333 +\subsubsection*{Terminal output}
 13.2334 +
 13.2335 +Solving large LP problems may take a long time, so the solver reports
 13.2336 +some information about every interior-point iteration,\footnote{Unlike
 13.2337 +the simplex method the interior point method usually needs 30---50
 13.2338 +iterations (independently on the problem size) in order to find an
 13.2339 +optimal solution.} which is sent to the terminal. This information has
 13.2340 +the following format:
 13.2341 +
 13.2342 +\begin{verbatim}
 13.2343 +nnn: obj = fff; rpi = ppp; rdi = ddd; gap = ggg
 13.2344 +\end{verbatim}
 13.2345 +
 13.2346 +\noindent where: \verb|nnn| is iteration number, \verb|fff| is the
 13.2347 +current value of the objective function (in the case of maximization it
 13.2348 +has wrong sign), \verb|ppp| is the current relative primal
 13.2349 +infeasibility (cf. (2.10)):
 13.2350 +$$\frac{\|Ax^{(k)}-b\|}{1+\|b\|},\eqno(2.14)$$
 13.2351 +\verb|ddd| is the current relative dual infeasibility (cf. (2.11)):
 13.2352 +$$\frac{\|A^T\pi^{(k)}+\lambda^{(k)}-c\|}{1+\|c\|},\eqno(2.15)$$
 13.2353 +\verb|ggg| is the current primal-dual gap (cf. (2.12)):
 13.2354 +$$\frac{|c^Tx^{(k)}-b^T\pi^{(k)}|}{1+|c^Tx^{(k)}|},\eqno(2.16)$$
 13.2355 +and $[x^{(k)},\pi^{(k)},\lambda^{(k)}]$ is the current point on $k$-th
 13.2356 +iteration, $k=0,1,2,\dots$\ . Note that all solution components are
 13.2357 +internally scaled, so information sent to the terminal is suitable only
 13.2358 +for visual inspection.
 13.2359 +
 13.2360 +\subsubsection*{Control parameters}
 13.2361 +
 13.2362 +This paragraph describes all control parameters currently used in the
 13.2363 +interior-point solver. Symbolic names of control parameters are names of
 13.2364 +corresponding members in the structure \verb|glp_iptcp|.
 13.2365 +
 13.2366 +\medskip
 13.2367 +
 13.2368 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.2369 +\multicolumn{2}{@{}l}{{\tt int msg\_lev} (default: {\tt GLP\_MSG\_ALL})}
 13.2370 +\\
 13.2371 +&Message level for terminal output:\\
 13.2372 +&\verb|GLP_MSG_OFF|---no output;\\
 13.2373 +&\verb|GLP_MSG_ERR|---error and warning messages only;\\
 13.2374 +&\verb|GLP_MSG_ON |---normal output;\\
 13.2375 +&\verb|GLP_MSG_ALL|---full output (including informational messages).
 13.2376 +\\
 13.2377 +\end{tabular}
 13.2378 +
 13.2379 +\medskip
 13.2380 +
 13.2381 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.2382 +\multicolumn{2}{@{}l}{{\tt int ord\_alg} (default: {\tt GLP\_ORD\_AMD})}
 13.2383 +\\
 13.2384 +&Ordering algorithm used prior to Cholesky factorization:\\
 13.2385 +&\verb|GLP_ORD_NONE  |---use natural (original) ordering;\\
 13.2386 +&\verb|GLP_ORD_QMD   |---quotient minimum degree (QMD);\\
 13.2387 +&\verb|GLP_ORD_AMD   |---approximate minimum degree (AMD);\\
 13.2388 +&\verb|GLP_ORD_SYMAMD|---approximate minimum degree (SYMAMD).\\
 13.2389 +\end{tabular}
 13.2390 +
 13.2391 +\subsubsection*{Example}
 13.2392 +
 13.2393 +The following main program reads LP problem instance in fixed MPS
 13.2394 +format from file \verb|25fv47.mps|,\footnote{This instance in fixed MPS
 13.2395 +format can be found in the Netlib LP collection; see
 13.2396 +{\tt ftp://ftp.netlib.org/lp/data/}.} solves it with the interior-point
 13.2397 +solver, and writes the solution to file \verb|25fv47.txt|.
 13.2398 +
 13.2399 +\begin{footnotesize}
 13.2400 +\begin{verbatim}
 13.2401 +/* iptsamp.c */
 13.2402 +
 13.2403 +#include <stdio.h>
 13.2404 +#include <stdlib.h>
 13.2405 +#include <glpk.h>
 13.2406 +
 13.2407 +int main(void)
 13.2408 +{     glp_prob *P;
 13.2409 +      P = glp_create_prob();
 13.2410 +      glp_read_mps(P, GLP_MPS_DECK, NULL, "25fv47.mps");
 13.2411 +      glp_interior(P, NULL);
 13.2412 +      glp_print_ipt(P, "25fv47.txt");
 13.2413 +      glp_delete_prob(P);
 13.2414 +      return 0;
 13.2415 +}
 13.2416 +
 13.2417 +/* eof */
 13.2418 +\end{verbatim}
 13.2419 +\end{footnotesize}
 13.2420 +
 13.2421 +\noindent
 13.2422 +Below here is shown the terminal output from this example program.
 13.2423 +
 13.2424 +\begin{footnotesize}
 13.2425 +\begin{verbatim}
 13.2426 +Reading problem data from `25fv47.mps'...
 13.2427 +Problem: 25FV47
 13.2428 +Objective: R0000
 13.2429 +822 rows, 1571 columns, 11127 non-zeros
 13.2430 +6919 records were read
 13.2431 +Original LP has 822 row(s), 1571 column(s), and 11127 non-zero(s)
 13.2432 +Working LP has 821 row(s), 1876 column(s), and 10705 non-zero(s)
 13.2433 +Matrix A has 10705 non-zeros
 13.2434 +Matrix S = A*A' has 11895 non-zeros (upper triangle)
 13.2435 +Minimal degree ordering...
 13.2436 +Computing Cholesky factorization S = L'*L...
 13.2437 +Matrix L has 35411 non-zeros
 13.2438 +Guessing initial point...
 13.2439 +Optimization begins...
 13.2440 +  0: obj =   1.823377629e+05; rpi =  1.3e+01; rdi =  1.4e+01; gap =  9.3e-01
 13.2441 +  1: obj =   9.260045192e+04; rpi =  5.3e+00; rdi =  5.6e+00; gap =  6.8e+00
 13.2442 +  2: obj =   3.596999742e+04; rpi =  1.5e+00; rdi =  1.2e+00; gap =  1.8e+01
 13.2443 +  3: obj =   1.989627568e+04; rpi =  4.7e-01; rdi =  3.0e-01; gap =  1.9e+01
 13.2444 +  4: obj =   1.430215557e+04; rpi =  1.1e-01; rdi =  8.6e-02; gap =  1.4e+01
 13.2445 +  5: obj =   1.155716505e+04; rpi =  2.3e-02; rdi =  2.4e-02; gap =  6.8e+00
 13.2446 +  6: obj =   9.660273208e+03; rpi =  6.7e-03; rdi =  4.6e-03; gap =  3.9e+00
 13.2447 +  7: obj =   8.694348283e+03; rpi =  3.7e-03; rdi =  1.7e-03; gap =  2.0e+00
 13.2448 +  8: obj =   8.019543639e+03; rpi =  2.4e-03; rdi =  3.9e-04; gap =  1.0e+00
 13.2449 +  9: obj =   7.122676293e+03; rpi =  1.2e-03; rdi =  1.5e-04; gap =  6.6e-01
 13.2450 + 10: obj =   6.514534518e+03; rpi =  6.1e-04; rdi =  4.3e-05; gap =  4.1e-01
 13.2451 + 11: obj =   6.361572203e+03; rpi =  4.8e-04; rdi =  2.2e-05; gap =  3.0e-01
 13.2452 + 12: obj =   6.203355508e+03; rpi =  3.2e-04; rdi =  1.7e-05; gap =  2.6e-01
 13.2453 + 13: obj =   6.032943411e+03; rpi =  2.0e-04; rdi =  9.3e-06; gap =  2.1e-01
 13.2454 + 14: obj =   5.796553021e+03; rpi =  9.8e-05; rdi =  3.2e-06; gap =  1.0e-01
 13.2455 + 15: obj =   5.667032431e+03; rpi =  4.4e-05; rdi =  1.1e-06; gap =  5.6e-02
 13.2456 + 16: obj =   5.613911867e+03; rpi =  2.5e-05; rdi =  4.1e-07; gap =  3.5e-02
 13.2457 + 17: obj =   5.560572626e+03; rpi =  9.9e-06; rdi =  2.3e-07; gap =  2.1e-02
 13.2458 + 18: obj =   5.537276001e+03; rpi =  5.5e-06; rdi =  8.4e-08; gap =  1.1e-02
 13.2459 + 19: obj =   5.522746942e+03; rpi =  2.2e-06; rdi =  4.0e-08; gap =  6.7e-03
 13.2460 + 20: obj =   5.509956679e+03; rpi =  7.5e-07; rdi =  1.8e-08; gap =  2.9e-03
 13.2461 + 21: obj =   5.504571733e+03; rpi =  1.6e-07; rdi =  5.8e-09; gap =  1.1e-03
 13.2462 + 22: obj =   5.502576367e+03; rpi =  3.4e-08; rdi =  1.0e-09; gap =  2.5e-04
 13.2463 + 23: obj =   5.502057119e+03; rpi =  8.1e-09; rdi =  3.0e-10; gap =  7.7e-05
 13.2464 + 24: obj =   5.501885996e+03; rpi =  9.4e-10; rdi =  1.2e-10; gap =  2.4e-05
 13.2465 + 25: obj =   5.501852464e+03; rpi =  1.4e-10; rdi =  1.2e-11; gap =  3.0e-06
 13.2466 + 26: obj =   5.501846549e+03; rpi =  1.4e-11; rdi =  1.2e-12; gap =  3.0e-07
 13.2467 + 27: obj =   5.501845954e+03; rpi =  1.4e-12; rdi =  1.2e-13; gap =  3.0e-08
 13.2468 + 28: obj =   5.501845895e+03; rpi =  1.5e-13; rdi =  1.2e-14; gap =  3.0e-09
 13.2469 +OPTIMAL SOLUTION FOUND
 13.2470 +Writing interior-point solution to `25fv47.txt'...
 13.2471 +\end{verbatim}
 13.2472 +\end{footnotesize}
 13.2473 +
 13.2474 +\subsection{glp\_init\_iptcp---initialize interior-point solver control
 13.2475 +parameters}
 13.2476 +
 13.2477 +\subsubsection*{Synopsis}
 13.2478 +
 13.2479 +\begin{verbatim}
 13.2480 +int glp_init_iptcp(glp_iptcp *parm);
 13.2481 +\end{verbatim}
 13.2482 +
 13.2483 +\subsubsection*{Description}
 13.2484 +
 13.2485 +The routine \verb|glp_init_iptcp| initializes control parameters, which
 13.2486 +are used by the interior-point solver, with default values.
 13.2487 +
 13.2488 +Default values of the control parameters are stored in the structure
 13.2489 +\verb|glp_iptcp|, which the parameter \verb|parm| points to.
 13.2490 +
 13.2491 +\subsection{glp\_ipt\_status---determine solution status}
 13.2492 +
 13.2493 +\subsubsection*{Synopsis}
 13.2494 +
 13.2495 +\begin{verbatim}
 13.2496 +int glp_ipt_status(glp_prob *lp);
 13.2497 +\end{verbatim}
 13.2498 +
 13.2499 +\subsubsection*{Returns}
 13.2500 +
 13.2501 +The routine \verb|glp_ipt_status| reports the status of a solution
 13.2502 +found by the interior-point solver as follows:
 13.2503 +
 13.2504 +\begin{tabular}{@{}p{25mm}p{91.3mm}@{}}
 13.2505 +\verb|GLP_UNDEF| & interior-point solution is undefined. \\
 13.2506 +\verb|GLP_OPT|   & interior-point solution is optimal. \\
 13.2507 +\verb|GLP_INFEAS|& interior-point solution is infeasible. \\
 13.2508 +\verb|GLP_NOFEAS|& no feasible primal-dual solution exists.\\
 13.2509 +\end{tabular}
 13.2510 +
 13.2511 +\subsection{glp\_ipt\_obj\_val---retrieve objective value}
 13.2512 +
 13.2513 +\subsubsection*{Synopsis}
 13.2514 +
 13.2515 +\begin{verbatim}
 13.2516 +double glp_ipt_obj_val(glp_prob *lp);
 13.2517 +\end{verbatim}
 13.2518 +
 13.2519 +\subsubsection*{Returns}
 13.2520 +
 13.2521 +The routine \verb|glp_ipt_obj_val| returns value of the objective
 13.2522 +function for interior-point solution.
 13.2523 +
 13.2524 +\subsection{glp\_ipt\_row\_prim---retrieve row primal value}
 13.2525 +
 13.2526 +\subsubsection*{Synopsis}
 13.2527 +
 13.2528 +\begin{verbatim}
 13.2529 +double glp_ipt_row_prim(glp_prob *lp, int i);
 13.2530 +\end{verbatim}
 13.2531 +
 13.2532 +\subsubsection*{Returns}
 13.2533 +
 13.2534 +The routine \verb|glp_ipt_row_prim| returns primal value of the
 13.2535 +auxiliary variable associated with \verb|i|-th row.
 13.2536 +
 13.2537 +\newpage
 13.2538 +
 13.2539 +\subsection{glp\_ipt\_row\_dual---retrieve row dual value}
 13.2540 +
 13.2541 +\subsubsection*{Synopsis}
 13.2542 +
 13.2543 +\begin{verbatim}
 13.2544 +double glp_ipt_row_dual(glp_prob *lp, int i);
 13.2545 +\end{verbatim}
 13.2546 +
 13.2547 +\subsubsection*{Returns}
 13.2548 +
 13.2549 +The routine \verb|glp_ipt_row_dual| returns dual value (i.e. reduced
 13.2550 +cost) of the auxiliary variable associated with \verb|i|-th row.
 13.2551 +
 13.2552 +\subsection{glp\_ipt\_col\_prim---retrieve column primal value}
 13.2553 +
 13.2554 +\subsubsection*{Synopsis}
 13.2555 +
 13.2556 +\begin{verbatim}
 13.2557 +double glp_ipt_col_prim(glp_prob *lp, int j);
 13.2558 +\end{verbatim}
 13.2559 +
 13.2560 +\subsubsection*{Returns}
 13.2561 +
 13.2562 +The routine \verb|glp_ipt_col_prim| returns primal value of the
 13.2563 +structural variable associated with \verb|j|-th column.
 13.2564 +
 13.2565 +\subsection{glp\_ipt\_col\_dual---retrieve column dual value}
 13.2566 +
 13.2567 +\subsubsection*{Synopsis}
 13.2568 +
 13.2569 +\begin{verbatim}
 13.2570 +double glp_ipt_col_dual(glp_prob *lp, int j);
 13.2571 +\end{verbatim}
 13.2572 +
 13.2573 +\subsubsection*{Returns}
 13.2574 +
 13.2575 +The routine \verb|glp_ipt_col_dual| returns dual value (i.e. reduced
 13.2576 +cost) of the structural variable associated with \verb|j|-th column.
 13.2577 +
 13.2578 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 13.2579 +
 13.2580 +\newpage
 13.2581 +
 13.2582 +\section{Mixed integer programming routines}
 13.2583 +
 13.2584 +\subsection{glp\_set\_col\_kind---set (change) column kind}
 13.2585 +
 13.2586 +\subsubsection*{Synopsis}
 13.2587 +
 13.2588 +\begin{verbatim}
 13.2589 +void glp_set_col_kind(glp_prob *mip, int j, int kind);
 13.2590 +\end{verbatim}
 13.2591 +
 13.2592 +\subsubsection*{Description}
 13.2593 +
 13.2594 +The routine \verb|glp_set_col_kind| sets (changes) the kind of
 13.2595 +\verb|j|-th column (structural variable) as specified by the parameter
 13.2596 +\verb|kind|:
 13.2597 +
 13.2598 +\begin{tabular}{@{}ll}
 13.2599 +\verb|GLP_CV| & continuous variable; \\
 13.2600 +\verb|GLP_IV| & integer variable; \\
 13.2601 +\verb|GLP_BV| & binary variable. \\
 13.2602 +\end{tabular}
 13.2603 +
 13.2604 +%If a column is set to \verb|GLP_IV|, its bounds must be exact integer
 13.2605 +%numbers with no tolerance, such that the condition
 13.2606 +%\verb|bnd == floor(bnd)| would hold.
 13.2607 +
 13.2608 +Setting a column to \verb|GLP_BV| has the same effect as if it were
 13.2609 +set to \verb|GLP_IV|, its lower bound were set 0, and its upper bound
 13.2610 +were set to 1.
 13.2611 +
 13.2612 +\subsection{glp\_get\_col\_kind---retrieve column kind}
 13.2613 +
 13.2614 +\subsubsection*{Synopsis}
 13.2615 +
 13.2616 +\begin{verbatim}
 13.2617 +int glp_get_col_kind(glp_prob *mip, int j);
 13.2618 +\end{verbatim}
 13.2619 +
 13.2620 +\subsubsection*{Returns}
 13.2621 +
 13.2622 +The routine \verb|glp_get_col_kind| returns the kind of \verb|j|-th
 13.2623 +column (structural variable) as follows:
 13.2624 +
 13.2625 +\begin{tabular}{@{}ll}
 13.2626 +\verb|GLP_CV| & continuous variable; \\
 13.2627 +\verb|GLP_IV| & integer variable; \\
 13.2628 +\verb|GLP_BV| & binary variable. \\
 13.2629 +\end{tabular}
 13.2630 +
 13.2631 +\subsection{glp\_get\_num\_int---retrieve number of integer columns}
 13.2632 +
 13.2633 +\subsubsection*{Synopsis}
 13.2634 +
 13.2635 +\begin{verbatim}
 13.2636 +int glp_get_num_int(glp_prob *mip);
 13.2637 +\end{verbatim}
 13.2638 +
 13.2639 +\subsubsection*{Returns}
 13.2640 +
 13.2641 +The routine \verb|glp_get_num_int| returns the number of columns
 13.2642 +(structural variables), which are marked as integer. Note that this
 13.2643 +number {\it does} include binary columns.
 13.2644 +
 13.2645 +\subsection{glp\_get\_num\_bin---retrieve number of binary columns}
 13.2646 +
 13.2647 +\subsubsection*{Synopsis}
 13.2648 +
 13.2649 +\begin{verbatim}
 13.2650 +int glp_get_num_bin(glp_prob *mip);
 13.2651 +\end{verbatim}
 13.2652 +
 13.2653 +\subsubsection*{Returns}
 13.2654 +
 13.2655 +The routine \verb|glp_get_num_bin| returns the number of columns
 13.2656 +(structural variables), which are marked as integer and whose lower
 13.2657 +bound is zero and upper bound is one.
 13.2658 +
 13.2659 +\subsection{glp\_intopt---solve MIP problem with the branch-and-cut
 13.2660 +method}
 13.2661 +
 13.2662 +\subsubsection*{Synopsis}
 13.2663 +
 13.2664 +\begin{verbatim}
 13.2665 +int glp_intopt(glp_prob *mip, const glp_iocp *parm);
 13.2666 +\end{verbatim}
 13.2667 +
 13.2668 +\subsubsection*{Description}
 13.2669 +
 13.2670 +The routine \verb|glp_intopt| is a driver to the MIP solver based on
 13.2671 +the branch-and-cut method, which is a hybrid of branch-and-bound and
 13.2672 +cutting plane methods.
 13.2673 +
 13.2674 +If the presolver is disabled (see paragraph ``Control parameters''
 13.2675 +below), on entry to the routine \verb|glp_intopt| the problem object,
 13.2676 +which the parameter \verb|mip| points to, should contain optimal
 13.2677 +solution to LP relaxation (it can be obtained, for example, with the
 13.2678 +routine \verb|glp_simplex|). Otherwise, if the presolver is enabled, it
 13.2679 +is not necessary.
 13.2680 +
 13.2681 +The MIP solver has a set of control parameters. Values of the control
 13.2682 +parameters can be passed in the structure \verb|glp_iocp|, which the
 13.2683 +parameter \verb|parm| points to. For detailed description of this
 13.2684 +structure see paragraph ``Control parameters'' below. Before specifying
 13.2685 +some control parameters the application program should initialize the
 13.2686 +structure \verb|glp_iocp| by default values of all control parameters
 13.2687 +using the routine \verb|glp_init_iocp| (see the next subsection). This
 13.2688 +is needed for backward compatibility, because in the future there may
 13.2689 +appear new members in the structure \verb|glp_iocp|.
 13.2690 +
 13.2691 +The parameter \verb|parm| can be specified as \verb|NULL|, in which case
 13.2692 +the solver uses default settings.
 13.2693 +
 13.2694 +Note that the GLPK branch-and-cut solver is not perfect, so it is unable
 13.2695 +to solve hard or very large scale MIP instances for a reasonable time.
 13.2696 +
 13.2697 +\subsubsection*{Returns}
 13.2698 +
 13.2699 +\def\arraystretch{1}
 13.2700 +
 13.2701 +\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
 13.2702 +0 & The MIP problem instance has been successfully solved. (This code
 13.2703 +does {\it not} necessarily mean that the solver has found optimal
 13.2704 +solution. It only means that the solution process was successful.) \\
 13.2705 +\verb|GLP_EBOUND| & Unable to start the search, because some
 13.2706 +double-bounded variables have incorrect bounds or some integer variables
 13.2707 +have non-integer (fractional) bounds.\\
 13.2708 +\verb|GLP_EROOT| & Unable to start the search, because optimal basis for
 13.2709 +initial LP relaxation is not provided. (This code may appear only if the
 13.2710 +presolver is disabled.)\\
 13.2711 +\verb|GLP_ENOPFS| & Unable to start the search, because LP relaxation
 13.2712 +of the MIP problem instance has no primal feasible solution. (This code
 13.2713 +may appear only if the presolver is enabled.)\\
 13.2714 +\verb|GLP_ENODFS| & Unable to start the search, because LP relaxation
 13.2715 +of the MIP problem instance has no dual feasible solution. In other
 13.2716 +word, this code means that if the LP relaxation has at least one primal
 13.2717 +feasible solution, its optimal solution is unbounded, so if the MIP
 13.2718 +problem has at least one integer feasible solution, its (integer)
 13.2719 +optimal solution is also unbounded. (This code may appear only if the
 13.2720 +presolver is enabled.)\\
 13.2721 +\verb|GLP_EFAIL| & The search was prematurely terminated due to the
 13.2722 +solver failure.\\
 13.2723 +\verb|GLP_EMIPGAP| & The search was prematurely terminated, because the
 13.2724 +relative mip gap tolerance has been reached.\\
 13.2725 +\verb|GLP_ETMLIM| & The search was prematurely terminated, because the
 13.2726 +time limit has been exceeded.\\
 13.2727 +\verb|GLP_ESTOP| & The search was prematurely terminated by application.
 13.2728 +(This code may appear only if the advanced solver interface is used.)\\
 13.2729 +\end{tabular}
 13.2730 +
 13.2731 +\subsubsection*{Built-in MIP presolver}
 13.2732 +
 13.2733 +The branch-and-cut solver has {\it built-in MIP presolver}. It is
 13.2734 +a subprogram that transforms the original MIP problem specified in the
 13.2735 +problem object to an equivalent MIP problem, which may be easier for
 13.2736 +solving with the branch-and-cut method than the original one. For
 13.2737 +example, the presolver can remove redundant constraints and variables,
 13.2738 +whose optimal values are known, perform bound and coefficient reduction,
 13.2739 +etc. Once the transformed MIP problem has been solved, the presolver
 13.2740 +transforms its solution back to corresponding solution of the original
 13.2741 +problem.
 13.2742 +
 13.2743 +Presolving is an optional feature of the routine \verb|glp_intopt|, and
 13.2744 +by default it is disabled. In order to enable the MIP presolver, the
 13.2745 +control parameter \verb|presolve| should be set to \verb|GLP_ON| (see
 13.2746 +paragraph ``Control parameters'' below).
 13.2747 +
 13.2748 +\subsubsection*{Advanced solver interface}
 13.2749 +
 13.2750 +The routine \verb|glp_intopt| allows the user to control the
 13.2751 +branch-and-cut search by passing to the solver a user-defined callback
 13.2752 +routine. For more details see Chapter ``Branch-and-Cut API Routines''.
 13.2753 +
 13.2754 +\subsubsection*{Terminal output}
 13.2755 +
 13.2756 +Solving a MIP problem may take a long time, so the solver reports some
 13.2757 +information about best known solutions, which is sent to the terminal.
 13.2758 +This information has the following format:
 13.2759 +
 13.2760 +\begin{verbatim}
 13.2761 ++nnn: mip = xxx <rho> yyy gap (ppp; qqq)
 13.2762 +\end{verbatim}
 13.2763 +
 13.2764 +\noindent
 13.2765 +where: `\verb|nnn|' is the simplex iteration number; `\verb|xxx|' is a
 13.2766 +value of the objective function for the best known integer feasible
 13.2767 +solution (if no integer feasible solution has been found yet,
 13.2768 +`\verb|xxx|' is the text `\verb|not found yet|'); `\verb|rho|' is the
 13.2769 +string `\verb|>=|' (in case of minimization) or `\verb|<=|' (in case of
 13.2770 +maximization); `\verb|yyy|' is a global bound for exact integer optimum
 13.2771 +(i.e. the exact integer optimum is always in the range from `\verb|xxx|'
 13.2772 +to `\verb|yyy|'); `\verb|gap|' is the relative mip gap, in percents,
 13.2773 +computed as $gap=|xxx-yyy|/(|xxx|+{\tt DBL\_EPSILON})\cdot 100\%$ (if
 13.2774 +$gap$ is greater than $999.9\%$, it is not printed); `\verb|ppp|' is the
 13.2775 +number of subproblems in the active list, `\verb|qqq|' is the number of
 13.2776 +subproblems which have been already fathomed and therefore removed from
 13.2777 +the branch-and-bound search tree.
 13.2778 +
 13.2779 +\subsubsection{Control parameters}
 13.2780 +
 13.2781 +This paragraph describes all control parameters currently used in the
 13.2782 +MIP solver. Symbolic names of control parameters are names of
 13.2783 +corresponding members in the structure \verb|glp_iocp|.
 13.2784 +
 13.2785 +\medskip
 13.2786 +
 13.2787 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.2788 +\multicolumn{2}{@{}l}{{\tt int msg\_lev} (default: {\tt GLP\_MSG\_ALL})}
 13.2789 +\\
 13.2790 +&Message level for terminal output:\\
 13.2791 +&\verb|GLP_MSG_OFF|---no output;\\
 13.2792 +&\verb|GLP_MSG_ERR|---error and warning messages only;\\
 13.2793 +&\verb|GLP_MSG_ON |---normal output;\\
 13.2794 +&\verb|GLP_MSG_ALL|---full output (including informational messages).
 13.2795 +\\
 13.2796 +\end{tabular}
 13.2797 +
 13.2798 +\medskip
 13.2799 +
 13.2800 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.2801 +\multicolumn{2}{@{}l}{{\tt int br\_tech} (default: {\tt GLP\_BR\_DTH})}
 13.2802 +\\
 13.2803 +&Branching technique option:\\
 13.2804 +&\verb|GLP_BR_FFV|---first fractional variable;\\
 13.2805 +&\verb|GLP_BR_LFV|---last fractional variable;\\
 13.2806 +&\verb|GLP_BR_MFV|---most fractional variable;\\
 13.2807 +&\verb|GLP_BR_DTH|---heuristic by Driebeck and Tomlin;\\
 13.2808 +&\verb|GLP_BR_PCH|---hybrid pseudocost heuristic.\\
 13.2809 +\end{tabular}
 13.2810 +
 13.2811 +\medskip
 13.2812 +
 13.2813 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.2814 +\multicolumn{2}{@{}l}{{\tt int bt\_tech} (default: {\tt GLP\_BT\_BLB})}
 13.2815 +\\
 13.2816 +&Backtracking technique option:\\
 13.2817 +&\verb|GLP_BT_DFS|---depth first search;\\
 13.2818 +&\verb|GLP_BT_BFS|---breadth first search;\\
 13.2819 +&\verb|GLP_BT_BLB|---best local bound;\\
 13.2820 +&\verb|GLP_BT_BPH|---best projection heuristic.\\
 13.2821 +\end{tabular}
 13.2822 +
 13.2823 +\medskip
 13.2824 +
 13.2825 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.2826 +\multicolumn{2}{@{}l}{{\tt int pp\_tech} (default: {\tt GLP\_PP\_ALL})}
 13.2827 +\\
 13.2828 +&Preprocessing technique option:\\
 13.2829 +&\verb|GLP_PP_NONE|---disable preprocessing;\\
 13.2830 +&\verb|GLP_PP_ROOT|---perform preprocessing only on the root level;\\
 13.2831 +&\verb|GLP_PP_ALL |---perform preprocessing on all levels.\\
 13.2832 +\end{tabular}
 13.2833 +
 13.2834 +\medskip
 13.2835 +
 13.2836 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.2837 +\multicolumn{2}{@{}l}{{\tt int fp\_heur} (default: {\tt GLP\_OFF})}
 13.2838 +\\
 13.2839 +&Feasibility pump heuristic option:\\
 13.2840 +&\verb|GLP_ON |---enable applying the feasibility pump heuristic;\\
 13.2841 +&\verb|GLP_OFF|---disable applying the feasibility pump heuristic.\\
 13.2842 +\end{tabular}
 13.2843 +
 13.2844 +\medskip
 13.2845 +
 13.2846 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.2847 +\multicolumn{2}{@{}l}{{\tt int gmi\_cuts} (default: {\tt GLP\_OFF})}\\
 13.2848 +&Gomory's mixed integer cut option:\\
 13.2849 +&\verb|GLP_ON |---enable generating Gomory's cuts;\\
 13.2850 +&\verb|GLP_OFF|---disable generating Gomory's cuts.\\
 13.2851 +\end{tabular}
 13.2852 +
 13.2853 +\medskip
 13.2854 +
 13.2855 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.2856 +\multicolumn{2}{@{}l}{{\tt int mir\_cuts} (default: {\tt GLP\_OFF})}\\
 13.2857 +&Mixed integer rounding (MIR) cut option:\\
 13.2858 +&\verb|GLP_ON |---enable generating MIR cuts;\\
 13.2859 +&\verb|GLP_OFF|---disable generating MIR cuts.\\
 13.2860 +\end{tabular}
 13.2861 +
 13.2862 +\medskip
 13.2863 +
 13.2864 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.2865 +\multicolumn{2}{@{}l}{{\tt int cov\_cuts} (default: {\tt GLP\_OFF})}\\
 13.2866 +&Mixed cover cut option:\\
 13.2867 +&\verb|GLP_ON |---enable generating mixed cover cuts;\\
 13.2868 +&\verb|GLP_OFF|---disable generating mixed cover cuts.\\
 13.2869 +\end{tabular}
 13.2870 +
 13.2871 +\medskip
 13.2872 +
 13.2873 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.2874 +\multicolumn{2}{@{}l}{{\tt int clq\_cuts} (default: {\tt GLP\_OFF})}\\
 13.2875 +&Clique cut option:\\
 13.2876 +&\verb|GLP_ON |---enable generating clique cuts;\\
 13.2877 +&\verb|GLP_OFF|---disable generating clique cuts.\\
 13.2878 +\end{tabular}
 13.2879 +
 13.2880 +\medskip
 13.2881 +
 13.2882 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.2883 +\multicolumn{2}{@{}l}{{\tt double tol\_int} (default: {\tt 1e-5})}\\
 13.2884 +&Absolute tolerance used to check if optimal solution to the current LP
 13.2885 +relaxation is integer feasible. (Do not change this parameter without
 13.2886 +detailed understanding its purpose.)\\
 13.2887 +\end{tabular}
 13.2888 +
 13.2889 +\medskip
 13.2890 +
 13.2891 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.2892 +\multicolumn{2}{@{}l}{{\tt double tol\_obj} (default: {\tt 1e-7})}\\
 13.2893 +&Relative tolerance used to check if the objective value in optimal
 13.2894 +solution to the current LP relaxation is not better than in the best
 13.2895 +known integer feasible solution. (Do not change this parameter without
 13.2896 +detailed understanding its purpose.)\\
 13.2897 +\end{tabular}
 13.2898 +
 13.2899 +\medskip
 13.2900 +
 13.2901 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.2902 +\multicolumn{2}{@{}l}{{\tt double mip\_gap} (default: {\tt 0.0})}\\
 13.2903 +&The relative mip gap tolerance. If the relative mip gap for currently
 13.2904 +known best integer feasible solution falls below this tolerance, the
 13.2905 +solver terminates the search. This allows obtainig suboptimal integer
 13.2906 +feasible solutions if solving the problem to optimality takes too long
 13.2907 +time.\\
 13.2908 +\end{tabular}
 13.2909 +
 13.2910 +\medskip
 13.2911 +
 13.2912 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.2913 +\multicolumn{2}{@{}l}{{\tt int tm\_lim} (default: {\tt INT\_MAX})}\\
 13.2914 +&Searching time limit, in milliseconds.\\
 13.2915 +\end{tabular}
 13.2916 +
 13.2917 +\medskip
 13.2918 +
 13.2919 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.2920 +\multicolumn{2}{@{}l}{{\tt int out\_frq} (default: {\tt 5000})}\\
 13.2921 +&Output frequency, in milliseconds. This parameter specifies how
 13.2922 +frequently the solver sends information about the solution process to
 13.2923 +the terminal.\\
 13.2924 +\end{tabular}
 13.2925 +
 13.2926 +\medskip
 13.2927 +
 13.2928 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.2929 +\multicolumn{2}{@{}l}{{\tt int out\_dly} (default: {\tt 10000})}\\
 13.2930 +&Output delay, in milliseconds. This parameter specifies how long the
 13.2931 +solver should delay sending information about solution of the current
 13.2932 +LP relaxation with the simplex method to the terminal.\\
 13.2933 +\end{tabular}
 13.2934 +
 13.2935 +\medskip
 13.2936 +
 13.2937 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.2938 +\multicolumn{2}{@{}l}
 13.2939 +{{\tt void (*cb\_func)(glp\_tree *tree, void *info)}
 13.2940 +(default: {\tt NULL})}\\
 13.2941 +&Entry point to the user-defined callback routine. \verb|NULL| means
 13.2942 +the advanced solver interface is not used. For more details see Chapter
 13.2943 +``Branch-and-Cut API Routines''.\\
 13.2944 +\end{tabular}
 13.2945 +
 13.2946 +\medskip
 13.2947 +
 13.2948 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.2949 +\multicolumn{2}{@{}l}{{\tt void *cb\_info} (default: {\tt NULL})}\\
 13.2950 +&Transit pointer passed to the routine \verb|cb_func| (see above).\\
 13.2951 +\end{tabular}
 13.2952 +
 13.2953 +\medskip
 13.2954 +
 13.2955 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.2956 +\multicolumn{2}{@{}l}{{\tt int cb\_size} (default: {\tt 0})}\\
 13.2957 +&The number of extra (up to 256) bytes allocated for each node of the
 13.2958 +branch-and-bound tree to store application-specific data. On creating
 13.2959 +a node these bytes are initialized by binary zeros.\\
 13.2960 +\end{tabular}
 13.2961 +
 13.2962 +\medskip
 13.2963 +
 13.2964 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.2965 +\multicolumn{2}{@{}l}{{\tt int presolve} (default: {\tt GLP\_OFF})}\\
 13.2966 +&MIP presolver option:\\
 13.2967 +&\verb|GLP_ON |---enable using the MIP presolver;\\
 13.2968 +&\verb|GLP_OFF|---disable using the MIP presolver.\\
 13.2969 +\end{tabular}
 13.2970 +
 13.2971 +\medskip
 13.2972 +
 13.2973 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
 13.2974 +\multicolumn{2}{@{}l}{{\tt int binarize} (default: {\tt GLP\_OFF})}\\
 13.2975 +&Binarization option (used only if the presolver is enabled):\\
 13.2976 +&\verb|GLP_ON |---replace general integer variables by binary ones;\\
 13.2977 +&\verb|GLP_OFF|---do not use binarization.\\
 13.2978 +\end{tabular}
 13.2979 +
 13.2980 +\subsection{glp\_init\_iocp---initialize integer optimizer control
 13.2981 +parameters}
 13.2982 +
 13.2983 +\subsubsection*{Synopsis}
 13.2984 +
 13.2985 +\begin{verbatim}
 13.2986 +void glp_init_iocp(glp_iocp *parm);
 13.2987 +\end{verbatim}
 13.2988 +
 13.2989 +\subsubsection*{Description}
 13.2990 +
 13.2991 +The routine \verb|glp_init_iocp| initializes control parameters, which
 13.2992 +are used by the branch-and-cut solver, with default values.
 13.2993 +
 13.2994 +Default values of the control parameters are stored in a \verb|glp_iocp|
 13.2995 +structure, which the parameter \verb|parm| points to.
 13.2996 +
 13.2997 +\subsection{glp\_mip\_status---determine status of MIP solution}
 13.2998 +
 13.2999 +\subsubsection*{Synopsis}
 13.3000 +
 13.3001 +\begin{verbatim}
 13.3002 +int glp_mip_status(glp_prob *mip);
 13.3003 +\end{verbatim}
 13.3004 +
 13.3005 +\subsubsection*{Returns}
 13.3006 +
 13.3007 +The routine \verb|glp_mip_status| reports the status of a MIP solution
 13.3008 +found by the MIP solver as follows:
 13.3009 +
 13.3010 +\smallskip
 13.3011 +
 13.3012 +\begin{tabular}{@{}p{25mm}p{91.3mm}@{}}
 13.3013 +\verb|GLP_UNDEF| & MIP solution is undefined. \\
 13.3014 +\verb|GLP_OPT|   & MIP solution is integer optimal. \\
 13.3015 +\verb|GLP_FEAS|  & MIP solution is integer feasible, however, its
 13.3016 +   optimality (or non-optimality) has not been proven, perhaps due to
 13.3017 +   premature termination of the search. \\
 13.3018 +\end{tabular}
 13.3019 +
 13.3020 +\begin{tabular}{@{}p{25mm}p{91.3mm}@{}}
 13.3021 +\verb|GLP_NOFEAS| & problem has no integer feasible solution (proven by
 13.3022 +   the solver). \\
 13.3023 +\end{tabular}
 13.3024 +
 13.3025 +\subsection{glp\_mip\_obj\_val---retrieve objective value}
 13.3026 +
 13.3027 +\subsubsection*{Synopsis}
 13.3028 +
 13.3029 +\begin{verbatim}
 13.3030 +double glp_mip_obj_val(glp_prob *mip);
 13.3031 +\end{verbatim}
 13.3032 +
 13.3033 +\subsubsection*{Returns}
 13.3034 +
 13.3035 +The routine \verb|glp_mip_obj_val| returns value of the objective
 13.3036 +function for MIP solution.
 13.3037 +
 13.3038 +\subsection{glp\_mip\_row\_val---retrieve row value}
 13.3039 +
 13.3040 +\subsubsection*{Synopsis}
 13.3041 +
 13.3042 +\begin{verbatim}
 13.3043 +double glp_mip_row_val(glp_prob *mip, int i);
 13.3044 +\end{verbatim}
 13.3045 +
 13.3046 +\subsubsection*{Returns}
 13.3047 +
 13.3048 +The routine \verb|glp_mip_row_val| returns value of the auxiliary
 13.3049 +variable associated with \verb|i|-th row for MIP solution.
 13.3050 +
 13.3051 +\subsection{glp\_mip\_col\_val---retrieve column value}
 13.3052 +
 13.3053 +\subsubsection*{Synopsis}
 13.3054 +
 13.3055 +\begin{verbatim}
 13.3056 +double glp_mip_col_val(glp_prob *mip, int j);
 13.3057 +\end{verbatim}
 13.3058 +
 13.3059 +\subsubsection*{Returns}
 13.3060 +
 13.3061 +The routine \verb|glp_mip_col_val| returns value of the structural
 13.3062 +variable associated with \verb|j|-th column for MIP solution.
 13.3063 +
 13.3064 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 13.3065 +
 13.3066 +\newpage
 13.3067 +
 13.3068 +\section{Additional routines}
 13.3069 +
 13.3070 +\subsection{lpx\_check\_kkt---check Karush-Kuhn-Tucker optimality
 13.3071 +conditions}
 13.3072 +
 13.3073 +\subsubsection*{Synopsis}
 13.3074 +
 13.3075 +\begin{verbatim}
 13.3076 +void lpx_check_kkt(glp_prob *lp, int scaled, LPXKKT *kkt);
 13.3077 +\end{verbatim}
 13.3078 +
 13.3079 +\subsubsection*{Description}
 13.3080 +
 13.3081 +The routine \verb|lpx_check_kkt| checks Karush-Kuhn-Tucker optimality
 13.3082 +conditions for basic solution. It is assumed that both primal and dual
 13.3083 +components of basic solution are valid.
 13.3084 +
 13.3085 +If the parameter \verb|scaled| is zero, the optimality conditions are
 13.3086 +checked for the original, unscaled LP problem. Otherwise, if the
 13.3087 +parameter \verb|scaled| is non-zero, the routine checks the conditions
 13.3088 +for an internally scaled LP problem.
 13.3089 +
 13.3090 +The parameter \verb|kkt| is a pointer to the structure \verb|LPXKKT|,
 13.3091 +to which the routine stores results of the check. Members of this
 13.3092 +structure are shown in the table below.
 13.3093 +
 13.3094 +\begin{table}[h]
 13.3095 +\begin{center}
 13.3096 +\begin{tabular}{@{}c|l|l@{}}
 13.3097 +Condition & Member & Comment \\
 13.3098 +\hline
 13.3099 +(KKT.PE) & \verb|pe_ae_max| &
 13.3100 +         Largest absolute error \\
 13.3101 +         & \verb|pe_ae_row| &
 13.3102 +         Number of row with largest absolute error \\
 13.3103 +         & \verb|pe_re_max| &
 13.3104 +         Largest relative error \\
 13.3105 +         & \verb|pe_re_row| &
 13.3106 +         Number of row with largest relative error \\
 13.3107 +         & \verb|pe_quality| &
 13.3108 +         Quality of primal solution \\
 13.3109 +\hline
 13.3110 +(KKT.PB) & \verb|pb_ae_max| &
 13.3111 +         Largest absolute error \\
 13.3112 +         & \verb|pb_ae_ind| &
 13.3113 +         Number of variable with largest absolute error \\
 13.3114 +         & \verb|pb_re_max| &
 13.3115 +         Largest relative error \\
 13.3116 +         & \verb|pb_re_ind| &
 13.3117 +         Number of variable with largest relative error \\
 13.3118 +         & \verb|pb_quality| &
 13.3119 +         Quality of primal feasibility \\
 13.3120 +\hline
 13.3121 +(KKT.DE) & \verb|de_ae_max| &
 13.3122 +         Largest absolute error \\
 13.3123 +         & \verb|de_ae_col| &
 13.3124 +         Number of column with largest absolute error \\
 13.3125 +         & \verb|de_re_max| &
 13.3126 +         Largest relative error \\
 13.3127 +         & \verb|de_re_col| &
 13.3128 +         Number of column with largest relative error \\
 13.3129 +         & \verb|de_quality| &
 13.3130 +         Quality of dual solution \\
 13.3131 +\hline
 13.3132 +(KKT.DB) & \verb|db_ae_max| &
 13.3133 +         Largest absolute error \\
 13.3134 +         & \verb|db_ae_ind| &
 13.3135 +         Number of variable with largest absolute error \\
 13.3136 +         & \verb|db_re_max| &
 13.3137 +         Largest relative error \\
 13.3138 +         & \verb|db_re_ind| &
 13.3139 +         Number of variable with largest relative error \\
 13.3140 +         & \verb|db_quality| &
 13.3141 +         Quality of dual feasibility \\
 13.3142 +\end{tabular}
 13.3143 +\end{center}
 13.3144 +\end{table}
 13.3145 +
 13.3146 +The routine performs all computations using only components of the
 13.3147 +given LP problem and the current basic solution.
 13.3148 +
 13.3149 +\subsubsection*{Background}
 13.3150 +
 13.3151 +The first condition checked by the routine is:
 13.3152 +$$x_R - A x_S = 0, \eqno{\rm (KKT.PE)}$$
 13.3153 +where $x_R$ is the subvector of auxiliary variables (rows), $x_S$ is the
 13.3154 +subvector of structural variables (columns), $A$ is the constraint
 13.3155 +matrix. This condition expresses the requirement that all primal
 13.3156 +variables must satisfy to the system of equality constraints of the
 13.3157 +original LP problem. In case of exact arithmetic this condition would be
 13.3158 +satisfied for any basic solution; however, in case of inexact
 13.3159 +(floating-point) arithmetic, this condition shows how accurate the
 13.3160 +primal basic solution is, that depends on accuracy of a representation
 13.3161 +of the basis matrix used by the simplex method routines.
 13.3162 +
 13.3163 +The second condition checked by the routine is:
 13.3164 +$$l_k \leq x_k \leq u_k {\rm \ \ \ for\ all}\ k=1,\dots,m+n,
 13.3165 +\eqno{\rm (KKT.PB)}$$
 13.3166 +where $x_k$ is auxiliary ($1\leq k\leq m$) or structural
 13.3167 +($m+1\leq k\leq m+n$) variable, $l_k$ and $u_k$ are, respectively,
 13.3168 +lower and upper bounds of the variable $x_k$ (including cases of
 13.3169 +infinite bounds). This condition expresses the requirement that all
 13.3170 +primal variables must satisfy to bound constraints of the original LP
 13.3171 +problem. Since in case of basic solution all non-basic variables are
 13.3172 +placed on their bounds, actually the condition (KKT.PB) needs to be
 13.3173 +checked for basic variables only. If the primal basic solution has
 13.3174 +sufficient accuracy, this condition shows primal feasibility of the
 13.3175 +solution.
 13.3176 +
 13.3177 +The third condition checked by the routine is:
 13.3178 +$${\rm grad}\;Z = c = (\tilde{A})^T \pi + d,$$
 13.3179 +where $Z$ is the objective function, $c$ is the vector of objective
 13.3180 +coefficients, $(\tilde{A})^T$ is a matrix transposed to the expanded
 13.3181 +constraint matrix $\tilde{A} = (I|-A)$, $\pi$ is a vector of Lagrange
 13.3182 +multipliers that correspond to equality constraints of the original LP
 13.3183 +problem, $d$ is a vector of Lagrange multipliers that correspond to
 13.3184 +bound constraints for all (auxiliary and structural) variables of the
 13.3185 +original LP problem. Geometrically the third condition expresses the
 13.3186 +requirement that the gradient of the objective function must belong to
 13.3187 +the orthogonal complement of a linear subspace defined by the equality
 13.3188 +and active bound constraints, i.e. that the gradient must be a linear
 13.3189 +combination of normals to the constraint planes, where Lagrange
 13.3190 +multipliers $\pi$ and $d$ are coefficients of that linear combination.
 13.3191 +
 13.3192 +To eliminate the vector $\pi$ the third condition can be rewritten as:
 13.3193 +$$
 13.3194 +\left(\begin{array}{@{}c@{}}I \\ -A^T\end{array}\right) \pi =
 13.3195 +\left(\begin{array}{@{}c@{}}d_R \\ d_S\end{array}\right) +
 13.3196 +\left(\begin{array}{@{}c@{}}c_R \\ c_S\end{array}\right),
 13.3197 +$$
 13.3198 +or, equivalently:
 13.3199 +$$
 13.3200 +\begin{array}{r@{}c@{}c}
 13.3201 +\pi + d_R&\ =\ &c_R, \\
 13.3202 +-A^T\pi + d_S&\ =\ &c_S. \\
 13.3203 +\end{array}
 13.3204 +$$
 13.3205 +Then substituting the vector $\pi$ from the first equation into the
 13.3206 +second one we have:
 13.3207 +$$A^T (d_R - c_R) + (d_S - c_S) = 0, \eqno{\rm (KKT.DE)}$$
 13.3208 +where $d_R$ is the subvector of reduced costs of auxiliary variables
 13.3209 +(rows), $d_S$ is the subvector of reduced costs of structural variables
 13.3210 +(columns), $c_R$ and $c_S$ are subvectors of objective coefficients at,
 13.3211 +respectively, auxiliary and structural variables, $A^T$ is a matrix
 13.3212 +transposed to the constraint matrix of the original LP problem. In case
 13.3213 +of exact arithmetic this condition would be satisfied for any basic
 13.3214 +solution; however, in case of inexact (floating-point) arithmetic, this
 13.3215 +condition shows how accurate the dual basic solution is, that depends on
 13.3216 +accuracy of a representation of the basis matrix used by the simplex
 13.3217 +method routines.
 13.3218 +
 13.3219 +The last, fourth condition checked by the routine is (KKT.DB):
 13.3220 +
 13.3221 +\medskip
 13.3222 +
 13.3223 +\begin{tabular}{r@{}c@{}ll}
 13.3224 +&$\ d_k\ $& $=0,$&if $x_k$ is basic or free non-basic variable \\
 13.3225 +$0\leq$&$\ d_k\ $&$<+\infty$&if $x_k$ is non-basic on its lower
 13.3226 +(minimization) \\
 13.3227 +&&&or upper (maximization) bound \\
 13.3228 +$-\infty<$&$\ d_k\ $&$\leq 0$&if $x_k$ is non-basic on its upper
 13.3229 +(minimization) \\
 13.3230 +&&&or lower (maximization) bound \\
 13.3231 +$-\infty<$&$\ d_k\ $&$<+\infty$&if $x_k$ is non-basic fixed variable \\
 13.3232 +\end{tabular}
 13.3233 +
 13.3234 +\medskip
 13.3235 +
 13.3236 +\noindent
 13.3237 +for all $k=1,\dots,m+n$, where $d_k$ is a reduced cost (Lagrange
 13.3238 +multiplier) of auxiliary ($1\leq k\leq m$) or structural
 13.3239 +($m+1\leq k\leq m+n$) variable $x_k$. Geometrically this condition
 13.3240 +expresses the requirement that constraints of the original problem must
 13.3241 +"hold" the point preventing its movement along the anti-gradient (in
 13.3242 +case of minimization) or the gradient (in case of maximization) of the
 13.3243 +objective function. Since in case of basic solution reduced costs of
 13.3244 +all basic variables are placed on their (zero) bounds, actually the
 13.3245 +condition (KKT.DB) needs to be checked for non-basic variables only.
 13.3246 +If the dual basic solution has sufficient accuracy, this condition shows
 13.3247 +dual feasibility of the solution.
 13.3248 +
 13.3249 +Should note that the complete set of Karush-Kuhn-Tucker optimality
 13.3250 +conditions also includes the fifth, so called complementary slackness
 13.3251 +condition, which expresses the requirement that at least either a primal
 13.3252 +variable $x_k$ or its dual counterpart $d_k$ must be on its bound for
 13.3253 +all $k=1,\dots,m+n$. However, being always satisfied by definition for
 13.3254 +any basic solution that condition is not checked by the routine.
 13.3255 +
 13.3256 +To check the first condition (KKT.PE) the routine computes a vector of
 13.3257 +residuals:
 13.3258 +$$g = x_R - A x_S,$$
 13.3259 +determines component of this vector that correspond to largest absolute
 13.3260 +and relative errors:
 13.3261 +
 13.3262 +\medskip
 13.3263 +
 13.3264 +\hspace{30mm}
 13.3265 +\verb|pe_ae_max| $\displaystyle{= \max_{1\leq i\leq m}|g_i|}$,
 13.3266 +
 13.3267 +\medskip
 13.3268 +
 13.3269 +\hspace{30mm}
 13.3270 +\verb|pe_re_max| $\displaystyle{= \max_{1\leq i\leq m}
 13.3271 +\frac{|g_i|}{1+|(x_R)_i|}}$,
 13.3272 +
 13.3273 +\medskip
 13.3274 +
 13.3275 +\noindent
 13.3276 +and stores these quantities and corresponding row indices to the
 13.3277 +structure \verb|LPXKKT|.
 13.3278 +
 13.3279 +To check the second condition (KKT.PB) the routine computes a vector
 13.3280 +of residuals:
 13.3281 +$$
 13.3282 +h_k = \left\{
 13.3283 +\begin{array}{ll}
 13.3284 +0,         & {\rm if}\ l_k \leq x_k \leq u_k \\
 13.3285 +x_k - l_k, & {\rm if}\ x_k < l_k \\
 13.3286 +x_k - u_k, & {\rm if}\ x_k > u_k \\
 13.3287 +\end{array}
 13.3288 +\right.
 13.3289 +$$
 13.3290 +for all $k=1,\dots,m+n$, determines components of this vector that
 13.3291 +correspond to largest absolute and relative errors:
 13.3292 +
 13.3293 +\medskip
 13.3294 +
 13.3295 +\hspace{30mm}
 13.3296 +\verb|pb_ae_max| $\displaystyle{= \max_{1\leq k \leq m+n}|h_k|}$,
 13.3297 +
 13.3298 +\medskip
 13.3299 +
 13.3300 +\hspace{30mm}
 13.3301 +\verb|pb_re_max| $\displaystyle{= \max_{1\leq k \leq m+n}
 13.3302 +\frac{|h_k|}{1+|x_k|}}$,
 13.3303 +
 13.3304 +\medskip
 13.3305 +
 13.3306 +\noindent
 13.3307 +and stores these quantities and corresponding variable indices to the
 13.3308 +structure \verb|LPXKKT|.
 13.3309 +
 13.3310 +To check the third condition (KKT.DE) the routine computes a vector of
 13.3311 +residuals:
 13.3312 +$$u = A^T (d_R - c_R) + (d_S - c_S),$$
 13.3313 +determines components of this vector that correspond to largest
 13.3314 +absolute and relative errors:
 13.3315 +
 13.3316 +\medskip
 13.3317 +
 13.3318 +\hspace{30mm}
 13.3319 +\verb|de_ae_max| $\displaystyle{= \max_{1\leq j\leq n}|u_j|}$,
 13.3320 +
 13.3321 +\medskip
 13.3322 +
 13.3323 +\hspace{30mm}
 13.3324 +\verb|de_re_max| $\displaystyle{= \max_{1\leq j\leq n}
 13.3325 +\frac{|u_j|}{1+|(d_S)_j - (c_S)_j|}}$,
 13.3326 +
 13.3327 +\medskip
 13.3328 +
 13.3329 +\noindent
 13.3330 +and stores these quantities and corresponding column indices to the
 13.3331 +structure \verb|LPXKKT|.
 13.3332 +
 13.3333 +To check the fourth condition (KKT.DB) the routine computes a vector
 13.3334 +of residuals:
 13.3335 +
 13.3336 +$$
 13.3337 +v_k = \left\{
 13.3338 +\begin{array}{ll}
 13.3339 +0,         & {\rm if}\ d_k\ {\rm has\ correct\ sign} \\
 13.3340 +d_k,       & {\rm if}\ d_k\ {\rm has\ wrong\ sign} \\
 13.3341 +\end{array}
 13.3342 +\right.
 13.3343 +$$
 13.3344 +for all $k=1,\dots,m+n$, determines components of this vector that
 13.3345 +correspond to largest absolute and relative errors:
 13.3346 +
 13.3347 +\medskip
 13.3348 +
 13.3349 +\hspace{30mm}
 13.3350 +\verb|db_ae_max| $\displaystyle{= \max_{1\leq k\leq m+n}|v_k|}$,
 13.3351 +
 13.3352 +\medskip
 13.3353 +
 13.3354 +\hspace{30mm}
 13.3355 +\verb|db_re_max| $\displaystyle{= \max_{1\leq k\leq m+n}
 13.3356 +\frac{|v_k|}{1+|d_k - c_k|}}$,
 13.3357 +
 13.3358 +\medskip
 13.3359 +
 13.3360 +\noindent
 13.3361 +and stores these quantities and corresponding variable indices to the
 13.3362 +structure \verb|LPXKKT|.
 13.3363 +
 13.3364 +Using the relative errors for all the four conditions listed above the
 13.3365 +routine
 13.3366 +\verb|lpx_check_kkt| also estimates a "quality" of the basic solution
 13.3367 +from the standpoint of these conditions and stores corresponding
 13.3368 +quality indicators to the structure \verb|LPXKKT|:
 13.3369 +
 13.3370 +\verb|pe_quality|---quality of primal solution;
 13.3371 +
 13.3372 +\verb|pb_quality|---quality of primal feasibility;
 13.3373 +
 13.3374 +\verb|de_quality|---quality of dual solution;
 13.3375 +
 13.3376 +\verb|db_quality|---quality of dual feasibility.
 13.3377 +
 13.3378 +Each of these indicators is assigned to one of the following four
 13.3379 +values:
 13.3380 +
 13.3381 +\verb|'H'| means high quality,
 13.3382 +
 13.3383 +\verb|'M'| means medium quality,
 13.3384 +
 13.3385 +\verb|'L'| means low quality, or
 13.3386 +
 13.3387 +\verb|'?'| means wrong or infeasible solution.
 13.3388 +
 13.3389 +If all the indicators show high or medium quality (for an internally
 13.3390 +scaled LP problem, i.e. when the parameter \verb|scaled| in a call to
 13.3391 +the routine \verb|lpx_check_kkt| is non-zero), the user can be sure that
 13.3392 +the obtained basic solution is quite accurate.
 13.3393 +
 13.3394 +If some of the indicators show low quality, the solution can still be
 13.3395 +considered as relevant, though an additional analysis is needed
 13.3396 +depending on which indicator shows low quality.
 13.3397 +
 13.3398 +If the indicator \verb|pe_quality| is assigned to \verb|'?'|, the
 13.3399 +primal solution is wrong. If the indicator \verb|de_quality| is assigned
 13.3400 +to \verb|'?'|, the dual solution is wrong.
 13.3401 +
 13.3402 +If the indicator \verb|db_quality| is assigned to \verb|'?'| while
 13.3403 +other indicators show a good quality, this means that the current
 13.3404 +basic solution being primal feasible is not dual feasible. Similarly,
 13.3405 +if the indicator \verb|pb_quality| is assigned to \verb|'?'| while
 13.3406 +other indicators are not, this means that the current basic solution
 13.3407 +being dual feasible is not primal feasible.
 13.3408 +
 13.3409 +%* eof *%
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/doc/glpk03.tex	Mon Dec 06 13:09:21 2010 +0100
    14.3 @@ -0,0 +1,1577 @@
    14.4 +%* glpk03.tex *%
    14.5 +
    14.6 +\chapter{Utility API routines}
    14.7 +
    14.8 +\section{Problem data reading/writing routines}
    14.9 +
   14.10 +\subsection{glp\_read\_mps---read problem data in MPS format}
   14.11 +
   14.12 +\subsubsection*{Synopsis}
   14.13 +
   14.14 +\begin{verbatim}
   14.15 +int glp_read_mps(glp_prob *lp, int fmt, const void *parm,
   14.16 +      const char *fname);
   14.17 +\end{verbatim}
   14.18 +
   14.19 +\subsubsection*{Description}
   14.20 +
   14.21 +The routine \verb|glp_read_mps| reads problem data in MPS format from a
   14.22 +text file. (The MPS format is described in Appendix \ref{champs}, page
   14.23 +\pageref{champs}.)
   14.24 +
   14.25 +The parameter \verb|fmt| specifies the MPS format version as follows:
   14.26 +
   14.27 +\begin{tabular}{@{}ll}
   14.28 +\verb|GLP_MPS_DECK| & fixed (ancient) MPS format; \\
   14.29 +\verb|GLP_MPS_FILE| & free (modern) MPS format. \\
   14.30 +\end{tabular}
   14.31 +
   14.32 +The parameter \verb|parm| is reserved for use in the future and must be
   14.33 +specified as \verb|NULL|.
   14.34 +
   14.35 +The character string \verb|fname| specifies a name of the text file to
   14.36 +be read in. (If the file name ends with suffix `\verb|.gz|', the file is
   14.37 +assumed to be compressed, in which case the routine \verb|glp_read_mps|
   14.38 +decompresses it ``on the fly''.)
   14.39 +
   14.40 +Note that before reading data the current content of the problem object
   14.41 +is completely erased with the routine \verb|glp_erase_prob|.
   14.42 +
   14.43 +\subsubsection*{Returns}
   14.44 +
   14.45 +If the operation was successful, the routine \verb|glp_read_mps|
   14.46 +returns zero. Otherwise, it prints an error message and returns
   14.47 +non-zero.
   14.48 +
   14.49 +\subsection{glp\_write\_mps---write problem data in MPS format}
   14.50 +
   14.51 +\subsubsection*{Synopsis}
   14.52 +
   14.53 +\begin{verbatim}
   14.54 +int glp_write_mps(glp_prob *lp, int fmt, const void *parm,
   14.55 +      const char *fname);
   14.56 +\end{verbatim}
   14.57 +
   14.58 +\subsubsection*{Description}
   14.59 +
   14.60 +The routine \verb|glp_write_mps| writes problem data in MPS format to a
   14.61 +text file. (The MPS format is described in Appendix \ref{champs}, page
   14.62 +\pageref{champs}.)
   14.63 +
   14.64 +The parameter \verb|fmt| specifies the MPS format version as follows:
   14.65 +
   14.66 +\begin{tabular}{@{}ll}
   14.67 +\verb|GLP_MPS_DECK| & fixed (ancient) MPS format; \\
   14.68 +\verb|GLP_MPS_FILE| & free (modern) MPS format. \\
   14.69 +\end{tabular}
   14.70 +
   14.71 +The parameter \verb|parm| is reserved for use in the future and must be
   14.72 +specified as \verb|NULL|.
   14.73 +
   14.74 +The character string \verb|fname| specifies a name of the text file to
   14.75 +be written out. (If the file name ends with suffix `\verb|.gz|', the
   14.76 +file is assumed to be compressed, in which case the routine
   14.77 +\verb|glp_write_mps| performs automatic compression on writing it.)
   14.78 +
   14.79 +\subsubsection*{Returns}
   14.80 +
   14.81 +If the operation was successful, the routine \verb|glp_write_mps|
   14.82 +returns zero. Otherwise, it prints an error message and returns
   14.83 +non-zero.
   14.84 +
   14.85 +\subsection{glp\_read\_lp---read problem data in CPLEX LP format}
   14.86 +
   14.87 +\subsubsection*{Synopsis}
   14.88 +
   14.89 +\begin{verbatim}
   14.90 +int glp_read_lp(glp_prob *lp, const void *parm,
   14.91 +      const char *fname);
   14.92 +\end{verbatim}
   14.93 +
   14.94 +\subsubsection*{Description}
   14.95 +
   14.96 +The routine \verb|glp_read_lp| reads problem data in CPLEX LP format
   14.97 +from a text file. (The CPLEX LP format is described in Appendix
   14.98 +\ref{chacplex}, page \pageref{chacplex}.)
   14.99 +
  14.100 +The parameter \verb|parm| is reserved for use in the future and must be
  14.101 +specified as \verb|NULL|.
  14.102 +
  14.103 +The character string \verb|fname| specifies a name of the text file to
  14.104 +be read in. (If the file name ends with suffix `\verb|.gz|', the file is
  14.105 +assumed to be compressed, in which case the routine \verb|glp_read_lp|
  14.106 +decompresses it ``on the fly''.)
  14.107 +
  14.108 +Note that before reading data the current content of the problem object
  14.109 +is completely erased with the routine \verb|glp_erase_prob|.
  14.110 +
  14.111 +\subsubsection*{Returns}
  14.112 +
  14.113 +If the operation was successful, the routine \verb|glp_read_lp| returns
  14.114 +zero. Otherwise, it prints an error message and returns non-zero.
  14.115 +
  14.116 +\subsection{glp\_write\_lp---write problem data in CPLEX LP format}
  14.117 +
  14.118 +\subsubsection*{Synopsis}
  14.119 +
  14.120 +\begin{verbatim}
  14.121 +int glp_write_lp(glp_prob *lp, const void *parm,
  14.122 +      const char *fname);
  14.123 +\end{verbatim}
  14.124 +
  14.125 +\subsubsection*{Description}
  14.126 +
  14.127 +The routine \verb|glp_write_lp| writes problem data in CPLEX LP format
  14.128 +to a text file. (The CPLEX LP format is described in Appendix
  14.129 +\ref{chacplex}, page \pageref{chacplex}.)
  14.130 +
  14.131 +The parameter \verb|parm| is reserved for use in the future and must be
  14.132 +specified as \verb|NULL|.
  14.133 +
  14.134 +The character string \verb|fname| specifies a name of the text file to
  14.135 +be written out. (If the file name ends with suffix `\verb|.gz|', the
  14.136 +file is assumed to be compressed, in which case the routine
  14.137 +\verb|glp_write_lp| performs automatic compression on writing it.)
  14.138 +
  14.139 +\subsubsection*{Returns}
  14.140 +
  14.141 +If the operation was successful, the routine \verb|glp_write_lp|
  14.142 +returns zero. Otherwise, it prints an error message and returns
  14.143 +non-zero.
  14.144 +
  14.145 +\subsection{glp\_read\_prob---read problem data in GLPK format}
  14.146 +
  14.147 +\subsubsection*{Synopsis}
  14.148 +
  14.149 +\begin{verbatim}
  14.150 +int glp_read_prob(glp_prob *P, int flags, const char *fname);
  14.151 +\end{verbatim}
  14.152 +
  14.153 +\subsubsection*{Description}
  14.154 +
  14.155 +The routine \verb|glp_read_prob| reads problem data in the GLPK LP/MIP
  14.156 +format from a text file. (For description of the GLPK LP/MIP format see
  14.157 +below.)
  14.158 +
  14.159 +The parameter \verb|flags| is reserved for use in the future and should
  14.160 +be specified as zero.
  14.161 +
  14.162 +The character string \verb|fname| specifies a name of the text file to
  14.163 +be read in. (If the file name ends with suffix `\verb|.gz|', the file
  14.164 +is assumed to be compressed, in which case the routine
  14.165 +\verb|glp_read_prob| decompresses it ``on the fly''.)
  14.166 +
  14.167 +Note that before reading data the current content of the problem object
  14.168 +is completely erased with the routine \verb|glp_erase_prob|.
  14.169 +
  14.170 +\subsubsection*{Returns}
  14.171 +
  14.172 +If the operation was successful, the routine \verb|glp_read_prob|
  14.173 +returns zero. Otherwise, it prints an error message and returns
  14.174 +non-zero.
  14.175 +
  14.176 +\subsubsection*{GLPK LP/MIP format}
  14.177 +
  14.178 +The GLPK LP/MIP format is a DIMACS-like format.\footnote{The DIMACS
  14.179 +formats were developed by the Center for Discrete Mathematics and
  14.180 +Theoretical Computer Science (DIMACS) to facilitate exchange of problem
  14.181 +data. For details see: {\tt <http://dimacs.rutgers.edu/Challenges/>}. }
  14.182 +The file in this format is a plain ASCII text file containing lines of
  14.183 +several types described below. A line is terminated with the end-of-line
  14.184 +character. Fields in each line are separated by at least one blank
  14.185 +space. Each line begins with a one-character designator to identify the
  14.186 +line type.
  14.187 +
  14.188 +The first line of the data file must be the problem line (except
  14.189 +optional comment lines, which may precede the problem line). The last
  14.190 +line of the data file must be the end line. Other lines may follow in
  14.191 +arbitrary order, however, duplicate lines are not allowed.
  14.192 +
  14.193 +\paragraph{Comment lines.} Comment lines give human-readable
  14.194 +information about the data file and are ignored by GLPK routines.
  14.195 +Comment lines can appear anywhere in the data file. Each comment line
  14.196 +begins with the lower-case character \verb|c|.
  14.197 +
  14.198 +\begin{verbatim}
  14.199 +   c This is an example of comment line
  14.200 +\end{verbatim}
  14.201 +
  14.202 +\paragraph{Problem line.} There must be exactly one problem line in the
  14.203 +data file. This line must appear before any other lines except comment
  14.204 +lines and has the following format:
  14.205 +
  14.206 +\begin{verbatim}
  14.207 +   p CLASS DIR ROWS COLS NONZ
  14.208 +\end{verbatim}
  14.209 +
  14.210 +The lower-case letter \verb|p| specifies that this is the problem line.
  14.211 +
  14.212 +The \verb|CLASS| field defines the problem class and can contain either
  14.213 +the keyword \verb|lp| (that means linear programming problem) or
  14.214 +\verb|mip| (that means mixed integer programming problem).
  14.215 +
  14.216 +The \verb|DIR| field defines the optimization direction (that is, the
  14.217 +objective function sense) and can contain either the keyword \verb|min|
  14.218 +(that means minimization) or \verb|max| (that means maximization).
  14.219 +
  14.220 +The \verb|ROWS|, \verb|COLS|, and \verb|NONZ| fields contain
  14.221 +non-negative integer values specifying, respectively, the number of
  14.222 +rows (constraints), columns (variables), and non-zero constraint
  14.223 +coefficients in the problem instance. Note that \verb|NONZ| value does
  14.224 +not account objective coefficients.
  14.225 +
  14.226 +\paragraph{Row descriptors.} There must be at most one row descriptor
  14.227 +line in the data file for each row (constraint). This line has one of
  14.228 +the following formats:
  14.229 +
  14.230 +\begin{verbatim}
  14.231 +   i ROW f
  14.232 +   i ROW l RHS
  14.233 +   i ROW u RHS
  14.234 +   i ROW d RHS1 RHS2
  14.235 +   i ROW s RHS
  14.236 +\end{verbatim}
  14.237 +
  14.238 +The lower-case letter \verb|i| specifies that this is the row
  14.239 +descriptor line.
  14.240 +
  14.241 +The \verb|ROW| field specifies the row ordinal number, an integer
  14.242 +between 1 and $m$, where $m$ is the number of rows in the problem
  14.243 +instance.
  14.244 +
  14.245 +The next lower-case letter specifies the row type as follows:
  14.246 +
  14.247 +\verb|f| --- free (unbounded) row: $-\infty<\sum a_jx_j<+\infty$;
  14.248 +
  14.249 +\verb|l| --- inequality constraint of `$\geq$' type:
  14.250 +$\sum a_jx_j\geq b$;
  14.251 +
  14.252 +\verb|u| --- inequality constraint of `$\leq$' type:
  14.253 +$\sum a_jx_j\leq b$;
  14.254 +
  14.255 +\verb|d| --- double-sided inequality constraint:
  14.256 +$b_1\leq\sum a_jx_j\leq b_2$;
  14.257 +
  14.258 +\verb|s| --- equality constraint: $\sum a_jx_j=b$.
  14.259 +
  14.260 +The \verb|RHS| field contains a floaing-point value specifying the
  14.261 +row right-hand side. The \verb|RHS1| and \verb|RHS2| fields contain
  14.262 +floating-point values specifying, respectively, the lower and upper
  14.263 +right-hand sides for the double-sided row.
  14.264 +
  14.265 +If for some row its descriptor line does not appear in the data file,
  14.266 +by default that row is assumed to be an equality constraint with zero
  14.267 +right-hand side.
  14.268 +
  14.269 +\paragraph{Column descriptors.} There must be at most one column
  14.270 +descriptor line in the data file for each column (variable). This line
  14.271 +has one of the following formats depending on the problem class
  14.272 +specified in the problem line:
  14.273 +
  14.274 +\bigskip
  14.275 +
  14.276 +\begin{tabular}{@{}l@{\hspace*{40pt}}l}
  14.277 +LP class & MIP class \\
  14.278 +\hline
  14.279 +\verb|j COL f|           & \verb|j COL KIND f|           \\
  14.280 +\verb|j COL l BND|       & \verb|j COL KIND l BND|       \\
  14.281 +\verb|j COL u BND|       & \verb|j COL KIND u BND|       \\
  14.282 +\verb|j COL d BND1 BND2| & \verb|j COL KIND d BND1 BND2| \\
  14.283 +\verb|j COL s BND|       & \verb|j COL KIND s BND|       \\
  14.284 +\end{tabular}
  14.285 +
  14.286 +\bigskip
  14.287 +
  14.288 +The lower-case letter \verb|j| specifies that this is the column
  14.289 +descriptor line.
  14.290 +
  14.291 +The \verb|COL| field specifies the column ordinal number, an integer
  14.292 +between 1 and $n$, where $n$ is the number of columns in the problem
  14.293 +instance.
  14.294 +
  14.295 +The \verb|KIND| field is used only for MIP problems and specifies the
  14.296 +column kind as follows:
  14.297 +
  14.298 +\verb|c| --- continuous column;
  14.299 +
  14.300 +\verb|i| --- integer column;
  14.301 +
  14.302 +\verb|b| --- binary column (in this case all remaining fields must be
  14.303 +omitted).
  14.304 +
  14.305 +The next lower-case letter specifies the column type as follows:
  14.306 +
  14.307 +\verb|f| --- free (unbounded) column: $-\infty<x<+\infty$;
  14.308 +
  14.309 +\verb|l| --- column with lower bound: $x\geq l$;
  14.310 +
  14.311 +\verb|u| --- column with upper bound: $x\leq u$;
  14.312 +
  14.313 +\verb|d| --- double-bounded column: $l\leq x\leq u$;
  14.314 +
  14.315 +\verb|s| --- fixed column: $x=s$.
  14.316 +
  14.317 +The \verb|BND| field contains a floating-point value that specifies the
  14.318 +column bound. The \verb|BND1| and \verb|BND2| fields contain
  14.319 +floating-point values specifying, respectively, the lower and upper
  14.320 +bounds for the double-bounded column.
  14.321 +
  14.322 +If for some column its descriptor line does not appear in the file, by
  14.323 +default that column is assumed to be non-negative (in case of LP class)
  14.324 +or binary (in case of MIP class).
  14.325 +
  14.326 +\paragraph{Coefficient descriptors.} There must be exactly one
  14.327 +coefficient descriptor line in the data file for each non-zero
  14.328 +objective or constraint coefficient. This line has the following format:
  14.329 +
  14.330 +\begin{verbatim}
  14.331 +   a ROW COL VAL
  14.332 +\end{verbatim}
  14.333 +
  14.334 +The lower-case letter \verb|a| specifies that this is the coefficient
  14.335 +descriptor line.
  14.336 +
  14.337 +For objective coefficients the \verb|ROW| field must contain 0. For
  14.338 +constraint coefficients the \verb|ROW| field specifies the row ordinal
  14.339 +number, an integer between 1 and $m$, where $m$ is the number of rows
  14.340 +in the problem instance.
  14.341 +
  14.342 +The \verb|COL| field specifies the column ordinal number, an integer
  14.343 +between 1 and $n$, where $n$ is the number of columns in the problem
  14.344 +instance.
  14.345 +
  14.346 +If both the \verb|ROW| and \verb|COL| fields contain 0, the line
  14.347 +specifies the constant term (``shift'') of the objective function
  14.348 +rather than objective coefficient.
  14.349 +
  14.350 +The \verb|VAL| field contains a floating-point coefficient value (it is
  14.351 +allowed to specify zero value in this field).
  14.352 +
  14.353 +The number of constraint coefficient descriptor lines must be exactly
  14.354 +the same as specified in the field \verb|NONZ| of the problem line.
  14.355 +
  14.356 +\paragraph{Symbolic name descriptors.} There must be at most one
  14.357 +symbolic name descriptor line for the problem instance, objective
  14.358 +function, each row (constraint), and each column (variable). This line
  14.359 +has one of the following formats:
  14.360 +
  14.361 +\begin{verbatim}
  14.362 +   n p NAME
  14.363 +   n z NAME
  14.364 +   n i ROW NAME
  14.365 +   n j COL NAME
  14.366 +\end{verbatim}
  14.367 +
  14.368 +The lower-case letter \verb|n| specifies that this is the symbolic name
  14.369 +descriptor line.
  14.370 +
  14.371 +The next lower-case letter specifies which object should be assigned a
  14.372 +symbolic name:
  14.373 +
  14.374 +\verb|p| --- problem instance;
  14.375 +
  14.376 +\verb|z| --- objective function;
  14.377 +
  14.378 +\verb|i| --- row (constraint);
  14.379 +
  14.380 +\verb|j| --- column (variable).
  14.381 +
  14.382 +The \verb|ROW| field specifies the row ordinal number, an integer
  14.383 +between 1 and $m$, where $m$ is the number of rows in the problem
  14.384 +instance.
  14.385 +
  14.386 +The \verb|COL| field specifies the column ordinal number, an integer
  14.387 +between 1 and $n$, where $n$ is the number of columns in the problem
  14.388 +instance.
  14.389 +
  14.390 +The \verb|NAME| field contains the symbolic name, a sequence from 1 to
  14.391 +255 arbitrary graphic ASCII characters, assigned to corresponding
  14.392 +object.
  14.393 +
  14.394 +\paragraph{End line.} There must be exactly one end line in the data
  14.395 +file. This line must appear last in the file and has the following
  14.396 +format:
  14.397 +
  14.398 +\begin{verbatim}
  14.399 +   e
  14.400 +\end{verbatim}
  14.401 +
  14.402 +The lower-case letter \verb|e| specifies that this is the end line.
  14.403 +Anything that follows the end line is ignored by GLPK routines.
  14.404 +
  14.405 +\subsubsection*{Example of data file in GLPK LP/MIP format}
  14.406 +
  14.407 +The following example of a data file in GLPK LP/MIP format specifies
  14.408 +the same LP problem as in Subsection ``Example of MPS file''.
  14.409 +
  14.410 +\begin{center}
  14.411 +\footnotesize\tt
  14.412 +\begin{tabular}{l@{\hspace*{50pt}}}
  14.413 +p lp min 8 7 48   \\
  14.414 +n p PLAN          \\
  14.415 +n z VALUE         \\
  14.416 +i 1 f             \\
  14.417 +n i 1 VALUE       \\
  14.418 +i 2 s 2000        \\
  14.419 +n i 2 YIELD       \\
  14.420 +i 3 u 60          \\
  14.421 +n i 3 FE          \\
  14.422 +i 4 u 100         \\
  14.423 +n i 4 CU          \\
  14.424 +i 5 u 40          \\
  14.425 +n i 5 MN          \\
  14.426 +i 6 u 30          \\
  14.427 +n i 6 MG          \\
  14.428 +i 7 l 1500        \\
  14.429 +n i 7 AL          \\
  14.430 +i 8 d 250 300     \\
  14.431 +n i 8 SI          \\
  14.432 +j 1 d 0 200       \\
  14.433 +n j 1 BIN1        \\
  14.434 +j 2 d 0 2500      \\
  14.435 +n j 2 BIN2        \\
  14.436 +j 3 d 400 800     \\
  14.437 +n j 3 BIN3        \\
  14.438 +j 4 d 100 700     \\
  14.439 +n j 4 BIN4        \\
  14.440 +j 5 d 0 1500      \\
  14.441 +n j 5 BIN5        \\
  14.442 +n j 6 ALUM        \\
  14.443 +n j 7 SILICON     \\
  14.444 +a 0 1 0.03        \\
  14.445 +a 0 2 0.08        \\
  14.446 +a 0 3 0.17        \\
  14.447 +a 0 4 0.12        \\
  14.448 +a 0 5 0.15        \\
  14.449 +a 0 6 0.21        \\
  14.450 +a 0 7 0.38        \\
  14.451 +a 1 1 0.03        \\
  14.452 +a 1 2 0.08        \\
  14.453 +a 1 3 0.17        \\
  14.454 +a 1 4 0.12        \\
  14.455 +a 1 5 0.15        \\
  14.456 +a 1 6 0.21        \\
  14.457 +\end{tabular}
  14.458 +\begin{tabular}{|@{\hspace*{80pt}}l}
  14.459 +a 1 7 0.38        \\
  14.460 +a 2 1 1           \\
  14.461 +a 2 2 1           \\
  14.462 +a 2 3 1           \\
  14.463 +a 2 4 1           \\
  14.464 +a 2 5 1           \\
  14.465 +a 2 6 1           \\
  14.466 +a 2 7 1           \\
  14.467 +a 3 1 0.15        \\
  14.468 +a 3 2 0.04        \\
  14.469 +a 3 3 0.02        \\
  14.470 +a 3 4 0.04        \\
  14.471 +a 3 5 0.02        \\
  14.472 +a 3 6 0.01        \\
  14.473 +a 3 7 0.03        \\
  14.474 +a 4 1 0.03        \\
  14.475 +a 4 2 0.05        \\
  14.476 +a 4 3 0.08        \\
  14.477 +a 4 4 0.02        \\
  14.478 +a 4 5 0.06        \\
  14.479 +a 4 6 0.01        \\
  14.480 +a 5 1 0.02        \\
  14.481 +a 5 2 0.04        \\
  14.482 +a 5 3 0.01        \\
  14.483 +a 5 4 0.02        \\
  14.484 +a 5 5 0.02        \\
  14.485 +a 6 1 0.02        \\
  14.486 +a 6 2 0.03        \\
  14.487 +a 6 5 0.01        \\
  14.488 +a 7 1 0.7         \\
  14.489 +a 7 2 0.75        \\
  14.490 +a 7 3 0.8         \\
  14.491 +a 7 4 0.75        \\
  14.492 +a 7 5 0.8         \\
  14.493 +a 7 6 0.97        \\
  14.494 +a 8 1 0.02        \\
  14.495 +a 8 2 0.06        \\
  14.496 +a 8 3 0.08        \\
  14.497 +a 8 4 0.12        \\
  14.498 +a 8 5 0.02        \\
  14.499 +a 8 6 0.01        \\
  14.500 +a 8 7 0.97        \\
  14.501 +e o f             \\
  14.502 +\\
  14.503 +\end{tabular}
  14.504 +\end{center}
  14.505 +
  14.506 +\newpage
  14.507 +
  14.508 +\subsection{glp\_write\_prob---write problem data in GLPK format}
  14.509 +
  14.510 +\subsubsection*{Synopsis}
  14.511 +
  14.512 +\begin{verbatim}
  14.513 +int glp_write_prob(glp_prob *P, int flags, const char *fname);
  14.514 +\end{verbatim}
  14.515 +
  14.516 +\subsubsection*{Description}
  14.517 +
  14.518 +The routine \verb|glp_write_prob| writes problem data in the GLPK
  14.519 +LP/MIP format to a text file. (For description of the GLPK LP/MIP
  14.520 +format see Subsection ``Read problem data in GLPK format''.)
  14.521 +
  14.522 +The parameter \verb|flags| is reserved for use in the future and should
  14.523 +be specified as zero.
  14.524 +
  14.525 +The character string \verb|fname| specifies a name of the text file to
  14.526 +be written out. (If the file name ends with suffix `\verb|.gz|', the
  14.527 +file is assumed to be compressed, in which case the routine
  14.528 +\verb|glp_write_prob| performs automatic compression on writing it.)
  14.529 +
  14.530 +\subsubsection*{Returns}
  14.531 +
  14.532 +If the operation was successful, the routine \verb|glp_read_prob|
  14.533 +returns zero. Otherwise, it prints an error message and returns
  14.534 +non-zero.
  14.535 +
  14.536 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  14.537 +
  14.538 +\newpage
  14.539 +
  14.540 +\section{Routines for processing MathProg models}
  14.541 +
  14.542 +\subsection{Introduction}
  14.543 +
  14.544 +GLPK supports the {\it GNU MathProg modeling language}.\footnote{The
  14.545 +GNU MathProg modeling language is a subset of the AMPL language. For
  14.546 +its detailed description see the document ``Modeling Language GNU
  14.547 +MathProg: Language Reference'' included in the GLPK distribution.}
  14.548 +As a rule, models written in MathProg are solved with the GLPK LP/MIP
  14.549 +stand-alone solver \verb|glpsol| (see Appendix D) and do not need any
  14.550 +programming with API routines. However, for various reasons the user
  14.551 +may need to process MathProg models directly in his/her application
  14.552 +program, in which case he/she may use API routines described in this
  14.553 +section. These routines provide an interface to the {\it MathProg
  14.554 +translator}, a component of GLPK, which translates MathProg models into
  14.555 +an internal code and then interprets (executes) this code.
  14.556 +
  14.557 +The processing of a model written in GNU MathProg includes several
  14.558 +steps, which should be performed in the following order:
  14.559 +
  14.560 +\begin{enumerate}
  14.561 +\item{\it Allocating the workspace.}
  14.562 +The translator allocates the workspace, an internal data structure used
  14.563 +on all subsequent steps.
  14.564 +\item{\it Reading model section.} The translator reads model section
  14.565 +and, optionally, data section from a specified text file and translates
  14.566 +them into the internal code. If necessary, on this step data section
  14.567 +may be ignored.
  14.568 +\item{\it Reading data section(s).} The translator reads one or more
  14.569 +data sections from specified text file(s) and translates them into the
  14.570 +internal code.
  14.571 +\item{\it Generating the model.} The translator executes the internal
  14.572 +code to evaluate the content of the model objects such as sets,
  14.573 +parameters, variables, constraints, and objectives. On this step the
  14.574 +execution is suspended at the solve statement.
  14.575 +\item {\it Building the problem object.} The translator obtains all
  14.576 +necessary information from the workspace and builds the standard
  14.577 +problem object (that is, the program object of type \verb|glp_prob|).
  14.578 +\item{\it Solving the problem.} On this step the problem object built
  14.579 +on the previous step is passed to a solver, which solves the problem
  14.580 +instance and stores its solution back to the problem object.
  14.581 +\item{\it Postsolving the model.} The translator copies the solution
  14.582 +from the problem object to the workspace and then executes the internal
  14.583 +code from the solve statement to the end of the model. (If model has
  14.584 +no solve statement, the translator does nothing on this step.)
  14.585 +\item{\it Freeing the workspace.} The translator frees all the memory
  14.586 +allocated to the workspace.
  14.587 +\end{enumerate}
  14.588 +
  14.589 +Note that the MathProg translator performs no error correction, so if
  14.590 +any of steps 2 to 7 fails (due to errors in the model), the application
  14.591 +program should terminate processing and go to step 8.
  14.592 +
  14.593 +\subsubsection*{Example 1}
  14.594 +
  14.595 +In this example the program reads model and data sections from input
  14.596 +file \verb|egypt.mod|\footnote{This is an example model included in
  14.597 +the GLPK distribution.} and writes the model to output file
  14.598 +\verb|egypt.mps| in free MPS format (see Appendix B). No solution is
  14.599 +performed.
  14.600 +
  14.601 +\begin{small}
  14.602 +\begin{verbatim}
  14.603 +/* mplsamp1.c */
  14.604 +
  14.605 +#include <stdio.h>
  14.606 +#include <stdlib.h>
  14.607 +#include <glpk.h>
  14.608 +
  14.609 +int main(void)
  14.610 +{     glp_prob *lp;
  14.611 +      glp_tran *tran;
  14.612 +      int ret;
  14.613 +      lp = glp_create_prob();
  14.614 +      tran = glp_mpl_alloc_wksp();
  14.615 +      ret = glp_mpl_read_model(tran, "egypt.mod", 0);
  14.616 +      if (ret != 0)
  14.617 +      {  fprintf(stderr, "Error on translating model\n");
  14.618 +         goto skip;
  14.619 +      }
  14.620 +      ret = glp_mpl_generate(tran, NULL);
  14.621 +      if (ret != 0)
  14.622 +      {  fprintf(stderr, "Error on generating model\n");
  14.623 +         goto skip;
  14.624 +      }
  14.625 +      glp_mpl_build_prob(tran, lp);
  14.626 +      ret = glp_write_mps(lp, GLP_MPS_FILE, NULL, "egypt.mps");
  14.627 +      if (ret != 0)
  14.628 +         fprintf(stderr, "Error on writing MPS file\n");
  14.629 +skip: glp_mpl_free_wksp(tran);
  14.630 +      glp_delete_prob(lp);
  14.631 +      return 0;
  14.632 +}
  14.633 +
  14.634 +/* eof */
  14.635 +\end{verbatim}
  14.636 +\end{small}
  14.637 +
  14.638 +\subsubsection*{Example 2}
  14.639 +
  14.640 +In this example the program reads model section from file
  14.641 +\verb|sudoku.mod|\footnote{This is an example model which is included
  14.642 +in the GLPK distribution along with alternative data file
  14.643 +{\tt sudoku.dat}.} ignoring data section in this file, reads alternative
  14.644 +data section from file \verb|sudoku.dat|, solves the problem instance
  14.645 +and passes the solution found back to the model.
  14.646 +
  14.647 +\begin{small}
  14.648 +\begin{verbatim}
  14.649 +/* mplsamp2.c */
  14.650 +
  14.651 +#include <stdio.h>
  14.652 +#include <stdlib.h>
  14.653 +#include <glpk.h>
  14.654 +
  14.655 +int main(void)
  14.656 +{     glp_prob *mip;
  14.657 +      glp_tran *tran;
  14.658 +      int ret;
  14.659 +      mip = glp_create_prob();
  14.660 +      tran = glp_mpl_alloc_wksp();
  14.661 +      ret = glp_mpl_read_model(tran, "sudoku.mod", 1);
  14.662 +      if (ret != 0)
  14.663 +      {  fprintf(stderr, "Error on translating model\n");
  14.664 +         goto skip;
  14.665 +      }
  14.666 +      ret = glp_mpl_read_data(tran, "sudoku.dat");
  14.667 +      if (ret != 0)
  14.668 +      {  fprintf(stderr, "Error on translating data\n");
  14.669 +         goto skip;
  14.670 +      }
  14.671 +      ret = glp_mpl_generate(tran, NULL);
  14.672 +      if (ret != 0)
  14.673 +      {  fprintf(stderr, "Error on generating model\n");
  14.674 +         goto skip;
  14.675 +      }
  14.676 +      glp_mpl_build_prob(tran, mip);
  14.677 +      glp_simplex(mip, NULL);
  14.678 +      glp_intopt(mip, NULL);
  14.679 +      ret = glp_mpl_postsolve(tran, mip, GLP_MIP);
  14.680 +      if (ret != 0)
  14.681 +         fprintf(stderr, "Error on postsolving model\n");
  14.682 +skip: glp_mpl_free_wksp(tran);
  14.683 +      glp_delete_prob(mip);
  14.684 +      return 0;
  14.685 +}
  14.686 +
  14.687 +/* eof */
  14.688 +\end{verbatim}
  14.689 +\end{small}
  14.690 +
  14.691 +\subsection{glp\_mpl\_alloc\_wksp---allocate the translator workspace}
  14.692 +
  14.693 +\subsubsection*{Synopsis}
  14.694 +
  14.695 +\begin{verbatim}
  14.696 +glp_tran *glp_mpl_alloc_wksp(void);
  14.697 +\end{verbatim}
  14.698 +
  14.699 +\subsubsection*{Description}
  14.700 +
  14.701 +The routine \verb|glp_mpl_alloc_wksp| allocates the MathProg translator
  14.702 +work\-space. (Note that multiple instances of the workspace may be
  14.703 +allocated, if necessary.)
  14.704 +
  14.705 +\subsubsection*{Returns}
  14.706 +
  14.707 +The routine returns a pointer to the workspace, which should be used in
  14.708 +all subsequent operations.
  14.709 +
  14.710 +\subsection{glp\_mpl\_read\_model---read and translate model section}
  14.711 +
  14.712 +\subsubsection*{Synopsis}
  14.713 +
  14.714 +\begin{verbatim}
  14.715 +int glp_mpl_read_model(glp_tran *tran, const char *fname,
  14.716 +      int skip);
  14.717 +\end{verbatim}
  14.718 +
  14.719 +\subsubsection*{Description}
  14.720 +
  14.721 +The routine \verb|glp_mpl_read_model| reads model section and,
  14.722 +optionally, data section, which may follow the model section, from a
  14.723 +text file, whose name is the character string \verb|fname|, performs
  14.724 +translation of model statements and data blocks, and stores all the
  14.725 +information in the workspace.
  14.726 +
  14.727 +The parameter \verb|skip| is a flag. If the input file contains the
  14.728 +data section and this flag is non-zero, the data section is not read as
  14.729 +if there were no data section and a warning message is printed. This
  14.730 +allows reading data section(s) from other file(s).
  14.731 +
  14.732 +\subsubsection*{Returns}
  14.733 +
  14.734 +If the operation is successful, the routine returns zero. Otherwise
  14.735 +the routine prints an error message and returns non-zero.
  14.736 +
  14.737 +\subsection{glp\_mpl\_read\_data---read and translate data section}
  14.738 +
  14.739 +\subsubsection*{Synopsis}
  14.740 +
  14.741 +\begin{verbatim}
  14.742 +int glp_mpl_read_data(glp_tran *tran, const char *fname);
  14.743 +\end{verbatim}
  14.744 +
  14.745 +\subsubsection*{Description}
  14.746 +
  14.747 +The routine \verb|glp_mpl_read_data| reads data section from a text
  14.748 +file, whose name is the character string \verb|fname|, performs
  14.749 +translation of data blocks, and stores the data read in the translator
  14.750 +workspace. If necessary, this routine may be called more than once.
  14.751 +
  14.752 +\subsubsection*{Returns}
  14.753 +
  14.754 +If the operation is successful, the routine returns zero. Otherwise
  14.755 +the routine prints an error message and returns non-zero.
  14.756 +
  14.757 +\subsection{glp\_mpl\_generate---generate the model}
  14.758 +
  14.759 +\subsubsection*{Synopsis}
  14.760 +
  14.761 +\begin{verbatim}
  14.762 +int glp_mpl_generate(glp_tran *tran, const char *fname);
  14.763 +\end{verbatim}
  14.764 +
  14.765 +\subsubsection*{Description}
  14.766 +
  14.767 +The routine \verb|glp_mpl_generate| generates the model using its
  14.768 +description stored in the translator workspace. This operation means
  14.769 +generating all variables, constraints, and objectives, executing check
  14.770 +and display statements, which precede the solve statement (if it is
  14.771 +presented).
  14.772 +
  14.773 +The character string \verb|fname| specifies the name of an output text
  14.774 +file, to which output produced by display statements should be written.
  14.775 +If \verb|fname| is \verb|NULL|, the output is sent to the terminal.
  14.776 +
  14.777 +\subsubsection*{Returns}
  14.778 +
  14.779 +If the operation is successful, the routine returns zero. Otherwise
  14.780 +the routine prints an error message and returns non-zero.
  14.781 +
  14.782 +\subsection{glp\_mpl\_build\_prob---build problem instance from the
  14.783 +model}
  14.784 +
  14.785 +\subsubsection*{Synopsis}
  14.786 +
  14.787 +\begin{verbatim}
  14.788 +void glp_mpl_build_prob(glp_tran *tran, glp_prob *prob);
  14.789 +\end{verbatim}
  14.790 +
  14.791 +\subsubsection*{Description}
  14.792 +
  14.793 +The routine \verb|glp_mpl_build_prob| obtains all necessary information
  14.794 +from the translator workspace and stores it in the specified problem
  14.795 +object \verb|prob|. Note that before building the current content of
  14.796 +the problem object is erased with the routine \verb|glp_erase_prob|.
  14.797 +
  14.798 +\subsection{glp\_mpl\_postsolve---postsolve the model}
  14.799 +
  14.800 +\subsubsection*{Synopsis}
  14.801 +
  14.802 +\begin{verbatim}
  14.803 +int glp_mpl_postsolve(glp_tran *tran, glp_prob *prob,
  14.804 +      int sol);
  14.805 +\end{verbatim}
  14.806 +
  14.807 +\subsubsection*{Description}
  14.808 +
  14.809 +The routine \verb|glp_mpl_postsolve| copies the solution from the
  14.810 +specified problem object \verb|prob| to the translator workspace and
  14.811 +then executes all the remaining model statements, which follow the
  14.812 +solve statement.
  14.813 +
  14.814 +The parameter \verb|sol| specifies which solution should be copied
  14.815 +from the problem object to the workspace as follows:
  14.816 +
  14.817 +\begin{tabular}{@{}ll}
  14.818 +\verb|GLP_SOL| & basic solution; \\
  14.819 +\verb|GLP_IPT| & interior-point solution; \\
  14.820 +\verb|GLP_MIP| & mixed integer solution. \\
  14.821 +\end{tabular}
  14.822 +
  14.823 +\subsubsection*{Returns}
  14.824 +
  14.825 +If the operation is successful, the routine returns zero. Otherwise
  14.826 +the routine prints an error message and returns non-zero.
  14.827 +
  14.828 +\subsection{glp\_mpl\_free\_wksp---free the translator workspace}
  14.829 +
  14.830 +\subsubsection*{Synopsis}
  14.831 +
  14.832 +\begin{verbatim}
  14.833 +void glp_mpl_free_wksp(glp_tran *tran);
  14.834 +\end{verbatim}
  14.835 +
  14.836 +\subsubsection*{Description}
  14.837 +
  14.838 +The routine \verb|glp_mpl_free_wksp| frees all the memory allocated to
  14.839 +the translator workspace. It also frees all other resources, which are
  14.840 +still used by the translator.
  14.841 +
  14.842 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  14.843 +
  14.844 +\newpage
  14.845 +
  14.846 +\section{Problem solution reading/writing routines}
  14.847 +
  14.848 +\subsection{glp\_print\_sol---write basic solution in printable format}
  14.849 +
  14.850 +\subsubsection*{Synopsis}
  14.851 +
  14.852 +\begin{verbatim}
  14.853 +int glp_print_sol(glp_prob *lp, const char *fname);
  14.854 +\end{verbatim}
  14.855 +
  14.856 +\subsubsection*{Description}
  14.857 +
  14.858 +The routine \verb|glp_print_sol writes| the current basic solution of
  14.859 +an LP problem, which is specified by the pointer \verb|lp|, to a text
  14.860 +file, whose name is the character string \verb|fname|, in printable
  14.861 +format.
  14.862 +
  14.863 +Information reported by the routine \verb|glp_print_sol| is intended
  14.864 +mainly for visual analysis.
  14.865 +
  14.866 +\subsubsection*{Returns}
  14.867 +
  14.868 +If no errors occurred, the routine returns zero. Otherwise the routine
  14.869 +prints an error message and returns non-zero.
  14.870 +
  14.871 +\subsection{glp\_read\_sol---read basic solution from text file}
  14.872 +
  14.873 +\subsubsection*{Synopsis}
  14.874 +
  14.875 +\begin{verbatim}
  14.876 +int glp_read_sol(glp_prob *lp, const char *fname);
  14.877 +\end{verbatim}
  14.878 +
  14.879 +\subsubsection*{Description}
  14.880 +
  14.881 +The routine \verb|glp_read_sol| reads basic solution from a text file
  14.882 +whose name is specified by the parameter \verb|fname| into the problem
  14.883 +object.
  14.884 +
  14.885 +For the file format see description of the routine \verb|glp_write_sol|.
  14.886 +
  14.887 +\subsubsection*{Returns}
  14.888 +
  14.889 +On success the routine returns zero, otherwise non-zero.
  14.890 +
  14.891 +\newpage
  14.892 +
  14.893 +\subsection{glp\_write\_sol---write basic solution to text file}
  14.894 +
  14.895 +\subsubsection*{Synopsis}
  14.896 +
  14.897 +\begin{verbatim}
  14.898 +int glp_write_sol(glp_prob *lp, const char *fname);
  14.899 +\end{verbatim}
  14.900 +
  14.901 +\subsubsection*{Description}
  14.902 +
  14.903 +The routine \verb|glp_write_sol| writes the current basic solution to a
  14.904 +text file whose name is specified by the parameter \verb|fname|. This
  14.905 +file can be read back with the routine \verb|glp_read_sol|.
  14.906 +
  14.907 +\subsubsection*{Returns}
  14.908 +
  14.909 +On success the routine returns zero, otherwise non-zero.
  14.910 +
  14.911 +\subsubsection*{File format}
  14.912 +
  14.913 +The file created by the routine \verb|glp_write_sol| is a plain text
  14.914 +file, which contains the following information:
  14.915 +
  14.916 +\begin{verbatim}
  14.917 +   m n
  14.918 +   p_stat d_stat obj_val
  14.919 +   r_stat[1] r_prim[1] r_dual[1]
  14.920 +   . . .
  14.921 +   r_stat[m] r_prim[m] r_dual[m]
  14.922 +   c_stat[1] c_prim[1] c_dual[1]
  14.923 +   . . .
  14.924 +   c_stat[n] c_prim[n] c_dual[n]
  14.925 +\end{verbatim}
  14.926 +
  14.927 +\noindent
  14.928 +where:
  14.929 +
  14.930 +\noindent
  14.931 +$m$ is the number of rows (auxiliary variables);
  14.932 +
  14.933 +\noindent
  14.934 +$n$ is the number of columns (structural variables);
  14.935 +
  14.936 +\noindent
  14.937 +\verb|p_stat| is the primal status of the basic solution
  14.938 +(\verb|GLP_UNDEF| = 1, \verb|GLP_FEAS| = 2, \verb|GLP_INFEAS| = 3, or
  14.939 +\verb|GLP_NOFEAS| = 4);
  14.940 +
  14.941 +\noindent
  14.942 +\verb|d_stat| is the dual status of the basic solution
  14.943 +(\verb|GLP_UNDEF| = 1, \verb|GLP_FEAS| = 2, \verb|GLP_INFEAS| = 3, or
  14.944 +\verb|GLP_NOFEAS| = 4);
  14.945 +
  14.946 +\noindent
  14.947 +\verb|obj_val| is the objective value;
  14.948 +
  14.949 +\noindent
  14.950 +\verb|r_stat[i]|, $i=1,\dots,m$, is the status of $i$-th row
  14.951 +(\verb|GLP_BS| = 1, \verb|GLP_NL| = 2, \verb|GLP_NU| = 3,
  14.952 +\verb|GLP_NF| = 4, or \verb|GLP_NS| = 5);
  14.953 +
  14.954 +\noindent
  14.955 +\verb|r_prim[i]|, $i=1,\dots,m$, is the primal value of $i$-th row;
  14.956 +
  14.957 +\noindent
  14.958 +\verb|r_dual[i]|, $i=1,\dots,m$, is the dual value of $i$-th row;
  14.959 +
  14.960 +\noindent
  14.961 +\verb|c_stat[j]|, $j=1,\dots,n$, is the status of $j$-th column
  14.962 +(\verb|GLP_BS| = 1, \verb|GLP_NL| = 2, \verb|GLP_NU| = 3,
  14.963 +\verb|GLP_NF| = 4, or \verb|GLP_NS| = 5);
  14.964 +
  14.965 +\noindent
  14.966 +\verb|c_prim[j]|, $j=1,\dots,n$, is the primal value of $j$-th column;
  14.967 +
  14.968 +\noindent
  14.969 +\verb|c_dual[j]|, $j=1,\dots,n$, is the dual value of $j$-th column.
  14.970 +
  14.971 +\subsection{glp\_print\_ipt---write interior-point solution in
  14.972 +printable format}
  14.973 +
  14.974 +\subsubsection*{Synopsis}
  14.975 +
  14.976 +\begin{verbatim}
  14.977 +int glp_print_ipt(glp_prob *lp, const char *fname);
  14.978 +\end{verbatim}
  14.979 +
  14.980 +\subsubsection*{Description}
  14.981 +
  14.982 +The routine \verb|glp_print_ipt| writes the current interior point
  14.983 +solution  of an LP problem, which the parameter \verb|lp| points to, to
  14.984 +a text file, whose name is the character string \verb|fname|, in
  14.985 +printable format.
  14.986 +
  14.987 +Information reported by the routine \verb|glp_print_ipt| is intended
  14.988 +mainly for visual analysis.
  14.989 +
  14.990 +\subsubsection*{Returns}
  14.991 +
  14.992 +If no errors occurred, the routine returns zero. Otherwise the routine
  14.993 +prints an error message and returns non-zero.
  14.994 +
  14.995 +\subsection{glp\_read\_ipt---read interior-point solution from text
  14.996 +file}
  14.997 +
  14.998 +\subsubsection*{Synopsis}
  14.999 +
 14.1000 +\begin{verbatim}
 14.1001 +int glp_read_ipt(glp_prob *lp, const char *fname);
 14.1002 +\end{verbatim}
 14.1003 +
 14.1004 +\subsubsection*{Description}
 14.1005 +
 14.1006 +The routine \verb|glp_read_ipt| reads interior-point solution from a
 14.1007 +text file whose name is specified by the parameter \verb|fname| into the
 14.1008 +problem object.
 14.1009 +
 14.1010 +For the file format see description of the routine \verb|glp_write_ipt|.
 14.1011 +
 14.1012 +\subsubsection*{Returns}
 14.1013 +
 14.1014 +On success the routine returns zero, otherwise non-zero.
 14.1015 +
 14.1016 +\subsection{glp\_write\_ipt---write interior-point solution to text
 14.1017 +file}
 14.1018 +
 14.1019 +\subsubsection*{Synopsis}
 14.1020 +
 14.1021 +\begin{verbatim}
 14.1022 +int glp_write_ipt(glp_prob *lp, const char *fname);
 14.1023 +\end{verbatim}
 14.1024 +
 14.1025 +\subsubsection*{Description}
 14.1026 +
 14.1027 +The routine \verb|glp_write_ipt| writes the current interior-point
 14.1028 +solution to a text file whose name is specified by the parameter
 14.1029 +\verb|fname|. This file can be read back with the routine
 14.1030 +\verb|glp_read_ipt|.
 14.1031 +
 14.1032 +\subsubsection*{Returns}
 14.1033 +
 14.1034 +On success the routine returns zero, otherwise non-zero.
 14.1035 +
 14.1036 +\subsubsection*{File format}
 14.1037 +
 14.1038 +The file created by the routine \verb|glp_write_ipt| is a plain text
 14.1039 +file, which contains the following information:
 14.1040 +
 14.1041 +\begin{verbatim}
 14.1042 +   m n
 14.1043 +   stat obj_val
 14.1044 +   r_prim[1] r_dual[1]
 14.1045 +   . . .
 14.1046 +   r_prim[m] r_dual[m]
 14.1047 +   c_prim[1] c_dual[1]
 14.1048 +   . . .
 14.1049 +   c_prim[n] c_dual[n]
 14.1050 +\end{verbatim}
 14.1051 +
 14.1052 +\noindent
 14.1053 +where:
 14.1054 +
 14.1055 +\noindent
 14.1056 +$m$ is the number of rows (auxiliary variables);
 14.1057 +
 14.1058 +\noindent
 14.1059 +$n$ is the number of columns (structural variables);
 14.1060 +
 14.1061 +\noindent
 14.1062 +\verb|stat| is the solution status (\verb|GLP_UNDEF| = 1 or
 14.1063 +\verb|GLP_OPT| = 5);
 14.1064 +
 14.1065 +\noindent
 14.1066 +\verb|obj_val| is the objective value;
 14.1067 +
 14.1068 +\noindent
 14.1069 +\verb|r_prim[i]|, $i=1,\dots,m$, is the primal value of $i$-th row;
 14.1070 +
 14.1071 +\noindent
 14.1072 +\verb|r_dual[i]|, $i=1,\dots,m$, is the dual value of $i$-th row;
 14.1073 +
 14.1074 +\noindent
 14.1075 +\verb|c_prim[j]|, $j=1,\dots,n$, is the primal value of $j$-th column;
 14.1076 +
 14.1077 +\noindent
 14.1078 +\verb|c_dual[j]|, $j=1,\dots,n$, is the dual value of $j$-th column.
 14.1079 +
 14.1080 +\subsection{glp\_print\_mip---write MIP solution in printable format}
 14.1081 +
 14.1082 +\subsubsection*{Synopsis}
 14.1083 +
 14.1084 +\begin{verbatim}
 14.1085 +int glp_print_mip(glp_prob *lp, const char *fname);
 14.1086 +\end{verbatim}
 14.1087 +
 14.1088 +\subsubsection*{Description}
 14.1089 +
 14.1090 +The routine \verb|glp_print_mip| writes a best known integer solution
 14.1091 +of a MIP problem, which is specified by the pointer \verb|lp|, to a text
 14.1092 +file, whose name is the character string \verb|fname|, in printable
 14.1093 +format.
 14.1094 +
 14.1095 +Information reported by the routine \verb|glp_print_mip| is intended
 14.1096 +mainly for visual analysis.
 14.1097 +
 14.1098 +\subsubsection*{Returns}
 14.1099 +
 14.1100 +If no errors occurred, the routine returns zero. Otherwise the routine
 14.1101 +prints an error message and returns non-zero.
 14.1102 +
 14.1103 +\newpage
 14.1104 +
 14.1105 +\subsection{glp\_read\_mip---read MIP solution from text file}
 14.1106 +
 14.1107 +\subsubsection*{Synopsis}
 14.1108 +
 14.1109 +\begin{verbatim}
 14.1110 +int glp_read_mip(glp_prob *mip, const char *fname);
 14.1111 +\end{verbatim}
 14.1112 +
 14.1113 +\subsubsection*{Description}
 14.1114 +
 14.1115 +The routine \verb|glp_read_mip| reads MIP solution from a text file
 14.1116 +whose name is specified by the parameter \verb|fname| into the problem
 14.1117 +object.
 14.1118 +
 14.1119 +For the file format see description of the routine \verb|glp_write_mip|.
 14.1120 +
 14.1121 +\subsubsection*{Returns}
 14.1122 +
 14.1123 +On success the routine returns zero, otherwise non-zero.
 14.1124 +
 14.1125 +\subsection{glp\_write\_mip---write MIP solution to text file}
 14.1126 +
 14.1127 +\subsubsection*{Synopsis}
 14.1128 +
 14.1129 +\begin{verbatim}
 14.1130 +int glp_write_mip(glp_prob *mip, const char *fname);
 14.1131 +\end{verbatim}
 14.1132 +
 14.1133 +\subsubsection*{Description}
 14.1134 +
 14.1135 +The routine \verb|glp_write_mip| writes the current MIP solution to a
 14.1136 +text file whose name is specified by the parameter \verb|fname|. This
 14.1137 +file can be read back with the routine \verb|glp_read_mip|.
 14.1138 +
 14.1139 +\subsubsection*{Returns}
 14.1140 +
 14.1141 +On success the routine returns zero, otherwise non-zero.
 14.1142 +
 14.1143 +\subsubsection*{File format}
 14.1144 +
 14.1145 +The file created by the routine \verb|glp_write_sol| is a plain text
 14.1146 +file, which contains the following information:
 14.1147 +
 14.1148 +\begin{verbatim}
 14.1149 +   m n
 14.1150 +   stat obj_val
 14.1151 +   r_val[1]
 14.1152 +   . . .
 14.1153 +   r_val[m]
 14.1154 +   c_val[1]
 14.1155 +   . . .
 14.1156 +   c_val[n]
 14.1157 +\end{verbatim}
 14.1158 +
 14.1159 +\noindent
 14.1160 +where:
 14.1161 +
 14.1162 +\noindent
 14.1163 +$m$ is the number of rows (auxiliary variables);
 14.1164 +
 14.1165 +\noindent
 14.1166 +$n$ is the number of columns (structural variables);
 14.1167 +
 14.1168 +\noindent
 14.1169 +\verb|stat| is the solution status (\verb|GLP_UNDEF| = 1,
 14.1170 +\verb|GLP_FEAS| = 2, \verb|GLP_NOFEAS| = 4, or \verb|GLP_OPT| = 5);
 14.1171 +
 14.1172 +\noindent
 14.1173 +\verb|obj_val| is the objective value;
 14.1174 +
 14.1175 +\noindent
 14.1176 +\verb|r_val[i]|, $i=1,\dots,m$, is the value of $i$-th row;
 14.1177 +
 14.1178 +\noindent
 14.1179 +\verb|c_val[j]|, $j=1,\dots,n$, is the value of $j$-th column.
 14.1180 +
 14.1181 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 14.1182 +
 14.1183 +\newpage
 14.1184 +
 14.1185 +\section{Post-optimal analysis routines}
 14.1186 +
 14.1187 +\subsection{glp\_print\_ranges---print sensitivity analysis report}
 14.1188 +
 14.1189 +\subsubsection*{Synopsis}
 14.1190 +
 14.1191 +\begin{verbatim}
 14.1192 +int glp_print_ranges(glp_prob *P, int len, const int list[],
 14.1193 +      int flags, const char *fname);
 14.1194 +\end{verbatim}
 14.1195 +
 14.1196 +\subsubsection*{Description}
 14.1197 +
 14.1198 +The routine \verb|glp_print_ranges| performs sensitivity analysis of
 14.1199 +current optimal basic solution and writes the analysis report in
 14.1200 +human-readable format to a text file, whose name is the character
 14.1201 +string {\it fname}. (Detailed description of the report structure is
 14.1202 +given below.)
 14.1203 +
 14.1204 +The parameter {\it len} specifies the length of the row/column list.
 14.1205 +
 14.1206 +The array {\it list} specifies ordinal number of rows and columns to be
 14.1207 +analyzed. The ordinal numbers should be passed in locations
 14.1208 +{\it list}[1], {\it list}[2], \dots, {\it list}[{\it len}]. Ordinal
 14.1209 +numbers from 1 to $m$ refer to rows, and ordinal numbers from $m+1$ to
 14.1210 +$m+n$ refer to columns, where $m$ and $n$ are, resp., the total number
 14.1211 +of rows and columns in the problem object. Rows and columns appear in
 14.1212 +the analysis report in the same order as they follow in the array list.
 14.1213 +
 14.1214 +It is allowed to specify $len=0$, in which case the array {\it list} is
 14.1215 +not used (so it can be specified as \verb|NULL|), and the routine
 14.1216 +performs analysis for all rows and columns of the problem object.
 14.1217 +
 14.1218 +The parameter {\it flags} is reserved for use in the future and must be
 14.1219 +specified as zero.
 14.1220 +
 14.1221 +On entry to the routine \verb|glp_print_ranges| the current basic
 14.1222 +solution must be optimal and the basis factorization must exist.
 14.1223 +The application program can check that with the routine
 14.1224 +\verb|glp_bf_exists|, and if the factorization does
 14.1225 +not exist, compute it with the routine \verb|glp_factorize|. Note that
 14.1226 +if the LP preprocessor is not used, on normal exit from the simplex
 14.1227 +solver routine \verb|glp_simplex| the basis factorization always exists.
 14.1228 +
 14.1229 +\subsubsection*{Returns}
 14.1230 +
 14.1231 +If the operation was successful, the routine \verb|glp_print_ranges|
 14.1232 +returns zero. Otherwise, it prints an error message and returns
 14.1233 +non-zero.
 14.1234 +
 14.1235 +\subsubsection*{Analysis report example}
 14.1236 +
 14.1237 +An example of the sensitivity analysis report is shown on the next two
 14.1238 +pages. This example corresponds to the example of LP problem described
 14.1239 +in Subsection ``Example of MPS file''.
 14.1240 +
 14.1241 +\subsubsection*{Structure of the analysis report}
 14.1242 +
 14.1243 +For each row and column specified in the array {\it list} the routine
 14.1244 +prints two lines containing generic information and analysis
 14.1245 +information, which depends on the status of corresponding row or column.
 14.1246 +
 14.1247 +Note that analysis of a row is analysis of its auxiliary variable,
 14.1248 +which is equal to the row linear form $\sum a_jx_j$, and analysis of
 14.1249 +a column is analysis of corresponding structural variable. Therefore,
 14.1250 +formally, on performing the sensitivity analysis there is no difference
 14.1251 +between rows and columns.
 14.1252 +
 14.1253 +\bigskip
 14.1254 +
 14.1255 +\noindent
 14.1256 +{\it Generic information}
 14.1257 +
 14.1258 +\medskip
 14.1259 +
 14.1260 +\noindent
 14.1261 +{\tt No.} is the row or column ordinal number in the problem object.
 14.1262 +Rows are numbered from 1 to $m$, and columns are numbered from 1 to $n$,
 14.1263 +where $m$ and $n$ are, resp., the total number of rows and columns in
 14.1264 +the problem object.
 14.1265 +
 14.1266 +\medskip
 14.1267 +
 14.1268 +\noindent
 14.1269 +{\tt Row name} is the symbolic name assigned to the row. If the row has
 14.1270 +no name assigned, this field contains blanks.
 14.1271 +
 14.1272 +\medskip
 14.1273 +
 14.1274 +\noindent
 14.1275 +{\tt Column name} is the symbolic name assigned to the column. If the
 14.1276 +column has no name assigned, this field contains blanks.
 14.1277 +
 14.1278 +\medskip
 14.1279 +
 14.1280 +\noindent
 14.1281 +{\tt St} is the status of the row or column in the optimal solution:
 14.1282 +
 14.1283 +{\tt BS} --- non-active constraint (row), basic column;
 14.1284 +
 14.1285 +{\tt NL} --- inequality constraint having its lower right-hand side
 14.1286 +active (row), non-basic column having its lower bound active;
 14.1287 +
 14.1288 +{\tt NU} --- inequality constraint having its upper right-hand side
 14.1289 +active (row), non-basic column having its upper bound active;
 14.1290 +
 14.1291 +{\tt NS} --- active equality constraint (row), non-basic fixed column.
 14.1292 +
 14.1293 +{\tt NF} --- active free row, non-basic free (unbounded) column. (This
 14.1294 +case means that the optimal solution is dual degenerate.)
 14.1295 +
 14.1296 +\medskip
 14.1297 +
 14.1298 +\noindent
 14.1299 +{\tt Activity} is the (primal) value of the auxiliary variable (row) or
 14.1300 +structural variable (column) in the optimal solution.
 14.1301 +
 14.1302 +\medskip
 14.1303 +
 14.1304 +\noindent
 14.1305 +{\tt Slack} is the (primal) value of the row slack variable.
 14.1306 +
 14.1307 +\medskip
 14.1308 +
 14.1309 +\noindent
 14.1310 +{\tt Obj coef} is the objective coefficient of the column (structural
 14.1311 +variable).
 14.1312 +
 14.1313 +\begin{landscape}
 14.1314 +\begin{scriptsize}
 14.1315 +\begin{verbatim}
 14.1316 +GLPK 4.42 - SENSITIVITY ANALYSIS REPORT                                                                         Page   1
 14.1317 +
 14.1318 +Problem:    PLAN
 14.1319 +Objective:  VALUE = 296.2166065 (MINimum)
 14.1320 +
 14.1321 +   No. Row name     St      Activity         Slack   Lower bound       Activity      Obj coef  Obj value at Limiting
 14.1322 +                                          Marginal   Upper bound          range         range   break point variable
 14.1323 +------ ------------ -- ------------- ------------- -------------  ------------- ------------- ------------- ------------
 14.1324 +     1 VALUE        BS     296.21661    -296.21661          -Inf      299.25255      -1.00000        .      MN
 14.1325 +                                            .               +Inf      296.21661          +Inf          +Inf
 14.1326 +
 14.1327 +     2 YIELD        NS    2000.00000        .         2000.00000     1995.06864          -Inf     296.28365 BIN3
 14.1328 +                                           -.01360    2000.00000     2014.03479          +Inf     296.02579 CU
 14.1329 +
 14.1330 +     3 FE           NU      60.00000        .               -Inf       55.89016          -Inf     306.77162 BIN4
 14.1331 +                                          -2.56823      60.00000       62.69978       2.56823     289.28294 BIN3
 14.1332 +
 14.1333 +     4 CU           BS      83.96751      16.03249          -Inf       93.88467       -.30613     270.51157 MN
 14.1334 +                                            .          100.00000       79.98213        .21474     314.24798 BIN5
 14.1335 +
 14.1336 +     5 MN           NU      40.00000        .               -Inf       34.42336          -Inf     299.25255 BIN4
 14.1337 +                                           -.54440      40.00000       41.68691        .54440     295.29825 BIN3
 14.1338 +
 14.1339 +     6 MG           BS      19.96029      10.03971          -Inf       24.74427      -1.79618     260.36433 BIN1
 14.1340 +                                            .           30.00000        9.40292        .28757     301.95652 MN
 14.1341 +
 14.1342 +     7 AL           NL    1500.00000        .         1500.00000     1485.78425       -.25199     292.63444 CU
 14.1343 +                                            .25199          +Inf     1504.92126          +Inf     297.45669 BIN3
 14.1344 +
 14.1345 +     8 SI           NL     250.00000      50.00000     250.00000      235.32871       -.48520     289.09812 CU
 14.1346 +                                            .48520     300.00000      255.06073          +Inf     298.67206 BIN3
 14.1347 +\end{verbatim}
 14.1348 +\end{scriptsize}
 14.1349 +\end{landscape}
 14.1350 +
 14.1351 +\begin{landscape}
 14.1352 +\begin{scriptsize}
 14.1353 +\begin{verbatim}
 14.1354 +GLPK 4.42 - SENSITIVITY ANALYSIS REPORT                                                                         Page   2
 14.1355 +
 14.1356 +Problem:    PLAN
 14.1357 +Objective:  VALUE = 296.2166065 (MINimum)
 14.1358 +
 14.1359 +   No. Column name  St      Activity      Obj coef   Lower bound       Activity      Obj coef  Obj value at Limiting
 14.1360 +                                          Marginal   Upper bound          range         range   break point variable
 14.1361 +------ ------------ -- ------------- ------------- -------------  ------------- ------------- ------------- ------------
 14.1362 +     1 BIN1         NL        .             .03000        .           -28.82475       -.22362     288.90594 BIN4
 14.1363 +                                            .25362     200.00000       33.88040          +Inf     304.80951 BIN4
 14.1364 +
 14.1365 +     2 BIN2         BS     665.34296        .08000        .           802.22222        .01722     254.44822 BIN1
 14.1366 +                                            .         2500.00000      313.43066        .08863     301.95652 MN
 14.1367 +
 14.1368 +     3 BIN3         BS     490.25271        .17000     400.00000      788.61314        .15982     291.22807 MN
 14.1369 +                                            .          800.00000     -347.42857        .17948     300.86548 BIN5
 14.1370 +
 14.1371 +     4 BIN4         BS     424.18773        .12000     100.00000      710.52632        .10899     291.54745 MN
 14.1372 +                                            .          700.00000     -256.15524        .14651     307.46010 BIN1
 14.1373 +
 14.1374 +     5 BIN5         NL        .             .15000        .          -201.78739        .13544     293.27940 BIN3
 14.1375 +                                            .01456    1500.00000       58.79586          +Inf     297.07244 BIN3
 14.1376 +
 14.1377 +     6 ALUM         BS     299.63899        .21000        .           358.26772        .18885     289.87879 AL
 14.1378 +                                            .               +Inf      112.40876        .22622     301.07527 MN
 14.1379 +
 14.1380 +     7 SILICON      BS     120.57762        .38000        .           124.27093        .14828     268.27586 BIN5
 14.1381 +                                            .               +Inf       85.54745        .46667     306.66667 MN
 14.1382 +
 14.1383 +End of report
 14.1384 +\end{verbatim}
 14.1385 +\end{scriptsize}
 14.1386 +\end{landscape}
 14.1387 +
 14.1388 +\noindent
 14.1389 +{\tt Marginal} is the reduced cost (dual activity) of the auxiliary
 14.1390 +variable (row) or structural variable (column).
 14.1391 +
 14.1392 +\medskip
 14.1393 +
 14.1394 +\noindent
 14.1395 +{\tt Lower bound} is the lower right-hand side (row) or lower bound
 14.1396 +(column). If the row or column has no lower bound, this field contains
 14.1397 +{\tt -Inf}.
 14.1398 +
 14.1399 +\medskip
 14.1400 +
 14.1401 +\noindent
 14.1402 +{\tt Upper bound} is the upper right-hand side (row) or upper bound
 14.1403 +(column). If the row or column has no upper bound, this field contains
 14.1404 +{\tt +Inf}.
 14.1405 +
 14.1406 +\bigskip
 14.1407 +
 14.1408 +\noindent
 14.1409 +{\it Sensitivity analysis of active bounds}
 14.1410 +
 14.1411 +\medskip
 14.1412 +
 14.1413 +\noindent
 14.1414 +The sensitivity analysis of active bounds is performed only for rows,
 14.1415 +which are active constraints, and only for non-basic columns, because
 14.1416 +inactive constraints and basic columns have no active bounds.
 14.1417 +
 14.1418 +For every auxiliary (row) or structural (column) non-basic variable the
 14.1419 +routine starts changing its active bound in both direction. The first
 14.1420 +of the two lines in the report corresponds to decreasing, and the
 14.1421 +second line corresponds to increasing of the active bound. Since the
 14.1422 +variable being analyzed is non-basic, its activity, which is equal to
 14.1423 +its active bound, also starts changing. This changing leads to changing
 14.1424 +of basic (auxiliary and structural) variables, which depend on the
 14.1425 +non-basic variable. The current basis remains primal feasible and
 14.1426 +therefore optimal while values of all basic variables are primal
 14.1427 +feasible, i.e. are within their bounds. Therefore, if some basic
 14.1428 +variable called the {\it limiting variable} reaches its (lower or
 14.1429 +upper) bound first, before any other basic variables, it thereby limits
 14.1430 +further changing of the non-basic variable, because otherwise the
 14.1431 +current basis would become primal infeasible. The point, at which this
 14.1432 +happens, is called the {\it break point}. Note that there are two break
 14.1433 +points: the lower break point, which corresponds to decreasing of the
 14.1434 +non-basic variable, and the upper break point, which corresponds to
 14.1435 +increasing of the non-basic variable.
 14.1436 +
 14.1437 +In the analysis report values of the non-basic variable (i.e. of its
 14.1438 +active bound) being analyzed at both lower and upper break points are
 14.1439 +printed in the field `{\tt Activity range}'. Corresponding values of
 14.1440 +the objective function are printed in the field `{\tt Obj value at
 14.1441 +break point}', and symbolic names of corresponding limiting basic
 14.1442 +variables are printed in the field `{\tt Limiting variable}'.
 14.1443 +If the active bound can decrease or/and increase unlimitedly, the field
 14.1444 +`{\tt Activity range}' contains {\tt -Inf} or/and {\tt +Inf}, resp.
 14.1445 +
 14.1446 +For example (see the example report above), row SI is a double-sided
 14.1447 +constraint, which is active on its lower bound (right-hand side), and
 14.1448 +its activity in the optimal solution being equal to the lower bound is
 14.1449 +250. The activity range for this row is $[235.32871,255.06073]$. This
 14.1450 +means that the basis remains optimal while the lower bound is
 14.1451 +increasing up to 255.06073, and further increasing is limited by
 14.1452 +(structural) variable BIN3. If the lower bound reaches this upper break
 14.1453 +point, the objective value becomes equal to 298.67206.
 14.1454 +
 14.1455 +Note that if the basis does not change, the objective function depends
 14.1456 +on the non-basic variable linearly, and the per-unit change of the
 14.1457 +objective function is the reduced cost (marginal value) of the
 14.1458 +non-basic variable.
 14.1459 +
 14.1460 +\bigskip
 14.1461 +
 14.1462 +\noindent
 14.1463 +{\it Sensitivity analysis of objective coefficients at non-basic
 14.1464 +variables}
 14.1465 +
 14.1466 +\medskip
 14.1467 +
 14.1468 +\noindent
 14.1469 +The sensitivity analysis of the objective coefficient at a non-basic
 14.1470 +variable is quite simple, because in this case change in the objective
 14.1471 +coefficient leads to equivalent change in the reduced cost (marginal
 14.1472 +value).
 14.1473 +
 14.1474 +For every auxiliary (row) or structural (column) non-basic variable the
 14.1475 +routine starts changing its objective coefficient in both direction.
 14.1476 +(Note that auxiliary variables are not included in the objective
 14.1477 +function and therefore always have zero objective coefficients.) The
 14.1478 +first of the two lines in the report corresponds to decreasing, and the
 14.1479 +second line corresponds to increasing of the objective coefficient.
 14.1480 +This changing leads to changing of the reduced cost of the non-basic
 14.1481 +variable to be analyzed and does affect reduced costs of all other
 14.1482 +non-basic variables. The current basis remains dual feasible and
 14.1483 +therefore optimal while the reduced cost keeps its sign. Therefore, if
 14.1484 +the reduced cost reaches zero, it limits further changing of the
 14.1485 +objective coefficient (if only the non-basic variable is non-fixed).
 14.1486 +
 14.1487 +In the analysis report minimal and maximal values of the objective
 14.1488 +coefficient, on which the basis remains optimal, are printed in the
 14.1489 +field `\verb|Obj coef range|'. If the objective coefficient can
 14.1490 +decrease or/and increase unlimitedly, this field contains {\tt -Inf}
 14.1491 +or/and {\tt +Inf}, resp.
 14.1492 +
 14.1493 +For example (see the example report above), column BIN5 is non-basic
 14.1494 +having its lower bound active. Its objective coefficient is 0.15, and
 14.1495 +reduced cost in the optimal solution 0.01456. The column lower bound
 14.1496 +remains active while the column reduced cost remains non-negative,
 14.1497 +thus, minimal value of the objective coefficient, on which the current
 14.1498 +basis still remains optimal, is $0.15-0.01456=0.13644$, that is
 14.1499 +indicated in the field `\verb|Obj coef range|'.
 14.1500 +
 14.1501 +\bigskip
 14.1502 +
 14.1503 +\noindent
 14.1504 +{\it Sensitivity analysis of objective coefficients at basic variables}
 14.1505 +
 14.1506 +\medskip
 14.1507 +
 14.1508 +\noindent
 14.1509 +To perform sensitivity analysis for every auxiliary (row) or structural
 14.1510 +(column) variable the routine starts changing its objective coefficient
 14.1511 +in both direction. (Note that auxiliary variables are not included in
 14.1512 +the objective function and therefore always have zero objective
 14.1513 +coefficients.) The first of the two lines in the report corresponds to
 14.1514 +decreasing, and the second line corresponds to increasing of the
 14.1515 +objective coefficient. This changing leads to changing of reduced costs
 14.1516 +of non-basic variables. The current basis remains dual feasible and
 14.1517 +therefore optimal while reduced costs of all non-basic variables
 14.1518 +(except fixed variables) keep their signs. Therefore, if the reduced
 14.1519 +cost of some non-basic non-fixed variable called the {\it limiting
 14.1520 +variable} reaches zero first, before reduced cost of any other
 14.1521 +non-basic non-fixed variable, it thereby limits further changing of the
 14.1522 +objective coefficient, because otherwise the current basis would become
 14.1523 +dual infeasible (non-optimal). The point, at which this happens, is
 14.1524 +called the {\it break point}. Note that there are two break points: the
 14.1525 +lower break point, which corresponds to decreasing of the objective
 14.1526 +coefficient, and the upper break point, which corresponds to increasing
 14.1527 +of the objective coefficient. Let the objective coefficient reach its
 14.1528 +limit value and continue changing a bit further in the same direction
 14.1529 +that makes the current basis dual infeasible (non-optimal). Then the
 14.1530 +reduced cost of the non-basic limiting variable becomes ``a bit'' dual
 14.1531 +infeasible that forces the limiting variable to enter the basis
 14.1532 +replacing there some basic variable, which leaves the basis to keep its
 14.1533 +primal feasibility. It should be understood that if we change the
 14.1534 +current basis in this way exactly at the break point, both the current
 14.1535 +and adjacent bases will be optimal with the same objective value,
 14.1536 +because at the break point the limiting variable has zero reduced cost.
 14.1537 +On the other hand, in the adjacent basis the value of the limiting
 14.1538 +variable changes, because there it becomes basic, that leads to
 14.1539 +changing of the value of the basic variable being analyzed. Note that
 14.1540 +on determining the adjacent basis the bounds of the analyzed basic
 14.1541 +variable are ignored as if it were a free (unbounded) variable, so it
 14.1542 +cannot leave the current basis.
 14.1543 +
 14.1544 +In the analysis report lower and upper limits of the objective
 14.1545 +coefficient at the basic variable being analyzed, when the basis
 14.1546 +remains optimal, are printed in the field `{\tt Obj coef range}'.
 14.1547 +Corresponding values of the objective function at both lower and upper
 14.1548 +break points are printed in the field `{\tt Obj value at break point}',
 14.1549 +symbolic names of corresponding non-basic limiting variables are
 14.1550 +printed in the field `{\tt Limiting variable}', and values of the basic
 14.1551 +variable, which it would take on in the adjacent bases (as was
 14.1552 +explained above) are printed in the field `{\tt Activity range}'.
 14.1553 +If the objective coefficient can increase or/and decrease unlimitedly,
 14.1554 +the field `{\tt Obj coef range}' contains {\tt -Inf} and/or {\tt +Inf},
 14.1555 +resp. It also may happen that no dual feasible adjacent basis exists
 14.1556 +(i.e. on entering the basis the limiting variable can increase or
 14.1557 +decrease unlimitedly), in which case the field `{\tt Activity range}'
 14.1558 +contains {\tt -Inf} and/or {\tt +Inf}.
 14.1559 +
 14.1560 +\newpage
 14.1561 +
 14.1562 +For example (see the example report above), structural variable
 14.1563 +(column) BIN3 is basic, its optimal value is 490.25271, and its
 14.1564 +objective coefficient is 0.17. The objective coefficient range for this
 14.1565 +column is $[0.15982,0.17948]$. This means that the basis remains
 14.1566 +optimal while the objective coefficient is decreasing down to 0.15982,
 14.1567 +and further decreasing is limited by (auxiliary) variable MN. If we
 14.1568 +make the objective coefficient a bit less than 0.15982, the limiting
 14.1569 +variable MN will enter the basis, and in that adjacent basis the
 14.1570 +structural variable BIN3 will take on new optimal value 788.61314. At
 14.1571 +the lower break point, where the objective coefficient is exactly
 14.1572 +0.15982, the objective function takes on the value 291.22807 in both
 14.1573 +the current and adjacent bases.
 14.1574 +
 14.1575 +Note that if the basis does not change, the objective function depends
 14.1576 +on the objective coefficient at the basic variable linearly, and the
 14.1577 +per-unit change of the objective function is the value of the basic
 14.1578 +variable.
 14.1579 +
 14.1580 +%* eof *%
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/doc/glpk04.tex	Mon Dec 06 13:09:21 2010 +0100
    15.3 @@ -0,0 +1,1411 @@
    15.4 +%* glpk04.tex *%
    15.5 +
    15.6 +\chapter{Advanced API Routines}
    15.7 +
    15.8 +\section{Background}
    15.9 +\label{basbgd}
   15.10 +
   15.11 +Using vector and matrix notations LP problem (1.1)---(1.3) (see Section
   15.12 +\ref{seclp}, page \pageref{seclp}) can be stated as follows:
   15.13 +
   15.14 +\medskip
   15.15 +
   15.16 +\noindent
   15.17 +\hspace{.5in} minimize (or maximize)
   15.18 +$$z=c^Tx_S+c_0\eqno(3.1)$$
   15.19 +\hspace{.5in} subject to linear constraints
   15.20 +$$x_R=Ax_S\eqno(3.2)$$
   15.21 +\hspace{.5in} and bounds of variables
   15.22 +$$
   15.23 +\begin{array}{l@{\ }c@{\ }l@{\ }c@{\ }l}
   15.24 +l_R&\leq&x_R&\leq&u_R\\
   15.25 +l_S&\leq&x_S&\leq&u_S\\
   15.26 +\end{array}\eqno(3.3)
   15.27 +$$
   15.28 +where:
   15.29 +
   15.30 +\noindent
   15.31 +$x_R=(x_1,\dots,x_m)$ is the vector of auxiliary variables;
   15.32 +
   15.33 +\noindent
   15.34 +$x_S=(x_{m+1},\dots,x_{m+n})$ is the vector of structural
   15.35 +variables;
   15.36 +
   15.37 +\noindent
   15.38 +$z$ is the objective function;
   15.39 +
   15.40 +\noindent
   15.41 +$c=(c_1,\dots,c_n)$ is the vector of objective coefficients;
   15.42 +
   15.43 +\noindent
   15.44 +$c_0$ is the constant term (``shift'') of the objective function;
   15.45 +
   15.46 +\noindent
   15.47 +$A=(a_{11},\dots,a_{mn})$ is the constraint matrix;
   15.48 +
   15.49 +\noindent
   15.50 +$l_R=(l_1,\dots,l_m)$ is the vector of lower bounds of auxiliary
   15.51 +variables;
   15.52 +
   15.53 +\noindent
   15.54 +$u_R=(u_1,\dots,u_m)$ is the vector of upper bounds of auxiliary
   15.55 +variables;
   15.56 +
   15.57 +\noindent
   15.58 +$l_S=(l_{m+1},\dots,l_{m+n})$ is the vector of lower bounds of
   15.59 +structural variables;
   15.60 +
   15.61 +\noindent
   15.62 +$u_S=(u_{m+1},\dots,u_{m+n})$ is the vector of upper bounds of
   15.63 +structural variables.
   15.64 +
   15.65 +\medskip
   15.66 +
   15.67 +From the simplex method's standpoint there is no difference between
   15.68 +auxiliary and structural variables. This allows combining all these
   15.69 +variables into one vector that leads to the following problem statement:
   15.70 +
   15.71 +\medskip
   15.72 +
   15.73 +\noindent
   15.74 +\hspace{.5in} minimize (or maximize)
   15.75 +$$z=(0\ |\ c)^Tx+c_0\eqno(3.4)$$
   15.76 +\hspace{.5in} subject to linear constraints
   15.77 +$$(I\ |-\!A)x=0\eqno(3.5)$$
   15.78 +\hspace{.5in} and bounds of variables
   15.79 +$$l\leq x\leq u\eqno(3.6)$$
   15.80 +where:
   15.81 +
   15.82 +\noindent
   15.83 +$x=(x_R\ |\ x_S)$ is the $(m+n)$-vector of (all) variables;
   15.84 +
   15.85 +\noindent
   15.86 +$(0\ |\ c)$ is the $(m+n)$-vector of objective
   15.87 +coefficients;\footnote{Subvector 0 corresponds to objective coefficients
   15.88 +at auxiliary variables.}
   15.89 +
   15.90 +\noindent
   15.91 +$(I\ |-\!A)$ is the {\it augmented} constraint
   15.92 +$m\times(m+n)$-matrix;\footnote{Note that due to auxiliary variables
   15.93 +matrix $(I\ |-\!A)$ contains the unity submatrix and therefore has full
   15.94 +rank. This means, in particular, that the system (3.5) has no linearly
   15.95 +dependent constraints.}
   15.96 +
   15.97 +\noindent
   15.98 +$l=(l_R\ |\ l_S)$ is the $(m+n)$-vector of lower bounds of (all)
   15.99 +variables;
  15.100 +
  15.101 +\noindent
  15.102 +$u=(u_R\ |\ u_S)$ is the $(m+n)$-vector of upper bounds of (all)
  15.103 +variables.
  15.104 +
  15.105 +\medskip
  15.106 +
  15.107 +By definition an {\it LP basic solution} geometrically is a point in
  15.108 +the space of all variables, which is the intersection of planes
  15.109 +corresponding to active constraints\footnote{A constraint is called
  15.110 +{\it active} if in a given point it is satisfied as equality, otherwise
  15.111 +it is called {\it inactive}.}. The space of all variables has the
  15.112 +dimension $m+n$, therefore, to define some basic solution we have to
  15.113 +define $m+n$ active constraints. Note that $m$ constraints (3.5) being
  15.114 +linearly independent equalities are always active, so remaining $n$
  15.115 +active constraints can be chosen only from bound constraints (3.6).
  15.116 +
  15.117 +A variable is called {\it non-basic}, if its (lower or upper) bound is
  15.118 +active, otherwise it is called {\it basic}. Since, as was said above,
  15.119 +exactly $n$ bound constraints must be active, in any basic solution
  15.120 +there are always $n$ non-basic variables and $m$ basic variables.
  15.121 +(Note that a free variable also can be non-basic. Although such
  15.122 +variable has no bounds, we can think it as the difference between two
  15.123 +non-negative variables, which both are non-basic in this case.)
  15.124 +
  15.125 +Now consider how to determine numeric values of all variables for a
  15.126 +given basic solution.
  15.127 +
  15.128 +Let $\Pi$ be an appropriate permutation matrix of the order $(m+n)$.
  15.129 +Then we can write:
  15.130 +$$\left(\begin{array}{@{}c@{}}x_B\\x_N\\\end{array}\right)=
  15.131 +\Pi\left(\begin{array}{@{}c@{}}x_R\\x_S\\\end{array}\right)=\Pi x,
  15.132 +\eqno(3.7)$$
  15.133 +where $x_B$ is the vector of basic variables, $x_N$ is the vector of
  15.134 +non-basic variables, $x=(x_R\ |\ x_S)$ is the vector of all variables
  15.135 +in the original order. In this case the system of linear constraints
  15.136 +(3.5) can be rewritten as follows:
  15.137 +$$(I\ |-\!A)\Pi^T\Pi x=0\ \ \ \Rightarrow\ \ \ (B\ |\ N)
  15.138 +\left(\begin{array}{@{}c@{}}x_B\\x_N\\\end{array}\right)=0,\eqno(3.8)$$
  15.139 +where
  15.140 +$$(B\ |\ N)=(I\ |-\!A)\Pi^T.\eqno(3.9)$$
  15.141 +Matrix $B$ is a square non-singular $m\times m$-matrix, which is
  15.142 +composed from columns of the augmented constraint matrix corresponding
  15.143 +to basic variables. It is called the {\it basis matrix} or simply the
  15.144 +{\it basis}. Matrix $N$ is a rectangular $m\times n$-matrix, which is
  15.145 +composed from columns of the augmented constraint matrix corresponding
  15.146 +to non-basic variables.
  15.147 +
  15.148 +From (3.8) it follows that:
  15.149 +$$Bx_B+Nx_N=0,\eqno(3.10)$$
  15.150 +therefore,
  15.151 +$$x_B=-B^{-1}Nx_N.\eqno(3.11)$$
  15.152 +Thus, the formula (3.11) shows how to determine numeric values of basic
  15.153 +variables $x_B$ assuming that non-basic variables $x_N$ are fixed on
  15.154 +their active bounds.
  15.155 +
  15.156 +The $m\times n$-matrix
  15.157 +$$\Xi=-B^{-1}N,\eqno(3.12)$$
  15.158 +which appears in (3.11), is called the {\it simplex
  15.159 +tableau}.\footnote{This definition corresponds to the GLPK
  15.160 +implementation.} It shows how basic variables depend on non-basic
  15.161 +variables:
  15.162 +$$x_B=\Xi x_N.\eqno(3.13)$$
  15.163 +
  15.164 +The system (3.13) is equivalent to the system (3.5) in the sense that
  15.165 +they both define the same set of points in the space of (primal)
  15.166 +variables, which satisfy to these systems. If, moreover, values of all
  15.167 +basic variables satisfy to their bound constraints (3.3), the
  15.168 +corresponding basic solution is called {\it (primal) feasible},
  15.169 +otherwise {\it (primal) infeasible}. It is understood that any (primal)
  15.170 +feasible basic solution satisfy to all constraints (3.2) and (3.3).
  15.171 +
  15.172 +The LP theory says that if LP has optimal solution, it has (at least
  15.173 +one) basic feasible solution, which corresponds to the optimum. And the
  15.174 +most natural way to determine whether a given basic solution is optimal
  15.175 +or not is to use the Karush---Kuhn---Tucker optimality conditions.
  15.176 +
  15.177 +\def\arraystretch{1.5}
  15.178 +
  15.179 +For the problem statement (3.4)---(3.6) the optimality conditions are
  15.180 +the following:\footnote{These conditions can be appiled to any solution,
  15.181 +not only to a basic solution.}
  15.182 +$$(I\ |-\!A)x=0\eqno(3.14)$$
  15.183 +$$(I\ |-\!A)^T\pi+\lambda_l+\lambda_u=\nabla z=(0\ |\ c)^T\eqno(3.15)$$
  15.184 +$$l\leq x\leq u\eqno(3.16)$$
  15.185 +$$\lambda_l\geq 0,\ \ \lambda_u\leq 0\ \ \mbox{(minimization)}
  15.186 +\eqno(3.17)$$
  15.187 +$$\lambda_l\leq 0,\ \ \lambda_u\geq 0\ \ \mbox{(maximization)}
  15.188 +\eqno(3.18)$$
  15.189 +$$(\lambda_l)_k(x_k-l_k)=0,\ \ (\lambda_u)_k(x_k-u_k)=0,\ \ k=1,2,\dots,
  15.190 +m+n\eqno(3.19)$$
  15.191 +where:
  15.192 +$\pi=(\pi_1,\pi_2,\dots,\pi_m)$ is a $m$-vector of Lagrange
  15.193 +multipliers for equality constraints (3.5);
  15.194 +$\lambda_l=[(\lambda_l)_1,(\lambda_l)_2,\dots,(\lambda_l)_n]$ is a
  15.195 +$n$-vector of Lagrange multipliers for lower bound constraints (3.6);
  15.196 +$\lambda_u=[(\lambda_u)_1,(\lambda_u)_2,\dots,(\lambda_u)_n]$ is a
  15.197 +$n$-vector of Lagrange multipliers for upper bound constraints (3.6).
  15.198 +
  15.199 +Condition (3.14) is the {\it primal} (original) system of equality
  15.200 +constraints (3.5).
  15.201 +
  15.202 +Condition (3.15) is the {\it dual} system of equality constraints.
  15.203 +It requires the gradient of the objective function to be a linear
  15.204 +combination of normals to the planes defined by constraints of the
  15.205 +original problem.
  15.206 +
  15.207 +Condition (3.16) is the primal (original) system of bound constraints
  15.208 +(3.6).
  15.209 +
  15.210 +Condition (3.17) (or (3.18) in case of maximization) is the dual system
  15.211 +of bound constraints.
  15.212 +
  15.213 +Condition (3.19) is the {\it complementary slackness condition}. It
  15.214 +requires, for each original (auxiliary or structural) variable $x_k$,
  15.215 +that either its (lower or upper) bound must be active, or zero bound of
  15.216 +the corresponding Lagrange multiplier ($(\lambda_l)_k$ or
  15.217 +$(\lambda_u)_k$) must be active.
  15.218 +
  15.219 +In GLPK two multipliers $(\lambda_l)_k$ and $(\lambda_u)_k$ for each
  15.220 +primal (original) variable $x_k$, $k=1,2,\dots,m+n$, are combined into
  15.221 +one multiplier:
  15.222 +$$\lambda_k=(\lambda_l)_k+(\lambda_u)_k,\eqno(3.20)$$
  15.223 +which is called a {\it dual variable} for $x_k$. This {\it cannot} lead
  15.224 +to the ambiguity, because both lower and upper bounds of $x_k$ cannot be
  15.225 +active at the same time,\footnote{If $x_k$ is a fixed variable, we can
  15.226 +think it as double-bounded variable $l_k\leq x_k\leq u_k$, where
  15.227 +$l_k=u_k.$} so at least one of $(\lambda_l)_k$ and $(\lambda_u)_k$ must
  15.228 +be equal to zero, and because these multipliers have different signs,
  15.229 +the combined multiplier, which is their sum, uniquely defines each of
  15.230 +them.
  15.231 +
  15.232 +\def\arraystretch{1}
  15.233 +
  15.234 +Using dual variables $\lambda_k$ the dual system of bound constraints
  15.235 +(3.17) and (3.18) can be written in the form of so called {\it ``rule of
  15.236 +signs''} as follows:
  15.237 +
  15.238 +\begin{center}
  15.239 +\begin{tabular}{|@{\,}c@{$\,$}|@{$\,$}c@{$\,$}|@{$\,$}c@{$\,$}|
  15.240 +@{$\,$}c|c@{$\,$}|@{$\,$}c@{$\,$}|@{$\,$}c@{$\,$}|}
  15.241 +\hline
  15.242 +Original bound&\multicolumn{3}{c|}{Minimization}&\multicolumn{3}{c|}
  15.243 +{Maximization}\\
  15.244 +\cline{2-7}
  15.245 +constraint&$(\lambda_l)_k$&$(\lambda_u)_k$&$(\lambda_l)_k+
  15.246 +(\lambda_u)_k$&$(\lambda_l)_k$&$(\lambda_u)_k$&$(\lambda_l)_k+
  15.247 +(\lambda_u)_k$\\
  15.248 +\hline
  15.249 +$-\infty<x_k<+\infty$&$=0$&$=0$&$\lambda_k=0$&$=0$&$=0$&$\lambda_k=0$\\
  15.250 +$x_k\geq l_k$&$\geq 0$&$=0$&$\lambda_k\geq 0$&$\leq 0$&$=0$&$\lambda_k
  15.251 +\leq0$\\
  15.252 +$x_k\leq u_k$&$=0$&$\leq 0$&$\lambda_k\leq 0$&$=0$&$\geq 0$&$\lambda_k
  15.253 +\geq0$\\
  15.254 +$l_k\leq x_k\leq u_k$&$\geq 0$& $\leq 0$& $-\infty\!<\!\lambda_k\!<
  15.255 +\!+\infty$
  15.256 +&$\leq 0$& $\geq 0$& $-\infty\!<\!\lambda_k\!<\!+\infty$\\
  15.257 +$x_k=l_k=u_k$&$\geq 0$& $\leq 0$& $-\infty\!<\!\lambda_k\!<\!+\infty$&
  15.258 +$\leq 0$&
  15.259 +$\geq 0$& $-\infty\!<\!\lambda_k\!<\!+\infty$\\
  15.260 +\hline
  15.261 +\end{tabular}
  15.262 +\end{center}
  15.263 +
  15.264 +May note that each primal variable $x_k$ has its dual counterpart
  15.265 +$\lambda_k$ and vice versa. This allows applying the same partition for
  15.266 +the vector of dual variables as (3.7):
  15.267 +$$\left(\begin{array}{@{}c@{}}\lambda_B\\\lambda_N\\\end{array}\right)=
  15.268 +\Pi\lambda,\eqno(3.21)$$
  15.269 +where $\lambda_B$ is a vector of dual variables for basic variables
  15.270 +$x_B$, $\lambda_N$ is a vector of dual variables for non-basic variables
  15.271 +$x_N$.
  15.272 +
  15.273 +By definition, bounds of basic variables are inactive constraints, so in
  15.274 +any basic solution $\lambda_B=0$. Corresponding values of dual variables
  15.275 +$\lambda_N$ for non-basic variables $x_N$ can be determined in the
  15.276 +following way. From the dual system (3.15) we have:
  15.277 +$$(I\ |-\!A)^T\pi+\lambda=(0\ |\ c)^T,\eqno(3.22)$$
  15.278 +so multiplying both sides of (3.22) by matrix $\Pi$ gives:
  15.279 +$$\Pi(I\ |-\!A)^T\pi+\Pi\lambda=\Pi(0\ |\ c)^T.\eqno(3.23)$$
  15.280 +From (3.9) it follows that
  15.281 +$$\Pi(I\ |-\!A)^T=[(I\ |-\!A)\Pi^T]^T=(B\ |\ N)^T.\eqno(3.24)$$
  15.282 +Further, we can apply the partition (3.7) also to the vector of
  15.283 +objective coefficients (see (3.4)):
  15.284 +$$\left(\begin{array}{@{}c@{}}c_B\\c_N\\\end{array}\right)=
  15.285 +\Pi\left(\begin{array}{@{}c@{}}0\\c\\\end{array}\right),\eqno(3.25)$$
  15.286 +where $c_B$ is a vector of objective coefficients at basic variables,
  15.287 +$c_N$ is a vector of objective coefficients at non-basic variables.
  15.288 +Now, substituting (3.24), (3.21), and (3.25) into (3.23), leads to:
  15.289 +$$(B\ |\ N)^T\pi+(\lambda_B\ |\ \lambda_N)^T=(c_B\ |\ c_N)^T,
  15.290 +\eqno(3.26)$$
  15.291 +and transposing both sides of (3.26) gives the system:
  15.292 +$$\left(\begin{array}{@{}c@{}}B^T\\N^T\\\end{array}\right)\pi+
  15.293 +\left(\begin{array}{@{}c@{}}\lambda_B\\\lambda_N\\\end{array}\right)=
  15.294 +\left(\begin{array}{@{}c@{}}c_B\\c_T\\\end{array}\right),\eqno(3.27)$$
  15.295 +which can be written as follows:
  15.296 +$$\left\{
  15.297 +\begin{array}{@{\ }r@{\ }c@{\ }r@{\ }c@{\ }l@{\ }}
  15.298 +B^T\pi&+&\lambda_B&=&c_B\\
  15.299 +N^T\pi&+&\lambda_N&=&c_N\\
  15.300 +\end{array}
  15.301 +\right.\eqno(3.28)
  15.302 +$$
  15.303 +Lagrange multipliers $\pi=(\pi_i)$ correspond to equality constraints
  15.304 +(3.5) and therefore can have any sign. This allows resolving the first
  15.305 +subsystem of (3.28) as follows:\footnote{$B^{-T}$ means $(B^T)^{-1}=
  15.306 +(B^{-1})^T$.}
  15.307 +$$\pi=B^{-T}(c_B-\lambda_B)=-B^{-T}\lambda_B+B^{-T}c_B,\eqno(3.29)$$
  15.308 +and substitution of $\pi$ from (3.29) into the second subsystem of
  15.309 +(3.28) gives:
  15.310 +$$\lambda_N=-N^T\pi+c_N=N^TB^{-T}\lambda_B+(c_N-N^TB^{-T}c_B).
  15.311 +\eqno(3.30)$$
  15.312 +The latter system can be written in the following final form:
  15.313 +$$\lambda_N=-\Xi^T\lambda_B+d,\eqno(3.31)$$
  15.314 +where $\Xi$ is the simplex tableau (see (3.12)), and
  15.315 +$$d=c_N-N^TB^{-T}c_B=c_N+\Xi^Tc_B\eqno(3.32)$$
  15.316 +is the vector of so called {\it reduced costs} of non-basic variables.
  15.317 +
  15.318 +\pagebreak
  15.319 +
  15.320 +Above it was said that in any basic solution $\lambda_B=0$, so
  15.321 +$\lambda_N=d$ as it follows from (3.31).
  15.322 +
  15.323 +The system (3.31) is equivalent to the system (3.15) in the sense that
  15.324 +they both define the same set of points in the space of dual variables
  15.325 +$\lambda$, which satisfy to these systems. If, moreover, values of all
  15.326 +dual variables $\lambda_N$ (i.e. reduced costs $d$) satisfy to their
  15.327 +bound constraints (i.e. to the ``rule of signs''; see the table above),
  15.328 +the corresponding basic solution is called {\it dual feasible},
  15.329 +otherwise {\it dual infeasible}. It is understood that any dual feasible
  15.330 +solution satisfy to all constraints (3.15) and (3.17) (or (3.18) in case
  15.331 +of maximization).
  15.332 +
  15.333 +It can be easily shown that the complementary slackness condition
  15.334 +(3.19) is always satisfied for {\it any} basic solution. Therefore,
  15.335 +a basic solution\footnote{It is assumed that a complete basic solution
  15.336 +has the form $(x,\lambda)$, i.e. it includes primal as well as dual
  15.337 +variables.} is {\it optimal} if and only if it is primal and dual
  15.338 +feasible, because in this case it satifies to all the optimality
  15.339 +conditions (3.14)---(3.19).
  15.340 +
  15.341 +\def\arraystretch{1.5}
  15.342 +
  15.343 +The meaning of reduced costs $d=(d_j)$ of non-basic variables can be
  15.344 +explained in the following way. From (3.4), (3.7), and (3.25) it follows
  15.345 +that:
  15.346 +$$z=c_B^Tx_B+c_N^Tx_N+c_0.\eqno(3.33)$$
  15.347 +Substituting $x_B$ from (3.11) into (3.33) we can eliminate basic
  15.348 +variables and express the objective only through non-basic variables:
  15.349 +$$
  15.350 +\begin{array}{r@{\ }c@{\ }l}
  15.351 +z&=&c_B^T(-B^{-1}Nx_N)+c_N^Tx_N+c_0=\\
  15.352 +&=&(c_N^T-c_B^TB^{-1}N)x_N+c_0=\\
  15.353 +&=&(c_N-N^TB^{-T}c_B)^Tx_N+c_0=\\
  15.354 +&=&d^Tx_N+c_0.
  15.355 +\end{array}\eqno(3.34)
  15.356 +$$
  15.357 +From (3.34) it is seen that reduced cost $d_j$ shows how the objective
  15.358 +function $z$ depends on non-basic variable $(x_N)_j$ in the neighborhood
  15.359 +of the current basic solution, i.e. while the current basis remains
  15.360 +unchanged.
  15.361 +
  15.362 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  15.363 +
  15.364 +\newpage
  15.365 +
  15.366 +\section{LP basis routines}
  15.367 +\label{lpbasis}
  15.368 +
  15.369 +\subsection{glp\_bf\_exists---check if the basis factorization exists}
  15.370 +
  15.371 +\subsubsection*{Synopsis}
  15.372 +
  15.373 +\begin{verbatim}
  15.374 +int glp_bf_exists(glp_prob *lp);
  15.375 +\end{verbatim}
  15.376 +
  15.377 +\subsubsection*{Returns}
  15.378 +
  15.379 +If the basis factorization for the current basis associated with the
  15.380 +specified problem object exists and therefore is available for
  15.381 +computations, the routine \verb|glp_bf_exists| returns non-zero.
  15.382 +Otherwise the routine returns zero.
  15.383 +
  15.384 +\subsubsection*{Comments}
  15.385 +
  15.386 +Let the problem object have $m$ rows and $n$ columns. In GLPK the
  15.387 +{\it basis matrix} $B$ is a square non-singular matrix of the order $m$,
  15.388 +whose columns correspond to basic (auxiliary and/or structural)
  15.389 +variables. It is defined by the following main
  15.390 +equality:\footnote{For more details see Subsection \ref{basbgd},
  15.391 +page \pageref{basbgd}.}
  15.392 +$$(B\ |\ N)=(I\ |-\!A)\Pi^T,$$
  15.393 +where $I$ is the unity matrix of the order $m$, whose columns correspond
  15.394 +to auxiliary variables; $A$ is the original constraint
  15.395 +$m\times n$-matrix, whose columns correspond to structural variables;
  15.396 +$(I\ |-\!A)$ is the augmented constraint\linebreak
  15.397 +$m\times(m+n)$-matrix, whose columns correspond to all (auxiliary and
  15.398 +structural) variables following in the original order; $\Pi$ is a
  15.399 +permutation matrix of the order $m+n$; and $N$ is a rectangular
  15.400 +$m\times n$-matrix, whose columns correspond to non-basic (auxiliary
  15.401 +and/or structural) variables.
  15.402 +
  15.403 +For various reasons it may be necessary to solve linear systems with
  15.404 +matrix $B$. To provide this possibility the GLPK implementation
  15.405 +maintains an invertable form of $B$ (that is, some representation of
  15.406 +$B^{-1}$) called the {\it basis factorization}, which is an internal
  15.407 +component of the problem object. Typically, the basis factorization is
  15.408 +computed by the simplex solver, which keeps it in the problem object
  15.409 +to be available for other computations.
  15.410 +
  15.411 +Should note that any changes in the problem object, which affects the
  15.412 +basis matrix (e.g. changing the status of a row or column, changing
  15.413 +a basic column of the constraint matrix, removing an active constraint,
  15.414 +etc.), invalidates the basis factorization. So before calling any API
  15.415 +routine, which uses the basis factorization, the application program
  15.416 +must make sure (using the routine \verb|glp_bf_exists|) that the
  15.417 +factorization exists and therefore available for computations.
  15.418 +
  15.419 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  15.420 +
  15.421 +\subsection{glp\_factorize---compute the basis factorization}
  15.422 +
  15.423 +\subsubsection*{Synopsis}
  15.424 +
  15.425 +\begin{verbatim}
  15.426 +int glp_factorize(glp_prob *lp);
  15.427 +\end{verbatim}
  15.428 +
  15.429 +\subsubsection*{Description}
  15.430 +
  15.431 +The routine \verb|glp_factorize| computes the basis factorization for
  15.432 +the current basis associated with the specified problem
  15.433 +object.\footnote{The current basis is defined by the current statuses
  15.434 +of rows (auxiliary variables) and columns (structural variables).}
  15.435 +
  15.436 +The basis factorization is computed from ``scratch'' even if it exists,
  15.437 +so the application program may use the routine \verb|glp_bf_exists|,
  15.438 +and, if the basis factorization already exists, not to call the routine
  15.439 +\verb|glp_factorize| to prevent an extra work.
  15.440 +
  15.441 +The routine \verb|glp_factorize| {\it does not} compute components of
  15.442 +the basic solution (i.e. primal and dual values).
  15.443 +
  15.444 +\subsubsection*{Returns}
  15.445 +
  15.446 +\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
  15.447 +0 & The basis factorization has been successfully computed.\\
  15.448 +\verb|GLP_EBADB| & The basis matrix is invalid, because the number of
  15.449 +basic (auxiliary and structural) variables is not the same as the number
  15.450 +of rows in the problem object.\\
  15.451 +\verb|GLP_ESING| & The basis matrix is singular within the working
  15.452 +precision.\\
  15.453 +\verb|GLP_ECOND| & The basis matrix is ill-conditioned, i.e. its
  15.454 +condition number is too large.\\
  15.455 +\end{tabular}
  15.456 +
  15.457 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  15.458 +
  15.459 +\newpage
  15.460 +
  15.461 +\subsection{glp\_bf\_updated---check if the basis factorization has\\
  15.462 +been updated}
  15.463 +
  15.464 +\subsubsection*{Synopsis}
  15.465 +
  15.466 +\begin{verbatim}
  15.467 +int glp_bf_updated(glp_prob *lp);
  15.468 +\end{verbatim}
  15.469 +
  15.470 +\subsubsection*{Returns}
  15.471 +
  15.472 +If the basis factorization has been just computed from ``scratch'', the
  15.473 +routine \verb|glp_bf_updated| returns zero. Otherwise, if the
  15.474 +factorization has been updated at least once, the routine returns
  15.475 +non-zero.
  15.476 +
  15.477 +\subsubsection*{Comments}
  15.478 +
  15.479 +{\it Updating} the basis factorization means recomputing it to reflect
  15.480 +changes in the basis matrix. For example, on every iteration of the
  15.481 +simplex method some column of the current basis matrix is replaced by a
  15.482 +new column that gives a new basis matrix corresponding to the adjacent
  15.483 +basis. In this case computing the basis factorization for the adjacent
  15.484 +basis from ``scratch'' (as the routine \verb|glp_factorize| does) would
  15.485 +be too time-consuming.
  15.486 +
  15.487 +On the other hand, since the basis factorization update is a numeric
  15.488 +computational procedure, applying it many times may lead to accumulating
  15.489 +round-off errors. Therefore the basis is periodically refactorized
  15.490 +(reinverted) from ``scratch'' (with the routine \verb|glp_factorize|)
  15.491 +that allows improving its numerical properties.
  15.492 +
  15.493 +The routine \verb|glp_bf_updated| allows determining if the basis
  15.494 +factorization has been updated at least once since it was computed from
  15.495 +``scratch''.
  15.496 +
  15.497 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  15.498 +
  15.499 +\newpage
  15.500 +
  15.501 +\subsection{glp\_get\_bfcp---retrieve basis factorization control
  15.502 +parameters}
  15.503 +
  15.504 +\subsubsection*{Synopsis}
  15.505 +
  15.506 +\begin{verbatim}
  15.507 +void glp_get_bfcp(glp_prob *lp, glp_bfcp *parm);
  15.508 +\end{verbatim}
  15.509 +
  15.510 +\subsubsection*{Description}
  15.511 +
  15.512 +The routine \verb|glp_get_bfcp| retrieves control parameters, which are
  15.513 +used on computing and updating the basis factorization associated with
  15.514 +the specified problem object.
  15.515 +
  15.516 +Current values of the control parameters are stored in a \verb|glp_bfcp|
  15.517 +structure, which the parameter \verb|parm| points to. For a detailed
  15.518 +description of the structure \verb|glp_bfcp| see comments to the routine
  15.519 +\verb|glp_set_bfcp| in the next subsection.
  15.520 +
  15.521 +\subsubsection*{Comments}
  15.522 +
  15.523 +The purpose of the routine \verb|glp_get_bfcp| is two-fold. First, it
  15.524 +allows the application program obtaining current values of control
  15.525 +parameters used by internal GLPK routines, which compute and update the
  15.526 +basis factorization.
  15.527 +
  15.528 +The second purpose of this routine is to provide proper values for all
  15.529 +fields of the structure \verb|glp_bfcp| in the case when the application
  15.530 +program needs to change some control parameters.
  15.531 +
  15.532 +\subsection{glp\_set\_bfcp---change basis factorization control
  15.533 +parameters}
  15.534 +
  15.535 +\subsubsection*{Synopsis}
  15.536 +
  15.537 +\begin{verbatim}
  15.538 +void glp_set_bfcp(glp_prob *lp, const glp_bfcp *parm);
  15.539 +\end{verbatim}
  15.540 +
  15.541 +\subsubsection*{Description}
  15.542 +
  15.543 +The routine \verb|glp_set_bfcp| changes control parameters, which are
  15.544 +used by internal GLPK routines on computing and updating the basis
  15.545 +factorization associated with the specified problem object.
  15.546 +
  15.547 +New values of the control parameters should be passed in a structure
  15.548 +\verb|glp_bfcp|, which the parameter \verb|parm| points to. For a
  15.549 +detailed description of the structure \verb|glp_bfcp| see paragraph
  15.550 +``Control parameters'' below.
  15.551 +
  15.552 +The parameter \verb|parm| can be specified as \verb|NULL|, in which case
  15.553 +all control parameters are reset to their default values.
  15.554 +
  15.555 +\subsubsection*{Comments}
  15.556 +
  15.557 +Before changing some control parameters with the routine
  15.558 +\verb|glp_set_bfcp| the application program should retrieve current
  15.559 +values of all control parameters with the routine \verb|glp_get_bfcp|.
  15.560 +This is needed for backward compatibility, because in the future there
  15.561 +may appear new members in the structure \verb|glp_bfcp|.
  15.562 +
  15.563 +Note that new values of control parameters come into effect on a next
  15.564 +computation of the basis factorization, not immediately.
  15.565 +
  15.566 +\subsubsection*{Example}
  15.567 +
  15.568 +\begin{verbatim}
  15.569 +glp_prob *lp;
  15.570 +glp_bfcp parm;
  15.571 +. . .
  15.572 +/* retrieve current values of control parameters */
  15.573 +glp_get_bfcp(lp, &parm);
  15.574 +/* change the threshold pivoting tolerance */
  15.575 +parm.piv_tol = 0.05;
  15.576 +/* set new values of control parameters */
  15.577 +glp_set_bfcp(lp, &parm);
  15.578 +. . .
  15.579 +\end{verbatim}
  15.580 +
  15.581 +\subsubsection*{Control parameters}
  15.582 +
  15.583 +This paragraph describes all basis factorization control parameters
  15.584 +currently used in the package. Symbolic names of control parameters are
  15.585 +names of corresponding members in the structure \verb|glp_bfcp|.
  15.586 +
  15.587 +\def\arraystretch{1}
  15.588 +
  15.589 +\medskip
  15.590 +
  15.591 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
  15.592 +\multicolumn{2}{@{}l}{{\tt int type} (default: {\tt GLP\_BF\_FT})} \\
  15.593 +&Basis factorization type:\\
  15.594 +&\verb|GLP_BF_FT|---$LU$ + Forrest--Tomlin update;\\
  15.595 +&\verb|GLP_BF_BG|---$LU$ + Schur complement + Bartels--Golub update;\\
  15.596 +&\verb|GLP_BF_GR|---$LU$ + Schur complement + Givens rotation update.
  15.597 +\\
  15.598 +&In case of \verb|GLP_BF_FT| the update is applied to matrix $U$, while
  15.599 +in cases of \verb|GLP_BF_BG| and \verb|GLP_BF_GR| the update is applied
  15.600 +to the Schur complement.
  15.601 +\end{tabular}
  15.602 +
  15.603 +\medskip
  15.604 +
  15.605 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
  15.606 +\multicolumn{2}{@{}l}{{\tt int lu\_size} (default: {\tt 0})} \\
  15.607 +&The initial size of the Sparse Vector Area, in non-zeros, used on
  15.608 +computing $LU$-factorization of the basis matrix for the first time.
  15.609 +If this parameter is set to 0, the initial SVA size is determined
  15.610 +automatically.\\
  15.611 +\end{tabular}
  15.612 +
  15.613 +\medskip
  15.614 +
  15.615 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
  15.616 +\multicolumn{2}{@{}l}{{\tt double piv\_tol} (default: {\tt 0.10})} \\
  15.617 +&Threshold pivoting (Markowitz) tolerance, 0 $<$ \verb|piv_tol| $<$ 1,
  15.618 +used on computing $LU$-factorization of the basis matrix. Element
  15.619 +$u_{ij}$ of the active submatrix of factor $U$ fits to be pivot if it
  15.620 +satisfies to the stability criterion
  15.621 +$|u_{ij}| >= {\tt piv\_tol}\cdot\max|u_{i*}|$, i.e. if it is not very
  15.622 +small in the magnitude among other elements in the same row. Decreasing
  15.623 +this parameter may lead to better sparsity at the expense of numerical
  15.624 +accuracy, and vice versa.\\
  15.625 +\end{tabular}
  15.626 +
  15.627 +\medskip
  15.628 +
  15.629 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
  15.630 +\multicolumn{2}{@{}l}{{\tt int piv\_lim} (default: {\tt 4})} \\
  15.631 +&This parameter is used on computing $LU$-factorization of the basis
  15.632 +matrix and specifies how many pivot candidates needs to be considered
  15.633 +on choosing a pivot element, \verb|piv_lim| $\geq$ 1. If \verb|piv_lim|
  15.634 +candidates have been considered, the pivoting routine prematurely
  15.635 +terminates the search with the best candidate found.\\
  15.636 +\end{tabular}
  15.637 +
  15.638 +\medskip
  15.639 +
  15.640 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
  15.641 +\multicolumn{2}{@{}l}{{\tt int suhl} (default: {\tt GLP\_ON})} \\
  15.642 +&This parameter is used on computing $LU$-factorization of the basis
  15.643 +matrix. Being set to {\tt GLP\_ON} it enables applying the following
  15.644 +heuristic proposed by Uwe Suhl: if a column of the active submatrix has
  15.645 +no eligible pivot candidates, it is no more considered until it becomes
  15.646 +a column singleton. In many cases this allows reducing the time needed
  15.647 +for pivot searching. To disable this heuristic the parameter \verb|suhl|
  15.648 +should be set to {\tt GLP\_OFF}.\\
  15.649 +\end{tabular}
  15.650 +
  15.651 +\medskip
  15.652 +
  15.653 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
  15.654 +\multicolumn{2}{@{}l}{{\tt double eps\_tol} (default: {\tt 1e-15})} \\
  15.655 +&Epsilon tolerance, \verb|eps_tol| $\geq$ 0, used on computing
  15.656 +$LU$-factorization of the basis matrix. If an element of the active
  15.657 +submatrix of factor $U$ is less than \verb|eps_tol| in the magnitude,
  15.658 +it is replaced by exact zero.\\
  15.659 +\end{tabular}
  15.660 +
  15.661 +\medskip
  15.662 +
  15.663 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
  15.664 +\multicolumn{2}{@{}l}{{\tt double max\_gro} (default: {\tt 1e+10})} \\
  15.665 +&Maximal growth of elements of factor $U$, \verb|max_gro| $\geq$ 1,
  15.666 +allowable on computing $LU$-factorization of the basis matrix. If on
  15.667 +some elimination step the ratio $u_{big}/b_{max}$ (where $u_{big}$ is
  15.668 +the largest magnitude of elements of factor $U$ appeared in its active
  15.669 +submatrix during all the factorization process, $b_{max}$ is the largest
  15.670 +magnitude of elements of the basis matrix to be factorized), the basis
  15.671 +matrix is considered as ill-conditioned.\\
  15.672 +\end{tabular}
  15.673 +
  15.674 +\medskip
  15.675 +
  15.676 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
  15.677 +\multicolumn{2}{@{}l}{{\tt int nfs\_max} (default: {\tt 100})} \\
  15.678 +&Maximal number of additional row-like factors (entries of the eta
  15.679 +file), \verb|nfs_max| $\geq$ 1, which can be added to $LU$-factorization
  15.680 +of the basis matrix on updating it with the Forrest--Tomlin technique.
  15.681 +This parameter is used only once, before $LU$-factorization is computed
  15.682 +for the first time, to allocate working arrays. As a rule, each update
  15.683 +adds one new factor (however, some updates may need no addition), so
  15.684 +this parameter limits the number of updates between refactorizations.\\
  15.685 +\end{tabular}
  15.686 +
  15.687 +\medskip
  15.688 +
  15.689 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
  15.690 +\multicolumn{2}{@{}l}{{\tt double upd\_tol} (default: {\tt 1e-6})} \\
  15.691 +&Update tolerance, 0 $<$ \verb|upd_tol| $<$ 1, used on updating
  15.692 +$LU$-factorization of the basis matrix with the Forrest--Tomlin
  15.693 +technique. If after updating the magnitude of some diagonal element
  15.694 +$u_{kk}$ of factor $U$ becomes less than
  15.695 +${\tt upd\_tol}\cdot\max(|u_{k*}|, |u_{*k}|)$, the factorization is
  15.696 +considered as inaccurate.\\
  15.697 +\end{tabular}
  15.698 +
  15.699 +\medskip
  15.700 +
  15.701 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
  15.702 +\multicolumn{2}{@{}l}{{\tt int nrs\_max} (default: {\tt 100})} \\
  15.703 +&Maximal number of additional rows and columns, \verb|nrs_max| $\geq$ 1,
  15.704 +which can be added to $LU$-factorization of the basis matrix on updating
  15.705 +it with the Schur complement technique. This parameter is used only
  15.706 +once, before $LU$-factorization is computed for the first time, to
  15.707 +allocate working arrays. As a rule, each update adds one new row and
  15.708 +column (however, some updates may need no addition), so this parameter
  15.709 +limits the number of updates between refactorizations.\\
  15.710 +\end{tabular}
  15.711 +
  15.712 +\medskip
  15.713 +
  15.714 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
  15.715 +\multicolumn{2}{@{}l}{{\tt int rs\_size} (default: {\tt 0})} \\
  15.716 +&The initial size of the Sparse Vector Area, in non-zeros, used to
  15.717 +store non-zero elements of additional rows and columns introduced on
  15.718 +updating $LU$-factorization of the basis matrix with the Schur
  15.719 +complement technique. If this parameter is set to 0, the initial SVA
  15.720 +size is determined automatically.\\
  15.721 +\end{tabular}
  15.722 +
  15.723 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  15.724 +
  15.725 +\newpage
  15.726 +
  15.727 +\subsection{glp\_get\_bhead---retrieve the basis header information}
  15.728 +
  15.729 +\subsubsection*{Synopsis}
  15.730 +
  15.731 +\begin{verbatim}
  15.732 +int glp_get_bhead(glp_prob *lp, int k);
  15.733 +\end{verbatim}
  15.734 +
  15.735 +\subsubsection*{Description}
  15.736 +
  15.737 +The routine \verb|glp_get_bhead| returns the basis header information
  15.738 +for the current basis associated with the specified problem object.
  15.739 +
  15.740 +\subsubsection*{Returns}
  15.741 +
  15.742 +If basic variable $(x_B)_k$, $1\leq k\leq m$, is $i$-th auxiliary
  15.743 +variable ($1\leq i\leq m$), the routine returns $i$. Otherwise, if
  15.744 +$(x_B)_k$ is $j$-th structural variable ($1\leq j\leq n$), the routine
  15.745 +returns $m+j$. Here $m$ is the number of rows and $n$ is the number of
  15.746 +columns in the problem object.
  15.747 +
  15.748 +\subsubsection*{Comments}
  15.749 +
  15.750 +Sometimes the application program may need to know which original
  15.751 +(auxiliary and structural) variable correspond to a given basic
  15.752 +variable, or, that is the same, which column of the augmented constraint
  15.753 +matrix $(I\ |-\!A)$ correspond to a given column of the basis matrix
  15.754 +$B$.
  15.755 +
  15.756 +\def\arraystretch{1}
  15.757 +
  15.758 +The correspondence is defined as follows:\footnote{For more details see
  15.759 +Subsection \ref{basbgd}, page \pageref{basbgd}.}
  15.760 +$$\left(\begin{array}{@{}c@{}}x_B\\x_N\\\end{array}\right)=
  15.761 +\Pi\left(\begin{array}{@{}c@{}}x_R\\x_S\\\end{array}\right)
  15.762 +\ \ \Leftrightarrow
  15.763 +\ \ \left(\begin{array}{@{}c@{}}x_R\\x_S\\\end{array}\right)=
  15.764 +\Pi^T\left(\begin{array}{@{}c@{}}x_B\\x_N\\\end{array}\right),$$
  15.765 +where $x_B$ is the vector of basic variables, $x_N$ is the vector of
  15.766 +non-basic variables, $x_R$ is the vector of auxiliary variables
  15.767 +following in their original order,\footnote{The original order of
  15.768 +auxiliary and structural variables is defined by the ordinal numbers
  15.769 +of corresponding rows and columns in the problem object.} $x_S$ is the
  15.770 +vector of structural variables following in their original order, $\Pi$
  15.771 +is a permutation matrix (which is a component of the basis
  15.772 +factorization).
  15.773 +
  15.774 +Thus, if $(x_B)_k=(x_R)_i$ is $i$-th auxiliary variable, the routine
  15.775 +returns $i$, and if $(x_B)_k=(x_S)_j$ is $j$-th structural variable,
  15.776 +the routine returns $m+j$, where $m$ is the number of rows in the
  15.777 +problem object.
  15.778 +
  15.779 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  15.780 +
  15.781 +\newpage
  15.782 +
  15.783 +\subsection{glp\_get\_row\_bind---retrieve row index in the basis\\
  15.784 +header}
  15.785 +
  15.786 +\subsubsection*{Synopsis}
  15.787 +
  15.788 +\begin{verbatim}
  15.789 +int glp_get_row_bind(glp_prob *lp, int i);
  15.790 +\end{verbatim}
  15.791 +
  15.792 +\subsubsection*{Returns}
  15.793 +
  15.794 +The routine \verb|glp_get_row_bind| returns the index $k$ of basic
  15.795 +variable $(x_B)_k$, $1\leq k\leq m$, which is $i$-th auxiliary variable
  15.796 +(that is, the auxiliary variable corresponding to $i$-th row),
  15.797 +$1\leq i\leq m$, in the current basis associated with the specified
  15.798 +problem object, where $m$ is the number of rows. However, if $i$-th
  15.799 +auxiliary variable is non-basic, the routine returns zero.
  15.800 +
  15.801 +\subsubsection*{Comments}
  15.802 +
  15.803 +The routine \verb|glp_get_row_bind| is an inverse to the routine
  15.804 +\verb|glp_get_bhead|: if \verb|glp_get_bhead|$(lp,k)$ returns $i$,
  15.805 +\verb|glp_get_row_bind|$(lp,i)$ returns $k$, and vice versa.
  15.806 +
  15.807 +\subsection{glp\_get\_col\_bind---retrieve column index in the basis
  15.808 +header}
  15.809 +
  15.810 +\subsubsection*{Synopsis}
  15.811 +
  15.812 +\begin{verbatim}
  15.813 +int glp_get_col_bind(glp_prob *lp, int j);
  15.814 +\end{verbatim}
  15.815 +
  15.816 +\subsubsection*{Returns}
  15.817 +
  15.818 +The routine \verb|glp_get_col_bind| returns the index $k$ of basic
  15.819 +variable $(x_B)_k$, $1\leq k\leq m$, which is $j$-th structural
  15.820 +variable (that is, the structural variable corresponding to $j$-th
  15.821 +column), $1\leq j\leq n$, in the current basis associated with the
  15.822 +specified problem object, where $m$ is the number of rows, $n$ is the
  15.823 +number of columns. However, if $j$-th structural variable is non-basic,
  15.824 +the routine returns zero.
  15.825 +
  15.826 +\subsubsection*{Comments}
  15.827 +
  15.828 +The routine \verb|glp_get_col_bind| is an inverse to the routine
  15.829 +\verb|glp_get_bhead|: if \verb|glp_get_bhead|$(lp,k)$ returns $m+j$,
  15.830 +\verb|glp_get_col_bind|$(lp,j)$ returns $k$, and vice versa.
  15.831 +
  15.832 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  15.833 +
  15.834 +\newpage
  15.835 +
  15.836 +\subsection{glp\_ftran---perform forward transformation}
  15.837 +
  15.838 +\subsubsection*{Synopsis}
  15.839 +
  15.840 +\begin{verbatim}
  15.841 +void glp_ftran(glp_prob *lp, double x[]);
  15.842 +\end{verbatim}
  15.843 +
  15.844 +\subsubsection*{Description}
  15.845 +
  15.846 +The routine \verb|glp_ftran| performs forward transformation (FTRAN),
  15.847 +i.e. it solves the system $Bx=b$, where $B$ is the basis matrix
  15.848 +associated with the specified problem object, $x$ is the vector of
  15.849 +unknowns to be computed, $b$ is the vector of right-hand sides.
  15.850 +
  15.851 +On entry to the routine elements of the vector $b$ should be stored in
  15.852 +locations \verb|x[1]|, \dots, \verb|x[m]|, where $m$ is the number of
  15.853 +rows. On exit the routine stores elements of the vector $x$ in the same
  15.854 +locations.
  15.855 +
  15.856 +\subsection{glp\_btran---perform backward transformation}
  15.857 +
  15.858 +\subsubsection*{Synopsis}
  15.859 +
  15.860 +\begin{verbatim}
  15.861 +void glp_btran(glp_prob *lp, double x[]);
  15.862 +\end{verbatim}
  15.863 +
  15.864 +\subsubsection*{Description}
  15.865 +
  15.866 +The routine \verb|glp_btran| performs backward transformation (BTRAN),
  15.867 +i.e. it solves the system $B^Tx=b$, where $B^T$ is a matrix transposed
  15.868 +to the basis matrix $B$ associated with the specified problem object,
  15.869 +$x$ is the vector of unknowns to be computed, $b$ is the vector of
  15.870 +right-hand sides.
  15.871 +
  15.872 +On entry to the routine elements of the vector $b$ should be stored in
  15.873 +locations \verb|x[1]|, \dots, \verb|x[m]|, where $m$ is the number of
  15.874 +rows. On exit the routine stores elements of the vector $x$ in the same
  15.875 +locations.
  15.876 +
  15.877 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  15.878 +
  15.879 +\newpage
  15.880 +
  15.881 +\subsection{glp\_warm\_up---``warm up'' LP basis}
  15.882 +
  15.883 +\subsubsection*{Synopsis}
  15.884 +
  15.885 +\begin{verbatim}
  15.886 +int glp_warm_up(glp_prob *P);
  15.887 +\end{verbatim}
  15.888 +
  15.889 +\subsubsection*{Description}
  15.890 +
  15.891 +The routine \verb|glp_warm_up| ``warms up'' the LP basis for the
  15.892 +specified problem object using current statuses assigned to rows and
  15.893 +columns (that is, to auxiliary and structural variables).
  15.894 +
  15.895 +This operation includes computing factorization of the basis matrix
  15.896 +(if it does not exist), computing primal and dual components of basic
  15.897 +solution, and determining the solution status.
  15.898 +
  15.899 +\subsubsection*{Returns}
  15.900 +
  15.901 +\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
  15.902 +0 & The operation has been successfully performed.\\
  15.903 +\verb|GLP_EBADB| & The basis matrix is invalid, because the number of
  15.904 +basic (auxiliary and structural) variables is not the same as the number
  15.905 +of rows in the problem object.\\
  15.906 +\verb|GLP_ESING| & The basis matrix is singular within the working
  15.907 +precision.\\
  15.908 +\verb|GLP_ECOND| & The basis matrix is ill-conditioned, i.e. its
  15.909 +condition number is too large.\\
  15.910 +\end{tabular}
  15.911 +
  15.912 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  15.913 +
  15.914 +\newpage
  15.915 +
  15.916 +\section{Simplex tableau routines}
  15.917 +
  15.918 +\subsection{glp\_eval\_tab\_row---compute row of the tableau}
  15.919 +
  15.920 +\subsubsection*{Synopsis}
  15.921 +
  15.922 +\begin{verbatim}
  15.923 +int glp_eval_tab_row(glp_prob *lp, int k, int ind[],
  15.924 +      double val[]);
  15.925 +\end{verbatim}
  15.926 +
  15.927 +\subsubsection*{Description}
  15.928 +
  15.929 +The routine \verb|glp_eval_tab_row| computes a row of the current
  15.930 +simplex tableau (see Subsection 3.1.1, formula (3.12)), which (row)
  15.931 +corresponds to some basic variable specified by the parameter $k$ as
  15.932 +follows: if $1\leq k\leq m$, the basic variable is $k$-th auxiliary
  15.933 +variable, and if $m+1\leq k\leq m+n$, the basic variable is $(k-m)$-th
  15.934 +structural variable, where $m$ is the number of rows and $n$ is the
  15.935 +number of columns in the specified problem object. The basis
  15.936 +factorization must exist.
  15.937 +
  15.938 +The computed row shows how the specified basic variable depends on
  15.939 +non-basic variables:
  15.940 +$$x_k=(x_B)_i=\xi_{i1}(x_N)_1+\xi_{i2}(x_N)_2+\dots+\xi_{in}(x_N)_n,$$
  15.941 +where $\xi_{i1}$, $\xi_{i2}$, \dots, $\xi_{in}$ are elements of the
  15.942 +simplex table row, $(x_N)_1$, $(x_N)_2$, \dots, $(x_N)_n$ are non-basic
  15.943 +(auxiliary and structural) variables.
  15.944 +
  15.945 +The routine stores column indices and corresponding numeric values of
  15.946 +non-zero elements of the computed row in unordered sparse format in
  15.947 +locations \verb|ind[1]|, \dots, \verb|ind[len]| and \verb|val[1]|,
  15.948 +\dots, \verb|val[len]|, respectively, where $0\leq{\tt len}\leq n$ is
  15.949 +the number of non-zero elements in the row returned on exit.
  15.950 +
  15.951 +Element indices stored in the array \verb|ind| have the same sense as
  15.952 +index $k$, i.e. indices 1 to $m$ denote auxiliary variables while
  15.953 +indices $m+1$ to $m+n$ denote structural variables (all these variables
  15.954 +are obviously non-basic by definition).
  15.955 +
  15.956 +\subsubsection*{Returns}
  15.957 +
  15.958 +The routine \verb|glp_eval_tab_row| returns \verb|len|, which is the
  15.959 +number of non-zero elements in the simplex table row stored in the
  15.960 +arrays \verb|ind| and \verb|val|.
  15.961 +
  15.962 +\subsubsection*{Comments}
  15.963 +
  15.964 +A row of the simplex table is computed as follows. At first, the
  15.965 +routine checks that the specified variable $x_k$ is basic and uses the
  15.966 +permutation matrix $\Pi$ (3.7) to determine index $i$ of basic variable
  15.967 +$(x_B)_i$, which corresponds to $x_k$.
  15.968 +
  15.969 +The row to be computed is $i$-th row of the matrix $\Xi$ (3.12),
  15.970 +therefore:
  15.971 +$$\xi_i=e_i^T\Xi=-e_i^TB^{-1}N=-(B^{-T}e_i)^TN,$$
  15.972 +where $e_i$ is $i$-th unity vector. So the routine performs BTRAN to
  15.973 +obtain $i$-th row of the inverse $B^{-1}$:
  15.974 +$$\varrho_i=B^{-T}e_i,$$
  15.975 +and then computes elements of the simplex table row as inner products:
  15.976 +$$\xi_{ij}=-\varrho_i^TN_j,\ \ j=1,2,\dots,n,$$
  15.977 +where $N_j$ is $j$-th column of matrix $N$ (3.9), which (column)
  15.978 +corresponds to non-basic variable $(x_N)_j$. The permutation matrix
  15.979 +$\Pi$ is used again to convert indices $j$ of non-basic columns to
  15.980 +original ordinal numbers of auxiliary and structural variables.
  15.981 +
  15.982 +\subsection{glp\_eval\_tab\_col---compute column of the tableau}
  15.983 +
  15.984 +\subsubsection*{Synopsis}
  15.985 +
  15.986 +\begin{verbatim}
  15.987 +int glp_eval_tab_col(glp_prob *lp, int k, int ind[],
  15.988 +      double val[]);
  15.989 +\end{verbatim}
  15.990 +
  15.991 +\subsubsection*{Description}
  15.992 +
  15.993 +The routine \verb|glp_eval_tab_col| computes a column of the current
  15.994 +simplex tableau (see Subsection 3.1.1, formula (3.12)), which (column)
  15.995 +corresponds to some non-basic variable specified by the parameter $k$:
  15.996 +if $1\leq k\leq m$, the non-basic variable is $k$-th auxiliary variable,
  15.997 +and if $m+1\leq k\leq m+n$, the non-basic variable is $(k-m)$-th
  15.998 +structural variable, where $m$ is the number of rows and $n$ is the
  15.999 +number of columns in the specified problem object. The basis
 15.1000 +factorization must exist.
 15.1001 +
 15.1002 +The computed column shows how basic variables depends on the specified
 15.1003 +non-basic variable $x_k=(x_N)_j$:
 15.1004 +$$
 15.1005 +\begin{array}{r@{\ }c@{\ }l@{\ }l}
 15.1006 +(x_B)_1&=&\dots+\xi_{1j}(x_N)_j&+\dots\\
 15.1007 +(x_B)_2&=&\dots+\xi_{2j}(x_N)_j&+\dots\\
 15.1008 +.\ \ .&.&.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\\
 15.1009 +(x_B)_m&=&\dots+\xi_{mj}(x_N)_j&+\dots\\
 15.1010 +\end{array}
 15.1011 +$$
 15.1012 +where $\xi_{1j}$, $\xi_{2j}$, \dots, $\xi_{mj}$ are elements of the
 15.1013 +simplex table column, $(x_B)_1$, $(x_B)_2$, \dots, $(x_B)_m$ are basic
 15.1014 +(auxiliary and structural) variables.
 15.1015 +
 15.1016 +The routine stores row indices and corresponding numeric values of
 15.1017 +non-zero elements of the computed column in unordered sparse format in
 15.1018 +locations \verb|ind[1]|, \dots, \verb|ind[len]| and \verb|val[1]|,
 15.1019 +\dots, \verb|val[len]|, respectively, where $0\leq{\tt len}\leq m$ is
 15.1020 +the number of non-zero elements in the column returned on exit.
 15.1021 +
 15.1022 +Element indices stored in the array \verb|ind| have the same sense as
 15.1023 +index $k$, i.e. indices 1 to $m$ denote auxiliary variables while
 15.1024 +indices $m+1$ to $m+n$ denote structural variables (all these variables
 15.1025 +are obviously basic by definition).
 15.1026 +
 15.1027 +\subsubsection*{Returns}
 15.1028 +
 15.1029 +The routine \verb|glp_eval_tab_col| returns \verb|len|, which is the
 15.1030 +number of non-zero elements in the simplex table column stored in the
 15.1031 +arrays \verb|ind| and \verb|val|.
 15.1032 +
 15.1033 +\subsubsection*{Comments}
 15.1034 +
 15.1035 +A column of the simplex table is computed as follows. At first, the
 15.1036 +routine checks that the specified variable $x_k$ is non-basic and uses
 15.1037 +the permutation matrix $\Pi$ (3.7) to determine index $j$ of non-basic
 15.1038 +variable $(x_N)_j$, which corresponds to $x_k$.
 15.1039 +
 15.1040 +The column to be computed is $j$-th column of the matrix $\Xi$ (3.12),
 15.1041 +therefore:
 15.1042 +$$\Xi_j=\Xi e_j=-B^{-1}Ne_j=-B^{-1}N_j,$$
 15.1043 +where $e_j$ is $j$-th unity vector, $N_j$ is $j$-th column of matrix
 15.1044 +$N$ (3.9). So the routine performs FTRAN to transform $N_j$ to the
 15.1045 +simplex table column $\Xi_j=(\xi_{ij})$ and uses the permutation matrix
 15.1046 +$\Pi$ to convert row indices $i$ to original ordinal numbers of
 15.1047 +auxiliary and structural variables.
 15.1048 +
 15.1049 +\newpage
 15.1050 +
 15.1051 +\subsection{glp\_transform\_row---transform explicitly specified\\
 15.1052 +row}
 15.1053 +
 15.1054 +\subsubsection*{Synopsis}
 15.1055 +
 15.1056 +\begin{verbatim}
 15.1057 +int glp_transform_row(glp_prob *P, int len, int ind[],
 15.1058 +      double val[]);
 15.1059 +\end{verbatim}
 15.1060 +
 15.1061 +\subsubsection*{Description}
 15.1062 +
 15.1063 +The routine \verb|glp_transform_row| performs the same operation as the
 15.1064 +routine \verb|glp_eval_tab_row| with exception that the row to be
 15.1065 +transformed is specified explicitly as a sparse vector.
 15.1066 +
 15.1067 +The explicitly specified row may be thought as a linear form:
 15.1068 +$$x=a_1x_{m+1}+a_2x_{m+2}+\dots+a_nx_{m+n},$$
 15.1069 +where $x$ is an auxiliary variable for this row, $a_j$ are coefficients
 15.1070 +of the linear form, $x_{m+j}$ are structural variables.
 15.1071 +
 15.1072 +On entry column indices and numerical values of non-zero coefficients
 15.1073 +$a_j$ of the specified row should be placed in locations \verb|ind[1]|,
 15.1074 +\dots, \verb|ind[len]| and \verb|val[1]|, \dots, \verb|val[len]|, where
 15.1075 +\verb|len| is number of non-zero coefficients.
 15.1076 +
 15.1077 +This routine uses the system of equality constraints and the current
 15.1078 +basis in order to express the auxiliary variable $x$ through the current
 15.1079 +non-basic variables (as if the transformed row were added to the problem
 15.1080 +object and the auxiliary variable $x$ were basic), i.e. the resultant
 15.1081 +row has the form:
 15.1082 +$$x=\xi_1(x_N)_1+\xi_2(x_N)_2+\dots+\xi_n(x_N)_n,$$
 15.1083 +where $\xi_j$ are influence coefficients, $(x_N)_j$ are non-basic
 15.1084 +(auxiliary and structural) variables, $n$ is the number of columns in
 15.1085 +the problem object.
 15.1086 +
 15.1087 +On exit the routine stores indices and numerical values of non-zero
 15.1088 +coefficients $\xi_j$ of the resultant row in locations \verb|ind[1]|,
 15.1089 +\dots, \verb|ind[len']| and \verb|val[1]|, \dots, \verb|val[len']|,
 15.1090 +where $0\leq{\tt len'}\leq n$ is the number of non-zero coefficients in
 15.1091 +the resultant row returned by the routine. Note that indices of
 15.1092 +non-basic variables stored in the array \verb|ind| correspond to
 15.1093 +original ordinal numbers of variables: indices 1 to $m$ mean auxiliary
 15.1094 +variables and indices $m+1$ to $m+n$ mean structural ones.
 15.1095 +
 15.1096 +\subsubsection*{Returns}
 15.1097 +
 15.1098 +The routine \verb|glp_transform_row| returns \verb|len'|, the number of
 15.1099 +non-zero coefficients in the resultant row stored in the arrays
 15.1100 +\verb|ind| and \verb|val|.
 15.1101 +
 15.1102 +\subsection{glp\_transform\_col---transform explicitly specified\\
 15.1103 +column}
 15.1104 +
 15.1105 +\subsubsection*{Synopsis}
 15.1106 +
 15.1107 +\begin{verbatim}
 15.1108 +int glp_transform_col(glp_prob *P, int len, int ind[],
 15.1109 +      double val[]);
 15.1110 +\end{verbatim}
 15.1111 +
 15.1112 +\subsubsection*{Description}
 15.1113 +
 15.1114 +The routine \verb|glp_transform_col| performs the same operation as the
 15.1115 +routine \verb|glp_eval_tab_col| with exception that the column to be
 15.1116 +transformed is specified explicitly as a sparse vector.
 15.1117 +
 15.1118 +The explicitly specified column may be thought as it were added to
 15.1119 +the original system of equality constraints:
 15.1120 +$$
 15.1121 +\begin{array}{l@{\ }c@{\ }r@{\ }c@{\ }r@{\ }c@{\ }r}
 15.1122 +x_1&=&a_{11}x_{m+1}&+\dots+&a_{1n}x_{m+n}&+&a_1x \\
 15.1123 +x_2&=&a_{21}x_{m+1}&+\dots+&a_{2n}x_{m+n}&+&a_2x \\
 15.1124 +\multicolumn{7}{c}
 15.1125 +{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .}\\
 15.1126 +x_m&=&a_{m1}x_{m+1}&+\dots+&a_{mn}x_{m+n}&+&a_mx \\
 15.1127 +\end{array}
 15.1128 +$$
 15.1129 +where $x_i$ are auxiliary variables, $x_{m+j}$ are structural variables
 15.1130 +(presented in the problem object), $x$ is a structural variable for the
 15.1131 +explicitly specified column, $a_i$ are constraint coefficients at $x$.
 15.1132 +
 15.1133 +On entry row indices and numerical values of non-zero coefficients
 15.1134 +$a_i$ of the specified column should be placed in locations
 15.1135 +\verb|ind[1]|, \dots, \verb|ind[len]| and \verb|val[1]|, \dots,
 15.1136 +\verb|val[len]|, where \verb|len| is number of non-zero coefficients.
 15.1137 +
 15.1138 +This routine uses the system of equality constraints and the current
 15.1139 +basis in order to express the current basic variables through the
 15.1140 +structural variable $x$ (as if the transformed column were added to the
 15.1141 +problem object and the variable $x$ were non-basic):
 15.1142 +$$
 15.1143 +\begin{array}{l@{\ }c@{\ }r}
 15.1144 +(x_B)_1&=\dots+&\xi_{1}x\\
 15.1145 +(x_B)_2&=\dots+&\xi_{2}x\\
 15.1146 +\multicolumn{3}{c}{.\ \ .\ \ .\ \ .\ \ .\ \ .}\\
 15.1147 +(x_B)_m&=\dots+&\xi_{m}x\\
 15.1148 +\end{array}
 15.1149 +$$
 15.1150 +where $\xi_i$ are influence coefficients, $x_B$ are basic (auxiliary
 15.1151 +and structural) variables, $m$ is the number of rows in the problem
 15.1152 +object.
 15.1153 +
 15.1154 +On exit the routine stores indices and numerical values of non-zero
 15.1155 +coefficients $\xi_i$ of the resultant column in locations \verb|ind[1]|,
 15.1156 +\dots, \verb|ind[len']| and \verb|val[1]|, \dots, \verb|val[len']|,
 15.1157 +where $0\leq{\tt len'}\leq m$ is the number of non-zero coefficients in
 15.1158 +the resultant column returned by the routine. Note that indices of basic
 15.1159 +variables stored in the array \verb|ind| correspond to original ordinal
 15.1160 +numbers of variables, i.e. indices 1 to $m$ mean auxiliary variables,
 15.1161 +indices $m+1$ to $m+n$ mean structural ones.
 15.1162 +
 15.1163 +\subsubsection*{Returns}
 15.1164 +
 15.1165 +The routine \verb|glp_transform_col| returns \verb|len'|, the number of
 15.1166 +non-zero coefficients in the resultant column stored in the arrays
 15.1167 +\verb|ind| and \verb|val|.
 15.1168 +
 15.1169 +\subsection{glp\_prim\_rtest---perform primal ratio test}
 15.1170 +
 15.1171 +\subsubsection*{Synopsis}
 15.1172 +
 15.1173 +\begin{verbatim}
 15.1174 +int glp_prim_rtest(glp_prob *P, int len, const int ind[],
 15.1175 +      const double val[], int dir, double eps);
 15.1176 +\end{verbatim}
 15.1177 +
 15.1178 +\subsubsection*{Description}
 15.1179 +
 15.1180 +The routine \verb|glp_prim_rtest| performs the primal ratio test using
 15.1181 +an explicitly specified column of the simplex table.
 15.1182 +
 15.1183 +The current basic solution associated with the LP problem object must be
 15.1184 +primal feasible.
 15.1185 +
 15.1186 +The explicitly specified column of the simplex table shows how the basic
 15.1187 +variables $x_B$ depend on some non-basic variable $x$ (which is not
 15.1188 +necessarily presented in the problem object):
 15.1189 +$$
 15.1190 +\begin{array}{l@{\ }c@{\ }r}
 15.1191 +(x_B)_1&=\dots+&\xi_{1}x\\
 15.1192 +(x_B)_2&=\dots+&\xi_{2}x\\
 15.1193 +\multicolumn{3}{c}{.\ \ .\ \ .\ \ .\ \ .\ \ .}\\
 15.1194 +(x_B)_m&=\dots+&\xi_{m}x\\
 15.1195 +\end{array}
 15.1196 +$$
 15.1197 +
 15.1198 +The column is specifed on entry to the routine in sparse format. Ordinal
 15.1199 +numbers of basic variables $(x_B)_i$ should be placed in locations
 15.1200 +\verb|ind[1]|, \dots, \verb|ind[len]|, where ordinal number 1 to $m$
 15.1201 +denote auxiliary variables, and ordinal numbers $m+1$ to $m+n$ denote
 15.1202 +structural variables. The corresponding non-zero coefficients $\xi_i$
 15.1203 +should be placed in locations \verb|val[1]|, \dots, \verb|val[len]|. The
 15.1204 +arrays \verb|ind| and \verb|val| are not changed by the routine.
 15.1205 +
 15.1206 +The parameter \verb|dir| specifies direction in which the variable $x$
 15.1207 +changes on entering the basis: $+1$ means increasing, $-1$ means
 15.1208 +decreasing.
 15.1209 +
 15.1210 +The parameter \verb|eps| is an absolute tolerance (small positive
 15.1211 +number, say, $10^{-9}$) used by the routine to skip $\xi_i$'s whose
 15.1212 +magnitude is less than \verb|eps|.
 15.1213 +
 15.1214 +The routine determines which basic variable (among those specified in
 15.1215 +\verb|ind[1]|, \dots, \verb|ind[len]|) reaches its (lower or upper)
 15.1216 +bound first before any other basic variables do, and which, therefore,
 15.1217 +should leave the basis in order to keep primal feasibility.
 15.1218 +
 15.1219 +\subsubsection*{Returns}
 15.1220 +
 15.1221 +The routine \verb|glp_prim_rtest| returns the index, \verb|piv|, in the
 15.1222 +arrays \verb|ind| and \verb|val| corresponding to the pivot element
 15.1223 +chosen, $1\leq$ \verb|piv| $\leq$ \verb|len|. If the adjacent basic
 15.1224 +solution is primal unbounded, and therefore the choice cannot be made,
 15.1225 +the routine returns zero.
 15.1226 +
 15.1227 +\subsubsection*{Comments}
 15.1228 +
 15.1229 +If the non-basic variable $x$ is presented in the LP problem object, the
 15.1230 +input column can be computed with the routine \verb|glp_eval_tab_col|;
 15.1231 +otherwise, it can be computed with the routine \verb|glp_transform_col|.
 15.1232 +
 15.1233 +\subsection{glp\_dual\_rtest---perform dual ratio test}
 15.1234 +
 15.1235 +\subsubsection*{Synopsis}
 15.1236 +
 15.1237 +\begin{verbatim}
 15.1238 +int glp_dual_rtest(glp_prob *P, int len, const int ind[],
 15.1239 +      const double val[], int dir, double eps);
 15.1240 +\end{verbatim}
 15.1241 +
 15.1242 +\subsubsection*{Description}
 15.1243 +
 15.1244 +The routine \verb|glp_dual_rtest| performs the dual ratio test using
 15.1245 +an explicitly specified row of the simplex table.
 15.1246 +
 15.1247 +The current basic solution associated with the LP problem object must be
 15.1248 +dual feasible.
 15.1249 +
 15.1250 +The explicitly specified row of the simplex table is a linear form
 15.1251 +that shows how some basic variable $x$ (which is not necessarily
 15.1252 +presented in the problem object) depends on non-basic variables $x_N$:
 15.1253 +$$x=\xi_1(x_N)_1+\xi_2(x_N)_2+\dots+\xi_n(x_N)_n.$$
 15.1254 +
 15.1255 +The row is specified on entry to the routine in sparse format. Ordinal
 15.1256 +numbers of non-basic variables $(x_N)_j$ should be placed in locations
 15.1257 +\verb|ind[1]|, \dots, \verb|ind[len]|, where ordinal numbers 1 to $m$
 15.1258 +denote auxiliary variables, and ordinal numbers $m+1$ to $m+n$ denote
 15.1259 +structural variables. The corresponding non-zero coefficients $\xi_j$
 15.1260 +should be placed in locations \verb|val[1]|, \dots, \verb|val[len]|.
 15.1261 +The arrays \verb|ind| and \verb|val| are not changed by the routine.
 15.1262 +
 15.1263 +The parameter \verb|dir| specifies direction in which the variable $x$
 15.1264 +changes on leaving the basis: $+1$ means that $x$ goes on its lower
 15.1265 +bound, so its reduced cost (dual variable) is increasing (minimization)
 15.1266 +or decreasing (maximization); $-1$ means that $x$ goes on its upper
 15.1267 +bound, so its reduced cost is decreasing (minimization) or increasing
 15.1268 +(maximization).
 15.1269 +
 15.1270 +The parameter \verb|eps| is an absolute tolerance (small positive
 15.1271 +number, say, $10^{-9}$) used by the routine to skip $\xi_j$'s whose
 15.1272 +magnitude is less than \verb|eps|.
 15.1273 +
 15.1274 +The routine determines which non-basic variable (among those specified
 15.1275 +in \verb|ind[1]|, \dots, \verb|ind[len]|) should enter the basis in
 15.1276 +order to keep dual feasibility, because its reduced cost reaches the
 15.1277 +(zero) bound first before this occurs for any other non-basic variables.
 15.1278 +
 15.1279 +\subsubsection*{Returns}
 15.1280 +
 15.1281 +The routine \verb|glp_dual_rtest| returns the index, \verb|piv|, in the
 15.1282 +arrays \verb|ind| and \verb|val| corresponding to the pivot element
 15.1283 +chosen, $1\leq$ \verb|piv| $\leq$ \verb|len|. If the adjacent basic
 15.1284 +solution is dual unbounded, and therefore the choice cannot be made,
 15.1285 +the routine returns zero.
 15.1286 +
 15.1287 +\subsubsection*{Comments}
 15.1288 +
 15.1289 +If the basic variable $x$ is presented in the LP problem object, the
 15.1290 +input row can be computed with the routine \verb|glp_eval_tab_row|;
 15.1291 +otherwise, it can be computed with the routine \verb|glp_transform_row|.
 15.1292 +
 15.1293 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 15.1294 +
 15.1295 +\newpage
 15.1296 +
 15.1297 +\section{Post-optimal analysis routines}
 15.1298 +
 15.1299 +\subsection{glp\_analyze\_bound---analyze active bound of non-basic
 15.1300 +variable}
 15.1301 +
 15.1302 +\subsubsection*{Synopsis}
 15.1303 +
 15.1304 +\begin{verbatim}
 15.1305 +void glp_analyze_bound(glp_prob *P, int k, double *limit1,
 15.1306 +      int *var1, double *limit2, int *var2);
 15.1307 +\end{verbatim}
 15.1308 +
 15.1309 +\subsubsection*{Description}
 15.1310 +
 15.1311 +The routine \verb|glp_analyze_bound| analyzes the effect of varying the
 15.1312 +active bound of specified non-basic variable.
 15.1313 +
 15.1314 +The non-basic variable is specified by the parameter $k$, where
 15.1315 +$1\leq k\leq m$ means auxiliary variable of corresponding row, and
 15.1316 +$m+1\leq k\leq m+n$ means structural variable (column).
 15.1317 +
 15.1318 +Note that the current basic solution must be optimal, and the basis
 15.1319 +factorization must exist.
 15.1320 +
 15.1321 +Results of the analysis have the following meaning.
 15.1322 +
 15.1323 +\verb|value1| is the minimal value of the active bound, at which the
 15.1324 +basis still remains primal feasible and thus optimal. \verb|-DBL_MAX|
 15.1325 +means that the active bound has no lower limit.
 15.1326 +
 15.1327 +\verb|var1| is the ordinal number of an auxiliary (1 to $m$) or
 15.1328 +structural ($m+1$ to $m+n$) basic variable, which reaches its bound
 15.1329 +first and thereby limits further decreasing the active bound being
 15.1330 +analyzed. if \verb|value1| = \verb|-DBL_MAX|, \verb|var1| is set to 0.
 15.1331 +
 15.1332 +\verb|value2| is the maximal value of the active bound, at which the
 15.1333 +basis still remains primal feasible and thus optimal. \verb|+DBL_MAX|
 15.1334 +means that the active bound has no upper limit.
 15.1335 +
 15.1336 +\verb|var2| is the ordinal number of an auxiliary (1 to $m$) or
 15.1337 +structural ($m+1$ to $m+n$) basic variable, which reaches its bound
 15.1338 +first and thereby limits further increasing the active bound being
 15.1339 +analyzed. if \verb|value2| = \verb|+DBL_MAX|, \verb|var2| is set to 0.
 15.1340 +
 15.1341 +The parameters \verb|value1|, \verb|var1|, \verb|value2|, \verb|var2|
 15.1342 +can be specified as \verb|NULL|, in which case corresponding information
 15.1343 +is not stored.
 15.1344 +
 15.1345 +\newpage
 15.1346 +
 15.1347 +\subsection{glp\_analyze\_coef---analyze objective coefficient at basic
 15.1348 +variable}
 15.1349 +
 15.1350 +\subsubsection*{Synopsis}
 15.1351 +
 15.1352 +\begin{verbatim}
 15.1353 +void glp_analyze_coef(glp_prob *P, int k, double *coef1,
 15.1354 +      int *var1, double *value1, double *coef2, int *var2,
 15.1355 +      double *value2);
 15.1356 +\end{verbatim}
 15.1357 +
 15.1358 +\subsubsection*{Description}
 15.1359 +
 15.1360 +The routine \verb|glp_analyze_coef| analyzes the effect of varying the
 15.1361 +objective coefficient at specified basic variable.
 15.1362 +
 15.1363 +The basic variable is specified by the parameter $k$, where
 15.1364 +$1\leq k\leq m$ means auxiliary variable of corresponding row, and
 15.1365 +$m+1\leq k\leq m+n$ means structural variable (column).
 15.1366 +
 15.1367 +Note that the current basic solution must be optimal, and the basis
 15.1368 +factorization must exist.
 15.1369 +
 15.1370 +Results of the analysis have the following meaning.
 15.1371 +
 15.1372 +\verb|coef1| is the minimal value of the objective coefficient, at
 15.1373 +which the basis still remains dual feasible and thus optimal.
 15.1374 +\verb|-DBL_MAX| means that the objective coefficient has no lower limit.
 15.1375 +
 15.1376 +\verb|var1| is the ordinal number of an auxiliary (1 to $m$) or
 15.1377 +structural ($m+1$ to $m+n$) non-basic variable, whose reduced cost
 15.1378 +reaches its zero bound first and thereby limits further decreasing the
 15.1379 +objective coefficient being analyzed. If \verb|coef1| = \verb|-DBL_MAX|,
 15.1380 +\verb|var1| is set to 0.
 15.1381 +
 15.1382 +\verb|value1| is value of the basic variable being analyzed in an
 15.1383 +adjacent basis, which is defined as follows. Let the objective
 15.1384 +coefficient reaches its minimal value (\verb|coef1|) and continues
 15.1385 +decreasing. Then the reduced cost of the limiting non-basic variable
 15.1386 +(\verb|var1|) becomes dual infeasible and the current basis becomes
 15.1387 +non-optimal that forces the limiting non-basic variable to enter the
 15.1388 +basis replacing there some basic variable that leaves the basis to keep
 15.1389 +primal feasibility. Should note that on determining the adjacent basis
 15.1390 +current bounds of the basic variable being analyzed are ignored as if
 15.1391 +it were free (unbounded) variable, so it cannot leave the basis. It may
 15.1392 +happen that no dual feasible adjacent basis exists, in which case
 15.1393 +\verb|value1| is set to \verb|-DBL_MAX| or \verb|+DBL_MAX|.
 15.1394 +
 15.1395 +\verb|coef2| is the maximal value of the objective coefficient, at
 15.1396 +which the basis still remains dual feasible and thus optimal.
 15.1397 +\verb|+DBL_MAX| means that the objective coefficient has no upper limit.
 15.1398 +
 15.1399 +\verb|var2| is the ordinal number of an auxiliary (1 to $m$) or
 15.1400 +structural ($m+1$ to $m+n$) non-basic variable, whose reduced cost
 15.1401 +reaches its zero bound first and thereby limits further increasing the
 15.1402 +objective coefficient being analyzed. If \verb|coef2| = \verb|+DBL_MAX|,
 15.1403 +\verb|var2| is set to 0.
 15.1404 +
 15.1405 +\verb|value2| is value of the basic variable being analyzed in an
 15.1406 +adjacent basis, which is defined exactly in the same way as
 15.1407 +\verb|value1| above with exception that now the objective coefficient
 15.1408 +is increasing.
 15.1409 +
 15.1410 +The parameters \verb|coef1|, \verb|var1|, \verb|value1|, \verb|coef2|,
 15.1411 +\verb|var2|, \verb|value2| can be specified as \verb|NULL|, in which
 15.1412 +case corresponding information is not stored.
 15.1413 +
 15.1414 +%* eof *%
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/doc/glpk05.tex	Mon Dec 06 13:09:21 2010 +0100
    16.3 @@ -0,0 +1,1100 @@
    16.4 +%* glpk05.tex *%
    16.5 +
    16.6 +\chapter{Branch-and-Cut API Routines}
    16.7 +
    16.8 +\section{Introduction}
    16.9 +
   16.10 +\subsection{Using the callback routine}
   16.11 +
   16.12 +The GLPK MIP solver based on the branch-and-cut method allows the
   16.13 +application program to control the solution process. This is attained
   16.14 +by means of the user-defined callback routine, which is called by the
   16.15 +solver at various points of the branch-and-cut algorithm.
   16.16 +
   16.17 +The callback routine passed to the MIP solver should be written by the
   16.18 +user and has the following specification:\footnote{The name
   16.19 +{\tt foo\_bar} used here is a placeholder for the callback routine
   16.20 +name.}
   16.21 +
   16.22 +\begin{verbatim}
   16.23 +   void foo_bar(glp_tree *tree, void *info);
   16.24 +\end{verbatim}
   16.25 +
   16.26 +\noindent
   16.27 +where \verb|tree| is a pointer to the data structure \verb|glp_tree|,
   16.28 +which should be used on subsequent calls to branch-and-cut interface
   16.29 +routines, and \verb|info| is a transit pointer passed to the routine
   16.30 +\verb|glp_intopt|, which may be used by the application program to pass
   16.31 +some external data to the callback routine.
   16.32 +
   16.33 +The callback routine is passed to the MIP solver through the control
   16.34 +parameter structure \verb|glp_iocp| (see Chapter ``Basic API Routines'',
   16.35 +Section ``Mixed integer programming routines'', Subsection ``Solve MIP
   16.36 +problem with the branch-and-cut method'') as follows:
   16.37 +
   16.38 +\newpage
   16.39 +
   16.40 +\begin{verbatim}
   16.41 +   glp_prob *mip;
   16.42 +   glp_iocp parm;
   16.43 +   . . .
   16.44 +   glp_init_iocp(&parm);
   16.45 +   . . .
   16.46 +   parm.cb_func = foo_bar;
   16.47 +   parm.cb_info = ... ;
   16.48 +   ret = glp_intopt(mip, &parm);
   16.49 +   . . .
   16.50 +\end{verbatim}
   16.51 +
   16.52 +To determine why it is being called by the MIP solver the callback
   16.53 +routine should use the routine \verb|glp_ios_reason| (described in this
   16.54 +section below), which returns a code indicating the reason for calling.
   16.55 +Depending on the reason the callback routine may perform necessary
   16.56 +actions to control the solution process.
   16.57 +
   16.58 +The reason codes, which correspond to various point of the
   16.59 +branch-and-cut algorithm implemented in the MIP solver, are described
   16.60 +in Subsection ``Reasons for calling the callback routine'' below.
   16.61 +
   16.62 +To ignore calls for reasons, which are not processed by the callback
   16.63 +routine, it should just return to the MIP solver doing nothing. For
   16.64 +example:
   16.65 +
   16.66 +\begin{verbatim}
   16.67 +void foo_bar(glp_tree *tree, void *info)
   16.68 +{     . . .
   16.69 +      switch (glp_ios_reason(tree))
   16.70 +      {  case GLP_IBRANCH:
   16.71 +            . . .
   16.72 +            break;
   16.73 +         case GLP_ISELECT:
   16.74 +            . . .
   16.75 +            break;
   16.76 +         default:
   16.77 +            /* ignore call for other reasons */
   16.78 +            break;
   16.79 +      }
   16.80 +      return;
   16.81 +}
   16.82 +\end{verbatim}
   16.83 +
   16.84 +To control the solution process as well as to obtain necessary
   16.85 +information the callback routine may use the branch-and-cut API
   16.86 +routines described in this chapter. Names of all these routines begin
   16.87 +with `\verb|glp_ios_|'.
   16.88 +
   16.89 +\subsection{Branch-and-cut algorithm}
   16.90 +
   16.91 +This section gives a schematic description of the branch-and-cut
   16.92 +algorithm as it is implemented in the GLPK MIP solver.
   16.93 +
   16.94 +\medskip
   16.95 +
   16.96 +{\it 1. Initialization}
   16.97 +
   16.98 +Set $L:=\{P_0\}$, where $L$ is the {\it active list} (i.e. the list of
   16.99 +active subproblems), $P_0$ is the original MIP problem to be solved.
  16.100 +
  16.101 +Set $z^{\it best}:=+\infty$ (in case of minimization) or
  16.102 +$z^{\it best}:=-\infty$ (in case of maximization), where $z^{\it best}$
  16.103 +is {\it incumbent value}, i.e. an upper (minimization) or lower
  16.104 +(maximization) global bound for $z^{\it opt}$, the optimal objective
  16.105 +value for $P^0$.
  16.106 +
  16.107 +\medskip
  16.108 +
  16.109 +{\it 2. Subproblem selection}
  16.110 +
  16.111 +If $L=\varnothing$ then GO TO 9.
  16.112 +
  16.113 +Select $P\in L$, i.e. make active subproblem $P$ current.
  16.114 +
  16.115 +\medskip
  16.116 +
  16.117 +{\it 3. Solving LP relaxation}
  16.118 +
  16.119 +Solve $P^{\it LP}$, which is LP relaxation of $P$.
  16.120 +
  16.121 +If $P^{\it LP}$ has no primal feasible solution then GO TO 8.
  16.122 +
  16.123 +Let $z^{\it LP}$ be the optimal objective value for $P^{\it LP}$.
  16.124 +
  16.125 +If $z^{\it LP}\geq z^{\it best}$ (in case of minimization) or
  16.126 +$z^{\it LP}\leq z^{\rm best}$ (in case of maximization) then GO TO 8.
  16.127 +
  16.128 +\medskip
  16.129 +
  16.130 +{\it 4. Adding ``lazy'' constraints}
  16.131 +
  16.132 +Let $x^{\it LP}$ be the optimal solution to $P^{\it LP}$.
  16.133 +
  16.134 +If there are ``lazy'' constraints (i.e. essential constraints not
  16.135 +included in the original MIP problem $P_0$), which are violated at the
  16.136 +optimal point $x^{\it LP}$, add them to $P$, and GO TO 3.
  16.137 +
  16.138 +\medskip
  16.139 +
  16.140 +{\it 5. Check for integrality}
  16.141 +
  16.142 +Let $x_j$ be a variable, which is required to be integer, and let
  16.143 +$x^{\it LP}_j\in x^{\it LP}$ be its value in the optimal solution to
  16.144 +$P^{\it LP}$.
  16.145 +
  16.146 +If $x^{\it LP}_j$ are integral for all integer variables, then a better
  16.147 +integer feasible solution is found. Store its components, set
  16.148 +$z^{\it best}:=z^{\it LP}$, and GO TO 8.
  16.149 +
  16.150 +\medskip
  16.151 +
  16.152 +{\it 6. Adding cutting planes}
  16.153 +
  16.154 +If there are cutting planes (i.e. valid constraints for $P$),
  16.155 +which are violated at the optimal point $x^{\it LP}$, add them to $P$,
  16.156 +and GO TO 3.
  16.157 +
  16.158 +\medskip
  16.159 +
  16.160 +{\it 7. Branching}
  16.161 +
  16.162 +Select {\it branching variable} $x_j$, i.e. a variable, which is
  16.163 +required to be integer, and whose value $x^{\it LP}_j\in x^{\it LP}$ is
  16.164 +fractional in the optimal solution to $P^{\it LP}$.
  16.165 +
  16.166 +Create new subproblem $P^D$ (so called {\it down branch}), which is
  16.167 +identical to the current subproblem $P$ with exception that the upper
  16.168 +bound of $x_j$ is replaced by $\lfloor x^{\it LP}_j\rfloor$. (For
  16.169 +example, if $x^{\it LP}_j=3.14$, the new upper bound of $x_j$ in the
  16.170 +down branch will be $\lfloor 3.14\rfloor=3$.)
  16.171 +
  16.172 +Create new subproblem $P^U$ (so called {\it up branch}), which is
  16.173 +identical to the current subproblem $P$ with exception that the lower
  16.174 +bound of $x_j$ is replaced by $\lceil x^{\it LP}_j\rceil$. (For example,
  16.175 +if $x^{\it LP}_j=3.14$, the new lower bound of $x_j$ in the up branch
  16.176 +will be $\lceil 3.14\rceil=4$.)
  16.177 +
  16.178 +Set $L:=(L\backslash\{P\})\cup\{P^D,P^U\}$, i.e. remove the current
  16.179 +subproblem $P$ from the active list $L$ and add two new subproblems
  16.180 +$P^D$ and $P^U$ to it. Then GO TO 2.
  16.181 +
  16.182 +\medskip
  16.183 +
  16.184 +{\it 8. Pruning}
  16.185 +
  16.186 +Remove from the active list $L$ all subproblems (including the current
  16.187 +one), whose local bound $\widetilde{z}$ is not better than the global
  16.188 +bound $z^{\it best}$, i.e. set $L:=L\backslash\{P\}$ for all $P$, where
  16.189 +$\widetilde{z}\geq z^{\it best}$ (in case of minimization) or
  16.190 +$\widetilde{z}\leq z^{\it best}$ (in case of maximization), and then
  16.191 +GO TO 2.
  16.192 +
  16.193 +The local bound $\widetilde{z}$ for subproblem $P$ is an lower
  16.194 +(minimization) or upper (maximization) bound for integer optimal
  16.195 +solution to {\it this} subproblem (not to the original problem). This
  16.196 +bound is local in the sense that only subproblems in the subtree rooted
  16.197 +at node $P$ cannot have better integer feasible solutions. Note that
  16.198 +the local bound is not necessarily the optimal objective value to LP
  16.199 +relaxation $P^{\it LP}$.
  16.200 +
  16.201 +\medskip
  16.202 +
  16.203 +{\it 9. Termination}
  16.204 +
  16.205 +If $z^{\it best}=+\infty$ (in case of minimization) or
  16.206 +$z^{\it best}=-\infty$ (in case of maximization), the original problem
  16.207 +$P_0$ has no integer feasible solution. Otherwise, the last integer
  16.208 +feasible solution stored on step 5 is the integer optimal solution to
  16.209 +the original problem $P_0$ with $z^{\it opt}=z^{\it best}$. STOP.
  16.210 +
  16.211 +\subsection{The search tree}
  16.212 +
  16.213 +On the branching step of the branch-and-cut algorithm the current
  16.214 +subproblem is divided into two\footnote{In more general cases the
  16.215 +current subproblem may be divided into more than two subproblems.
  16.216 +However, currently such feature is not used in GLPK.} new subproblems,
  16.217 +so the set of all subproblems can be represented in the form of a rooted
  16.218 +tree, which is called the {\it search} or {\it branch-and-bound} tree.
  16.219 +An example of the search tree is shown on Fig.~1. Each node of the
  16.220 +search tree corresponds to a subproblem, so the terms `node' and
  16.221 +`subproblem' may be used synonymously.
  16.222 +
  16.223 +\newpage
  16.224 +
  16.225 +\begin{figure}[t]
  16.226 +\noindent\hfil
  16.227 +\xymatrix @R=20pt @C=10pt
  16.228 +{&&&&&&*+<14pt>[o][F=]{A}\ar@{-}[dllll]\ar@{-}[dr]\ar@{-}[drrrr]&&&&\\
  16.229 +&&*+<14pt>[o][F=]{B}\ar@{-}[dl]\ar@{-}[dr]&&&&&*+<14pt>[o][F=]{C}
  16.230 +\ar@{-}[dll]\ar@{-}[dr]\ar@{-}[drrr]&&&*+<14pt>[o][F-]{\times}\\
  16.231 +&*+<14pt>[o][F-]{\times}\ar@{-}[dl]\ar@{-}[d]\ar@{-}[dr]&&
  16.232 +*+<14pt>[o][F-]{D}&&*+<14pt>[o][F=]{E}\ar@{-}[dl]\ar@{-}[dr]&&&
  16.233 +*+<14pt>[o][F=]{F}\ar@{-}[dl]\ar@{-}[dr]&&*+<14pt>[o][F-]{G}\\
  16.234 +*+<14pt>[o][F-]{\times}&*+<14pt>[o][F-]{\times}&*+<14pt>[o][F-]{\times}
  16.235 +&&*+<14pt>[][F-]{H}&&*+<14pt>[o][F-]{I}&*+<14pt>[o][F-]{\times}&&
  16.236 +*+<14pt>[o][F-]{J}&\\}
  16.237 +
  16.238 +\bigskip
  16.239 +
  16.240 +\noindent\hspace{.8in}
  16.241 +\xymatrix @R=11pt
  16.242 +{*+<20pt>[][F-]{}&*\txt{\makebox[1in][l]{Current}}&&
  16.243 +*+<20pt>[o][F-]{}&*\txt{\makebox[1in][l]{Active}}\\
  16.244 +*+<20pt>[o][F=]{}&*\txt{\makebox[1in][l]{Non-active}}&&
  16.245 +*+<14pt>[o][F-]{\times}&*\txt{\makebox[1in][l]{Fathomed}}\\
  16.246 +}
  16.247 +
  16.248 +\begin{center}
  16.249 +Fig. 1. An example of the search tree.
  16.250 +\end{center}
  16.251 +\end{figure}
  16.252 +
  16.253 +In GLPK each node may have one of the following four statuses:
  16.254 +
  16.255 +$\bullet$ {\it current node} is the active node currently being
  16.256 +processed;
  16.257 +
  16.258 +$\bullet$ {\it active node} is a leaf node, which still has to be
  16.259 +processed;
  16.260 +
  16.261 +$\bullet$ {\it non-active node} is a node, which has been processed,
  16.262 +but not fathomed;
  16.263 +
  16.264 +$\bullet$ {\it fathomed node} is a node, which has been processed and
  16.265 +fathomed.
  16.266 +
  16.267 +In the data structure representing the search tree GLPK keeps only
  16.268 +current, active, and non-active nodes. Once a node has been fathomed,
  16.269 +it is removed from the tree data structure.
  16.270 +
  16.271 +Being created each node of the search tree is assigned a distinct
  16.272 +positive integer called the {\it subproblem reference number}, which
  16.273 +may be used by the application program to specify a particular node of
  16.274 +the tree. The root node corresponding to the original problem to be
  16.275 +solved is always assigned the reference number 1.
  16.276 +
  16.277 +\subsection{Current subproblem}
  16.278 +
  16.279 +The current subproblem is a MIP problem corresponding to the current
  16.280 +node of the search tree. It is represented as the GLPK problem object
  16.281 +(\verb|glp_prob|) that allows the application program using API routines
  16.282 +to access its content in the standard way. If the MIP presolver is not
  16.283 +used, it is the original problem object passed to the routine
  16.284 +\verb|glp_intopt|; otherwise, it is an internal problem object built by
  16.285 +the MIP presolver.
  16.286 +
  16.287 +Note that the problem object is used by the MIP solver itself during
  16.288 +the solution process for various purposes (to solve LP relaxations, to
  16.289 +perfom branching, etc.), and even if the MIP presolver is not used, the
  16.290 +current content of the problem object may differ from its original
  16.291 +content. For example, it may have additional rows, bounds of some rows
  16.292 +and columns may be changed, etc. In particular, LP segment of the
  16.293 +problem object corresponds to LP relaxation of the current subproblem.
  16.294 +However, on exit from the MIP solver the content of the problem object
  16.295 +is restored to its original state.
  16.296 +
  16.297 +To obtain information from the problem object the application program
  16.298 +may use any API routines, which do not change the object. Using API
  16.299 +routines, which change the problem object, is restricted to stipulated
  16.300 +cases.
  16.301 +
  16.302 +\subsection{The cut pool}
  16.303 +
  16.304 +The {\it cut pool} is a set of cutting plane constraints maintained by
  16.305 +the MIP solver. It is used by the GLPK cut generation routines and may
  16.306 +be used by the application program in the same way, i.e. rather than
  16.307 +to add cutting plane constraints directly to the problem object the
  16.308 +application program may store them to the cut pool. In the latter case
  16.309 +the solver looks through the cut pool, selects efficient constraints,
  16.310 +and adds them to the problem object.
  16.311 +
  16.312 +\subsection{Reasons for calling the callback routine}
  16.313 +
  16.314 +The callback routine may be called by the MIP solver for the following
  16.315 +reasons.
  16.316 +
  16.317 +\subsubsection*{Request for subproblem selection}
  16.318 +
  16.319 +The callback routine is called with the reason code \verb|GLP_ISELECT|
  16.320 +if the current subproblem has been fathomed and therefore there is no
  16.321 +current subproblem.
  16.322 +
  16.323 +In response the callback routine may select some subproblem from the
  16.324 +active list and pass its reference number to the solver using the
  16.325 +routine \verb|glp_ios_select_node|, in which case the solver continues
  16.326 +the search from the specified active subproblem. If no selection is made
  16.327 +by the callback routine, the solver uses a backtracking technique
  16.328 +specified by the control parameter \verb|bt_tech|.
  16.329 +
  16.330 +To explore the active list (i.e. active nodes of the branch-and-bound
  16.331 +tree) the callback routine may use the routines \verb|glp_ios_next_node|
  16.332 +and \verb|glp_ios_prev_node|.
  16.333 +
  16.334 +\subsubsection*{Request for preprocessing}
  16.335 +
  16.336 +The callback routine is called with the reason code \verb|GLP_IPREPRO|
  16.337 +if the current subproblem has just been selected from the active list
  16.338 +and its LP relaxation is not solved yet.
  16.339 +
  16.340 +In response the callback routine may perform some preprocessing of the
  16.341 +current subproblem like tightening bounds of some variables or removing
  16.342 +bounds of some redundant constraints.
  16.343 +
  16.344 +\subsubsection*{Request for row generation}
  16.345 +
  16.346 +The callback routine is called with the reason code \verb|GLP_IROWGEN|
  16.347 +if LP relaxation of the current subproblem has just been solved to
  16.348 +optimality and its objective value is better than the best known integer
  16.349 +feasible solution.
  16.350 +
  16.351 +In response the callback routine may add one or more ``lazy''
  16.352 +constraints (rows), which are violated by the current optimal solution
  16.353 +of LP relaxation, using API routines \verb|glp_add_rows|,
  16.354 +\verb|glp_set_row_name|, \verb|glp_set_row_bnds|, and
  16.355 +\verb|glp_set_mat_row|, in which case the solver will perform
  16.356 +re-optimization of LP relaxation. If there are no violated constraints,
  16.357 +the callback routine should just return.
  16.358 +
  16.359 +Optimal solution components for LP relaxation can be obtained with API
  16.360 +routines \verb|glp_get_obj_val|, \verb|glp_get_row_prim|,
  16.361 +\verb|glp_get_row_dual|, \verb|glp_get_col_prim|, and
  16.362 +\verb|glp_get_col_dual|.
  16.363 +
  16.364 +\subsubsection*{Request for heuristic solution}
  16.365 +
  16.366 +The callback routine is called with the reason code \verb|GLP_IHEUR|
  16.367 +if LP relaxation of the current subproblem being solved to optimality
  16.368 +is integer infeasible (i.e. values of some structural variables of
  16.369 +integer kind are fractional), though its objective value is better than
  16.370 +the best known integer feasible solution.
  16.371 +
  16.372 +In response the callback routine may try applying a primal heuristic
  16.373 +to find an integer feasible solution,\footnote{Integer feasible to the
  16.374 +original MIP problem, not to the current subproblem.} which is better
  16.375 +than the best known one. In case of success the callback routine may
  16.376 +store such better solution in the problem object using the routine
  16.377 +\verb|glp_ios_heur_sol|.
  16.378 +
  16.379 +\subsubsection*{Request for cut generation}
  16.380 +
  16.381 +The callback routine is called with the reason code \verb|GLP_ICUTGEN|
  16.382 +if LP relaxation of the current subproblem being solved to optimality
  16.383 +is integer infeasible (i.e. values of some structural variables of
  16.384 +integer kind are fractional), though its objective value is better than
  16.385 +the best known integer feasible solution.
  16.386 +
  16.387 +In response the callback routine may reformulate the {\it current}
  16.388 +subproblem (before it will be splitted up due to branching) by adding to
  16.389 +the problem object one or more {\it cutting plane constraints}, which
  16.390 +cut off the fractional optimal point from the MIP
  16.391 +polytope.\footnote{Since these constraints are added to the current
  16.392 +subproblem, they may be globally as well as locally valid.}
  16.393 +
  16.394 +Adding cutting plane constraints may be performed in two ways.
  16.395 +One way is the same as for the reason code \verb|GLP_IROWGEN| (see
  16.396 +above), in which case the callback routine adds new rows corresponding
  16.397 +to cutting plane constraints directly to the current subproblem.
  16.398 +
  16.399 +The other way is to add cutting plane constraints to the {\it cut pool},
  16.400 +a set of cutting plane constraints maintained by the solver, rather than
  16.401 +directly to the current subproblem. In this case after return from the
  16.402 +callback routine the solver looks through the cut pool, selects
  16.403 +efficient cutting plane constraints, adds them to the current
  16.404 +subproblem, drops other constraints, and then performs re-optimization.
  16.405 +
  16.406 +\subsubsection*{Request for branching}
  16.407 +
  16.408 +The callback routine is called with the reason code \verb|GLP_IBRANCH|
  16.409 +if LP relaxation of the current subproblem being solved to optimality
  16.410 +is integer infeasible (i.e. values of some structural variables of
  16.411 +integer kind are fractional), though its objective value is better than
  16.412 +the best known integer feasible solution.
  16.413 +
  16.414 +In response the callback routine may choose some variable suitable for
  16.415 +branching (i.e. integer variable, whose value in optimal solution to
  16.416 +LP relaxation of the current subproblem is fractional) and pass its
  16.417 +ordinal number to the solver using the routine
  16.418 +\verb|glp_ios_branch_upon|, in which case the solver splits the current
  16.419 +subproblem in two new subproblems and continues the search. If no choice
  16.420 +is made by the callback routine, the solver uses a branching technique
  16.421 +specified by the control parameter \verb|br_tech|.
  16.422 +
  16.423 +\subsubsection*{Better integer solution found}
  16.424 +
  16.425 +The callback routine is called with the reason code \verb|GLP_IBINGO|
  16.426 +if LP relaxation of the current subproblem being solved to optimality
  16.427 +is integer feasible (i.e. values of all structural variables of integer
  16.428 +kind are integral within the working precision) and its objective value
  16.429 +is better than the best known integer feasible solution.
  16.430 +
  16.431 +Optimal solution components for LP relaxation can be obtained in the
  16.432 +same way as for the reason code \verb|GLP_IROWGEN| (see above).
  16.433 +
  16.434 +Components of the new MIP solution can be obtained with API routines
  16.435 +\verb|glp_mip_obj_val|, \verb|glp_mip_row_val|, and
  16.436 +\verb|glp_mip_col_val|. Note, however, that due to row/cut generation
  16.437 +there may be additional rows in the problem object.
  16.438 +
  16.439 +The difference between optimal solution to LP relaxation and
  16.440 +corresponding MIP solution is that in the former case some structural
  16.441 +variables of integer kind (namely, basic variables) may have values,
  16.442 +which are close to nearest integers within the working precision, while
  16.443 +in the latter case all such variables have exact integral values.
  16.444 +
  16.445 +The reason \verb|GLP_IBINGO| is intended only for informational
  16.446 +purposes, so the callback routine should not modify the problem object
  16.447 +in this case.
  16.448 +
  16.449 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  16.450 +
  16.451 +\newpage
  16.452 +
  16.453 +\section{Basic routines}
  16.454 +
  16.455 +\subsection{glp\_ios\_reason---determine reason for calling the
  16.456 +callback routine}
  16.457 +
  16.458 +\subsubsection*{Synopsis}
  16.459 +
  16.460 +\begin{verbatim}
  16.461 +int glp_ios_reason(glp_tree *tree);
  16.462 +\end{verbatim}
  16.463 +
  16.464 +\subsubsection*{Returns}
  16.465 +
  16.466 +The routine \verb|glp_ios_reason| returns a code, which indicates why
  16.467 +the user-defined callback routine is being called:
  16.468 +
  16.469 +\verb|GLP_ISELECT|---request for subproblem selection;
  16.470 +
  16.471 +\verb|GLP_IPREPRO|---request for preprocessing;
  16.472 +
  16.473 +\verb|GLP_IROWGEN|---request for row generation;
  16.474 +
  16.475 +\verb|GLP_IHEUR  |---request for heuristic solution;
  16.476 +
  16.477 +\verb|GLP_ICUTGEN|---request for cut generation;
  16.478 +
  16.479 +\verb|GLP_IBRANCH|---request for branching;
  16.480 +
  16.481 +\verb|GLP_IBINGO |---better integer solution found.
  16.482 +
  16.483 +\subsection{glp\_ios\_get\_prob---access the problem object}
  16.484 +
  16.485 +\subsubsection*{Synopsis}
  16.486 +
  16.487 +\begin{verbatim}
  16.488 +glp_prob *glp_ios_get_prob(glp_tree *tree);
  16.489 +\end{verbatim}
  16.490 +
  16.491 +\subsubsection*{Description}
  16.492 +
  16.493 +The routine \verb|glp_ios_get_prob| can be called from the user-defined
  16.494 +callback routine to access the problem object, which is used by the MIP
  16.495 +solver. It is the original problem object passed to the routine
  16.496 +\verb|glp_intopt| if the MIP presolver is not used; otherwise it is an
  16.497 +internal problem object built by the presolver.
  16.498 +
  16.499 +\subsubsection*{Returns}
  16.500 +
  16.501 +The routine \verb|glp_ios_get_prob| returns a pointer to the problem
  16.502 +object used by the MIP solver.
  16.503 +
  16.504 +\subsubsection*{Comments}
  16.505 +
  16.506 +To obtain various information about the problem instance the callback
  16.507 +routine can access the problem object (i.e. the object of type
  16.508 +\verb|glp_prob|) using the routine \verb|glp_ios_get_prob|. It is the
  16.509 +original problem object passed to the routine \verb|glp_intopt| if the
  16.510 +MIP presolver is not used; otherwise it is an internal problem object
  16.511 +built by the presolver.
  16.512 +
  16.513 +\subsection{glp\_ios\_row\_attr---determine additional row attributes}
  16.514 +
  16.515 +\subsubsection*{Synopsis}
  16.516 +
  16.517 +\begin{verbatim}
  16.518 +void glp_ios_row_attr(glp_tree *tree, int i, glp_attr *attr);
  16.519 +\end{verbatim}
  16.520 +
  16.521 +\subsubsection*{Description}
  16.522 +
  16.523 +The routine \verb|glp_ios_row_attr| retrieves additional attributes of
  16.524 +$i$-th row of the current subproblem and stores them in the structure
  16.525 +\verb|glp_attr|, which the parameter \verb|attr| points to.
  16.526 +
  16.527 +The structure \verb|glp_attr| has the following fields:
  16.528 +
  16.529 +\medskip
  16.530 +
  16.531 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
  16.532 +\multicolumn{2}{@{}l}{{\tt int level}}\\
  16.533 +&Subproblem level at which the row was created. (If \verb|level| = 0,
  16.534 +the row was added either to the original problem object passed to the
  16.535 +routine \verb|glp_intopt| or to the root subproblem on generating
  16.536 +``lazy'' or/and cutting plane constraints.)\\
  16.537 +\end{tabular}
  16.538 +
  16.539 +\medskip
  16.540 +
  16.541 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
  16.542 +\multicolumn{2}{@{}l}{{\tt int origin}}\\
  16.543 +&The row origin flag:\\
  16.544 +&\verb|GLP_RF_REG |---regular constraint;\\
  16.545 +&\verb|GLP_RF_LAZY|---``lazy'' constraint;\\
  16.546 +&\verb|GLP_RF_CUT |---cutting plane constraint.\\
  16.547 +\end{tabular}
  16.548 +
  16.549 +\medskip
  16.550 +
  16.551 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
  16.552 +\multicolumn{2}{@{}l}{{\tt int klass}}\\
  16.553 +&The row class descriptor, which is a number passed to the routine
  16.554 +\verb|glp_ios_add_row| as its third parameter. If the row is a cutting
  16.555 +plane constraint generated by the solver, its class may be the
  16.556 +following:\\
  16.557 +&\verb|GLP_RF_GMI |---Gomory's mixed integer cut;\\
  16.558 +&\verb|GLP_RF_MIR |---mixed integer rounding cut;\\
  16.559 +&\verb|GLP_RF_COV |---mixed cover cut;\\
  16.560 +&\verb|GLP_RF_CLQ |---clique cut.\\
  16.561 +\end{tabular}
  16.562 +
  16.563 +\newpage
  16.564 +
  16.565 +\subsection{glp\_ios\_mip\_gap---compute relative MIP gap}
  16.566 +
  16.567 +\subsubsection*{Synopsis}
  16.568 +
  16.569 +\begin{verbatim}
  16.570 +double glp_ios_mip_gap(glp_tree *tree);
  16.571 +\end{verbatim}
  16.572 +
  16.573 +\subsubsection*{Description}
  16.574 +
  16.575 +The routine \verb|glp_ios_mip_gap| computes the relative MIP gap (also
  16.576 +called {\it duality gap}) with the following formula:
  16.577 +$${\tt gap} = \frac{|{\tt best\_mip} - {\tt best\_bnd}|}
  16.578 +{|{\tt best\_mip}| + {\tt DBL\_EPSILON}}$$
  16.579 +where \verb|best_mip| is the best integer feasible solution found so
  16.580 +far, \verb|best_bnd| is the best (global) bound. If no integer feasible
  16.581 +solution has been found yet, \verb|gap| is set to \verb|DBL_MAX|.
  16.582 +
  16.583 +\subsubsection*{Returns}
  16.584 +
  16.585 +The routine \verb|glp_ios_mip_gap| returns the relative MIP gap.
  16.586 +
  16.587 +\subsubsection*{Comments}
  16.588 +
  16.589 +The relative MIP gap is used to measure the quality of the best integer
  16.590 +feasible solution found so far, because the optimal solution value
  16.591 +$z^*$ for the original MIP problem always lies in the range
  16.592 +$${\tt best\_bnd}\leq z^*\leq{\tt best\_mip}$$
  16.593 +in case of minimization, or in the range
  16.594 +$${\tt best\_mip}\leq z^*\leq{\tt best\_bnd}$$
  16.595 +in case of maximization.
  16.596 +
  16.597 +To express the relative MIP gap in percents the value returned by the
  16.598 +routine \verb|glp_ios_mip_gap| should be multiplied by 100\%.
  16.599 +
  16.600 +\newpage
  16.601 +
  16.602 +\subsection{glp\_ios\_node\_data---access application-specific data}
  16.603 +
  16.604 +\subsubsection*{Synopsis}
  16.605 +
  16.606 +\begin{verbatim}
  16.607 +void *glp_ios_node_data(glp_tree *tree, int p);
  16.608 +\end{verbatim}
  16.609 +
  16.610 +\subsubsection*{Description}
  16.611 +
  16.612 +The routine \verb|glp_ios_node_data| allows the application accessing a
  16.613 +memory block allocated for the subproblem (which may be active or
  16.614 +inactive), whose reference number is $p$.
  16.615 +
  16.616 +The size of the block is defined by the control parameter \verb|cb_size|
  16.617 +passed to the routine \verb|glp_intopt|. The block is initialized by
  16.618 +binary zeros on creating corresponding subproblem, and its contents is
  16.619 +kept until the subproblem will be removed from the tree.
  16.620 +
  16.621 +The application may use these memory blocks to store specific data for
  16.622 +each subproblem.
  16.623 +
  16.624 +\subsubsection*{Returns}
  16.625 +
  16.626 +The routine \verb|glp_ios_node_data| returns a pointer to the memory
  16.627 +block for the specified subproblem. Note that if \verb|cb_size| = 0, the
  16.628 +routine returns a null pointer.
  16.629 +
  16.630 +\subsection{glp\_ios\_select\_node---select subproblem to continue the
  16.631 +search}
  16.632 +
  16.633 +\subsubsection*{Synopsis}
  16.634 +
  16.635 +\begin{verbatim}
  16.636 +void glp_ios_select_node(glp_tree *tree, int p);
  16.637 +\end{verbatim}
  16.638 +
  16.639 +\subsubsection*{Description}
  16.640 +
  16.641 +The routine \verb|glp_ios_select_node| can be called from the
  16.642 +user-defined callback routine in response to the reason
  16.643 +\verb|GLP_ISELECT| to select an active subproblem, whose reference
  16.644 +number is $p$. The search will be continued from the subproblem
  16.645 +selected.
  16.646 +
  16.647 +\newpage
  16.648 +
  16.649 +\subsection{glp\_ios\_heur\_sol---provide solution found by heuristic}
  16.650 +
  16.651 +\subsubsection*{Synopsis}
  16.652 +
  16.653 +\begin{verbatim}
  16.654 +int glp_ios_heur_sol(glp_tree *tree, const double x[]);
  16.655 +\end{verbatim}
  16.656 +
  16.657 +\subsubsection*{Description}
  16.658 +
  16.659 +The routine \verb|glp_ios_heur_sol| can be called from the user-defined
  16.660 +callback routine in response to the reason \verb|GLP_IHEUR| to provide
  16.661 +an integer feasible solution found by a primal heuristic.
  16.662 +
  16.663 +Primal values of {\it all} variables (columns) found by the heuristic
  16.664 +should be placed in locations $x[1]$, \dots, $x[n]$, where $n$ is the
  16.665 +number of columns in the original problem object. Note that the routine
  16.666 +\verb|glp_ios_heur_sol| does {\it not} check primal feasibility of the
  16.667 +solution provided.
  16.668 +
  16.669 +Using the solution passed in the array $x$ the routine computes value
  16.670 +of the objective function. If the objective value is better than the
  16.671 +best known integer feasible solution, the routine computes values of
  16.672 +auxiliary variables (rows) and stores all solution components in the
  16.673 +problem object.
  16.674 +
  16.675 +\subsubsection*{Returns}
  16.676 +
  16.677 +If the provided solution is accepted, the routine
  16.678 +\verb|glp_ios_heur_sol| returns zero. Otherwise, if the provided
  16.679 +solution is rejected, the routine returns non-zero.
  16.680 +
  16.681 +\subsection{glp\_ios\_can\_branch---check if can branch upon specified
  16.682 +variable}
  16.683 +
  16.684 +\subsubsection*{Synopsis}
  16.685 +
  16.686 +\begin{verbatim}
  16.687 +int glp_ios_can_branch(glp_tree *tree, int j);
  16.688 +\end{verbatim}
  16.689 +
  16.690 +\subsubsection*{Returns}
  16.691 +
  16.692 +If $j$-th variable (column) can be used to branch upon, the routine
  16.693 +returns non-zero, otherwise zero.
  16.694 +
  16.695 +\newpage
  16.696 +
  16.697 +\subsection{glp\_ios\_branch\_upon---choose variable to branch upon}
  16.698 +
  16.699 +\subsubsection*{Synopsis}
  16.700 +
  16.701 +\begin{verbatim}
  16.702 +void glp_ios_branch_upon(glp_tree *tree, int j, int sel);
  16.703 +\end{verbatim}
  16.704 +
  16.705 +\subsubsection*{Description}
  16.706 +
  16.707 +The routine \verb|glp_ios_branch_upon| can be called from the
  16.708 +user-defined callback routine in response to the reason
  16.709 +\verb|GLP_IBRANCH| to choose a branching variable, whose ordinal number
  16.710 +is $j$. Should note that only variables, for which the routine
  16.711 +\verb|glp_ios_can_branch| returns non-zero, can be used to branch upon.
  16.712 +
  16.713 +The parameter \verb|sel| is a flag that indicates which branch
  16.714 +(subproblem) should be selected next to continue the search:
  16.715 +
  16.716 +\verb|GLP_DN_BRNCH|---select down-branch;
  16.717 +
  16.718 +\verb|GLP_UP_BRNCH|---select up-branch;
  16.719 +
  16.720 +\verb|GLP_NO_BRNCH|---use general selection technique.
  16.721 +
  16.722 +\subsubsection*{Comments}
  16.723 +
  16.724 +On branching the solver removes the current active subproblem from the
  16.725 +active list and creates two new subproblems ({\it down-} and {\it
  16.726 +up-branches}), which are added to the end of the active list. Note that
  16.727 +the down-branch is created before the up-branch, so the last active
  16.728 +subproblem will be the up-branch.
  16.729 +
  16.730 +The down- and up-branches are identical to the current subproblem with
  16.731 +exception that in the down-branch the upper bound of $x_j$, the variable
  16.732 +chosen to branch upon, is replaced by $\lfloor x_j^*\rfloor$, while in
  16.733 +the up-branch the lower bound of $x_j$ is replaced by
  16.734 +$\lceil x_j^*\rceil$, where $x_j^*$ is the value of $x_j$ in optimal
  16.735 +solution to LP relaxation of the current subproblem. For example, if
  16.736 +$x_j^*=3.14$, the new upper bound of $x_j$ in the down-branch is
  16.737 +$\lfloor 3.14\rfloor=3$, and the new lower bound in the up-branch is
  16.738 +$\lceil 3.14\rceil=4$.)
  16.739 +
  16.740 +Additionally the callback routine may select either down- or up-branch,
  16.741 +from which the solver will continue the search. If none of the branches
  16.742 +is selected, a general selection technique will be used.
  16.743 +
  16.744 +\newpage
  16.745 +
  16.746 +\subsection{glp\_ios\_terminate---terminate the solution process}
  16.747 +
  16.748 +\subsubsection*{Synopsis}
  16.749 +
  16.750 +\begin{verbatim}
  16.751 +void glp_ios_terminate(glp_tree *tree);
  16.752 +\end{verbatim}
  16.753 +
  16.754 +\subsubsection*{Description}
  16.755 +
  16.756 +The routine \verb|glp_ios_terminate| sets a flag indicating that the
  16.757 +MIP solver should prematurely terminate the search.
  16.758 +
  16.759 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  16.760 +
  16.761 +\newpage
  16.762 +
  16.763 +\section{The search tree exploring routines}
  16.764 +
  16.765 +\subsection{glp\_ios\_tree\_size---determine size of the search tree}
  16.766 +
  16.767 +\subsubsection*{Synopsis}
  16.768 +
  16.769 +\begin{verbatim}
  16.770 +void glp_ios_tree_size(glp_tree *tree, int *a_cnt, int *n_cnt,
  16.771 +      int *t_cnt);
  16.772 +\end{verbatim}
  16.773 +
  16.774 +\subsubsection*{Description}
  16.775 +
  16.776 +The routine \verb|glp_ios_tree_size| stores the following three counts
  16.777 +which characterize the current size of the search tree:
  16.778 +
  16.779 +\verb|a_cnt| is the current number of active nodes, i.e. the current
  16.780 +size of the active list;
  16.781 +
  16.782 +\verb|n_cnt| is the current number of all (active and inactive) nodes;
  16.783 +
  16.784 +\verb|t_cnt| is the total number of nodes including those which have
  16.785 +been already removed from the tree. This count is increased whenever
  16.786 +a new node appears in the tree and never decreased.
  16.787 +
  16.788 +If some of the parameters \verb|a_cnt|, \verb|n_cnt|, \verb|t_cnt| is
  16.789 +a null pointer, the corresponding count is not stored.
  16.790 +
  16.791 +\subsection{glp\_ios\_curr\_node---determine current active subprob-\\
  16.792 +lem}
  16.793 +
  16.794 +\subsubsection*{Synopsis}
  16.795 +
  16.796 +\begin{verbatim}
  16.797 +int glp_ios_curr_node(glp_tree *tree);
  16.798 +\end{verbatim}
  16.799 +
  16.800 +\subsubsection*{Returns}
  16.801 +
  16.802 +The routine \verb|glp_ios_curr_node| returns the reference number of the
  16.803 +current active subproblem. However, if the current subproblem does not
  16.804 +exist, the routine returns zero.
  16.805 +
  16.806 +\newpage
  16.807 +
  16.808 +\subsection{glp\_ios\_next\_node---determine next active subproblem}
  16.809 +
  16.810 +\subsubsection*{Synopsis}
  16.811 +
  16.812 +\begin{verbatim}
  16.813 +int glp_ios_next_node(glp_tree *tree, int p);
  16.814 +\end{verbatim}
  16.815 +
  16.816 +\subsubsection*{Returns}
  16.817 +
  16.818 +If the parameter $p$ is zero, the routine \verb|glp_ios_next_node|
  16.819 +returns the reference number of the first active subproblem. However,
  16.820 +if the tree is empty, zero is returned.
  16.821 +
  16.822 +If the parameter $p$ is not zero, it must specify the reference number
  16.823 +of some active subproblem, in which case the routine returns the
  16.824 +reference number of the next active subproblem. However, if there is
  16.825 +no next active subproblem in the list, zero is returned.
  16.826 +
  16.827 +All subproblems in the active list are ordered chronologically, i.e.
  16.828 +subproblem $A$ precedes subproblem $B$ if $A$ was created before $B$.
  16.829 +
  16.830 +\subsection{glp\_ios\_prev\_node---determine previous active subproblem}
  16.831 +
  16.832 +\subsubsection*{Synopsis}
  16.833 +
  16.834 +\begin{verbatim}
  16.835 +int glp_ios_prev_node(glp_tree *tree, int p);
  16.836 +\end{verbatim}
  16.837 +
  16.838 +\subsubsection*{Returns}
  16.839 +
  16.840 +If the parameter $p$ is zero, the routine \verb|glp_ios_prev_node|
  16.841 +returns the reference number of the last active subproblem. However, if
  16.842 +the tree is empty, zero is returned.
  16.843 +
  16.844 +If the parameter $p$ is not zero, it must specify the reference number
  16.845 +of some active subproblem, in which case the routine returns the
  16.846 +reference number of the previous active subproblem. However, if there
  16.847 +is no previous active subproblem in the list, zero is returned.
  16.848 +
  16.849 +All subproblems in the active list are ordered chronologically, i.e.
  16.850 +subproblem $A$ precedes subproblem $B$ if $A$ was created before $B$.
  16.851 +
  16.852 +\newpage
  16.853 +
  16.854 +\subsection{glp\_ios\_up\_node---determine parent subproblem}
  16.855 +
  16.856 +\subsubsection*{Synopsis}
  16.857 +
  16.858 +\begin{verbatim}
  16.859 +int glp_ios_up_node(glp_tree *tree, int p);
  16.860 +\end{verbatim}
  16.861 +
  16.862 +\subsubsection*{Returns}
  16.863 +
  16.864 +The parameter $p$ must specify the reference number of some (active or
  16.865 +inactive) subproblem, in which case the routine \verb|iet_get_up_node|
  16.866 +returns the reference number of its parent subproblem. However, if the
  16.867 +specified subproblem is the root of the tree and, therefore, has
  16.868 +no parent, the routine returns zero.
  16.869 +
  16.870 +\subsection{glp\_ios\_node\_level---determine subproblem level}
  16.871 +
  16.872 +\subsubsection*{Synopsis}
  16.873 +
  16.874 +\begin{verbatim}
  16.875 +int glp_ios_node_level(glp_tree *tree, int p);
  16.876 +\end{verbatim}
  16.877 +
  16.878 +\subsubsection*{Returns}
  16.879 +
  16.880 +The routine \verb|glp_ios_node_level| returns the level of the
  16.881 +subproblem,\linebreak whose reference number is $p$, in the
  16.882 +branch-and-bound tree. (The root subproblem has level 0, and the level
  16.883 +of any other subproblem is the level of its parent plus one.)
  16.884 +
  16.885 +\subsection{glp\_ios\_node\_bound---determine subproblem local\\bound}
  16.886 +
  16.887 +\subsubsection*{Synopsis}
  16.888 +
  16.889 +\begin{verbatim}
  16.890 +double glp_ios_node_bound(glp_tree *tree, int p);
  16.891 +\end{verbatim}
  16.892 +
  16.893 +\subsubsection*{Returns}
  16.894 +
  16.895 +The routine \verb|glp_ios_node_bound| returns the local bound for
  16.896 +(active or inactive) subproblem, whose reference number is $p$.
  16.897 +
  16.898 +\subsubsection*{Comments}
  16.899 +
  16.900 +The local bound for subproblem $p$ is an lower (minimization) or upper
  16.901 +(maximization) bound for integer optimal solution to {\it this}
  16.902 +subproblem (not to the original problem). This bound is local in the
  16.903 +sense that only subproblems in the subtree rooted at node $p$ cannot
  16.904 +have better integer feasible solutions.
  16.905 +
  16.906 +On creating a subproblem (due to the branching step) its local bound is
  16.907 +inherited from its parent and then may get only stronger (never weaker).
  16.908 +For the root subproblem its local bound is initially set to
  16.909 +\verb|-DBL_MAX| (minimization) or \verb|+DBL_MAX| (maximization) and
  16.910 +then improved as the root LP relaxation has been solved.
  16.911 +
  16.912 +Note that the local bound is not necessarily the optimal objective value
  16.913 +to corresponding LP relaxation.
  16.914 +
  16.915 +\subsection{glp\_ios\_best\_node---find active subproblem with best
  16.916 +local bound}
  16.917 +
  16.918 +\subsubsection*{Synopsis}
  16.919 +
  16.920 +\begin{verbatim}
  16.921 +int glp_ios_best_node(glp_tree *tree);
  16.922 +\end{verbatim}
  16.923 +
  16.924 +\subsubsection*{Returns}
  16.925 +
  16.926 +The routine \verb|glp_ios_best_node| returns the reference number of
  16.927 +the active subproblem, whose local bound is best (i.e. smallest in case
  16.928 +of minimization or largest in case of maximization). However, if the
  16.929 +tree is empty, the routine returns zero.
  16.930 +
  16.931 +\subsubsection*{Comments}
  16.932 +
  16.933 +The best local bound is an lower (minimization) or upper (maximization)
  16.934 +bound for integer optimal solution to the original MIP problem.
  16.935 +
  16.936 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  16.937 +
  16.938 +\newpage
  16.939 +
  16.940 +\section{The cut pool routines}
  16.941 +
  16.942 +\subsection{glp\_ios\_pool\_size---determine current size of the cut\\
  16.943 +pool}
  16.944 +
  16.945 +\subsubsection*{Synopsis}
  16.946 +
  16.947 +\begin{verbatim}
  16.948 +int glp_ios_pool_size(glp_tree *tree);
  16.949 +\end{verbatim}
  16.950 +
  16.951 +\subsubsection*{Returns}
  16.952 +
  16.953 +The routine \verb|glp_ios_pool_size| returns the current size of the
  16.954 +cut pool, that is, the number of cutting plane constraints currently
  16.955 +added to it.
  16.956 +
  16.957 +\subsection{glp\_ios\_add\_row---add constraint to the cut pool}
  16.958 +
  16.959 +\subsubsection*{Synopsis}
  16.960 +
  16.961 +\begin{verbatim}
  16.962 +int glp_ios_add_row(glp_tree *tree, const char *name,
  16.963 +      int klass, int flags, int len, const int ind[],
  16.964 +      const double val[], int type, double rhs);
  16.965 +\end{verbatim}
  16.966 +
  16.967 +\subsubsection*{Description}
  16.968 +
  16.969 +The routine \verb|glp_ios_add_row| adds specified row (cutting plane
  16.970 +constraint) to the cut pool.
  16.971 +
  16.972 +The cutting plane constraint should have the following format:
  16.973 +$$\sum_{j\in J}a_jx_j\left\{\begin{array}{@{}c@{}}\geq\\\leq\\
  16.974 +\end{array}\right\}b,$$
  16.975 +where $J$ is a set of indices (ordinal numbers) of structural variables,
  16.976 +$a_j$ are constraint coefficients, $x_j$ are structural variables, $b$
  16.977 +is the right-hand side.
  16.978 +
  16.979 +The parameter \verb|name| specifies a symbolic name assigned to the
  16.980 +constraint (1 up to 255 characters). If it is \verb|NULL| or an empty
  16.981 +string, no name is assigned.
  16.982 +
  16.983 +The parameter \verb|klass| specifies the constraint class, which must
  16.984 +be either zero or a number in the range from 101 to 200. The application
  16.985 +may use this attribute to distinguish between cutting plane constraints
  16.986 +of different classes.\footnote{Constraint classes numbered from 1 to 100
  16.987 +are reserved for GLPK cutting plane generators.}
  16.988 +
  16.989 +The parameter \verb|flags| currently is not used and must be zero.
  16.990 +
  16.991 +Ordinal numbers of structural variables (i.e. column indices) $j\in J$
  16.992 +and numerical values of corresponding constraint coefficients $a_j$ must
  16.993 +be placed in locations \verb|ind[1]|, \dots, \verb|ind[len]| and
  16.994 +\verb|val[1]|, \dots, \verb|val[len]|, respectively, where
  16.995 +${\tt len}=|J|$ is the number of constraint coefficients,
  16.996 +$0\leq{\tt len}\leq n$, and $n$ is the number of columns in the problem
  16.997 +object. Coefficients with identical column indices are not allowed.
  16.998 +Zero coefficients are allowed, however, they are ignored.
  16.999 +
 16.1000 +The parameter \verb|type| specifies the constraint type as follows:
 16.1001 +
 16.1002 +\verb|GLP_LO| means inequality constraint $\Sigma a_jx_j\geq b$;
 16.1003 +
 16.1004 +\verb|GLP_UP| means inequality constraint $\Sigma a_jx_j\leq b$;
 16.1005 +
 16.1006 +The parameter \verb|rhs| specifies the right-hand side $b$.
 16.1007 +
 16.1008 +All cutting plane constraints in the cut pool are identified by their
 16.1009 +ordinal numbers 1, 2, \dots, $size$, where $size$ is the current size
 16.1010 +of the cut pool. New constraints are always added to the end of the cut
 16.1011 +pool, thus, ordinal numbers of previously added constraints are not
 16.1012 +changed.
 16.1013 +
 16.1014 +\subsubsection*{Returns}
 16.1015 +
 16.1016 +The routine \verb|glp_ios_add_row| returns the ordinal number of the
 16.1017 +cutting plane constraint added, which is the new size of the cut pool.
 16.1018 +
 16.1019 +\subsubsection*{Example}
 16.1020 +
 16.1021 +\begin{verbatim}
 16.1022 +/* generate triangle cutting plane:
 16.1023 +   x[i] + x[j] + x[k] <= 1 */
 16.1024 +. . .
 16.1025 +/* add the constraint to the cut pool */
 16.1026 +ind[1] = i, val[1] = 1.0;
 16.1027 +ind[2] = j, val[2] = 1.0;
 16.1028 +ind[3] = k, val[3] = 1.0;
 16.1029 +glp_ios_add_row(tree, NULL, TRIANGLE_CUT, 0, 3, ind, val,
 16.1030 +                GLP_UP, 1.0);
 16.1031 +\end{verbatim}
 16.1032 +
 16.1033 +\subsubsection*{Comments}
 16.1034 +
 16.1035 +Cutting plane constraints added to the cut pool are intended to be then
 16.1036 +added only to the {\it current} subproblem, so these constraints can be
 16.1037 +globally as well as locally valid. However, adding a constraint to the
 16.1038 +cut pool does not mean that it will be added to the current
 16.1039 +subproblem---it depends on the solver's decision: if the constraint
 16.1040 +seems to be efficient, it is moved from the pool to the current
 16.1041 +subproblem, otherwise it is simply dropped.\footnote{Globally valid
 16.1042 +constraints could be saved and then re-used for other subproblems, but
 16.1043 +currently such feature is not implemented.}
 16.1044 +
 16.1045 +Normally, every time the callback routine is called for cut generation,
 16.1046 +the cut pool is empty. On the other hand, the solver itself can generate
 16.1047 +cutting plane constraints (like Gomory's or mixed integer rounding
 16.1048 +cuts), in which case the cut pool may be non-empty.
 16.1049 +
 16.1050 +\subsection{glp\_ios\_del\_row---remove constraint from the cut pool}
 16.1051 +
 16.1052 +\subsubsection*{Synopsis}
 16.1053 +
 16.1054 +\begin{verbatim}
 16.1055 +void glp_ios_del_row(glp_tree *tree, int i);
 16.1056 +\end{verbatim}
 16.1057 +
 16.1058 +\subsubsection*{Description}
 16.1059 +
 16.1060 +The routine \verb|glp_ios_del_row| deletes $i$-th row (cutting plane
 16.1061 +constraint) from the cut pool, where $1\leq i\leq size$ is the ordinal
 16.1062 +number of the constraint in the pool, $size$ is the current size of the
 16.1063 +cut pool.
 16.1064 +
 16.1065 +Note that deleting a constraint from the cut pool leads to changing
 16.1066 +ordinal numbers of other constraints remaining in the pool. New ordinal
 16.1067 +numbers of the remaining constraints are assigned under assumption that
 16.1068 +the original order of constraints is not changed. Let, for example,
 16.1069 +there be four constraints $a$, $b$, $c$ and $d$ in the cut pool, which
 16.1070 +have ordinal numbers 1, 2, 3 and 4, respectively, and let constraint
 16.1071 +$b$ have been deleted. Then after deletion the remaining constraint $a$,
 16.1072 +$c$ and $d$ are assigned new ordinal numbers 1, 2 and 3, respectively.
 16.1073 +
 16.1074 +To find the constraint to be deleted the routine \verb|glp_ios_del_row|
 16.1075 +uses ``smart'' linear search, so it is recommended to remove constraints
 16.1076 +in a natural or reverse order and avoid removing them in a random order.
 16.1077 +
 16.1078 +\subsubsection*{Example}
 16.1079 +
 16.1080 +\begin{verbatim}
 16.1081 +/* keep first 10 constraints in the cut pool and remove other
 16.1082 +   constraints */
 16.1083 +while (glp_ios_pool_size(tree) > 10)
 16.1084 +   glp_ios_del_row(tree, glp_ios_pool_size(tree));
 16.1085 +\end{verbatim}
 16.1086 +
 16.1087 +\newpage
 16.1088 +
 16.1089 +\subsection{glp\_ios\_clear\_pool---remove all constraints from the cut
 16.1090 +pool}
 16.1091 +
 16.1092 +\subsubsection*{Synopsis}
 16.1093 +
 16.1094 +\begin{verbatim}
 16.1095 +void glp_ios_clear_pool(glp_tree *tree);
 16.1096 +\end{verbatim}
 16.1097 +
 16.1098 +\subsubsection*{Description}
 16.1099 +
 16.1100 +The routine \verb|glp_ios_clear_pool| makes the cut pool empty deleting
 16.1101 +all existing rows (cutting plane constraints) from it.
 16.1102 +
 16.1103 +%* eof *%
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/doc/glpk06.tex	Mon Dec 06 13:09:21 2010 +0100
    17.3 @@ -0,0 +1,896 @@
    17.4 +%* glpk06.tex *%
    17.5 +
    17.6 +\chapter{Miscellaneous API Routines}
    17.7 +
    17.8 +\section{GLPK environment routines}
    17.9 +
   17.10 +\subsection{glp\_long---64-bit integer data type}
   17.11 +
   17.12 +Some GLPK API routines use 64-bit integer data type, which is declared
   17.13 +in the header \verb|glpk.h| as follows:
   17.14 +
   17.15 +\begin{verbatim}
   17.16 +typedef struct { int lo, hi; } glp_long;
   17.17 +\end{verbatim}
   17.18 +
   17.19 +\noindent
   17.20 +where \verb|lo| contains low 32 bits, and \verb|hi| contains high 32
   17.21 +bits of 64-bit integer value.\footnote{GLPK conforms to ILP32, LLP64,
   17.22 +and LP64 programming models, where the built-in type {\tt int}
   17.23 +corresponds to 32-bit integers.}
   17.24 +
   17.25 +\subsection{glp\_init\_env---initialize GLPK environment}
   17.26 +
   17.27 +\subsubsection*{Synopsis}
   17.28 +
   17.29 +\begin{verbatim}
   17.30 +int glp_init_env(void);
   17.31 +\end{verbatim}
   17.32 +
   17.33 +\subsubsection*{Description}
   17.34 +
   17.35 +The routine \verb|glp_init_env| initializes the GLPK environment.
   17.36 +Normally the application program does not need to call this routine,
   17.37 +because it is called automatically on the first call to any API routine.
   17.38 +
   17.39 +\newpage
   17.40 +
   17.41 +\subsubsection*{Returns}
   17.42 +
   17.43 +The routine \verb|glp_init_env| returns one of the following codes:
   17.44 +
   17.45 +\noindent
   17.46 +0 --- initialization successful;
   17.47 +
   17.48 +\noindent
   17.49 +1 --- environment is already initialized;
   17.50 +
   17.51 +\noindent
   17.52 +2 --- initialization failed (insufficient memory);
   17.53 +
   17.54 +\noindent
   17.55 +3 --- initialization failed (unsupported programming model).
   17.56 +
   17.57 +\subsection{glp\_version---determine library version}
   17.58 +
   17.59 +\subsubsection*{Synopsis}
   17.60 +
   17.61 +\begin{verbatim}
   17.62 +const char *glp_version(void);
   17.63 +\end{verbatim}
   17.64 +
   17.65 +\subsubsection*{Returns}
   17.66 +
   17.67 +The routine \verb|glp_version| returns a pointer to a null-terminated
   17.68 +character string, which specifies the version of the GLPK library in
   17.69 +the form \verb|"X.Y"|, where `\verb|X|' is the major version number, and
   17.70 +`\verb|Y|' is the minor version number, for example, \verb|"4.16"|.
   17.71 +
   17.72 +\subsubsection*{Example}
   17.73 +
   17.74 +\begin{footnotesize}
   17.75 +\begin{verbatim}
   17.76 +printf("GLPK version is %s\n", glp_version());
   17.77 +\end{verbatim}
   17.78 +\end{footnotesize}
   17.79 +
   17.80 +\subsection{glp\_free\_env---free GLPK environment}
   17.81 +
   17.82 +\subsubsection*{Synopsis}
   17.83 +
   17.84 +\begin{verbatim}
   17.85 +int glp_free_env(void);
   17.86 +\end{verbatim}
   17.87 +
   17.88 +\subsubsection*{Description}
   17.89 +
   17.90 +The routine \verb|glp_free_env| frees all resources used by GLPK
   17.91 +routines (memory blocks, etc.) which are currently still in use.
   17.92 +
   17.93 +Normally the application program does not need to call this routine,
   17.94 +because GLPK routines always free all unused resources. However, if
   17.95 +the application program even has deleted all problem objects, there
   17.96 +will be several memory blocks still allocated for the internal library
   17.97 +needs. For some reasons the application program may want GLPK to free
   17.98 +this memory, in which case it should call \verb|glp_free_env|.
   17.99 +
  17.100 +Note that a call to \verb|glp_free_env| invalidates all problem objects
  17.101 +which still exist.
  17.102 +
  17.103 +\subsubsection*{Returns}
  17.104 +
  17.105 +The routine \verb|glp_free_env| returns one of the following codes:
  17.106 +
  17.107 +\noindent
  17.108 +0 --- termination successful;
  17.109 +
  17.110 +\noindent
  17.111 +1 --- environment is inactive (was not initialized).
  17.112 +
  17.113 +\subsection{glp\_printf---write formatted output to terminal}
  17.114 +
  17.115 +\subsubsection*{Synopsis}
  17.116 +
  17.117 +\begin{verbatim}
  17.118 +void glp_printf(const char *fmt, ...);
  17.119 +\end{verbatim}
  17.120 +
  17.121 +\subsubsection*{Description}
  17.122 +
  17.123 +The routine \verb|glp_printf| uses the format control string
  17.124 +\verb|fmt| to format its parameters and writes the formatted output to
  17.125 +the terminal.
  17.126 +
  17.127 +This routine is a replacement of the standard C function
  17.128 +\verb|printf| and used by all GLPK routines to perform terminal
  17.129 +output. The application program may use \verb|glp_printf| for the same
  17.130 +purpose that allows controlling its terminal output with the routines
  17.131 +\verb|glp_term_out| and \verb|glp_term_hook|.
  17.132 +
  17.133 +\subsection{glp\_vprintf---write formatted output to terminal}
  17.134 +
  17.135 +\subsubsection*{Synopsis}
  17.136 +
  17.137 +\begin{verbatim}
  17.138 +void glp_vprintf(const char *fmt, va_list arg);
  17.139 +\end{verbatim}
  17.140 +
  17.141 +\subsubsection*{Description}
  17.142 +
  17.143 +The routine \verb|glp_vprintf| uses the format control string
  17.144 +\verb|fmt| to format its parameters specified by the list \verb|arg|
  17.145 +and writes the formatted output to the terminal.
  17.146 +
  17.147 +This routine is a replacement of the standard C function
  17.148 +\verb|vprintf| and used by all GLPK routines to perform terminal
  17.149 +output. The application program may use \verb|glp_vprintf| for the same
  17.150 +purpose that allows controlling its terminal output with the routines
  17.151 +\verb|glp_term_out| and \verb|glp_term_hook|.
  17.152 +
  17.153 +\newpage
  17.154 +
  17.155 +\subsection{glp\_term\_out---enable/disable terminal output}
  17.156 +
  17.157 +\subsubsection*{Synopsis}
  17.158 +
  17.159 +\begin{verbatim}
  17.160 +int glp_term_out(int flag);
  17.161 +\end{verbatim}
  17.162 +
  17.163 +\subsubsection*{Description}
  17.164 +
  17.165 +Depending on the parameter flag the routine \verb|glp_term_out| enables
  17.166 +or disables terminal output performed by glpk routines:
  17.167 +
  17.168 +\verb|GLP_ON | --- enable terminal output;
  17.169 +
  17.170 +\verb|GLP_OFF| --- disable terminal output.
  17.171 +
  17.172 +\subsubsection*{Returns}
  17.173 +
  17.174 +The routine \verb|glp_term_out| returns the previous value of the
  17.175 +terminal output flag (\verb|GLP_ON| or \verb|GLP_OFF|).
  17.176 +
  17.177 +\subsection{glp\_term\_hook---intercept terminal output}
  17.178 +
  17.179 +\subsubsection*{Synopsis}
  17.180 +
  17.181 +\begin{verbatim}
  17.182 +void glp_term_hook(int (*func)(void *info, const char *s),
  17.183 +      void *info);
  17.184 +\end{verbatim}
  17.185 +
  17.186 +\subsubsection*{Description}
  17.187 +
  17.188 +The routine \verb|glp_term_hook| installs the user-defined hook routine
  17.189 +to intercept all terminal output performed by GLPK routines.
  17.190 +
  17.191 +%This feature can be used to redirect the terminal output to other
  17.192 +%destination, for example, to a file or a text window.
  17.193 +
  17.194 +The parameter {\it func} specifies the user-defined hook routine. It is
  17.195 +called from an internal printing routine, which passes to it two
  17.196 +parameters: {\it info} and {\it s}. The parameter {\it info} is a
  17.197 +transit pointer specified in corresponding call to the routine
  17.198 +\verb|glp_term_hook|; it may be used to pass some additional information
  17.199 +to the hook routine. The parameter {\it s} is a pointer to the null
  17.200 +terminated character string, which is intended to be written to the
  17.201 +terminal. If the hook routine returns zero, the printing routine writes
  17.202 +the string {\it s} to the terminal in a usual way; otherwise, if the
  17.203 +hook routine returns non-zero, no terminal output is performed.
  17.204 +
  17.205 +To uninstall the hook routine both parameters {\it func} and {\it info}
  17.206 +should be specified as \verb|NULL|.
  17.207 +
  17.208 +\newpage
  17.209 +
  17.210 +\subsubsection*{Example}
  17.211 +
  17.212 +\begin{footnotesize}
  17.213 +\begin{verbatim}
  17.214 +static int hook(void *info, const char *s)
  17.215 +{     FILE *foo = info;
  17.216 +      fputs(s, foo);
  17.217 +      return 1;
  17.218 +}
  17.219 +
  17.220 +int main(void)
  17.221 +{     FILE *foo;
  17.222 +      . . .
  17.223 +      /* redirect terminal output */
  17.224 +      glp_term_hook(hook, foo);
  17.225 +      . . .
  17.226 +      /* resume terminal output */
  17.227 +      glp_term_hook(NULL, NULL);
  17.228 +      . . .
  17.229 +}
  17.230 +\end{verbatim}
  17.231 +\end{footnotesize}
  17.232 +
  17.233 +\subsection{glp\_open\_tee---start copying terminal output}
  17.234 +
  17.235 +\subsubsection*{Synopsis}
  17.236 +
  17.237 +\begin{verbatim}
  17.238 +int glp_open_tee(const char *fname);
  17.239 +\end{verbatim}
  17.240 +
  17.241 +\subsubsection*{Description}
  17.242 +
  17.243 +The routine \verb|glp_open_tee| starts copying all the terminal output
  17.244 +to an output text file, whose name is specified by the character string
  17.245 +\verb|fname|.
  17.246 +
  17.247 +\subsubsection*{Returns}
  17.248 +
  17.249 +The routine \verb|glp_open_tee| returns one of the following codes:
  17.250 +
  17.251 +\noindent
  17.252 +0 --- operation successful;
  17.253 +
  17.254 +\noindent
  17.255 +1 --- copying terminal output is already active;
  17.256 +
  17.257 +\noindent
  17.258 +2 --- unable to create output file.
  17.259 +
  17.260 +\newpage
  17.261 +
  17.262 +\subsection{glp\_close\_tee---stop copying terminal output}
  17.263 +
  17.264 +\subsubsection*{Synopsis}
  17.265 +
  17.266 +\begin{verbatim}
  17.267 +int glp_close_tee(void);
  17.268 +\end{verbatim}
  17.269 +
  17.270 +\subsubsection*{Description}
  17.271 +
  17.272 +The routine \verb|glp_close_tee| stops copying the terminal output to
  17.273 +the output text file previously open by the routine \verb|glp_open_tee|
  17.274 +closing that file.
  17.275 +
  17.276 +\subsubsection*{Returns}
  17.277 +
  17.278 +The routine \verb|glp_close_tee| returns one of the following codes:
  17.279 +
  17.280 +\noindent
  17.281 +0 --- operation successful;
  17.282 +
  17.283 +\noindent
  17.284 +1 --- copying terminal output was not started.
  17.285 +
  17.286 +\subsection{glp\_error---display error message and terminate execution}
  17.287 +
  17.288 +\subsubsection*{Synopsis}
  17.289 +
  17.290 +\begin{verbatim}
  17.291 +void glp_error(const char *fmt, ...);
  17.292 +\end{verbatim}
  17.293 +
  17.294 +\subsubsection*{Description}
  17.295 +
  17.296 +The routine \verb|glp_error| (implemented as a macro) formats its
  17.297 +parameters using the format control string \verb|fmt|, writes the
  17.298 +formatted message to the terminal, and then abnormally terminates the
  17.299 +program.
  17.300 +
  17.301 +\subsection{glp\_assert---check logical condition}
  17.302 +
  17.303 +\subsubsection*{Synopsis}
  17.304 +
  17.305 +\begin{verbatim}
  17.306 +void glp_assert(int expr);
  17.307 +\end{verbatim}
  17.308 +
  17.309 +\subsubsection*{Description}
  17.310 +
  17.311 +The routine \verb|glp_assert| (implemented as a macro) checks
  17.312 +a logical condition specified by the expression \verb|expr|. If the
  17.313 +condition is true (non-zero), the routine does nothing; otherwise, if
  17.314 +the condition is false (zero), the routine prints an error message and
  17.315 +abnormally terminates the program.
  17.316 +
  17.317 +This routine is a replacement of the standard C function \verb|assert|
  17.318 +and used by all GLPK routines to check program logic. The application
  17.319 +program may use \verb|glp_assert| for the same purpose.
  17.320 +
  17.321 +\subsection{glp\_error\_hook---install hook to intercept abnormal
  17.322 +termination}
  17.323 +
  17.324 +\subsubsection*{Synopsis}
  17.325 +
  17.326 +\begin{verbatim}
  17.327 +void glp_error_hook(void (*func)(void *info), void *info);
  17.328 +\end{verbatim}
  17.329 +
  17.330 +\subsubsection*{Description}
  17.331 +
  17.332 +The routine \verb|glp_error_hook| installs a user-defined hook routine
  17.333 +to intercept abnormal termination.
  17.334 +
  17.335 +The parameter \verb|func| specifies the user-defined hook routine. It
  17.336 +is called from the routine \verb|glp_error| before the latter calls the
  17.337 +abort function to abnormally terminate the application program because
  17.338 +of fatal error. The parameter \verb|info| is a transit pointer,
  17.339 +specified in the corresponding call to the routine
  17.340 +\verb|glp_error_hook|; it may be used to pass some information to the
  17.341 +hook routine.
  17.342 +
  17.343 +To uninstall the hook routine the parameters \verb|func| and \verb|info|
  17.344 +should be specified as \verb|NULL|.
  17.345 +
  17.346 +\subsubsection*{Usage note}
  17.347 +
  17.348 +If the hook routine returns, the application program is abnormally
  17.349 +terminated. To prevent abnormal termnation the hook routine may perform
  17.350 +a global jump using the standard function \verb|longjmp|, in which case
  17.351 +the application program {\it must} call the routine \verb|glp_free_env|.
  17.352 +
  17.353 +\subsection{glp\_malloc---allocate memory block}
  17.354 +
  17.355 +\subsubsection*{Synopsis}
  17.356 +
  17.357 +\begin{verbatim}
  17.358 +void *glp_malloc(int size);
  17.359 +\end{verbatim}
  17.360 +
  17.361 +\subsubsection*{Description}
  17.362 +
  17.363 +The routine \verb|glp_malloc| dynamically allocates a memory block of
  17.364 +\verb|size| bytes long. Should note that:
  17.365 +
  17.366 +1) the parameter \verb|size| must be positive;
  17.367 +
  17.368 +2) being allocated the memory block contains arbitrary data, that is,
  17.369 +it is {\it not} initialized by binary zeros;
  17.370 +
  17.371 +3) if the block cannot be allocated due to insufficient memory, the
  17.372 +routine prints an error message and abnormally terminates the program.
  17.373 +
  17.374 +This routine is a replacement of the standard C function \verb|malloc|
  17.375 +and used by all GLPK routines for dynamic memory allocation. The
  17.376 +application program may use \verb|glp_malloc| for the same purpose.
  17.377 +
  17.378 +\subsubsection*{Returns}
  17.379 +
  17.380 +The routine \verb|glp_malloc| returns a pointer to the memory block
  17.381 +allocated. To free this block the routine \verb|glp_free| (not the
  17.382 +standard C function \verb|free|!) must be used.
  17.383 +
  17.384 +\subsection{glp\_calloc---allocate memory block}
  17.385 +
  17.386 +\subsubsection*{Synopsis}
  17.387 +
  17.388 +\begin{verbatim}
  17.389 +void *glp_calloc(int n, int size);
  17.390 +\end{verbatim}
  17.391 +
  17.392 +\subsubsection*{Description}
  17.393 +
  17.394 +The routine \verb|glp_calloc| dynamically allocates a memory block of
  17.395 +\verb|n|$\times$\verb|size| bytes long. Should note that:
  17.396 +
  17.397 +1) both parameters \verb|n| and \verb|size| must be positive;
  17.398 +
  17.399 +2) being allocated the memory block contains arbitrary data, that is,
  17.400 +it is {\it not} initialized by binary zeros;
  17.401 +
  17.402 +3) if the block cannot be allocated due to insufficient memory, the
  17.403 +routine prints an error message and abnormally terminates the program.
  17.404 +
  17.405 +This routine is a replacement of the standard C function \verb|calloc|
  17.406 +(with exception that the block is not cleaned) and used by all GLPK
  17.407 +routines for dynamic memory allocation. The application program may use
  17.408 +\verb|glp_calloc| for the same purpose.
  17.409 +
  17.410 +\subsubsection*{Returns}
  17.411 +
  17.412 +The routine \verb|glp_calloc| returns a pointer to the memory block
  17.413 +allocated. To free this block the routine \verb|glp_free| (not the
  17.414 +standard C function \verb|free|!) must be used.
  17.415 +
  17.416 +\subsection{glp\_free---free memory block}
  17.417 +
  17.418 +\subsubsection*{Synopsis}
  17.419 +
  17.420 +\begin{verbatim}
  17.421 +void glp_free(void *ptr);
  17.422 +\end{verbatim}
  17.423 +
  17.424 +\subsubsection*{Description}
  17.425 +
  17.426 +The routine \verb|glp_free| frees (deallocates) a memory block pointed
  17.427 +to by \verb|ptr|, which was previously allocated by the routine
  17.428 +\verb|glp_malloc| or \verb|glp_calloc|. Note that the pointer \verb|ptr|
  17.429 +must valid and must not be \verb|NULL|.
  17.430 +
  17.431 +This routine is a replacement of the standard C function \verb|free|
  17.432 +and used by all GLPK routines for dynamic memory allocation. The
  17.433 +application program may use \verb|glp_free| for the same purpose.
  17.434 +
  17.435 +\subsection{glp\_mem\_usage---get memory usage information}
  17.436 +
  17.437 +\subsubsection*{Synopsis}
  17.438 +
  17.439 +\begin{verbatim}
  17.440 +void glp_mem_usage(int *count, int *cpeak, glp_long *total,
  17.441 +      glp_long *tpeak);
  17.442 +\end{verbatim}
  17.443 +
  17.444 +\subsubsection*{Description}
  17.445 +
  17.446 +The routine \verb|glp_mem_usage| reports some information about
  17.447 +utilization of the memory by the routines \verb|glp_malloc|,
  17.448 +\verb|glp_calloc|, and \verb|glp_free|. Information is stored to
  17.449 +locations specified by corresponding parameters (see below). Any
  17.450 +parameter can be specified as \verb|NULL|, in which case corresponding
  17.451 +information is not stored.
  17.452 +
  17.453 +\verb|*count| is the number of currently allocated memory blocks.
  17.454 +
  17.455 +\verb|*cpeak| is the peak value of \verb|*count| reached since the
  17.456 +initialization of the GLPK library environment.
  17.457 +
  17.458 +\verb|*total| is the total amount, in bytes, of currently allocated
  17.459 +memory blocks.
  17.460 +
  17.461 +\verb|*tpeak| is the peak value of \verb|*total| reached since the
  17.462 +initialization of the GLPK library envirionment.
  17.463 +
  17.464 +\subsubsection*{Example}
  17.465 +
  17.466 +\begin{footnotesize}
  17.467 +\begin{verbatim}
  17.468 +glp_mem_usage(&count, NULL, NULL, NULL);
  17.469 +printf("%d memory block(s) are still allocated\n", count);
  17.470 +\end{verbatim}
  17.471 +\end{footnotesize}
  17.472 +
  17.473 +\subsection{glp\_mem\_limit---set memory usage limit}
  17.474 +
  17.475 +\subsubsection*{Synopsis}
  17.476 +
  17.477 +\begin{verbatim}
  17.478 +void glp_mem_limit(int limit);
  17.479 +\end{verbatim}
  17.480 +
  17.481 +\subsubsection*{Description}
  17.482 +
  17.483 +The routine \verb|glp_mem_limit| limits the amount of memory available
  17.484 +for dynamic allocation (with the routines \verb|glp_malloc| and
  17.485 +\verb|glp_calloc|) to \verb|limit| megabytes.
  17.486 +
  17.487 +\subsection{glp\_time---determine current universal time}
  17.488 +
  17.489 +\subsubsection*{Synopsis}
  17.490 +
  17.491 +\begin{verbatim}
  17.492 +glp_long glp_time(void);
  17.493 +\end{verbatim}
  17.494 +
  17.495 +\subsection*{Returns}
  17.496 +
  17.497 +The routine \verb|glp_time| returns the current universal time (UTC),
  17.498 +in milliseconds, elapsed since 00:00:00 GMT January 1, 1970.
  17.499 +
  17.500 +\subsection{glp\_difftime---compute difference between two time values}
  17.501 +
  17.502 +\subsubsection*{Synopsis}
  17.503 +
  17.504 +\begin{verbatim}
  17.505 +double glp_difftime(glp_long t1, glp_long t0);
  17.506 +\end{verbatim}
  17.507 +
  17.508 +\subsection*{Returns}
  17.509 +
  17.510 +The routine \verb|glp_difftime| returns the difference between two time
  17.511 +values \verb|t1| and \verb|t0|, expressed in seconds.
  17.512 +
  17.513 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  17.514 +
  17.515 +\newpage
  17.516 +
  17.517 +\section{Plain data file reading routines}
  17.518 +
  17.519 +\subsection{Introduction}
  17.520 +
  17.521 +On developing simple applications to solve optimization problems it is
  17.522 +often needed to read data from plain text files. To do this the standard
  17.523 +C function \verb|fscanf| may be used, however, it is not convenient; for
  17.524 +example, if it scans an integer number according to the format
  17.525 +specification `\verb|%d|', and that number is coded incorrectly,
  17.526 +no diagnostics is provided.
  17.527 +
  17.528 +This section describes a set of GLPK API routines, which may be used in
  17.529 +application programs to simplify reading data from plain text files.
  17.530 +
  17.531 +\subsubsection*{Example 1}
  17.532 +
  17.533 +The following main program reads ten integer numbers from plain text
  17.534 +file \verb|data.txt| and prints their sum.
  17.535 +
  17.536 +\begin{footnotesize}
  17.537 +\begin{verbatim}
  17.538 +/* sdfsamp1.c */
  17.539 +
  17.540 +#include <stdio.h>
  17.541 +#include <stdlib.h>
  17.542 +#include <glpk.h>
  17.543 +
  17.544 +int main(void)
  17.545 +{     glp_data *data;
  17.546 +      int j, num, sum;
  17.547 +      /* open plain data file */
  17.548 +      data = glp_sdf_open_file("data.txt");
  17.549 +      if (data == NULL) exit(EXIT_FAILURE);
  17.550 +      sum = 0;
  17.551 +      for (j = 1; j <= 10; j++)
  17.552 +      {  /* read next integer number */
  17.553 +         num = glp_sdf_read_int(data);
  17.554 +         sum += num;
  17.555 +      }
  17.556 +      printf("sum = %d\n", sum);
  17.557 +      /* close plain data file */
  17.558 +      glp_sdf_close_file(data);
  17.559 +      return 0;
  17.560 +}
  17.561 +
  17.562 +/* eof */
  17.563 +\end{verbatim}
  17.564 +\end{footnotesize}
  17.565 +
  17.566 +The input data are coded in free format. For example, the file
  17.567 +\verb|data.txt| may look like this:
  17.568 +
  17.569 +\begin{footnotesize}
  17.570 +\begin{verbatim}
  17.571 +123 65 432 890 -12 743 895 -7 111 326
  17.572 +\end{verbatim}
  17.573 +\end{footnotesize}
  17.574 +
  17.575 +\noindent
  17.576 +or like this:
  17.577 +
  17.578 +\begin{footnotesize}
  17.579 +\begin{verbatim}
  17.580 +123   65  432  890  -12
  17.581 +743  895   -7  111  326
  17.582 +\end{verbatim}
  17.583 +\end{footnotesize}
  17.584 +
  17.585 +\noindent
  17.586 +If the input data file contains incorrect data, the routine
  17.587 +\verb|glp_sdf_read_int| prints an error message and, if no error
  17.588 +handling is provided by the application program, abnormally terminates
  17.589 +program execution. For example, the file \verb|data.txt| could contain
  17.590 +the following data:
  17.591 +
  17.592 +\begin{footnotesize}
  17.593 +\begin{verbatim}
  17.594 +123   65  432  890  -12
  17.595 +743  895   =7  111  326
  17.596 +\end{verbatim}
  17.597 +\end{footnotesize}
  17.598 +
  17.599 +\noindent
  17.600 +in which case the error message would be the following:
  17.601 +
  17.602 +\begin{footnotesize}
  17.603 +\begin{verbatim}
  17.604 +data.txt:2: cannot convert `=7' to integer
  17.605 +\end{verbatim}
  17.606 +\end{footnotesize}
  17.607 +
  17.608 +\subsubsection*{Example 2}
  17.609 +
  17.610 +As it was said above, by default any attempt to read incorrect data
  17.611 +leads to abnormal termination. However, sometimes it is desirable to
  17.612 +catch such errors. This feature is illustrated by the following main
  17.613 +program, which does the same job as in the previous example.
  17.614 +
  17.615 +\begin{footnotesize}
  17.616 +\begin{verbatim}
  17.617 +/* sdfsamp2.c */
  17.618 +
  17.619 +#include <setjmp.h>
  17.620 +#include <stdio.h>
  17.621 +#include <stdlib.h>
  17.622 +#include <glpk.h>
  17.623 +
  17.624 +int main(void)
  17.625 +{     glp_data *data;
  17.626 +      jmp_buf jump;
  17.627 +      int j, num, sum, ret;
  17.628 +      /* open plain data file */
  17.629 +      data = glp_sdf_open_file("data.txt");
  17.630 +      if (data == NULL)
  17.631 +      {  ret = EXIT_FAILURE;
  17.632 +         goto done;
  17.633 +      }
  17.634 +      /* set up error handling */
  17.635 +      if (setjmp(jump))
  17.636 +      {  ret = EXIT_FAILURE;
  17.637 +         goto done;
  17.638 +      }
  17.639 +      glp_sdf_set_jump(data, jump);
  17.640 +      /* read and process data */
  17.641 +      sum = 0;
  17.642 +      for (j = 1; j <= 10; j++)
  17.643 +      {  /* read next integer number */
  17.644 +         num = glp_sdf_read_int(data);
  17.645 +         if (abs(num) > 1000)
  17.646 +            glp_sdf_error(data, "integer %d too big\n", num);
  17.647 +         if (num < 0)
  17.648 +            glp_sdf_warning(data, "integer %d is negative\n", num);
  17.649 +         sum += num;
  17.650 +      }
  17.651 +      printf("sum = %d\n", sum);
  17.652 +      ret = EXIT_SUCCESS;
  17.653 +done: /* close plain data file */
  17.654 +      if (data != NULL) glp_sdf_close_file(data);
  17.655 +      return ret;
  17.656 +}
  17.657 +
  17.658 +/* eof */
  17.659 +\end{verbatim}
  17.660 +\end{footnotesize}
  17.661 +
  17.662 +\subsection{glp\_sdf\_open\_file---open plain data file}
  17.663 +
  17.664 +\subsubsection*{Synopsis}
  17.665 +
  17.666 +\begin{verbatim}
  17.667 +glp_data *glp_sdf_open_file(const char *fname);
  17.668 +\end{verbatim}
  17.669 +
  17.670 +\subsubsection*{Description}
  17.671 +
  17.672 +The routine \verb|glp_sdf_open_file| opens a plain data file, whose
  17.673 +name is specified by the character string \verb|fname|.
  17.674 +
  17.675 +\subsubsection*{Returns}
  17.676 +
  17.677 +If the operation was successful, the routine \verb|glp_sdf_open_file|
  17.678 +returns a pointer to the opaque program object of the type
  17.679 +\verb|glp_data|\footnote{This data structure is declared in the header
  17.680 +file {\tt glpk.h}.} associated with the plain data file. Otherwise, if
  17.681 +the operation failed, the routine prints an error message and returns
  17.682 +\verb|NULL|.
  17.683 +
  17.684 +\subsubsection*{Note}
  17.685 +
  17.686 +The application program should use the pointer returned by the routine
  17.687 +\verb|glp_sdf_open_file| to perform all subsequent operations on the
  17.688 +data file.
  17.689 +
  17.690 +\newpage
  17.691 +
  17.692 +\subsection{glp\_sdf\_set\_jump---set up error handling}
  17.693 +
  17.694 +\subsubsection*{Synopsis}
  17.695 +
  17.696 +\begin{verbatim}
  17.697 +void glp_sdf_set_jump(glp_data *data, jmp_buf jump);
  17.698 +\end{verbatim}
  17.699 +
  17.700 +\subsubsection*{Description}
  17.701 +
  17.702 +The routine \verb|glp_sdf_set_jump| sets up error handling for the
  17.703 +plain data file specified by the parameter \verb|data|.
  17.704 +
  17.705 +The parameter \verb|jump| specifies the environment buffer, which must
  17.706 +be initialized with the standard C function \verb|setjmp| prior to call
  17.707 +to the routine \verb|glp_sdf_set_jump|. Detecting any incorrect data in
  17.708 +the corresponding plain data file will cause non-local ``go to'' by
  17.709 +a call to the standard C function \verb|longjmp|.
  17.710 +
  17.711 +The parameter \verb|jump| can be specified as \verb|NULL|, in which
  17.712 +case the routine \verb|glp_sdf_set_jump| restores the default behavior,
  17.713 +in which case detecting incorrect data leads to abnormal termination.
  17.714 +
  17.715 +\subsection{glp\_sdf\_error---print error message}
  17.716 +
  17.717 +\subsubsection*{Synopsis}
  17.718 +
  17.719 +\begin{verbatim}
  17.720 +void glp_sdf_error(glp_data *data, const char *fmt, ...);
  17.721 +\end{verbatim}
  17.722 +
  17.723 +\subsubsection*{Description}
  17.724 +
  17.725 +The routine \verb|glp_sdf_error| prints an error message related to the
  17.726 +plain data file specified by the parameter \verb|data|. If error handing
  17.727 +was not previously provided, the routine then abnormally terminates
  17.728 +execution of the application program. Otherwise, it signals about the
  17.729 +error by a call to the standard C function \verb|longjmp|.
  17.730 +
  17.731 +The character string \verb|fmt| and optional parameters following it
  17.732 +have the same meaning as for the standard C function \verb|printf|.
  17.733 +
  17.734 +The message produced by the routine \verb|glp_sdf_error| looks like
  17.735 +follows:
  17.736 +
  17.737 +\medskip
  17.738 +
  17.739 +{\it file}{\tt :}{\it line}{\tt :} {\it message text}
  17.740 +
  17.741 +\medskip
  17.742 +
  17.743 +\noindent
  17.744 +where {\it file} is the filename passed to the routine
  17.745 +\verb|glp_sdf_open| and {\it line} is the current line number.
  17.746 +
  17.747 +\newpage
  17.748 +
  17.749 +\subsection{glp\_sdf\_warning---print warning message}
  17.750 +
  17.751 +\subsubsection*{Synopsis}
  17.752 +
  17.753 +\begin{verbatim}
  17.754 +void glp_sdf_warning(glp_data *data, const char *fmt, ...);
  17.755 +\end{verbatim}
  17.756 +
  17.757 +\subsubsection*{Description}
  17.758 +
  17.759 +The routine \verb|glp_sdf_warning| prints a warning message related to
  17.760 +the plain data file specified by the parameter \verb|data|.
  17.761 +
  17.762 +The character string \verb|fmt| and optional parameters following it
  17.763 +have the same meaning as for the standard C function \verb|printf|.
  17.764 +
  17.765 +The message produced by the routine \verb|glp_sdf_warning| looks like
  17.766 +follows:
  17.767 +
  17.768 +\medskip
  17.769 +
  17.770 +{\it file}{\tt :}{\it line}\verb|: warning:| {\it message text}
  17.771 +
  17.772 +\medskip
  17.773 +
  17.774 +\noindent
  17.775 +where {\it file} is the filename passed to the routine
  17.776 +\verb|glp_sdf_open| and {\it line} is the current line number.
  17.777 +
  17.778 +\subsection{glp\_sdf\_read\_int---read integer number}
  17.779 +
  17.780 +\subsubsection*{Synopsis}
  17.781 +
  17.782 +\begin{verbatim}
  17.783 +int glp_sdf_read_int(glp_data *data);
  17.784 +\end{verbatim}
  17.785 +
  17.786 +\subsubsection*{Description}
  17.787 +
  17.788 +The routine \verb|glp_sdf_read_int| skips optional white-space
  17.789 +characters and then reads an integer number from the plain data file
  17.790 +specified by the parameter \verb|data|. If the operation failed, the
  17.791 +routine \verb|glp_sdf_read_int| calls the routine \verb|glp_sdf_error|
  17.792 +(see above).
  17.793 +
  17.794 +\subsubsection*{Returns}
  17.795 +
  17.796 +The routine \verb|glp_sdf_read_int| returns the integer number read.
  17.797 +
  17.798 +\newpage
  17.799 +
  17.800 +\subsection{glp\_sdf\_read\_num---read floating-point number}
  17.801 +
  17.802 +\subsubsection*{Synopsis}
  17.803 +
  17.804 +\begin{verbatim}
  17.805 +double glp_sdf_read_num(glp_data *data);
  17.806 +\end{verbatim}
  17.807 +
  17.808 +\subsubsection*{Description}
  17.809 +
  17.810 +The routine \verb|glp_sdf_read_num| skips optional white-space
  17.811 +characters and then reads a floating-point number from the plain data
  17.812 +file specified by the parameter \verb|data|. If the operation failed,
  17.813 +the routine \verb|glp_sdf_num| calls the routine \verb|glp_sdf_error|
  17.814 +(see above).
  17.815 +
  17.816 +\subsubsection*{Returns}
  17.817 +
  17.818 +The routine \verb|glp_sdf_read_num| returns the floating-point number
  17.819 +read.
  17.820 +
  17.821 +\subsection{glp\_sdf\_read\_item---read data item}
  17.822 +
  17.823 +\subsubsection*{Synopsis}
  17.824 +
  17.825 +\begin{verbatim}
  17.826 +const char *glp_sdf_read_item(glp_data *data);
  17.827 +\end{verbatim}
  17.828 +
  17.829 +\subsubsection*{Description}
  17.830 +
  17.831 +The routine \verb|glp_sdf_read_item| skips optional white-space
  17.832 +characters and then reads a data item from the plain data file specified
  17.833 +by the parameter \verb|data|. If the operation failed, the routine
  17.834 +\verb|glp_sdf_read_item| calls the routine \verb|glp_sdf_error| (see
  17.835 +above).
  17.836 +
  17.837 +{\it Data item} is a sequence of 1 to 255 arbitrary graphic characters
  17.838 +delimited by white-space characters. Data items may be used to represent
  17.839 +symbolic names, identifiers, etc.
  17.840 +
  17.841 +\subsubsection*{Returns}
  17.842 +
  17.843 +The routine \verb|glp_sdf_read_item| returns a pointer to the internal
  17.844 +buffer, which contains the data item read in the form of a
  17.845 +null-terminated character string.
  17.846 +
  17.847 +\newpage
  17.848 +
  17.849 +\subsection{glp\_sdf\_read\_text---read text until end of line}
  17.850 +
  17.851 +\subsubsection*{Synopsis}
  17.852 +
  17.853 +\begin{verbatim}
  17.854 +const char *glp_sdf_read_text(glp_data *data);
  17.855 +\end{verbatim}
  17.856 +
  17.857 +\subsubsection*{Description}
  17.858 +
  17.859 +The routine \verb|glp_sdf_read_text| reads a text from the plain data
  17.860 +file specified by the parameter \verb|data|.
  17.861 +
  17.862 +Reading starts from the current position and extends until end of the
  17.863 +current line. Initial and trailing white-space characters as well as
  17.864 +the newline character are not included in the text.
  17.865 +
  17.866 +\subsubsection*{Returns}
  17.867 +
  17.868 +The routine \verb|glp_sdf_read_text| returns a pointer to the internal
  17.869 +buffer, which contains the text read in the form of a null-terminated
  17.870 +character string.
  17.871 +
  17.872 +\subsection{glp\_sdf\_line---determine current line number}
  17.873 +
  17.874 +\subsubsection*{Synopsis}
  17.875 +
  17.876 +\begin{verbatim}
  17.877 +int glp_sdf_line(glp_data *data);
  17.878 +\end{verbatim}
  17.879 +
  17.880 +\subsubsection*{Returns}
  17.881 +
  17.882 +The routine \verb|glp_sdf_line| returns the current line number for the
  17.883 +plain data file specified by the parameter \verb|data|.
  17.884 +
  17.885 +\subsection{glp\_sdf\_close\_file---close plain data file}
  17.886 +
  17.887 +\subsubsection*{Synopsis}
  17.888 +
  17.889 +\begin{verbatim}
  17.890 +void glp_sdf_close_file(glp_data *data);
  17.891 +\end{verbatim}
  17.892 +
  17.893 +\subsubsection*{Description}
  17.894 +
  17.895 +The routine \verb|glp_sdf_close_file| closes the plain data file
  17.896 +specified by the parameter \verb|data| and frees all the resources
  17.897 +allocated to this program object.
  17.898 +
  17.899 +%* eof *%
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/doc/glpk07.tex	Mon Dec 06 13:09:21 2010 +0100
    18.3 @@ -0,0 +1,336 @@
    18.4 +%* glpk07.tex *%
    18.5 +
    18.6 +\chapter{Installing GLPK on Your Computer}
    18.7 +\label{install}
    18.8 +
    18.9 +\section{Downloading the distribution tarball}
   18.10 +
   18.11 +The distribution tarball of the most recent version of the GLPK
   18.12 +package can be found on \url{http://ftp.gnu.org/gnu/glpk/} [via http]
   18.13 +and \url{ftp://ftp.gnu.org/gnu/glpk/} [via FTP]. It can also be found
   18.14 +on one of the FTP mirrors; see \url{http://www.gnu.org/prep/ftp.html}.
   18.15 +Please use a mirror if possible.
   18.16 +
   18.17 +To make sure that the GLPK distribution tarball you have downloaded is
   18.18 +intact you need to download the corresponding `\verb|.sig|' file and
   18.19 +run a command like this:
   18.20 +
   18.21 +\begin{verbatim}
   18.22 +   gpg --verify glpk-4.38.tar.gz.sig
   18.23 +\end{verbatim}
   18.24 +
   18.25 +\noindent
   18.26 +If that command fails because you do not have the required public key,
   18.27 +run the following command to import it:
   18.28 +
   18.29 +\begin{verbatim}
   18.30 +   gpg --keyserver keys.gnupg.net --recv-keys 5981E818
   18.31 +\end{verbatim}
   18.32 +
   18.33 +\noindent
   18.34 +and then re-run the previous command.
   18.35 +
   18.36 +\section{Unpacking the distribution tarball}
   18.37 +
   18.38 +The GLPK package (like all other GNU software) is distributed in the
   18.39 +form of packed archive. This is one file named \verb|glpk-X.Y.tar.gz|,
   18.40 +where {\it X} is the major version number and {\it Y} is the minor
   18.41 +version number.
   18.42 +
   18.43 +In order to prepare the distribution for installation you should:
   18.44 +
   18.45 +\medskip
   18.46 +
   18.47 +1. Copy the GLPK distribution file to a working subdirectory.
   18.48 +
   18.49 +\medskip
   18.50 +
   18.51 +2. Unpack the distribution file with the following command:
   18.52 +
   18.53 +\begin{verbatim}
   18.54 +   gzip -d glpk-X.Y.tar.gz
   18.55 +\end{verbatim}
   18.56 +
   18.57 +\noindent
   18.58 +that renames the distribution file to \verb|glpk-X.Y.tar|.
   18.59 +
   18.60 +\medskip
   18.61 +
   18.62 +3. Unarchive the distribution file with the following command:
   18.63 +
   18.64 +\begin{verbatim}
   18.65 +   tar -x < glpk-X.Y.tar
   18.66 +\end{verbatim}
   18.67 +
   18.68 +\noindent
   18.69 +that automatically creates the subdirectory \verb|glpk-X.Y| containing
   18.70 +the GLPK distribution.
   18.71 +
   18.72 +
   18.73 +\section{Configuring the package}
   18.74 +
   18.75 +After unpacking and unarchiving the GLPK distribution you should
   18.76 +configure the package, i.e. automatically tune it for your platform.
   18.77 +
   18.78 +Normally, you should just \verb|cd| to the subdirectory
   18.79 +\verb|glpk-X.Y| and run the configure script, e.g.
   18.80 +
   18.81 +\begin{verbatim}
   18.82 +   ./configure
   18.83 +\end{verbatim}
   18.84 +
   18.85 +The `\verb|configure|' shell script attempts to guess correct values
   18.86 +for various system-dependent variables used during compilation. It uses
   18.87 +those values to create a `\verb|Makefile|' in each directory of the
   18.88 +package. It also creates file `\verb|config.h|' containing
   18.89 +platform-dependent definitions. Finally, it creates a shell script
   18.90 +`\verb|config.status|' that you can run in the future to recreate the
   18.91 +current configuration, a file `\verb|config.cache|' that saves the
   18.92 +results of its tests to speed up reconfiguring, and a file
   18.93 +`\verb|config.log|' containing compiler output (useful mainly for
   18.94 +debugging `\verb|configure|').
   18.95 +
   18.96 +Running `\verb|configure|' takes about a few minutes. While it is
   18.97 +running, it displays some informational messages that tell you what it
   18.98 +is doing. If you don't want to see these messages, run
   18.99 +`\verb|configure|' with its standard output redirected to
  18.100 +`\verb|dev/null|'; for example, `\verb|./configure > /dev/null|'.
  18.101 +
  18.102 +By default both static and shared versions of the GLPK library will be
  18.103 +compiled. Compilation of the shared librariy can be turned off by
  18.104 +specifying the `\verb|--disable-shared|' option to `\verb|configure|',
  18.105 +e.g.
  18.106 +
  18.107 +\begin{verbatim}
  18.108 +   ./configure --disable-shared
  18.109 +\end{verbatim}
  18.110 +
  18.111 +\noindent
  18.112 +If you encounter problems building the library try using the above
  18.113 +option, because some platforms do not support shared libraries.
  18.114 +
  18.115 +\newpage
  18.116 +
  18.117 +The GLPK package has some optional features listed below. By default
  18.118 +all these features are disabled. To enable a feature the corresponding
  18.119 +option should be passed to the configure script.
  18.120 +
  18.121 +\bigskip
  18.122 +
  18.123 +\noindent
  18.124 +\verb|--with-gmp         | Enable using the GNU MP bignum library
  18.125 +
  18.126 +\medskip
  18.127 +
  18.128 +This feature allows the exact simplex solver to use the GNU MP bignum
  18.129 +library. If it is disabled, the exact simplex solver uses the GLPK
  18.130 +bignum module, which provides the same functionality as GNU MP, however,
  18.131 +it is much less efficient.
  18.132 +
  18.133 +For details about the GNU MP bignum library see its web page at
  18.134 +\url{http://gmplib.org/}.
  18.135 +
  18.136 +\bigskip
  18.137 +
  18.138 +\noindent
  18.139 +\verb|--with-zlib        |
  18.140 +Enable using the zlib data compression library
  18.141 +
  18.142 +\medskip
  18.143 +
  18.144 +This feature allows GLPK API routines and the stand-alone solver to
  18.145 +read and write compressed data files performing compression and
  18.146 +decompression ``on the fly'' (compressed data files are recognized by
  18.147 +suffix `\verb|.gz|' in the file name). It may be useful in case of
  18.148 +large MPS files to save the disk space.
  18.149 +
  18.150 +For details about the zlib compression library see its web page at
  18.151 +\url{http://www.zlib.net/}.
  18.152 +
  18.153 +\bigskip
  18.154 +
  18.155 +\noindent
  18.156 +\verb|--enable-dl        | The same as `\verb|--enable-dl=ltdl|'
  18.157 +
  18.158 +\noindent
  18.159 +\verb|--enable-dl=ltdl   | Enable shared library support (GNU)
  18.160 +
  18.161 +\noindent
  18.162 +\verb|--enable-dl=dlfcn  | Enable shared library support (POSIX)
  18.163 +
  18.164 +\medskip
  18.165 +
  18.166 +Currently this feature is only needed to provide dynamic linking to
  18.167 +ODBC and MySQL shared libraries (see below).
  18.168 +
  18.169 +For details about the GNU shared library support see the manual at
  18.170 +\url{http://www.gnu.org/software/libtool/manual/}.
  18.171 +
  18.172 +\bigskip
  18.173 +
  18.174 +\noindent
  18.175 +\verb|--enable-odbc      |
  18.176 +Enable using ODBC table driver (\verb|libiodbc|)
  18.177 +
  18.178 +\noindent
  18.179 +\verb|--enable-odbc=unix |
  18.180 +Enable using ODBC table driver (\verb|libodbc|)
  18.181 +
  18.182 +\medskip
  18.183 +
  18.184 +This feature allows transmitting data between MathProg model objects
  18.185 +and relational databases accessed through ODBC.
  18.186 +
  18.187 +For more details about this feature see the supplement ``Using Data
  18.188 +Tables in the GNU MathProg Modeling Language'' (\verb|doc/tables.pdf|).
  18.189 +
  18.190 +\bigskip
  18.191 +
  18.192 +\noindent
  18.193 +\verb|--enable-mysql     |
  18.194 +Enable using MySQL table driver (\verb|libmysql|)
  18.195 +
  18.196 +\medskip
  18.197 +
  18.198 +This feature allows transmitting data between MathProg model objects
  18.199 +and MySQL relational databases.
  18.200 +
  18.201 +For more details about this feature see the supplement ``Using Data
  18.202 +Tables in the GNU MathProg Modeling Language'' (\verb|doc/tables.pdf|).
  18.203 +
  18.204 +\section{Compiling the package}
  18.205 +
  18.206 +Normally, you can compile (build) the package by typing the command:
  18.207 +
  18.208 +\begin{verbatim}
  18.209 +   make
  18.210 +\end{verbatim}
  18.211 +
  18.212 +\noindent
  18.213 +It reads `\verb|Makefile|' generated by `\verb|configure|' and performs
  18.214 +all necessary jobs.
  18.215 +
  18.216 +If you want, you can override the `\verb|make|' variables \verb|CFLAGS|
  18.217 +and \verb|LDFLAGS| like this:
  18.218 +
  18.219 +\begin{verbatim}
  18.220 +   make CFLAGS=-O2 LDFLAGS=-s
  18.221 +\end{verbatim}
  18.222 +
  18.223 +To compile the package in a different directory from the one containing
  18.224 +the source code, you must use a version of `\verb|make|' that supports
  18.225 +`\verb|VPATH|' variable, such as GNU `\verb|make|'. `\verb|cd|' to the
  18.226 +directory where you want the object files and executables to go and run
  18.227 +the `\verb|configure|' script. `\verb|configure|' automatically checks
  18.228 +for the source code in the directory that `\verb|configure|' is in and
  18.229 +in `\verb|..|'. If for some reason `\verb|configure|' is not in the
  18.230 +source code directory that you are configuring, then it will report that
  18.231 +it can't find the source code. In that case, run `\verb|configure|' with
  18.232 +the option `\verb|--srcdir=DIR|', where \verb|DIR| is the directory that
  18.233 +contains the source code.
  18.234 +
  18.235 +Some systems require unusual options for compilation or linking that
  18.236 +the `\verb|configure|' script does not know about. You can give
  18.237 +`\verb|configure|' initial values for variables by setting them in the
  18.238 +environment. Using a Bourne-compatible shell, you can do that on the
  18.239 +command line like this:
  18.240 +
  18.241 +\begin{verbatim}
  18.242 +   CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
  18.243 +\end{verbatim}
  18.244 +
  18.245 +\noindent
  18.246 +Or on systems that have the `\verb|env|' program, you can do it like
  18.247 +this:
  18.248 +
  18.249 +\begin{verbatim}
  18.250 +   env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
  18.251 +\end{verbatim}
  18.252 +
  18.253 +Here are the `\verb|make|' variables that you might want to override
  18.254 +with environment variables when running `\verb|configure|'.
  18.255 +
  18.256 +For these variables, any value given in the environment overrides the
  18.257 +value that `\verb|configure|' would choose:
  18.258 +
  18.259 +\medskip
  18.260 +
  18.261 +\noindent
  18.262 +\verb|CC      | C compiler program. The default is `\verb|cc|'.
  18.263 +
  18.264 +\medskip
  18.265 +
  18.266 +\noindent
  18.267 +\verb|INSTALL | Program used to install files. The default value is
  18.268 +`\verb|install|' if
  18.269 +
  18.270 +\noindent
  18.271 +\verb|        | you have it, otherwise `\verb|cp|'.
  18.272 +
  18.273 +\medskip
  18.274 +
  18.275 +For these variables, any value given in the environment is added to the
  18.276 +value that `\verb|configure|' chooses:
  18.277 +
  18.278 +\medskip
  18.279 +
  18.280 +\noindent
  18.281 +\verb|DEFS    | Configuration options, in the form
  18.282 +`\verb|-Dfoo -Dbar| \dots'.
  18.283 +
  18.284 +\medskip
  18.285 +
  18.286 +\noindent
  18.287 +\verb|LIBS    | Libraries to link with, in the form
  18.288 +`\verb|-lfoo -lbar| \dots'.
  18.289 +
  18.290 +\section{Checking the package}
  18.291 +
  18.292 +To check the package, i.e. to run some tests included in the package,
  18.293 +you can use the following command:
  18.294 +
  18.295 +\begin{verbatim}
  18.296 +   make check
  18.297 +\end{verbatim}
  18.298 +
  18.299 +\section{Installing the package}
  18.300 +
  18.301 +Normally, to install the GLPK package you should type the following
  18.302 +command:
  18.303 +
  18.304 +\begin{verbatim}
  18.305 +   make install
  18.306 +\end{verbatim}
  18.307 +
  18.308 +\noindent
  18.309 +By default, `\verb|make install|' will install the package's files in
  18.310 +`\verb|usr/local/bin|', `\verb|usr/local/lib|', etc. You can specify an
  18.311 +installation prefix other than `\verb|/usr/local|' by giving
  18.312 +`\verb|configure|' the option `\verb|--prefix=PATH|'. Alternately, you
  18.313 +can do so by consistently giving a value for the `\verb|prefix|'
  18.314 +variable when you run `\verb|make|', e.g.
  18.315 +
  18.316 +\begin{verbatim}
  18.317 +   make prefix=/usr/gnu
  18.318 +   make prefix=/usr/gnu install
  18.319 +\end{verbatim}
  18.320 +
  18.321 +After installing you can remove the program binaries and object files
  18.322 +from the source directory by typing `\verb|make clean|'. To remove all
  18.323 +files that `\verb|configure|' created (`\verb|Makefile|',
  18.324 +`\verb|config.status|', etc.), just type `\verb|make distclean|'.
  18.325 +
  18.326 +The file `\verb|configure.ac|' is used to create `\verb|configure|' by
  18.327 +a program called `\verb|autoconf|'. You only need it if you want to
  18.328 +remake `\verb|configure|' using a newer version of `\verb|autoconf|'.
  18.329 +
  18.330 +\section{Uninstalling the package}
  18.331 +
  18.332 +To uninstall the GLPK package, i.e. to remove all the package's files
  18.333 +from the system places, you can use the following command:
  18.334 +
  18.335 +\begin{verbatim}
  18.336 +   make uninstall
  18.337 +\end{verbatim}
  18.338 +
  18.339 +%* eof *%
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/doc/glpk08.tex	Mon Dec 06 13:09:21 2010 +0100
    19.3 @@ -0,0 +1,696 @@
    19.4 +%* glpk08.tex *%
    19.5 +
    19.6 +\chapter{MPS Format}
    19.7 +\label{champs}
    19.8 +
    19.9 +\section{Fixed MPS Format}
   19.10 +\label{secmps}
   19.11 +
   19.12 +The MPS format\footnote{The MPS format was developed in 1960's by IBM
   19.13 +as input format for their mathematical programming system MPS/360.
   19.14 +Today the MPS format is a most widely used format understood by most
   19.15 +mathematical programming packages. This appendix describes only the
   19.16 +features of the MPS format, which are implemented in the GLPK package.}
   19.17 +is intended for coding LP/MIP problem data. This format assumes the
   19.18 +formulation of LP/MIP problem (1.1)---(1.3) (see Section \ref{seclp},
   19.19 +page \pageref{seclp}).
   19.20 +
   19.21 +{\it MPS file} is a text file, which contains two types of
   19.22 +cards\footnote{In 1960's MPS file was a deck of 80-column punched cards,
   19.23 +so the author decided to keep the word ``card'', which may be understood
   19.24 +as ``line of text file''.}: indicator cards and data cards.
   19.25 +
   19.26 +Indicator cards determine a kind of succeeding data. Each indicator card
   19.27 +has one word in uppercase letters beginning in column 1.
   19.28 +
   19.29 +Data cards contain problem data. Each data card is divided into six
   19.30 +fixed fields:
   19.31 +
   19.32 +\begin{center}
   19.33 +\begin{tabular}{lcccccc}
   19.34 +& Field 1 & Field 2 & Field 3 & Field 4 & Field 5 & Feld 6 \\
   19.35 +\hline
   19.36 +Columns & 2---3 & 5---12 & 15---22 & 25---36 & 40---47 & 50---61 \\
   19.37 +Contents & Code & Name & Name & Number & Name & Number \\
   19.38 +\end{tabular}
   19.39 +\end{center}
   19.40 +
   19.41 +On a particular data card some fields may be optional.
   19.42 +
   19.43 +Names are used to identify rows, columns, and some vectors (see below).
   19.44 +
   19.45 +Aligning the indicator code in the field 1 to the left margin is
   19.46 +optional.
   19.47 +
   19.48 +All names specified in the fields 2, 3, and 5 should contain from 1 up
   19.49 +to 8 arbitrary characters (except control characters). If a name is
   19.50 +placed in the field 3 or 5, its first character should not be the dollar
   19.51 +sign `\verb|$|'. If a name contains spaces, the spaces are ignored.
   19.52 +
   19.53 +All numerical values in the fields 4 and 6 should be coded in the form
   19.54 +$sxx$\verb|E|$syy$, where $s$ is the plus `\verb|+|' or the minus
   19.55 +`\verb|-|' sign, $xx$ is a real number with optional decimal point,
   19.56 +$yy$ is an integer decimal exponent. Any number should contain up to 12
   19.57 +characters. If the sign $s$ is omitted, the plus sign is assumed. The
   19.58 +exponent part is optional. If a number contains spaces, the spaces are
   19.59 +ignored.
   19.60 +
   19.61 +If a card has the asterisk `\verb|*|' in the column 1, this card is
   19.62 +considered as a comment and ignored. Besides, if the first character in
   19.63 +the field 3 or 5 is the dollar sign `\verb|$|', all characters from the
   19.64 +dollar sign to the end of card are considered as a comment and ignored.
   19.65 +
   19.66 +MPS file should contain cards in the following order:
   19.67 +
   19.68 +$\bullet$ NAME indicator card;
   19.69 +
   19.70 +$\bullet$ ROWS indicator card;
   19.71 +
   19.72 +$\bullet$ data cards specifying rows (constraints);
   19.73 +
   19.74 +$\bullet$ COLUMNS indicator card;
   19.75 +
   19.76 +$\bullet$ data cards specifying columns (structural variables) and
   19.77 +constraint coefficients;
   19.78 +
   19.79 +$\bullet$ RHS indicator card;
   19.80 +
   19.81 +$\bullet$ data cards specifying right-hand sides of constraints;
   19.82 +
   19.83 +$\bullet$ RANGES indicator card;
   19.84 +
   19.85 +$\bullet$ data cards specifying ranges for double-bounded constraints;
   19.86 +
   19.87 +$\bullet$ BOUNDS indicator card;
   19.88 +
   19.89 +$\bullet$ data cards specifying types and bounds of structural
   19.90 +variables;
   19.91 +
   19.92 +$\bullet$ ENDATA indicator card.
   19.93 +
   19.94 +{\it Section} is a group of cards consisting of an indicator card and
   19.95 +data cards succeeding this indicator card. For example, the ROWS section
   19.96 +consists of the ROWS indicator card and data cards specifying rows.
   19.97 +
   19.98 +The sections RHS, RANGES, and BOUNDS are optional and may be omitted.
   19.99 +
  19.100 +\section{Free MPS Format}
  19.101 +
  19.102 +{\it Free MPS format} is an improved version of the standard (fixed)
  19.103 +MPS format described above.\footnote{This format was developed in the
  19.104 +beginning of 1990's by IBM as an alternative to the standard fixed MPS
  19.105 +format for Optimization Subroutine Library (OSL).} Note that all
  19.106 +changes in free MPS format concern only the coding of data while the
  19.107 +structure of data is the same for both fixed and free versions of the
  19.108 +MPS format.
  19.109 +
  19.110 +In free MPS format indicator and data records\footnote{{\it Record} in
  19.111 +free MPS format has the same meaning as {\it card} in fixed MPS format.}
  19.112 +may have arbitrary length not limited to 80 characters. Fields of data
  19.113 +records have no predefined positions, i.e. the fields may begin in any
  19.114 +position, except position 1, which must be blank, and must be separated
  19.115 +from each other by one or more blanks. However, the fields must appear
  19.116 +in the same order as in fixed MPS format.
  19.117 +
  19.118 +Symbolic names in fields 2, 3, and 5 may be longer than 8
  19.119 +characters\footnote{GLPK allows symbolic names having up to 255
  19.120 +characters.}
  19.121 +and must not contain embedded blanks.
  19.122 +
  19.123 +Numeric values in fields 4 and 6 are limited to 12 characters and must
  19.124 +not contain embedded blanks.
  19.125 +
  19.126 +Only six fields on each data record are used. Any other fields are
  19.127 +ignored.
  19.128 +
  19.129 +If the first character of any field (not necessarily fields 3 and 5)
  19.130 +is the dollar sign (\$), all characters from the dollar sign to the end
  19.131 +of record are considered as a comment and ignored.
  19.132 +
  19.133 +\section{NAME indicator card}
  19.134 +
  19.135 +The NAME indicator card should be the first card in the MPS file (except
  19.136 +optional comment cards, which may precede the NAME card). This card
  19.137 +should contain the word \verb|NAME| in the columns 1---4 and the problem
  19.138 +name in the field 3. The problem name is optional and may be omitted.
  19.139 +
  19.140 +\section{ROWS section}
  19.141 +\label{secrows}
  19.142 +
  19.143 +The ROWS section should start with the indicator card, which contains
  19.144 +the word \verb|ROWS| in the columns 1---4.
  19.145 +
  19.146 +Each data card in the ROWS section specifies one row (constraint) of the
  19.147 +problem. All these data cards have the following format.
  19.148 +
  19.149 +`\verb|N|' in the field 1 means that the row is free (unbounded):
  19.150 +$$-\infty < x_i = a_{i1}x_{m+1} + a_{i2}x_{m+2} + \dots + a_{in}x_{m+n}
  19.151 +< +\infty;$$
  19.152 +
  19.153 +`\verb|L|' in the field 1 means that the row is of ``less than or equal
  19.154 +to'' type:
  19.155 +$$-\infty < x_i = a_{i1}x_{m+1} + a_{i2}x_{m+2} + \dots + a_{in}x_{m+n}
  19.156 +\leq b_i;$$
  19.157 +
  19.158 +`\verb|G|' in the field 1 means that the row is of ``greater than or
  19.159 +equal to'' type:
  19.160 +$$b_i \leq x_i = a_{i1}x_{m+1} + a_{i2}x_{m+2} + \dots + a_{in}x_{m+n}
  19.161 +< +\infty;$$
  19.162 +
  19.163 +`\verb|E|' in the field 1 means that the row is of ``equal to'' type:
  19.164 +$$x_i = a_{i1}x_{m+1} + a_{i2}x_{m+2} + \dots + a_{in}x_{m+n} \leq
  19.165 +b_i,$$
  19.166 +where $b_i$ is a right-hand side. Note that each constraint has a
  19.167 +corresponding implictly defined auxiliary variable ($x_i$ above), whose
  19.168 +value is a value of the corresponding linear form, therefore row bounds
  19.169 +can be considered as bounds of such auxiliary variable.
  19.170 +
  19.171 +The filed 2 specifies a row name (which is considered as the name of
  19.172 +the corresponding auxiliary variable).
  19.173 +
  19.174 +The fields 3, 4, 5, and 6 are not used and should be empty.
  19.175 +
  19.176 +Numerical values of all non-zero right-hand sides $b_i$ should be
  19.177 +specified in the RHS section (see below). All double-bounded (ranged)
  19.178 +constraints should be specified in the RANGES section (see below).
  19.179 +
  19.180 +\section{COLUMNS section}
  19.181 +
  19.182 +The COLUMNS section should start with the indicator card, which contains
  19.183 +the word \verb|COLUMNS| in the columns 1---7.
  19.184 +
  19.185 +Each data card in the COLUMNS section specifies one or two constraint
  19.186 +coefficients $a_{ij}$ and also introduces names of columns, i.e. names
  19.187 +of structural variables. All these data cards have the following format.
  19.188 +
  19.189 +The field 1 is not used and should be empty.
  19.190 +
  19.191 +The field 2 specifies a column name. If this field is empty, the column
  19.192 +name from the immediately preceeding data card is assumed.
  19.193 +
  19.194 +The field 3 specifies a row name defined in the ROWS section.
  19.195 +
  19.196 +The field 4 specifies a numerical value of the constraint coefficient
  19.197 +$a_{ij}$, which is placed in the corresponding row and column.
  19.198 +
  19.199 +The fields 5 and 6 are optional. If they are used, they should contain
  19.200 +a second pair ``row name---constraint coefficient'' for the same column.
  19.201 +
  19.202 +Elements of the constraint matrix (i.e. constraint coefficients) should
  19.203 +be enumerated in the column wise manner: all elements for the current
  19.204 +column should be specified before elements for the next column. However,
  19.205 +the order of rows in the COLUMNS section may differ from the order of
  19.206 +rows in the ROWS section.
  19.207 +
  19.208 +Constraint coefficients not specified in the COLUMNS section are
  19.209 +considered as zeros. Therefore zero coefficients may be omitted,
  19.210 +although it is allowed to explicitly specify them.
  19.211 +
  19.212 +\section{RHS section}
  19.213 +
  19.214 +The RHS section should start with the indicator card, which contains the
  19.215 +word \verb|RHS| in the columns 1---3.
  19.216 +
  19.217 +Each data card in the RHS section specifies one or two right-hand sides
  19.218 +$b_i$ (see Section \ref{secrows}, page \pageref{secrows}). All these
  19.219 +data cards have the following format.
  19.220 +
  19.221 +The field 1 is not used and should be empty.
  19.222 +
  19.223 +The field 2 specifies a name of the right-hand side (RHS)
  19.224 +vector\footnote{This feature allows the user to specify several RHS
  19.225 +vectors in the same MPS file. However, before solving the problem a
  19.226 +particular RHS vector should be chosen.}. If this field is empty, the
  19.227 +RHS vector name from the immediately preceeding data card is assumed.
  19.228 +
  19.229 +The field 3 specifies a row name defined in the ROWS section.
  19.230 +
  19.231 +The field 4 specifies a right-hand side $b_i$ for the row, whose name is
  19.232 +specified in the field 3. Depending on the row type $b_i$ is a lower
  19.233 +bound (for the row of \verb|G| type), an upper bound (for the row of
  19.234 +\verb|L| type), or a fixed value (for the row of \verb|E|
  19.235 +type).\footnote{If the row is of {\tt N} type, $b_i$ is considered as
  19.236 +a constant term of the corresponding linear form. Should note, however,
  19.237 +this convention is non-standard.}
  19.238 +
  19.239 +The fields 5 and 6 are optional. If they are used, they should contain
  19.240 +a second pair ``row name---right-hand side'' for the same RHS vector.
  19.241 +
  19.242 +All right-hand sides for the current RHS vector should be specified
  19.243 +before right-hand sides for the next RHS vector. However, the order of
  19.244 +rows in the RHS section may differ from the order of rows in the ROWS
  19.245 +section.
  19.246 +
  19.247 +Right-hand sides not specified in the RHS section are considered as
  19.248 +zeros. Therefore zero right-hand sides may be omitted, although it is
  19.249 +allowed to explicitly specify them.
  19.250 +
  19.251 +\section{RANGES section}
  19.252 +
  19.253 +The RANGES section should start with the indicator card, which contains
  19.254 +the word \verb|RANGES| in the columns 1---6.
  19.255 +
  19.256 +Each data card in the RANGES section specifies one or two ranges for
  19.257 +double-side constraints, i.e. for constraints that are of the types
  19.258 +\verb|L| and \verb|G| at the same time:
  19.259 +$$l_i \leq x_i = a_{i1}x_{m+1} + a_{i2}x_{m+2} + \dots + a_{in}x_{m+n}
  19.260 +\leq u_i,$$
  19.261 +where $l_i$ is a lower bound, $u_i$ is an upper bound. All these data
  19.262 +cards have the following format.
  19.263 +
  19.264 +The field 1 is not used and should be empty.
  19.265 +
  19.266 +The field 2 specifies a name of the range vector\footnote{This feature
  19.267 +allows the user to specify several range vectors in the same MPS file.
  19.268 +However, before solving the problem a particular range vector should be
  19.269 +chosen.}. If this field is empty, the range vector name from the
  19.270 +immediately preceeding data card is assumed.
  19.271 +
  19.272 +The field 3 specifies a row name defined in the ROWS section.
  19.273 +
  19.274 +The field 4 specifies a range value $r_i$ (see the table below) for the
  19.275 +row, whose name is specified in the field 3.
  19.276 +
  19.277 +The fields 5 and 6 are optional. If they are used, they should contain
  19.278 +a second pair ``row name---range value'' for the same range vector.
  19.279 +
  19.280 +All range values for the current range vector should be specified before
  19.281 +range values for the next range vector. However, the order of rows in
  19.282 +the RANGES section may differ from the order of rows in the ROWS
  19.283 +section.
  19.284 +
  19.285 +For each double-side constraint specified in the RANGES section its
  19.286 +lower and upper bounds are determined as follows:
  19.287 +
  19.288 +\begin{center}
  19.289 +\begin{tabular}{cccc}
  19.290 +Row type & Sign of $r_i$ & Lower bound & Upper bound \\
  19.291 +\hline
  19.292 +{\tt G} & $+$ or $-$ & $b_i$ & $b_i + |r_i|$ \\
  19.293 +{\tt L} & $+$ or $-$ & $b_i - |r_i|$ & $b_i$ \\
  19.294 +{\tt E} & $+$ & $b_i$ & $b_i + |r_i|$ \\
  19.295 +{\tt E} & $-$ & $b_i - |r_i|$ & $b_i$ \\
  19.296 +\end{tabular}
  19.297 +\end{center}
  19.298 +
  19.299 +\noindent
  19.300 +where $b_i$ is a right-hand side specified in the RHS section (if $b_i$
  19.301 +is not specified, it is considered as zero), $r_i$ is a range value
  19.302 +specified in the RANGES section.
  19.303 +
  19.304 +\section{BOUNDS section}
  19.305 +\label{secbounds}
  19.306 +
  19.307 +The BOUNDS section should start with the indicator card, which contains
  19.308 +the word \verb|BOUNDS| in the columns 1---6.
  19.309 +
  19.310 +Each data card in the BOUNDS section specifies one (lower or upper)
  19.311 +bound for one structural variable (column). All these data cards have
  19.312 +the following format.
  19.313 +
  19.314 +The indicator in the field 1 specifies the bound type:
  19.315 +
  19.316 +\begin{tabular}{@{}ll}
  19.317 +\verb|LO| & lower bound; \\
  19.318 +\verb|UP| & upper bound; \\
  19.319 +\verb|FX| & fixed variable (lower and upper bounds are equal); \\
  19.320 +\verb|FR| & free variable (no bounds); \\
  19.321 +\verb|MI| & no lower bound (lower bound is ``minus infinity''); \\
  19.322 +\verb|PL| & no upper bound (upper bound is ``plus infinity''); \\
  19.323 +\end{tabular}
  19.324 +
  19.325 +The field 2 specifies a name of the bound vector\footnote{This feature
  19.326 +allows the user to specify several bound vectors in the same MPS file.
  19.327 +However, before solving the problem a particular bound vector should be
  19.328 +chosen.}. If this field is empty, the bound vector name from the
  19.329 +immediately preceeding data card is assumed.
  19.330 +
  19.331 +The field 3 specifies a column name defined in the COLUMNS section.
  19.332 +
  19.333 +The field 4 specifies a bound value. If the bound type in the field 1
  19.334 +differs from \verb|LO|, \verb|UP|, and \verb|FX|, the value in the field
  19.335 +4 is ignored and may be omitted.
  19.336 +
  19.337 +The fields 5 and 6 are not used and should be empty.
  19.338 +
  19.339 +All bound values for the current bound vector should be specified before
  19.340 +bound values for the next bound vector. However, the order of columns in
  19.341 +the BOUNDS section may differ from the order of columns in the COLUMNS
  19.342 +section. Specification of a lower bound should precede specification of
  19.343 +an upper bound for the same column (if both the lower and upper bounds
  19.344 +are explicitly specified).
  19.345 +
  19.346 +By default, all columns (structural variables) are non-negative, i.e.
  19.347 +have zero lower bound and no upper bound. Lower ($l_j$) and upper
  19.348 +($u_j$) bounds of some column (structural variable $x_j$) are set in the
  19.349 +following way, where $s_j$ is a corresponding bound value explicitly
  19.350 +specified in the BOUNDS section:
  19.351 +
  19.352 +\begin{tabular}{@{}ll}
  19.353 +\verb|LO| & sets $l_j$ to $s_j$; \\
  19.354 +\verb|UP| & sets $u_j$ to $s_j$; \\
  19.355 +\verb|FX| & sets both $l_j$ and $u_j$ to $s_j$; \\
  19.356 +\verb|FR| & sets $l_j$ to $-\infty$ and $u_j$ to $+\infty$; \\
  19.357 +\verb|MI| & sets $l_j$ to $-\infty$; \\
  19.358 +\verb|PL| & sets $u_j$ to $+\infty$. \\
  19.359 +\end{tabular}
  19.360 +
  19.361 +\section{ENDATA indicator card}
  19.362 +
  19.363 +The ENDATA indicator card should be the last card of MPS file (except
  19.364 +optional comment cards, which may follow the ENDATA card). This card
  19.365 +should contain the word \verb|ENDATA| in the columns 1---6.
  19.366 +
  19.367 +\section{Specifying objective function}
  19.368 +
  19.369 +It is impossible to explicitly specify the objective function and
  19.370 +optimization direction in the MPS file. However, the following implicit
  19.371 +rule is used by default: the first row of \verb|N| type is considered
  19.372 +as a row of the objective function (i.e. the objective function is the
  19.373 +corresponding auxiliary variable), which should be {\it minimized}.
  19.374 +
  19.375 +GLPK also allows specifying a constant term of the objective function
  19.376 +as a right-hand side of the corresponding row in the RHS section.
  19.377 +
  19.378 +\section{Example of MPS file}
  19.379 +\label{secmpsex}
  19.380 +
  19.381 +In order to illustrate what the MPS format is, consider the following
  19.382 +example of LP problem:
  19.383 +
  19.384 +\medskip
  19.385 +\noindent minimize
  19.386 +$$
  19.387 +value = .03\ bin_1 + .08\ bin_2 + .17\ bin_3 + .12\ bin_4 + .15\ bin_5
  19.388 ++ .21\ al + .38\ si
  19.389 +$$
  19.390 +
  19.391 +\noindent subject to linear constraints
  19.392 +$$
  19.393 +\begin{array}{@{}l@{\:}l@{}}
  19.394 +yield &= \ \ \ \ \;bin_1 + \ \ \ \ \;bin_2 + \ \ \ \ \;bin_3 +
  19.395 +         \ \ \ \ \;bin_4 + \ \ \ \ \;bin_5 + \ \ \ \ \;al +
  19.396 +         \ \ \ \ \;si \\
  19.397 +FE    &= .15\ bin_1 + .04\ bin_2 + .02\ bin_3 + .04\ bin_4 + .02\ bin_5
  19.398 +         + .01\ al + .03\ si \\
  19.399 +CU    &= .03\ bin_1 + .05\ bin_2 + .08\ bin_3 + .02\ bin_4 + .06\ bin_5
  19.400 +         + .01\ al \\
  19.401 +MN    &= .02\ bin_1 + .04\ bin_2 + .01\ bin_3 + .02\ bin_4 + .02\ bin_5
  19.402 +         \\
  19.403 +MG    &= .02\ bin_1 + .03\ bin_2
  19.404 +\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ + .01\ bin_5 \\
  19.405 +AL    &= .70\ bin_1 + .75\ bin_2 + .80\ bin_3 + .75\ bin_4 + .80\ bin_5
  19.406 +         + .97\ al \\
  19.407 +SI    &= .02\ bin_1 + .06\ bin_2 + .08\ bin_3 + .12\ bin_4 + .02\ bin_5
  19.408 +         + .01\ al + .97\ si \\
  19.409 +\end{array}
  19.410 +$$
  19.411 +and bounds of (auxiliary and structural) variables
  19.412 +$$
  19.413 +\begin{array}{r@{\ }l@{\ }l@{\ }l@{\ }rcr@{\ }l@{\ }l@{\ }l@{\ }r}
  19.414 +&&yield&=&2000&&0&\leq&bin_1&\leq&200\\
  19.415 +-\infty&<&FE&\leq&60&&0&\leq&bin_2&\leq&2500\\
  19.416 +-\infty&<&CU&\leq&100&&400&\leq&bin_3&\leq&800\\
  19.417 +-\infty&<&MN&\leq&40&&100&\leq&bin_4&\leq&700\\
  19.418 +-\infty&<&MG&\leq&30&&0&\leq&bin_5&\leq&1500\\
  19.419 +1500&\leq&AL&<&+\infty&&0&\leq&al&<&+\infty\\
  19.420 +250&\leq&SI&\leq&300&&0&\leq&si&<&+\infty\\
  19.421 +\end{array}
  19.422 +$$
  19.423 +
  19.424 +A complete MPS file which specifies data for this example is shown
  19.425 +below (the first two comment lines show card positions).
  19.426 +
  19.427 +\begin{verbatim}
  19.428 +*000000001111111111222222222233333333334444444444555555555566
  19.429 +*234567890123456789012345678901234567890123456789012345678901
  19.430 +NAME          PLAN
  19.431 +ROWS
  19.432 + N  VALUE
  19.433 + E  YIELD
  19.434 + L  FE
  19.435 + L  CU
  19.436 + L  MN
  19.437 + L  MG
  19.438 + G  AL
  19.439 + L  SI
  19.440 +COLUMNS
  19.441 +    BIN1      VALUE           .03000   YIELD          1.00000
  19.442 +              FE              .15000   CU              .03000
  19.443 +              MN              .02000   MG              .02000
  19.444 +              AL              .70000   SI              .02000
  19.445 +    BIN2      VALUE           .08000   YIELD          1.00000
  19.446 +              FE              .04000   CU              .05000
  19.447 +              MN              .04000   MG              .03000
  19.448 +              AL              .75000   SI              .06000
  19.449 +    BIN3      VALUE           .17000   YIELD          1.00000
  19.450 +              FE              .02000   CU              .08000
  19.451 +              MN              .01000   AL              .80000
  19.452 +              SI              .08000
  19.453 +    BIN4      VALUE           .12000   YIELD          1.00000
  19.454 +              FE              .04000   CU              .02000
  19.455 +              MN              .02000   AL              .75000
  19.456 +              SI              .12000
  19.457 +    BIN5      VALUE           .15000   YIELD          1.00000
  19.458 +              FE              .02000   CU              .06000
  19.459 +              MN              .02000   MG              .01000
  19.460 +              AL              .80000   SI              .02000
  19.461 +    ALUM      VALUE           .21000   YIELD          1.00000
  19.462 +              FE              .01000   CU              .01000
  19.463 +              AL              .97000   SI              .01000
  19.464 +    SILICON   VALUE           .38000   YIELD          1.00000
  19.465 +              FE              .03000   SI              .97000
  19.466 +RHS
  19.467 +    RHS1      YIELD       2000.00000   FE            60.00000
  19.468 +              CU           100.00000   MN            40.00000
  19.469 +              SI           300.00000
  19.470 +              MG            30.00000   AL          1500.00000
  19.471 +RANGES
  19.472 +    RNG1      SI            50.00000
  19.473 +BOUNDS
  19.474 + UP BND1      BIN1         200.00000
  19.475 + UP           BIN2        2500.00000
  19.476 + LO           BIN3         400.00000
  19.477 + UP           BIN3         800.00000
  19.478 + LO           BIN4         100.00000
  19.479 + UP           BIN4         700.00000
  19.480 + UP           BIN5        1500.00000
  19.481 +ENDATA
  19.482 +\end{verbatim}
  19.483 +
  19.484 +\section{MIP features}
  19.485 +
  19.486 +The MPS format provides two ways for introducing integer variables into
  19.487 +the problem.
  19.488 +
  19.489 +The first way is most general and based on using special marker cards
  19.490 +INTORG and INTEND. These marker cards are placed in the COLUMNS section.
  19.491 +The INTORG card indicates the start of a group of integer variables
  19.492 +(columns), and the card INTEND indicates the end of the group. The MPS
  19.493 +file may contain arbitrary number of the marker cards.
  19.494 +
  19.495 +The marker cards have the same format as the data cards (see Section
  19.496 +\ref{secmps}, page \pageref{secmps}).
  19.497 +
  19.498 +The fields 1, 2, and 6 are not used and should be empty.
  19.499 +
  19.500 +The field 2 should contain a marker name. This name may be arbitrary.
  19.501 +
  19.502 +The field 3 should contain the word \verb|'MARKER'| (including
  19.503 +apostrophes).
  19.504 +
  19.505 +The field 5 should contain either the word \verb|'INTORG'| (including
  19.506 +apostrophes) for the marker card, which begins a group of integer
  19.507 +columns, or the word \verb|'INTEND'| (including apostrophes) for the
  19.508 +marker card, which ends the group.
  19.509 +
  19.510 +The second way is less general but more convenient in some cases. It
  19.511 +allows the user declaring integer columns using three additional types
  19.512 +of bounds, which are specified in the field 1 of data cards in the
  19.513 +BOUNDS section (see Section \ref{secbounds}, page \pageref{secbounds}):
  19.514 +
  19.515 +\begin{tabular}{@{}lp{112.3mm}@{}}
  19.516 +\verb|LI| & lower integer. This bound type specifies that the
  19.517 +corresponding column (structural variable), whose name is specified in
  19.518 +field 3, is of integer kind. In this case an lower bound of the
  19.519 +column should be specified in field 4 (like in the case of \verb|LO|
  19.520 +bound type). \\
  19.521 +\verb|UI| & upper integer. This bound type specifies that the
  19.522 +corresponding column (structural variable), whose name is specified in
  19.523 +field 3, is of integer kind. In this case an upper bound of the
  19.524 +column should be specified in field 4 (like in the case of \verb|UP|
  19.525 +bound type). \\
  19.526 +\end{tabular}
  19.527 +
  19.528 +\pagebreak
  19.529 +
  19.530 +\begin{tabular}{@{}lp{112.3mm}@{}}
  19.531 +\verb|BV| & binary variable. This bound type specifies that the
  19.532 +corresponding column (structural variable), whose name is specified in
  19.533 +the field 3, is of integer kind, its lower bound is zero, and its upper
  19.534 +bound is one (thus, such variable being of integer kind can have only
  19.535 +two values zero and one). In this case a numeric value specified in the
  19.536 +field 4 is ignored and may be omitted.\\
  19.537 +\end{tabular}
  19.538 +
  19.539 +Consider the following example of MIP problem:
  19.540 +
  19.541 +\medskip
  19.542 +
  19.543 +\noindent
  19.544 +\hspace{1in} minimize
  19.545 +$$Z = 3 x_1 + 7 x_2 - x_3 + x4$$
  19.546 +\hspace{1in} subject to linear constraints
  19.547 +$$
  19.548 +\begin{array}{c}
  19.549 +\nonumber r_1 = 2   x_1 - \ \ x_2 + \ \ x_3 - \ \;x_4 \\
  19.550 +\nonumber r_2 = \ \;x_1 - \ \;x_2 - 6   x_3 + 4   x_4 \\
  19.551 +\nonumber r_3 = 5   x_1 +   3 x_2 \ \ \ \ \ \ \ \ \ + \ \ x_4 \\
  19.552 +\end{array}
  19.553 +$$
  19.554 +\hspace{1in} and bound of variables
  19.555 +$$
  19.556 +\begin{array}{cccl}
  19.557 +\nonumber 1 \leq r_1 < +\infty && 0 \leq x_1 \leq 4 &{\rm(continuous)}\\
  19.558 +\nonumber 8 \leq r_2 < +\infty && 2 \leq x_2 \leq 5 &{\rm(integer)}   \\
  19.559 +\nonumber 5 \leq r_3 < +\infty && 0 \leq x_3 \leq 1 &{\rm(integer)}   \\
  19.560 +\nonumber                      && 3 \leq x_4 \leq 8 &{\rm(continuous)}\\
  19.561 +\end{array}
  19.562 +$$
  19.563 +
  19.564 +The corresponding MPS file may look like the following:
  19.565 +
  19.566 +\begin{verbatim}
  19.567 +NAME          SAMP1
  19.568 +ROWS
  19.569 + N  Z
  19.570 + G  R1
  19.571 + G  R2
  19.572 + G  R3
  19.573 +COLUMNS
  19.574 +    X1        R1                2.0    R2                 1.0
  19.575 +    X1        R3                5.0    Z                  3.0
  19.576 +    MARK0001  'MARKER'                 'INTORG'
  19.577 +    X2        R1               -1.0    R2                -1.0
  19.578 +    X2        R3                3.0    Z                  7.0
  19.579 +    X3        R1                1.0    R2                -6.0
  19.580 +    X3        Z                -1.0
  19.581 +    MARK0002  'MARKER'                 'INTEND'
  19.582 +    X4        R1               -1.0    R2                 4.0
  19.583 +    X4        R3                1.0    Z                  1.0
  19.584 +RHS
  19.585 +    RHS1      R1                1.0
  19.586 +    RHS1      R2                8.0
  19.587 +    RHS1      R3                5.0
  19.588 +BOUNDS
  19.589 + UP BND1      X1                4.0
  19.590 + LO BND1      X2                2.0
  19.591 + UP BND1      X2                5.0
  19.592 + UP BND1      X3                1.0
  19.593 + LO BND1      X4                3.0
  19.594 + UP BND1      X4                8.0
  19.595 +ENDATA
  19.596 +\end{verbatim}
  19.597 +
  19.598 +The same example may be coded without INTORG/INTEND markers using the
  19.599 +bound type UI for the variable $x_2$ and the bound type BV for the
  19.600 +variable $x_3$:
  19.601 +
  19.602 +\begin{verbatim}
  19.603 +NAME          SAMP2
  19.604 +ROWS
  19.605 + N  Z
  19.606 + G  R1
  19.607 + G  R2
  19.608 + G  R3
  19.609 +COLUMNS
  19.610 +    X1        R1                2.0    R2                 1.0
  19.611 +    X1        R3                5.0    Z                  3.0
  19.612 +    X2        R1               -1.0    R2                -1.0
  19.613 +    X2        R3                3.0    Z                  7.0
  19.614 +    X3        R1                1.0    R2                -6.0
  19.615 +    X3        Z                -1.0
  19.616 +    X4        R1               -1.0    R2                 4.0
  19.617 +    X4        R3                1.0    Z                  1.0
  19.618 +RHS
  19.619 +    RHS1      R1                1.0
  19.620 +    RHS1      R2                8.0
  19.621 +    RHS1      R3                5.0
  19.622 +BOUNDS
  19.623 + UP BND1      X1                4.0
  19.624 + LO BND1      X2                2.0
  19.625 + UI BND1      X2                5.0
  19.626 + BV BND1      X3
  19.627 + LO BND1      X4                3.0
  19.628 + UP BND1      X4                8.0
  19.629 +ENDATA
  19.630 +\end{verbatim}
  19.631 +
  19.632 +%\section{Specifying predefined basis}
  19.633 +%\label{secbas}
  19.634 +%
  19.635 +%The MPS format can also be used to specify some predefined basis for an
  19.636 +%LP problem, i.e. to specify which rows and columns are basic and which
  19.637 +%are non-basic.
  19.638 +%
  19.639 +%The order of a basis file in the MPS format is:
  19.640 +%
  19.641 +%$\bullet$ NAME indicator card;
  19.642 +%
  19.643 +%$\bullet$ data cards (can appear in arbitrary order);
  19.644 +%
  19.645 +%$\bullet$ ENDATA indicator card.
  19.646 +%
  19.647 +%Each data card specifies either a pair "basic column---non-basic row"
  19.648 +%or a non-basic column. All the data cards have the following format.
  19.649 +%
  19.650 +%`\verb|XL|' in the field 1 means that a column, whose name is given in
  19.651 +%the field 2, is basic, and a row, whose name is given in the field 3,
  19.652 +%is non-basic and placed on its lower bound.
  19.653 +%
  19.654 +%`\verb|XU|' in the field 1 means that a column, whose name is given in
  19.655 +%the field 2, is basic, and a row, whose name is given in the field 3,
  19.656 +%is non-basic and placed on its upper bound.
  19.657 +%
  19.658 +%`\verb|LL|' in the field 1 means that a column, whose name is given in
  19.659 +%the field 3, is non-basic and placed on its lower bound.
  19.660 +%
  19.661 +%`\verb|UL|' in the field 1 means that a column, whose name is given in
  19.662 +%the field 3, is non-basic and placed on its upper bound.
  19.663 +%
  19.664 +%The field 2 contains a column name.
  19.665 +%
  19.666 +%If the indicator given in the field 1 is `\verb|XL|' or `\verb|XU|',
  19.667 +%the field 3 contains a row name. Otherwise, if the indicator is
  19.668 +%`\verb|LL|' or `\verb|UL|', the field 3 is not used and should be
  19.669 +%empty.
  19.670 +%
  19.671 +%The field 4, 5, and 6 are not used and should be empty.
  19.672 +%
  19.673 +%A basis file in the MPS format acts like a patch: it doesn't specify
  19.674 +%a basis completely, instead that it is just shows in what a given basis
  19.675 +%differs from the "standard" basis, where all rows (auxiliary variables)
  19.676 +%are assumed to be basic and all columns (structural variables) are
  19.677 +%assumed to be non-basic.
  19.678 +%
  19.679 +%As an example here is a basis file that specifies an optimal basis
  19.680 +%for the example LP problem given in Section \ref{secmpsex},
  19.681 +%Page \pageref{secmpsex}:
  19.682 +%
  19.683 +%\pagebreak
  19.684 +%
  19.685 +%\begin{verbatim}
  19.686 +%*000000001111111111222222222233333333334444444444555555555566
  19.687 +%*234567890123456789012345678901234567890123456789012345678901
  19.688 +%NAME          PLAN
  19.689 +% XL BIN2      YIELD
  19.690 +% XL BIN3      FE
  19.691 +% XL BIN4      MN
  19.692 +% XL ALUM      AL
  19.693 +% XL SILICON   SI
  19.694 +% LL BIN1
  19.695 +% LL BIN5
  19.696 +%ENDATA
  19.697 +%\end{verbatim}
  19.698 +
  19.699 +%* eof *%
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/doc/glpk09.tex	Mon Dec 06 13:09:21 2010 +0100
    20.3 @@ -0,0 +1,413 @@
    20.4 +%* glpk09.tex *%
    20.5 +
    20.6 +\chapter{CPLEX LP Format}
    20.7 +\label{chacplex}
    20.8 +
    20.9 +\section{Prelude}
   20.10 +
   20.11 +The CPLEX LP format\footnote{The CPLEX LP format was developed in
   20.12 +the end of 1980's by CPLEX Optimization, Inc. as an input format for
   20.13 +the CPLEX linear programming system. Although the CPLEX LP format is
   20.14 +not as widely used as the MPS format, being row-oriented it is more
   20.15 +convenient for coding mathematical programming models by human. This
   20.16 +appendix describes only the features of the CPLEX LP format which are
   20.17 +implemented in the GLPK package.} is intended for coding LP/MIP problem
   20.18 +data. It is a row-oriented format that assumes the formulation of LP/MIP
   20.19 +problem (1.1)---(1.3) (see Section \ref{seclp}, page \pageref{seclp}).
   20.20 +
   20.21 +CPLEX LP file is a plain text file written in CPLEX LP format. Each text
   20.22 +line of this file may contain up to 255 characters\footnote{GLPK allows
   20.23 +text lines of arbitrary length.}. Blank lines are ignored. If a line
   20.24 +contains the backslash character ($\backslash$), this character and
   20.25 +everything that follows it until the end of line are considered as a
   20.26 +comment and also ignored.
   20.27 +
   20.28 +An LP file is coded by the user using the following elements:
   20.29 +
   20.30 +$\bullet$ keywords;
   20.31 +
   20.32 +$\bullet$ symbolic names;
   20.33 +
   20.34 +$\bullet$ numeric constants;
   20.35 +
   20.36 +$\bullet$ delimiters;
   20.37 +
   20.38 +$\bullet$ blanks.
   20.39 +
   20.40 +\newpage
   20.41 +
   20.42 +{\it Keywords} which may be used in the LP file are the following:
   20.43 +
   20.44 +\begin{verbatim}
   20.45 +      minimize        minimum        min
   20.46 +      maximize        maximum        max
   20.47 +      subject to      such that      s.t.      st.      st
   20.48 +      bounds          bound
   20.49 +      general         generals       gen
   20.50 +      integer         integers       int
   20.51 +      binary          binaries       bin
   20.52 +      infinity        inf
   20.53 +      free
   20.54 +      end
   20.55 +\end{verbatim}
   20.56 +
   20.57 +\noindent
   20.58 +All the keywords are case insensitive. Keywords given above on the same
   20.59 +line are equivalent. Any keyword (except \verb|infinity|, \verb|inf|,
   20.60 +and \verb|free|) being used in the LP file must start at the beginning
   20.61 +of a text line.
   20.62 +
   20.63 +{\it Symbolic names} are used to identify the objective function,
   20.64 +constraints (rows), and variables (columns). All symbolic names are case
   20.65 +sensitive and may contain up to 16 alphanumeric characters\footnote{GLPK
   20.66 +allows symbolic names having up to 255 characters.} (\verb|a|, \dots,
   20.67 +\verb|z|, \verb|A|, \dots, \verb|Z|, \verb|0|, \dots, \verb|9|) as well
   20.68 +as the following characters:
   20.69 +
   20.70 +\begin{verbatim}
   20.71 +!  "  #  $  %  &  (  )  /  ,  .  ;  ?  @  _  `  '  {  }  |  ~
   20.72 +\end{verbatim}
   20.73 +
   20.74 +\noindent
   20.75 +with exception that no symbolic name can begin with a digit or a period.
   20.76 +
   20.77 +{\it Numeric constants} are used to denote constraint and objective
   20.78 +coefficients, right-hand sides of constraints, and bounds of variables.
   20.79 +They are coded in the standard form $xx$\verb|E|$syy$, where $xx$ is
   20.80 +a real number with optional decimal point, $s$ is a sign (\verb|+| or
   20.81 +\verb|-|), $yy$ is an integer decimal exponent. Numeric constants may
   20.82 +contain arbitrary number of characters. The exponent part is optional.
   20.83 +The letter `\verb|E|' can be coded as `\verb|e|'. If the sign $s$ is
   20.84 +omitted, plus is assumed.
   20.85 +
   20.86 +{\it Delimiters} that may be used in the LP file are the following:
   20.87 +
   20.88 +\begin{verbatim}
   20.89 +      :
   20.90 +      +
   20.91 +      -
   20.92 +      <   <=   =<
   20.93 +      >   >=   =>
   20.94 +      =
   20.95 +\end{verbatim}
   20.96 +
   20.97 +\noindent
   20.98 +Delimiters given above on the same line are equivalent. The meaning of
   20.99 +the delimiters will be explained below.
  20.100 +
  20.101 +{\it Blanks} are non-significant characters. They may be used freely to
  20.102 +improve readability of the LP file. Besides, blanks should be used to
  20.103 +separate elements from each other if there is no other way to do that
  20.104 +(for example, to separate a keyword from a following symbolic name).
  20.105 +
  20.106 +The order of an LP file is:
  20.107 +
  20.108 +$\bullet$ objective function definition;
  20.109 +
  20.110 +$\bullet$ constraints section;
  20.111 +
  20.112 +$\bullet$ bounds section;
  20.113 +
  20.114 +$\bullet$ general, integer, and binary sections (can appear in arbitrary
  20.115 +order);
  20.116 +
  20.117 +$\bullet$ end keyword.
  20.118 +
  20.119 +These components are discussed in following sections.
  20.120 +
  20.121 +\section{Objective function definition}
  20.122 +
  20.123 +The objective function definition must appear first in the LP file. It
  20.124 +defines the objective function and specifies the optimization direction.
  20.125 +
  20.126 +The objective function definition has the following form:
  20.127 +$$
  20.128 +\left\{
  20.129 +\begin{array}{@{}c@{}}
  20.130 +{\tt minimize} \\ {\tt maximize}
  20.131 +\end{array}
  20.132 +\right\}\ f\ {\tt :}\ s\ c\ x\ s\ c\ x\ \dots\ s\ c\ x
  20.133 +$$
  20.134 +where $f$ is a symbolic name of the objective function, $s$ is a sign
  20.135 +\verb|+| or \verb|-|, $c$ is a numeric constant that denotes an
  20.136 +objective coefficient, $x$ is a symbolic name of a variable.
  20.137 +
  20.138 +If necessary, the objective function definition can be continued on as
  20.139 +many text lines as desired.
  20.140 +
  20.141 +The name of the objective function is optional and may be omitted
  20.142 +(together with the semicolon that follows it). In this case the default
  20.143 +name `\verb|obj|' is assigned to the objective function.
  20.144 +
  20.145 +If the very first sign $s$ is omitted, the sign plus is assumed. Other
  20.146 +signs cannot be omitted.
  20.147 +
  20.148 +If some objective coefficient $c$ is omitted, 1 is assumed.
  20.149 +
  20.150 +Symbolic names $x$ used to denote variables are recognized by context
  20.151 +and therefore needn't to be declared somewhere else.
  20.152 +
  20.153 +Here is an example of the objective function definition:
  20.154 +
  20.155 +\begin{verbatim}
  20.156 +   Minimize Z : - x1 + 2 x2 - 3.5 x3 + 4.997e3x(4) + x5 + x6 +
  20.157 +      x7 - .01x8
  20.158 +\end{verbatim}
  20.159 +
  20.160 +\section{Constraints section}
  20.161 +
  20.162 +The constraints section must follow the objective function definition.
  20.163 +It defines a system of equality and/or inequality constraints.
  20.164 +
  20.165 +The constraint section has the following form:
  20.166 +
  20.167 +\begin{center}
  20.168 +\begin{tabular}{l}
  20.169 +\verb|subject to| \\
  20.170 +{\it constraint}$_1$ \\
  20.171 +{\it constraint}$_2$ \\
  20.172 +\hspace{20pt}\dots \\
  20.173 +{\it constraint}$_m$ \\
  20.174 +\end{tabular}
  20.175 +\end{center}
  20.176 +
  20.177 +\noindent where {\it constraint}$_i, i=1,\dots,m,$ is a particular
  20.178 +constraint definition.
  20.179 +
  20.180 +Each constraint definition can be continued on as many text lines as
  20.181 +desired. However, each constraint definition must begin on a new line
  20.182 +except the very first constraint definition which can begin on the same
  20.183 +line as the keyword `\verb|subject to|'.
  20.184 +
  20.185 +Constraint definitions have the following form:
  20.186 +$$
  20.187 +r\ {\tt:}\ s\ c\ x\ s\ c\ x\ \dots\ s\ c\ x
  20.188 +\ \left\{
  20.189 +\begin{array}{@{}c@{}}
  20.190 +\mbox{\tt<=} \\ \mbox{\tt>=} \\ \mbox{\tt=}
  20.191 +\end{array}
  20.192 +\right\}\ b
  20.193 +$$
  20.194 +where $r$ is a symbolic name of a constraint, $s$ is a sign \verb|+| or
  20.195 +\verb|-|, $c$ is a numeric constant that denotes a constraint
  20.196 +coefficient, $x$ is a symbolic name of a variable, $b$ is a right-hand
  20.197 +side.
  20.198 +
  20.199 +The name $r$ of a constraint (which is the name of the corresponding
  20.200 +auxiliary variable) is optional and may be omitted (together with the
  20.201 +semicolon that follows it). In this case the default names like
  20.202 +`\verb|r.nnn|' are assigned to unnamed constraints.
  20.203 +
  20.204 +The linear form $s\ c\ x\ s\ c\ x\ \dots\ s\ c\ x$ in the left-hand
  20.205 +side of a constraint definition has exactly the same meaning as in the
  20.206 +case of the objective function definition (see above).
  20.207 +
  20.208 +After the linear form one of the following delimiters that indicate
  20.209 +the constraint sense must be specified:
  20.210 +
  20.211 +\verb|<=| \ means `less than or equal to'
  20.212 +
  20.213 +\verb|>=| \ means `greater than or equal to'
  20.214 +
  20.215 +\verb|= | \ means `equal to'
  20.216 +
  20.217 +The right hand side $b$ is a numeric constant with an optional sign.
  20.218 +
  20.219 +Here is an example of the constraints section:
  20.220 +
  20.221 +\begin{verbatim}
  20.222 +   Subject To
  20.223 +      one: y1 + 3 a1 - a2 - b >= 1.5
  20.224 +      y2 + 2 a3 + 2
  20.225 +         a4 - b >= -1.5
  20.226 +      two : y4 + 3 a1 + 4 a5 - b <= +1
  20.227 +      .20y5 + 5 a2 - b = 0
  20.228 +      1.7 y6 - a6 + 5 a777 - b >= 1
  20.229 +\end{verbatim}
  20.230 +
  20.231 +(Should note that it is impossible to express ranged constraints in the
  20.232 +CPLEX LP format. Each a ranged constraint can be coded as two
  20.233 +constraints with identical linear forms in the left-hand side, one of
  20.234 +which specifies a lower bound and other does an upper one of the
  20.235 +original ranged constraint.)
  20.236 +
  20.237 +\section{Bounds section}
  20.238 +
  20.239 +The bounds section is intended to define bounds of variables. This
  20.240 +section is optional; if it is specified, it must follow the constraints
  20.241 +section. If the bound section is omitted, all variables are assumed to
  20.242 +be non-negative (i.e. that they have zero lower bound and no upper
  20.243 +bound).
  20.244 +
  20.245 +The bounds section has the following form:
  20.246 +
  20.247 +\begin{center}
  20.248 +\begin{tabular}{l}
  20.249 +\verb|bounds| \\
  20.250 +{\it definition}$_1$ \\
  20.251 +{\it definition}$_2$ \\
  20.252 +\hspace{20pt}\dots \\
  20.253 +{\it definition}$_p$ \\
  20.254 +\end{tabular}
  20.255 +\end{center}
  20.256 +
  20.257 +\noindent
  20.258 +where {\it definition}$_k, k=1,\dots,p,$ is a particular bound
  20.259 +definition.
  20.260 +
  20.261 +Each bound definition must begin on a new line\footnote{The GLPK
  20.262 +implementation allows several bound definitions to be placed on the same
  20.263 +line.} except the very first bound definition which can begin on the
  20.264 +same line as the keyword `\verb|bounds|'.
  20.265 +
  20.266 +Syntactically constraint definitions can have one of the following six
  20.267 +forms:
  20.268 +
  20.269 +\begin{center}
  20.270 +\begin{tabular}{ll}
  20.271 +$x$ \verb|>=| $l$ &              specifies a lower bound \\
  20.272 +$l$ \verb|<=| $x$ &              specifies a lower bound \\
  20.273 +$x$ \verb|<=| $u$ &              specifies an upper bound \\
  20.274 +$l$ \verb|<=| $x$ \verb|<=| $u$ &specifies both lower and upper bounds\\
  20.275 +$x$ \verb|=| $t$                &specifies a fixed value \\
  20.276 +$x$ \verb|free|                 &specifies free variable
  20.277 +\end{tabular}
  20.278 +\end{center}
  20.279 +
  20.280 +\noindent
  20.281 +where $x$ is a symbolic name of a variable, $l$ is a numeric constant
  20.282 +with an optional sign that defines a lower bound of the variable or
  20.283 +\verb|-inf| that means that the variable has no lower bound, $u$ is a
  20.284 +numeric constant with an optional sign that defines an upper bound of
  20.285 +the variable or \verb|+inf| that means that the variable has no upper
  20.286 +bound, $t$ is a numeric constant with an optional sign that defines a
  20.287 +fixed value of the variable.
  20.288 +
  20.289 +By default all variables are non-negative, i.e. have zero lower bound
  20.290 +and no upper bound. Therefore definitions of these default bounds can be
  20.291 +omitted in the bounds section.
  20.292 +
  20.293 +Here is an example of the bounds section:
  20.294 +
  20.295 +\begin{verbatim}
  20.296 +   Bounds
  20.297 +      -inf <= a1 <= 100
  20.298 +      -100 <= a2
  20.299 +      b <= 100
  20.300 +      x2 = +123.456
  20.301 +      x3 free
  20.302 +\end{verbatim}
  20.303 +
  20.304 +\section{General, integer, and binary sections}
  20.305 +
  20.306 +The general, integer, and binary sections are intended to define
  20.307 +some variables as integer or binary. All these sections are optional
  20.308 +and needed only in case of MIP problems. If they are specified, they
  20.309 +must follow the bounds section or, if the latter is omitted, the
  20.310 +constraints section.
  20.311 +
  20.312 +All the general, integer, and binary sections have the same form as
  20.313 +follows:
  20.314 +
  20.315 +\begin{center}
  20.316 +\begin{tabular}{l}
  20.317 +$
  20.318 +\left\{
  20.319 +\begin{array}{@{}l@{}}
  20.320 +\verb|general| \\
  20.321 +\verb|integer| \\
  20.322 +\verb|binary | \\
  20.323 +\end{array}
  20.324 +\right\}
  20.325 +$ \\
  20.326 +\hspace{10pt}$x_1$ \\
  20.327 +\hspace{10pt}$x_2$ \\
  20.328 +\hspace{10pt}\dots \\
  20.329 +\hspace{10pt}$x_q$ \\
  20.330 +\end{tabular}
  20.331 +\end{center}
  20.332 +
  20.333 +\noindent
  20.334 +where $x_k$ is a symbolic name of variable, $k=1,\dots,q$.
  20.335 +
  20.336 +Each symbolic name must begin on a new line\footnote{The GLPK
  20.337 +implementation allows several symbolic names to be placed on the same
  20.338 +line.} except the very first symbolic name which can begin on the same
  20.339 +line as the keyword `\verb|general|', `\verb|integer|', or
  20.340 +`\verb|binary|'.
  20.341 +
  20.342 +If a variable appears in the general or the integer section, it is
  20.343 +assumed to be general integer variable. If a variable appears in the
  20.344 +binary section, it is assumed to be binary variable, i.e. an integer
  20.345 +variable whose lower bound is zero and upper bound is one. (Note that
  20.346 +if bounds of a variable are specified in the bounds section and then
  20.347 +the variable appears in the binary section, its previously specified
  20.348 +bounds are ignored.)
  20.349 +
  20.350 +Here is an example of the integer section:
  20.351 +
  20.352 +\begin{verbatim}
  20.353 +   Integer
  20.354 +      z12
  20.355 +      z22
  20.356 +      z35
  20.357 +\end{verbatim}
  20.358 +
  20.359 +\section{End keyword}
  20.360 +
  20.361 +The keyword `\verb|end|' is intended to end the LP file. It must begin
  20.362 +on a separate line and no other elements (except comments and blank
  20.363 +lines) must follow it. Although this keyword is optional, it is strongly
  20.364 +recommended to include it in the LP file.
  20.365 +
  20.366 +\section{Example of CPLEX LP file}
  20.367 +
  20.368 +Here is a complete example of CPLEX LP file that corresponds to the
  20.369 +example given in Section \ref{secmpsex}, page \pageref{secmpsex}.
  20.370 +
  20.371 +{\footnotesize
  20.372 +\begin{verbatim}
  20.373 +\* plan.lp *\
  20.374 +
  20.375 +Minimize
  20.376 +   value: .03 bin1 + .08 bin2 + .17 bin3 + .12 bin4 + .15 bin5 +
  20.377 +          .21 alum + .38 silicon
  20.378 +
  20.379 +Subject To
  20.380 +   yield:     bin1 +     bin2 +     bin3 +     bin4 +     bin5 +
  20.381 +              alum +     silicon                                 =  2000
  20.382 +
  20.383 +   fe:    .15 bin1 + .04 bin2 + .02 bin3 + .04 bin4 + .02 bin5 +
  20.384 +          .01 alum + .03 silicon                                 <=   60
  20.385 +
  20.386 +   cu:    .03 bin1 + .05 bin2 + .08 bin3 + .02 bin4 + .06 bin5 +
  20.387 +          .01 alum                                               <=  100
  20.388 +
  20.389 +   mn:    .02 bin1 + .04 bin2 + .01 bin3 + .02 bin4 + .02 bin5   <=   40
  20.390 +
  20.391 +   mg:    .02 bin1 + .03 bin2                       + .01 bin5   <=   30
  20.392 +
  20.393 +   al:    .70 bin1 + .75 bin2 + .80 bin3 + .75 bin4 + .80 bin5 +
  20.394 +          .97 alum                                               >= 1500
  20.395 +
  20.396 +   si1:   .02 bin1 + .06 bin2 + .08 bin3 + .12 bin4 + .02 bin5 +
  20.397 +          .01 alum + .97 silicon                                 >=  250
  20.398 +
  20.399 +   si2:   .02 bin1 + .06 bin2 + .08 bin3 + .12 bin4 + .02 bin5 +
  20.400 +          .01 alum + .97 silicon                                 <=  300
  20.401 +
  20.402 +Bounds
  20.403 +          bin1 <=  200
  20.404 +          bin2 <= 2500
  20.405 +   400 <= bin3 <=  800
  20.406 +   100 <= bin4 <=  700
  20.407 +          bin5 <= 1500
  20.408 +
  20.409 +End
  20.410 +
  20.411 +\* eof *\
  20.412 +\end{verbatim}
  20.413 +
  20.414 +}
  20.415 +
  20.416 +%* eof *%
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/doc/glpk10.tex	Mon Dec 06 13:09:21 2010 +0100
    21.3 @@ -0,0 +1,210 @@
    21.4 +%* glpk10.tex *%
    21.5 +
    21.6 +\chapter{Stand-alone LP/MIP Solver}
    21.7 +\label{chaglpsol}
    21.8 +
    21.9 +The GLPK package includes the program \verb|glpsol|, which is a
   21.10 +stand-alone LP/MIP solver. This program can be invoked from the command
   21.11 +line of from the shell to read LP/MIP problem data in any format
   21.12 +supported by GLPK, solve the problem, and write the problem solution
   21.13 +obtained to an output text file.
   21.14 +
   21.15 +\subsubsection*{Usage}
   21.16 +
   21.17 +\noindent
   21.18 +\verb|glpsol| [{\it options\dots}] [{\it filename}]
   21.19 +
   21.20 +\subsubsection*{General options}
   21.21 +
   21.22 +\noindent
   21.23 +\begin{tabular}{@{}p{30mm}p{92.3mm}@{}}
   21.24 +\verb|--mps|      &  read LP/MIP problem in fixed MPS format \\
   21.25 +\verb|--freemps|  &  read LP/MIP problem in free MPS format (default)\\
   21.26 +\verb|--lp|       &  read LP/MIP problem in CPLEX LP format \\
   21.27 +\verb|--glp|      &  read LP/MIP problem in GLPK format \\
   21.28 +\verb|--math|     &  read LP/MIP model written in GNU MathProg modeling
   21.29 +                     language \\
   21.30 +\multicolumn{2}{@{}l}{{\tt -m} {\it filename}, {\tt --model}
   21.31 +{\it filename}} \\
   21.32 +                  &  read model section and optional data section from
   21.33 +                     {\it filename} (the same as \verb|--math|) \\
   21.34 +\multicolumn{2}{@{}l}{{\tt -d} {\it filename}, {\tt --data}
   21.35 +{\it filename}} \\
   21.36 +                  &  read data section from {\it filename}
   21.37 +                     (for \verb|--math| only); if model file also has
   21.38 +                     data section, that section is ignored \\
   21.39 +\multicolumn{2}{@{}l}{{\tt -y} {\it filename}, {\tt --display}
   21.40 +{\it filename}} \\
   21.41 +                  &  send display output to {\it filename}
   21.42 +                     (for \verb|--math| only); by default the output is
   21.43 +                     sent to \verb|stdout| \\
   21.44 +\end{tabular}
   21.45 +
   21.46 +\noindent
   21.47 +\begin{tabular}{@{}p{30mm}p{92.3mm}@{}}
   21.48 +\verb|--seed| {\it value}
   21.49 +                  &  initialize pseudo-random number generator used in
   21.50 +                     MathProg model with specified seed (any integer);
   21.51 +                     if the seed value is specified as \verb|?|
   21.52 +                     (question mark), some random seed will be used\\
   21.53 +\verb|--mincost|  &  read min-cost flow problem in DIMACS format\\
   21.54 +\verb|--maxflow|  &  read maximum flow problem in DIMACS format\\
   21.55 +\verb|--simplex|  &  use simplex method (default) \\
   21.56 +\verb|--interior| &  use interior point method (for pure LP only) \\
   21.57 +\multicolumn{2}{@{}l}{{\tt -r} {\it filename}, {\tt --read}
   21.58 +{\it filename}} \\
   21.59 +                  &  read solution from {\it filename} rather to find
   21.60 +                     it with the solver \\
   21.61 +\verb|--min|      &  minimization \\
   21.62 +\verb|--max|      &  maximization \\
   21.63 +\verb|--scale|    &  scale problem (default) \\
   21.64 +\verb|--noscale|  &  do not scale problem \\
   21.65 +\multicolumn{2}{@{}l}{{\tt -o} {\it filename}, {\tt --output}
   21.66 +{\it filename}} \\
   21.67 +                  &  write solution to {\it filename} in printable
   21.68 +                     format \\
   21.69 +\multicolumn{2}{@{}l}{{\tt -w} {\it filename}, {\tt --write}
   21.70 +{\it filename}} \\
   21.71 +                  &  write solution to {\it filename} in plain text
   21.72 +                     format \\
   21.73 +\multicolumn{2}{@{}l}{{\tt --ranges} {\it filename}} \\
   21.74 +                  &  write sensitivity analysis report to {\it filename}
   21.75 +                     in printable format (simplex only) \\
   21.76 +\verb|--tmlim| {\it nnn}
   21.77 +                  &  limit solution time to {\it nnn} seconds
   21.78 +                     (\verb|--tmlim 0| allows obtaining solution at
   21.79 +                     initial point) \\
   21.80 +\verb|--memlim| {\it nnn}
   21.81 +                  &  limit available memory to {\it nnn} megabytes \\
   21.82 +\verb|--check|    &  do not solve problem, check input data only \\
   21.83 +\verb|--name| {\it probname}
   21.84 +                  &  change problem name to {\it probname} \\
   21.85 +\verb|--wmps| {\it filename}
   21.86 +                  &  write problem to {\it filename} in fixed MPS
   21.87 +                     format \\
   21.88 +\multicolumn{2}{@{}l}{{\tt --wfreemps} {\it filename}} \\
   21.89 +                  &  write problem to {\it filename} in free MPS
   21.90 +                     format \\
   21.91 +\verb|--wlp| {\it filename}
   21.92 +                  &  write problem to {\it filename} in CPLEX LP
   21.93 +                     format \\
   21.94 +\verb|--wglp| {\it filename}
   21.95 +                  &  write problem to {\it filename} in GLPK format \\
   21.96 +\verb|--log| {\it filename}
   21.97 +                  &  write copy of terminal output to {\it filename} \\
   21.98 +\verb|-h|, \verb|--help|
   21.99 +                  &  display this help information and exit \\
  21.100 +\verb|-v|, \verb|--version|
  21.101 +                  &  display program version and exit \\
  21.102 +\end{tabular}
  21.103 +
  21.104 +\subsection*{LP basis factorization options}
  21.105 +
  21.106 +\noindent
  21.107 +\begin{tabular}{@{}p{30mm}p{92.3mm}@{}}
  21.108 +\verb|--luf|      &  LU + Forrest--Tomlin update \\
  21.109 +                  &  (faster, less stable; default) \\
  21.110 +\verb|--cbg|      &  LU + Schur complement + Bartels--Golub update \\
  21.111 +                  &  (slower, more stable) \\
  21.112 +\verb|--cgr|      &  LU + Schur complement + Givens rotation update \\
  21.113 +                  &  (slower, more stable) \\
  21.114 +\end{tabular}
  21.115 +
  21.116 +\subsubsection*{Options specific to the simplex solver}
  21.117 +
  21.118 +\noindent
  21.119 +\begin{tabular}{@{}p{30mm}p{92.3mm}@{}}
  21.120 +\verb|--primal|   &  use primal simplex (default) \\
  21.121 +\verb|--dual|     &  use dual simplex \\
  21.122 +\verb|--std|      &  use standard initial basis of all slacks \\
  21.123 +\verb|--adv|      &  use advanced initial basis (default) \\
  21.124 +\verb|--bib|      &  use Bixby's initial basis\\
  21.125 +\verb|--ini| {\it filename}
  21.126 +                  &  use as initial basis previously saved with
  21.127 +                     \verb|-w| \\
  21.128 +                  & (disables LP presolver) \\
  21.129 +\verb|--steep|    &  use steepest edge technique (default) \\
  21.130 +\verb|--nosteep|  &  use standard ``textbook'' pricing \\
  21.131 +\verb|--relax|    &  use Harris' two-pass ratio test (default) \\
  21.132 +\verb|--norelax|  &  use standard ``textbook'' ratio test \\
  21.133 +\verb|--presol|   &  use LP presolver (default; assumes \verb|--scale|
  21.134 +                     and \verb|--adv|) \\
  21.135 +\verb|--nopresol| &  do not use LP presolver \\
  21.136 +\verb|--exact|    & use simplex method based on exact arithmetic \\
  21.137 +\verb|--xcheck|   & check final basis using exact arithmetic \\
  21.138 +\end{tabular}
  21.139 +
  21.140 +\subsubsection*{Options specific to the interior-point solver}
  21.141 +
  21.142 +\noindent
  21.143 +\begin{tabular}{@{}p{30mm}p{92.3mm}@{}}
  21.144 +\verb|--nord|     &  use natural (original) ordering \\
  21.145 +\verb|--qmd|      &  use quotient minimum degree ordering \\
  21.146 +\verb|--amd|      &  use approximate minimum degree ordering (default)\\
  21.147 +\verb|--symamd|   &  use approximate minimum degree ordering \\
  21.148 +\end{tabular}
  21.149 +
  21.150 +\subsubsection*{Options specific to the MIP solver}
  21.151 +
  21.152 +\noindent
  21.153 +\begin{tabular}{@{}p{30mm}p{92.3mm}@{}}
  21.154 +\verb|--nomip|    &  consider all integer variables as continuous
  21.155 +                     (allows solving MIP as pure LP) \\
  21.156 +\verb|--first|    &  branch on first integer variable \\
  21.157 +\verb|--last|     &  branch on last integer variable \\
  21.158 +\verb|--mostf|    &  branch on most fractional variable \\
  21.159 +\end{tabular}
  21.160 +
  21.161 +\noindent
  21.162 +\begin{tabular}{@{}p{30mm}p{92.3mm}@{}}
  21.163 +\verb|--drtom|    &  branch using heuristic by Driebeck and Tomlin
  21.164 +                     (default) \\
  21.165 +\verb|--pcost|    &  branch using hybrid pseudocost heuristic (may be
  21.166 +                     useful for hard instances) \\
  21.167 +\verb|--dfs|      &  backtrack using depth first search \\
  21.168 +\verb|--bfs|      &  backtrack using breadth first search \\
  21.169 +\verb|--bestp|    &  backtrack using the best projection heuristic
  21.170 +                     (default) \\
  21.171 +\verb|--bestb|    &  backtrack using node with best local bound \\
  21.172 +\verb|--intopt|   &  use MIP presolver (default)\\
  21.173 +\verb|--nointopt| &  do not use MIP presolver\\
  21.174 +\verb|--binarize| &  replace general integer variables by binary ones
  21.175 +                     (assumes \verb|--intopt|)\\
  21.176 +\verb|--fpump|    & apply feasibility pump heuristic\\
  21.177 +\verb|--gomory|   &  generate Gomory's mixed integer cuts\\
  21.178 +\verb|--mir|      &  generate MIR (mixed integer rounding) cuts\\
  21.179 +\verb|--cover|    &  generate mixed cover cuts\\
  21.180 +\verb|--clique|   &  generate clique cuts\\
  21.181 +\verb|--cuts|     &  generate cuts of all classes above (assumes
  21.182 +                     \verb|--intopt|)\\
  21.183 +\verb|--mipgap| {\it tol}
  21.184 +                  & set relative mip gap tolerance to {\it tol}\\
  21.185 +\end{tabular}
  21.186 +
  21.187 +\bigskip
  21.188 +
  21.189 +\noindent
  21.190 +For description of the MPS format see Appendix \ref{champs},
  21.191 +page \pageref{champs}.
  21.192 +
  21.193 +\bigskip
  21.194 +
  21.195 +\noindent
  21.196 +For description of the CPLEX LP format see Appendix \ref{chacplex},
  21.197 +page \pageref{chacplex}.
  21.198 +
  21.199 +\bigskip
  21.200 +
  21.201 +\noindent
  21.202 +For description of the modeling language see the document ``Modeling
  21.203 +Language GNU MathProg: Language Reference'' included in the GLPK
  21.204 +distribution.
  21.205 +
  21.206 +\bigskip
  21.207 +
  21.208 +\noindent
  21.209 +For description of the DIMACS min-cost flow problem format and DIMACS
  21.210 +maximum flow problem format see the document ``GLPK: Graph and Network
  21.211 +Routines'' included in the GLPK distribution.
  21.212 +
  21.213 +%* eof *%
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/doc/glpk11.tex	Mon Dec 06 13:09:21 2010 +0100
    22.3 @@ -0,0 +1,124 @@
    22.4 +%* glpk11.tex *%
    22.5 +
    22.6 +\begin{footnotesize}
    22.7 +
    22.8 +\chapter{External Software Modules Used In GLPK}
    22.9 +
   22.10 +In the GLPK package there are used some external software modules
   22.11 +listed in this Appendix. Note that these modules are {\it not} part of
   22.12 +GLPK, but are used with GLPK and included in the distribution.
   22.13 +
   22.14 +\section{AMD}
   22.15 +
   22.16 +AMD Version 2.2, Copyright {\copyright} 2007 by Timothy A. Davis,
   22.17 +Patrick R. Amestoy, and Iain S. Duff.  All Rights Reserved.
   22.18 +
   22.19 +\subsection*{Description}
   22.20 +
   22.21 +AMD is a set of routines for pre-ordering sparse matrices prior to
   22.22 +Cholesky or LU factorization, using the approximate minimum degree
   22.23 +ordering algorithm.
   22.24 +
   22.25 +\subsection*{License}
   22.26 +
   22.27 +This library is free software; you can redistribute it and/or
   22.28 +modify it under the terms of the GNU Lesser General Public License
   22.29 +as published by the Free Software Foundation; either version 2.1 of
   22.30 +the License, or (at your option) any later version.
   22.31 +
   22.32 +This library is distributed in the hope that it will be useful,
   22.33 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   22.34 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   22.35 +Lesser General Public License for more details.
   22.36 +
   22.37 +You should have received a copy of the GNU Lesser General Public
   22.38 +License along with this library; if not, write to the Free Software
   22.39 +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
   22.40 +USA.
   22.41 +
   22.42 +Permission is hereby granted to use or copy this program under the
   22.43 +terms of the GNU LGPL, provided that the Copyright, this License,
   22.44 +and the Availability of the original version is retained on all
   22.45 +copies.  User documentation of any code that uses this code or any
   22.46 +modified version of this code must cite the Copyright, this License,
   22.47 +the Availability note, and ``Used by permission.''  Permission to
   22.48 +modify the code and to distribute modified code is granted, provided
   22.49 +the Copyright, this License, and the Availability note are retained,
   22.50 +and a notice that the code was modified is included.
   22.51 +
   22.52 +AMD is available under alternate licences; contact T. Davis for
   22.53 +details.
   22.54 +
   22.55 +\subsection*{Availability}
   22.56 +
   22.57 +\verb|http://www.cise.ufl.edu/research/sparse/amd|
   22.58 +
   22.59 +\bigskip
   22.60 +
   22.61 +\noindent
   22.62 +Used by permission.
   22.63 +
   22.64 +\section{COLAMD/SYMAMD}
   22.65 +
   22.66 +COLAMD/SYMAMD Version 2.7, Copyright {\copyright} 1998-2007, Timothy A.
   22.67 +Davis, All Rights Reserved.
   22.68 +
   22.69 +\subsection*{Description}
   22.70 +
   22.71 +\paragraph{colamd:} an approximate minimum degree column ordering
   22.72 +algorithm, for LU factorization of symmetric or unsymmetric matrices,
   22.73 +QR factorization, least squares, interior point methods for linear
   22.74 +programming problems, and other related problems.
   22.75 +
   22.76 +\paragraph{symamd:} an approximate minimum degree ordering algorithm
   22.77 +for Cholesky factorization of symmetric matrices.
   22.78 +
   22.79 +\subsection*{Authors}
   22.80 +
   22.81 +The authors of the code itself are Stefan I. Larimore and Timothy A.
   22.82 +Davis (davis at cise.ufl.edu), University of Florida.  The algorithm
   22.83 +was developed in collaboration with John Gilbert, Xerox PARC, and
   22.84 +Esmond Ng, Oak Ridge National Laboratory.
   22.85 +
   22.86 +\subsection*{License}
   22.87 +
   22.88 +This library is free software; you can redistribute it and/or
   22.89 +modify it under the terms of the GNU Lesser General Public License
   22.90 +as published by the Free Software Foundation; either version 2.1 of
   22.91 +the License, or (at your option) any later version.
   22.92 +
   22.93 +This library is distributed in the hope that it will be useful,
   22.94 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   22.95 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   22.96 +Lesser General Public License for more details.
   22.97 +
   22.98 +You should have received a copy of the GNU Lesser General Public
   22.99 +License along with this library; if not, write to the Free Software
  22.100 +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
  22.101 +USA.
  22.102 +
  22.103 +Permission is hereby granted to use or copy this program under the
  22.104 +terms of the GNU LGPL, provided that the Copyright, this License,
  22.105 +and the Availability of the original version is retained on all
  22.106 +copies.  User documentation of any code that uses this code or any
  22.107 +modified version of this code must cite the Copyright, this License,
  22.108 +the Availability note, and ``Used by permission.''  Permission to
  22.109 +modify the code and to distribute modified code is granted, provided
  22.110 +the Copyright, this License, and the Availability note are retained,
  22.111 +and a notice that the code was modified is included.
  22.112 +
  22.113 +COLAMD is also available under alternate licenses, contact T. Davis for
  22.114 +details.
  22.115 +
  22.116 +\subsection*{Availability}
  22.117 +
  22.118 +\verb|http://www.cise.ufl.edu/research/sparse/colamd|
  22.119 +
  22.120 +\bigskip
  22.121 +
  22.122 +\noindent
  22.123 +Used by permission.
  22.124 +
  22.125 +\end{footnotesize}
  22.126 +
  22.127 +%* eof *%
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/doc/glpk12.tex	Mon Dec 06 13:09:21 2010 +0100
    23.3 @@ -0,0 +1,726 @@
    23.4 +%* glpk12.tex *%
    23.5 +
    23.6 +\begin{footnotesize}
    23.7 +
    23.8 +\chapter*{\sf\bfseries GNU General Public License}
    23.9 +\addcontentsline{toc}{chapter}{GNU General Public License}
   23.10 +
   23.11 +\begin{center}
   23.12 +{\bf Version 3, 29 June 2007}
   23.13 +\end{center}
   23.14 +
   23.15 +\begin{quotation}
   23.16 +\noindent
   23.17 +Copyright {\copyright} 2007 Free Software Foundation, Inc.
   23.18 +\verb|<http://fsf.org/>|
   23.19 +\end{quotation}
   23.20 +
   23.21 +\begin{quotation}
   23.22 +\noindent
   23.23 +Everyone is permitted to copy and distribute verbatim copies
   23.24 +of this license document, but changing it is not allowed.
   23.25 +\end{quotation}
   23.26 +
   23.27 +\section*{Preamble}
   23.28 +
   23.29 +\noindent\indent
   23.30 +  The GNU General Public License is a free, copyleft license for
   23.31 +software and other kinds of works.
   23.32 +
   23.33 +  The licenses for most software and other practical works are designed
   23.34 +to take away your freedom to share and change the works.  By contrast,
   23.35 +the GNU General Public License is intended to guarantee your freedom to
   23.36 +share and change all versions of a program--to make sure it remains free
   23.37 +software for all its users.  We, the Free Software Foundation, use the
   23.38 +GNU General Public License for most of our software; it applies also to
   23.39 +any other work released this way by its authors.  You can apply it to
   23.40 +your programs, too.
   23.41 +
   23.42 +  When we speak of free software, we are referring to freedom, not
   23.43 +price.  Our General Public Licenses are designed to make sure that you
   23.44 +have the freedom to distribute copies of free software (and charge for
   23.45 +them if you wish), that you receive source code or can get it if you
   23.46 +want it, that you can change the software or use pieces of it in new
   23.47 +free programs, and that you know you can do these things.
   23.48 +
   23.49 +  To protect your rights, we need to prevent others from denying you
   23.50 +these rights or asking you to surrender the rights.  Therefore, you have
   23.51 +certain responsibilities if you distribute copies of the software, or if
   23.52 +you modify it: responsibilities to respect the freedom of others.
   23.53 +
   23.54 +  For example, if you distribute copies of such a program, whether
   23.55 +gratis or for a fee, you must pass on to the recipients the same
   23.56 +freedoms that you received.  You must make sure that they, too, receive
   23.57 +or can get the source code.  And you must show them these terms so they
   23.58 +know their rights.
   23.59 +
   23.60 +  Developers that use the GNU GPL protect your rights with two steps:
   23.61 +(1) assert copyright on the software, and (2) offer you this License
   23.62 +giving you legal permission to copy, distribute and/or modify it.
   23.63 +
   23.64 +  For the developers' and authors' protection, the GPL clearly explains
   23.65 +that there is no warranty for this free software.  For both users' and
   23.66 +authors' sake, the GPL requires that modified versions be marked as
   23.67 +changed, so that their problems will not be attributed erroneously to
   23.68 +authors of previous versions.
   23.69 +
   23.70 +  Some devices are designed to deny users access to install or run
   23.71 +modified versions of the software inside them, although the manufacturer
   23.72 +can do so.  This is fundamentally incompatible with the aim of
   23.73 +protecting users' freedom to change the software.  The systematic
   23.74 +pattern of such abuse occurs in the area of products for individuals to
   23.75 +use, which is precisely where it is most unacceptable.  Therefore, we
   23.76 +have designed this version of the GPL to prohibit the practice for those
   23.77 +products.  If such problems arise substantially in other domains, we
   23.78 +stand ready to extend this provision to those domains in future versions
   23.79 +of the GPL, as needed to protect the freedom of users.
   23.80 +
   23.81 +  Finally, every program is threatened constantly by software patents.
   23.82 +States should not allow patents to restrict development and use of
   23.83 +software on general-purpose computers, but in those that do, we wish to
   23.84 +avoid the special danger that patents applied to a free program could
   23.85 +make it effectively proprietary.  To prevent this, the GPL assures that
   23.86 +patents cannot be used to render the program non-free.
   23.87 +
   23.88 +  The precise terms and conditions for copying, distribution and
   23.89 +modification follow.
   23.90 +
   23.91 +\section*{TERMS AND CONDITIONS}
   23.92 +
   23.93 +\subsubsection*{0. Definitions.}
   23.94 +
   23.95 +\noindent\indent
   23.96 +  ``This License'' refers to version 3 of the GNU General Public
   23.97 +License.
   23.98 +
   23.99 +  ``Copyright'' also means copyright-like laws that apply to other kinds
  23.100 +of works, such as semiconductor masks.
  23.101 +
  23.102 +  ``The Program'' refers to any copyrightable work licensed under this
  23.103 +License.  Each licensee is addressed as ``you''.  ``Licensees'' and
  23.104 +``recipients'' may be individuals or organizations.
  23.105 +
  23.106 +  To ``modify'' a work means to copy from or adapt all or part of the
  23.107 +work in a fashion requiring copyright permission, other than the making
  23.108 +of an exact copy.  The resulting work is called a ``modified version''
  23.109 +of the earlier work or a work ``based on'' the earlier work.
  23.110 +
  23.111 +  A ``covered work'' means either the unmodified Program or a work based
  23.112 +on the Program.
  23.113 +
  23.114 +  To ``propagate'' a work means to do anything with it that, without
  23.115 +permission, would make you directly or secondarily liable for
  23.116 +infringement under applicable copyright law, except executing it on a
  23.117 +computer or modifying a private copy.  Propagation includes copying,
  23.118 +distribution (with or without modification), making available to the
  23.119 +public, and in some countries other activities as well.
  23.120 +
  23.121 +  To ``convey'' a work means any kind of propagation that enables other
  23.122 +parties to make or receive copies.  Mere interaction with a user through
  23.123 +a computer network, with no transfer of a copy, is not conveying.
  23.124 +
  23.125 +  An interactive user interface displays ``Appropriate Legal Notices''
  23.126 +to the extent that it includes a convenient and prominently visible
  23.127 +feature that (1) displays an appropriate copyright notice, and (2)
  23.128 +tells the user that there is no warranty for the work (except to the
  23.129 +extent that warranties are provided), that licensees may convey the
  23.130 +work under this License, and how to view a copy of this License.  If
  23.131 +the interface presents a list of user commands or options, such as a
  23.132 +menu, a prominent item in the list meets this criterion.
  23.133 +
  23.134 +\subsubsection*{1. Source Code.}
  23.135 +
  23.136 +\noindent\indent
  23.137 +  The ``source code'' for a work means the preferred form of the work
  23.138 +for making modifications to it.  ``Object code'' means any non-source
  23.139 +form of a work.
  23.140 +
  23.141 +  A ``Standard Interface'' means an interface that either is an official
  23.142 +standard defined by a recognized standards body, or, in the case of
  23.143 +interfaces specified for a particular programming language, one that
  23.144 +is widely used among developers working in that language.
  23.145 +
  23.146 +  The ``System Libraries'' of an executable work include anything, other
  23.147 +than the work as a whole, that (a) is included in the normal form of
  23.148 +packaging a Major Component, but which is not part of that Major
  23.149 +Component, and (b) serves only to enable use of the work with that
  23.150 +Major Component, or to implement a Standard Interface for which an
  23.151 +implementation is available to the public in source code form.  A
  23.152 +``Major Component'', in this context, means a major essential component
  23.153 +(kernel, window system, and so on) of the specific operating system
  23.154 +(if any) on which the executable work runs, or a compiler used to
  23.155 +produce the work, or an object code interpreter used to run it.
  23.156 +
  23.157 +  The ``Corresponding Source'' for a work in object code form means all
  23.158 +the source code needed to generate, install, and (for an executable
  23.159 +work) run the object code and to modify the work, including scripts to
  23.160 +control those activities.  However, it does not include the work's
  23.161 +System Libraries, or general-purpose tools or generally available free
  23.162 +programs which are used unmodified in performing those activities but
  23.163 +which are not part of the work.  For example, Corresponding Source
  23.164 +includes interface definition files associated with source files for
  23.165 +the work, and the source code for shared libraries and dynamically
  23.166 +linked subprograms that the work is specifically designed to require,
  23.167 +such as by intimate data communication or control flow between those
  23.168 +subprograms and other parts of the work.
  23.169 +
  23.170 +  The Corresponding Source need not include anything that users
  23.171 +can regenerate automatically from other parts of the Corresponding
  23.172 +Source.
  23.173 +
  23.174 +  The Corresponding Source for a work in source code form is that
  23.175 +same work.
  23.176 +
  23.177 +\subsubsection*{2. Basic Permissions.}
  23.178 +
  23.179 +\noindent\indent
  23.180 +  All rights granted under this License are granted for the term of
  23.181 +copyright on the Program, and are irrevocable provided the stated
  23.182 +conditions are met.  This License explicitly affirms your unlimited
  23.183 +permission to run the unmodified Program.  The output from running a
  23.184 +covered work is covered by this License only if the output, given its
  23.185 +content, constitutes a covered work.  This License acknowledges your
  23.186 +rights of fair use or other equivalent, as provided by copyright law.
  23.187 +
  23.188 +  You may make, run and propagate covered works that you do not
  23.189 +convey, without conditions so long as your license otherwise remains
  23.190 +in force.  You may convey covered works to others for the sole purpose
  23.191 +of having them make modifications exclusively for you, or provide you
  23.192 +with facilities for running those works, provided that you comply with
  23.193 +the terms of this License in conveying all material for which you do
  23.194 +not control copyright.  Those thus making or running the covered works
  23.195 +for you must do so exclusively on your behalf, under your direction
  23.196 +and control, on terms that prohibit them from making any copies of
  23.197 +your copyrighted material outside their relationship with you.
  23.198 +
  23.199 +  Conveying under any other circumstances is permitted solely under
  23.200 +the conditions stated below.  Sublicensing is not allowed; section 10
  23.201 +makes it unnecessary.
  23.202 +
  23.203 +\subsubsection*{3. Protecting Users' Legal Rights From
  23.204 +Anti-Circumvention Law.}
  23.205 +
  23.206 +\noindent\indent
  23.207 +  No covered work shall be deemed part of an effective technological
  23.208 +measure under any applicable law fulfilling obligations under article
  23.209 +11 of the WIPO copyright treaty adopted on 20 December 1996, or
  23.210 +similar laws prohibiting or restricting circumvention of such
  23.211 +measures.
  23.212 +
  23.213 +  When you convey a covered work, you waive any legal power to forbid
  23.214 +circumvention of technological measures to the extent such circumvention
  23.215 +is effected by exercising rights under this License with respect to
  23.216 +the covered work, and you disclaim any intention to limit operation or
  23.217 +modification of the work as a means of enforcing, against the work's
  23.218 +users, your or third parties' legal rights to forbid circumvention of
  23.219 +technological measures.
  23.220 +
  23.221 +\subsubsection*{4. Conveying Verbatim Copies.}
  23.222 +
  23.223 +\noindent\indent
  23.224 +  You may convey verbatim copies of the Program's source code as you
  23.225 +receive it, in any medium, provided that you conspicuously and
  23.226 +appropriately publish on each copy an appropriate copyright notice;
  23.227 +keep intact all notices stating that this License and any
  23.228 +non-permissive terms added in accord with section 7 apply to the code;
  23.229 +keep intact all notices of the absence of any warranty; and give all
  23.230 +recipients a copy of this License along with the Program.
  23.231 +
  23.232 +  You may charge any price or no price for each copy that you convey,
  23.233 +and you may offer support or warranty protection for a fee.
  23.234 +
  23.235 +\subsubsection*{5. Conveying Modified Source Versions.}
  23.236 +
  23.237 +  You may convey a work based on the Program, or the modifications to
  23.238 +produce it from the Program, in the form of source code under the
  23.239 +terms of section 4, provided that you also meet all of these conditions:
  23.240 +
  23.241 +    a) The work must carry prominent notices stating that you modified
  23.242 +    it, and giving a relevant date.
  23.243 +
  23.244 +    b) The work must carry prominent notices stating that it is
  23.245 +    released under this License and any conditions added under section
  23.246 +    7.  This requirement modifies the requirement in section 4 to
  23.247 +    ``keep intact all notices''.
  23.248 +
  23.249 +    c) You must license the entire work, as a whole, under this
  23.250 +    License to anyone who comes into possession of a copy.  This
  23.251 +    License will therefore apply, along with any applicable section 7
  23.252 +    additional terms, to the whole of the work, and all its parts,
  23.253 +    regardless of how they are packaged.  This License gives no
  23.254 +    permission to license the work in any other way, but it does not
  23.255 +    invalidate such permission if you have separately received it.
  23.256 +
  23.257 +    d) If the work has interactive user interfaces, each must display
  23.258 +    Appropriate Legal Notices; however, if the Program has interactive
  23.259 +    interfaces that do not display Appropriate Legal Notices, your
  23.260 +    work need not make them do so.
  23.261 +
  23.262 +  A compilation of a covered work with other separate and independent
  23.263 +works, which are not by their nature extensions of the covered work,
  23.264 +and which are not combined with it such as to form a larger program,
  23.265 +in or on a volume of a storage or distribution medium, is called an
  23.266 +``aggregate'' if the compilation and its resulting copyright are not
  23.267 +used to limit the access or legal rights of the compilation's users
  23.268 +beyond what the individual works permit.  Inclusion of a covered work
  23.269 +in an aggregate does not cause this License to apply to the other
  23.270 +parts of the aggregate.
  23.271 +
  23.272 +\subsubsection*{6. Conveying Non-Source Forms.}
  23.273 +
  23.274 +  You may convey a covered work in object code form under the terms
  23.275 +of sections 4 and 5, provided that you also convey the
  23.276 +machine-readable Corresponding Source under the terms of this License,
  23.277 +in one of these ways:
  23.278 +
  23.279 +    a) Convey the object code in, or embodied in, a physical product
  23.280 +    (including a physical distribution medium), accompanied by the
  23.281 +    Corresponding Source fixed on a durable physical medium
  23.282 +    customarily used for software interchange.
  23.283 +
  23.284 +    b) Convey the object code in, or embodied in, a physical product
  23.285 +    (including a physical distribution medium), accompanied by a
  23.286 +    written offer, valid for at least three years and valid for as
  23.287 +    long as you offer spare parts or customer support for that product
  23.288 +    model, to give anyone who possesses the object code either (1) a
  23.289 +    copy of the Corresponding Source for all the software in the
  23.290 +    product that is covered by this License, on a durable physical
  23.291 +    medium customarily used for software interchange, for a price no
  23.292 +    more than your reasonable cost of physically performing this
  23.293 +    conveying of source, or (2) access to copy the
  23.294 +    Corresponding Source from a network server at no charge.
  23.295 +
  23.296 +    c) Convey individual copies of the object code with a copy of the
  23.297 +    written offer to provide the Corresponding Source.  This
  23.298 +    alternative is allowed only occasionally and noncommercially, and
  23.299 +    only if you received the object code with such an offer, in accord
  23.300 +    with subsection 6b.
  23.301 +
  23.302 +    d) Convey the object code by offering access from a designated
  23.303 +    place (gratis or for a charge), and offer equivalent access to the
  23.304 +    Corresponding Source in the same way through the same place at no
  23.305 +    further charge.  You need not require recipients to copy the
  23.306 +    Corresponding Source along with the object code.  If the place to
  23.307 +    copy the object code is a network server, the Corresponding Source
  23.308 +    may be on a different server (operated by you or a third party)
  23.309 +    that supports equivalent copying facilities, provided you maintain
  23.310 +    clear directions next to the object code saying where to find the
  23.311 +    Corresponding Source.  Regardless of what server hosts the
  23.312 +    Corresponding Source, you remain obligated to ensure that it is
  23.313 +    available for as long as needed to satisfy these requirements.
  23.314 +
  23.315 +    e) Convey the object code using peer-to-peer transmission, provided
  23.316 +    you inform other peers where the object code and Corresponding
  23.317 +    Source of the work are being offered to the general public at no
  23.318 +    charge under subsection 6d.
  23.319 +
  23.320 +  A separable portion of the object code, whose source code is excluded
  23.321 +from the Corresponding Source as a System Library, need not be
  23.322 +included in conveying the object code work.
  23.323 +
  23.324 +  A ``User Product'' is either (1) a ``consumer product'', which means
  23.325 +any tangible personal property which is normally used for personal,
  23.326 +family, or household purposes, or (2) anything designed or sold for
  23.327 +incorporation into a dwelling.  In determining whether a product is a
  23.328 +consumer product, doubtful cases shall be resolved in favor of coverage.
  23.329 +For a particular product received by a particular user, ``normally
  23.330 +used'' refers to a typical or common use of that class of product,
  23.331 +regardless of the status of the particular user or of the way in which
  23.332 +the particular user actually uses, or expects or is expected to use, the
  23.333 +product.  A product is a consumer product regardless of whether the
  23.334 +product has substantial commercial, industrial or non-consumer uses,
  23.335 +unless such uses represent the only significant mode of use of the
  23.336 +product.
  23.337 +
  23.338 +  ``Installation Information'' for a User Product means any methods,
  23.339 +procedures, authorization keys, or other information required to install
  23.340 +and execute modified versions of a covered work in that User Product
  23.341 +from a modified version of its Corresponding Source.  The information
  23.342 +must suffice to ensure that the continued functioning of the modified
  23.343 +object code is in no case prevented or interfered with solely because
  23.344 +modification has been made.
  23.345 +
  23.346 +  If you convey an object code work under this section in, or with, or
  23.347 +specifically for use in, a User Product, and the conveying occurs as
  23.348 +part of a transaction in which the right of possession and use of the
  23.349 +User Product is transferred to the recipient in perpetuity or for a
  23.350 +fixed term (regardless of how the transaction is characterized), the
  23.351 +Corresponding Source conveyed under this section must be accompanied
  23.352 +by the Installation Information.  But this requirement does not apply
  23.353 +if neither you nor any third party retains the ability to install
  23.354 +modified object code on the User Product (for example, the work has
  23.355 +been installed in ROM).
  23.356 +
  23.357 +  The requirement to provide Installation Information does not include a
  23.358 +requirement to continue to provide support service, warranty, or updates
  23.359 +for a work that has been modified or installed by the recipient, or for
  23.360 +the User Product in which it has been modified or installed.  Access to
  23.361 +a network may be denied when the modification itself materially and
  23.362 +adversely affects the operation of the network or violates the rules and
  23.363 +protocols for communication across the network.
  23.364 +
  23.365 +  Corresponding Source conveyed, and Installation Information provided,
  23.366 +in accord with this section must be in a format that is publicly
  23.367 +documented (and with an implementation available to the public in
  23.368 +source code form), and must require no special password or key for
  23.369 +unpacking, reading or copying.
  23.370 +
  23.371 +\subsubsection*{7. Additional Terms.}
  23.372 +
  23.373 +\noindent\indent
  23.374 +  ``Additional permissions'' are terms that supplement the terms of this
  23.375 +License by making exceptions from one or more of its conditions.
  23.376 +Additional permissions that are applicable to the entire Program shall
  23.377 +be treated as though they were included in this License, to the extent
  23.378 +that they are valid under applicable law.  If additional permissions
  23.379 +apply only to part of the Program, that part may be used separately
  23.380 +under those permissions, but the entire Program remains governed by
  23.381 +this License without regard to the additional permissions.
  23.382 +
  23.383 +  When you convey a copy of a covered work, you may at your option
  23.384 +remove any additional permissions from that copy, or from any part of
  23.385 +it.  (Additional permissions may be written to require their own
  23.386 +removal in certain cases when you modify the work.)  You may place
  23.387 +additional permissions on material, added by you to a covered work,
  23.388 +for which you have or can give appropriate copyright permission.
  23.389 +
  23.390 +  Notwithstanding any other provision of this License, for material you
  23.391 +add to a covered work, you may (if authorized by the copyright holders
  23.392 +of that material) supplement the terms of this License with terms:
  23.393 +
  23.394 +    a) Disclaiming warranty or limiting liability differently from the
  23.395 +    terms of sections 15 and 16 of this License; or
  23.396 +
  23.397 +    b) Requiring preservation of specified reasonable legal notices or
  23.398 +    author attributions in that material or in the Appropriate Legal
  23.399 +    Notices displayed by works containing it; or
  23.400 +
  23.401 +    c) Prohibiting misrepresentation of the origin of that material, or
  23.402 +    requiring that modified versions of such material be marked in
  23.403 +    reasonable ways as different from the original version; or
  23.404 +
  23.405 +    d) Limiting the use for publicity purposes of names of licensors or
  23.406 +    authors of the material; or
  23.407 +
  23.408 +    e) Declining to grant rights under trademark law for use of some
  23.409 +    trade names, trademarks, or service marks; or
  23.410 +
  23.411 +    f) Requiring indemnification of licensors and authors of that
  23.412 +    material by anyone who conveys the material (or modified versions of
  23.413 +    it) with contractual assumptions of liability to the recipient, for
  23.414 +    any liability that these contractual assumptions directly impose on
  23.415 +    those licensors and authors.
  23.416 +
  23.417 +  All other non-permissive additional terms are considered ``further
  23.418 +restrictions'' within the meaning of section 10.  If the Program as you
  23.419 +received it, or any part of it, contains a notice stating that it is
  23.420 +governed by this License along with a term that is a further
  23.421 +restriction, you may remove that term.  If a license document contains
  23.422 +a further restriction but permits relicensing or conveying under this
  23.423 +License, you may add to a covered work material governed by the terms
  23.424 +of that license document, provided that the further restriction does
  23.425 +not survive such relicensing or conveying.
  23.426 +
  23.427 +  If you add terms to a covered work in accord with this section, you
  23.428 +must place, in the relevant source files, a statement of the
  23.429 +additional terms that apply to those files, or a notice indicating
  23.430 +where to find the applicable terms.
  23.431 +
  23.432 +  Additional terms, permissive or non-permissive, may be stated in the
  23.433 +form of a separately written license, or stated as exceptions;
  23.434 +the above requirements apply either way.
  23.435 +
  23.436 +\subsubsection*{8. Termination.}
  23.437 +
  23.438 +\noindent\indent
  23.439 +  You may not propagate or modify a covered work except as expressly
  23.440 +provided under this License.  Any attempt otherwise to propagate or
  23.441 +modify it is void, and will automatically terminate your rights under
  23.442 +this License (including any patent licenses granted under the third
  23.443 +paragraph of section 11).
  23.444 +
  23.445 +  However, if you cease all violation of this License, then your
  23.446 +license from a particular copyright holder is reinstated (a)
  23.447 +provisionally, unless and until the copyright holder explicitly and
  23.448 +finally terminates your license, and (b) permanently, if the copyright
  23.449 +holder fails to notify you of the violation by some reasonable means
  23.450 +prior to 60 days after the cessation.
  23.451 +
  23.452 +  Moreover, your license from a particular copyright holder is
  23.453 +reinstated permanently if the copyright holder notifies you of the
  23.454 +violation by some reasonable means, this is the first time you have
  23.455 +received notice of violation of this License (for any work) from that
  23.456 +copyright holder, and you cure the violation prior to 30 days after
  23.457 +your receipt of the notice.
  23.458 +
  23.459 +  Termination of your rights under this section does not terminate the
  23.460 +licenses of parties who have received copies or rights from you under
  23.461 +this License.  If your rights have been terminated and not permanently
  23.462 +reinstated, you do not qualify to receive new licenses for the same
  23.463 +material under section 10.
  23.464 +
  23.465 +\subsubsection*{9. Acceptance Not Required for Having Copies.}
  23.466 +
  23.467 +\noindent\indent
  23.468 +  You are not required to accept this License in order to receive or
  23.469 +run a copy of the Program.  Ancillary propagation of a covered work
  23.470 +occurring solely as a consequence of using peer-to-peer transmission
  23.471 +to receive a copy likewise does not require acceptance.  However,
  23.472 +nothing other than this License grants you permission to propagate or
  23.473 +modify any covered work.  These actions infringe copyright if you do
  23.474 +not accept this License.  Therefore, by modifying or propagating a
  23.475 +covered work, you indicate your acceptance of this License to do so.
  23.476 +
  23.477 +\subsubsection*{10. Automatic Licensing of Downstream Recipients.}
  23.478 +
  23.479 +\noindent\indent
  23.480 +  Each time you convey a covered work, the recipient automatically
  23.481 +receives a license from the original licensors, to run, modify and
  23.482 +propagate that work, subject to this License.  You are not responsible
  23.483 +for enforcing compliance by third parties with this License.
  23.484 +
  23.485 +  An ``entity transaction'' is a transaction transferring control of an
  23.486 +organization, or substantially all assets of one, or subdividing an
  23.487 +organization, or merging organizations.  If propagation of a covered
  23.488 +work results from an entity transaction, each party to that
  23.489 +transaction who receives a copy of the work also receives whatever
  23.490 +licenses to the work the party's predecessor in interest had or could
  23.491 +give under the previous paragraph, plus a right to possession of the
  23.492 +Corresponding Source of the work from the predecessor in interest, if
  23.493 +the predecessor has it or can get it with reasonable efforts.
  23.494 +
  23.495 +  You may not impose any further restrictions on the exercise of the
  23.496 +rights granted or affirmed under this License.  For example, you may
  23.497 +not impose a license fee, royalty, or other charge for exercise of
  23.498 +rights granted under this License, and you may not initiate litigation
  23.499 +(including a cross-claim or counterclaim in a lawsuit) alleging that
  23.500 +any patent claim is infringed by making, using, selling, offering for
  23.501 +sale, or importing the Program or any portion of it.
  23.502 +
  23.503 +\subsubsection*{11. Patents.}
  23.504 +
  23.505 +\noindent\indent
  23.506 +  A ``contributor'' is a copyright holder who authorizes use under this
  23.507 +License of the Program or a work on which the Program is based.  The
  23.508 +work thus licensed is called the contributor's ``contributor version''.
  23.509 +
  23.510 +  A contributor's ``essential patent claims'' are all patent claims
  23.511 +owned or controlled by the contributor, whether already acquired or
  23.512 +hereafter acquired, that would be infringed by some manner, permitted
  23.513 +by this License, of making, using, or selling its contributor version,
  23.514 +but do not include claims that would be infringed only as a
  23.515 +consequence of further modification of the contributor version.  For
  23.516 +purposes of this definition, ``control'' includes the right to grant
  23.517 +patent sublicenses in a manner consistent with the requirements of
  23.518 +this License.
  23.519 +
  23.520 +  Each contributor grants you a non-exclusive, worldwide, royalty-free
  23.521 +patent license under the contributor's essential patent claims, to
  23.522 +make, use, sell, offer for sale, import and otherwise run, modify and
  23.523 +propagate the contents of its contributor version.
  23.524 +
  23.525 +  In the following three paragraphs, a ``patent license'' is any express
  23.526 +agreement or commitment, however denominated, not to enforce a patent
  23.527 +(such as an express permission to practice a patent or covenant not to
  23.528 +sue for patent infringement).  To ``grant'' such a patent license to a
  23.529 +party means to make such an agreement or commitment not to enforce a
  23.530 +patent against the party.
  23.531 +
  23.532 +  If you convey a covered work, knowingly relying on a patent license,
  23.533 +and the Corresponding Source of the work is not available for anyone
  23.534 +to copy, free of charge and under the terms of this License, through a
  23.535 +publicly available network server or other readily accessible means,
  23.536 +then you must either (1) cause the Corresponding Source to be so
  23.537 +available, or (2) arrange to deprive yourself of the benefit of the
  23.538 +patent license for this particular work, or (3) arrange, in a manner
  23.539 +consistent with the requirements of this License, to extend the patent
  23.540 +license to downstream recipients.  ``Knowingly relying'' means you have
  23.541 +actual knowledge that, but for the patent license, your conveying the
  23.542 +covered work in a country, or your recipient's use of the covered work
  23.543 +in a country, would infringe one or more identifiable patents in that
  23.544 +country that you have reason to believe are valid.
  23.545 +
  23.546 +  If, pursuant to or in connection with a single transaction or
  23.547 +arrangement, you convey, or propagate by procuring conveyance of, a
  23.548 +covered work, and grant a patent license to some of the parties
  23.549 +receiving the covered work authorizing them to use, propagate, modify
  23.550 +or convey a specific copy of the covered work, then the patent license
  23.551 +you grant is automatically extended to all recipients of the covered
  23.552 +work and works based on it.
  23.553 +
  23.554 +  A patent license is ``discriminatory'' if it does not include within
  23.555 +the scope of its coverage, prohibits the exercise of, or is
  23.556 +conditioned on the non-exercise of one or more of the rights that are
  23.557 +specifically granted under this License.  You may not convey a covered
  23.558 +work if you are a party to an arrangement with a third party that is
  23.559 +in the business of distributing software, under which you make payment
  23.560 +to the third party based on the extent of your activity of conveying
  23.561 +the work, and under which the third party grants, to any of the
  23.562 +parties who would receive the covered work from you, a discriminatory
  23.563 +patent license (a) in connection with copies of the covered work
  23.564 +conveyed by you (or copies made from those copies), or (b) primarily
  23.565 +for and in connection with specific products or compilations that
  23.566 +contain the covered work, unless you entered into that arrangement,
  23.567 +or that patent license was granted, prior to 28 March 2007.
  23.568 +
  23.569 +  Nothing in this License shall be construed as excluding or limiting
  23.570 +any implied license or other defenses to infringement that may
  23.571 +otherwise be available to you under applicable patent law.
  23.572 +
  23.573 +\subsubsection*{12. No Surrender of Others' Freedom.}
  23.574 +
  23.575 +\noindent\indent
  23.576 +  If conditions are imposed on you (whether by court order, agreement or
  23.577 +otherwise) that contradict the conditions of this License, they do not
  23.578 +excuse you from the conditions of this License.  If you cannot convey a
  23.579 +covered work so as to satisfy simultaneously your obligations under this
  23.580 +License and any other pertinent obligations, then as a consequence you
  23.581 +may not convey it at all.  For example, if you agree to terms that
  23.582 +obligate you to collect a royalty for further conveying from those to
  23.583 +whom you convey the Program, the only way you could satisfy both those
  23.584 +terms and this License would be to refrain entirely from conveying the
  23.585 +Program.
  23.586 +
  23.587 +\subsubsection*{13. Use with the GNU Affero General Public License.}
  23.588 +
  23.589 +\noindent\indent
  23.590 +  Notwithstanding any other provision of this License, you have
  23.591 +permission to link or combine any covered work with a work licensed
  23.592 +under version 3 of the GNU Affero General Public License into a single
  23.593 +combined work, and to convey the resulting work.  The terms of this
  23.594 +License will continue to apply to the part which is the covered work,
  23.595 +but the special requirements of the GNU Affero General Public License,
  23.596 +section 13, concerning interaction through a network will apply to the
  23.597 +combination as such.
  23.598 +
  23.599 +\subsubsection*{14. Revised Versions of this License.}
  23.600 +
  23.601 +\noindent\indent
  23.602 +  The Free Software Foundation may publish revised and/or new versions
  23.603 +of the GNU General Public License from time to time.  Such new versions
  23.604 +will be similar in spirit to the present version, but may differ in
  23.605 +detail to address new problems or concerns.
  23.606 +
  23.607 +  Each version is given a distinguishing version number.  If the
  23.608 +Program specifies that a certain numbered version of the GNU General
  23.609 +Public License ``or any later version'' applies to it, you have the
  23.610 +option of following the terms and conditions either of that numbered
  23.611 +version or of any later version published by the Free Software
  23.612 +Foundation.  If the Program does not specify a version number of the
  23.613 +GNU General Public License, you may choose any version ever published
  23.614 +by the Free Software Foundation.
  23.615 +
  23.616 +  If the Program specifies that a proxy can decide which future
  23.617 +versions of the GNU General Public License can be used, that proxy's
  23.618 +public statement of acceptance of a version permanently authorizes you
  23.619 +to choose that version for the Program.
  23.620 +
  23.621 +  Later license versions may give you additional or different
  23.622 +permissions.  However, no additional obligations are imposed on any
  23.623 +author or copyright holder as a result of your choosing to follow a
  23.624 +later version.
  23.625 +
  23.626 +\subsubsection*{15. Disclaimer of Warranty.}
  23.627 +
  23.628 +\noindent\indent
  23.629 +  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
  23.630 +APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
  23.631 +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM ``AS IS'' WITHOUT
  23.632 +WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT
  23.633 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  23.634 +PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
  23.635 +OF THE PROGRAM IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU
  23.636 +ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
  23.637 +
  23.638 +\subsubsection*{16. Limitation of Liability.}
  23.639 +
  23.640 +\noindent\indent
  23.641 +  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
  23.642 +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR
  23.643 +CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
  23.644 +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
  23.645 +ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT
  23.646 +NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES
  23.647 +SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE
  23.648 +WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN
  23.649 +ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
  23.650 +
  23.651 +\subsubsection*{17. Interpretation of Sections 15 and 16.}
  23.652 +
  23.653 +\noindent\indent
  23.654 +  If the disclaimer of warranty and limitation of liability provided
  23.655 +above cannot be given local legal effect according to their terms,
  23.656 +reviewing courts shall apply local law that most closely approximates
  23.657 +an absolute waiver of all civil liability in connection with the
  23.658 +Program, unless a warranty or assumption of liability accompanies a
  23.659 +copy of the Program in return for a fee.
  23.660 +
  23.661 +\section*{END OF TERMS AND CONDITIONS}
  23.662 +
  23.663 +\newpage
  23.664 +
  23.665 +\section*{How to Apply These Terms to Your New Programs}
  23.666 +
  23.667 +\noindent\indent
  23.668 +  If you develop a new program, and you want it to be of the greatest
  23.669 +possible use to the public, the best way to achieve this is to make it
  23.670 +free software which everyone can redistribute and change under these
  23.671 +terms.
  23.672 +
  23.673 +  To do so, attach the following notices to the program.  It is safest
  23.674 +to attach them to the start of each source file to most effectively
  23.675 +state the exclusion of warranty; and each file should have at least
  23.676 +the ``copyright'' line and a pointer to where the full notice is found.
  23.677 +
  23.678 +\begin{verbatim}
  23.679 +<one line to give the program's name and a brief idea of what it does.>
  23.680 +Copyright (C) <year>  <name of author>
  23.681 +
  23.682 +This program is free software: you can redistribute it and/or modify
  23.683 +it under the terms of the GNU General Public License as published by
  23.684 +the Free Software Foundation, either version 3 of the License, or
  23.685 +(at your option) any later version.
  23.686 +
  23.687 +This program is distributed in the hope that it will be useful,
  23.688 +but WITHOUT ANY WARRANTY; without even the implied warranty of
  23.689 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23.690 +GNU General Public License for more details.
  23.691 +
  23.692 +You should have received a copy of the GNU General Public License
  23.693 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
  23.694 +\end{verbatim}
  23.695 +
  23.696 +\noindent
  23.697 +Also add information on how to contact you by electronic and paper mail.
  23.698 +
  23.699 +  If the program does terminal interaction, make it output a short
  23.700 +notice like this when it starts in an interactive mode:
  23.701 +
  23.702 +\begin{verbatim}
  23.703 +<program>  Copyright (C) <year>  <name of author>
  23.704 +This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
  23.705 +This is free software, and you are welcome to redistribute it
  23.706 +under certain conditions; type `show c' for details.
  23.707 +\end{verbatim}
  23.708 +
  23.709 +\noindent
  23.710 +The hypothetical commands `show w' and `show c' should show the
  23.711 +appropriate parts of the General Public License.  Of course, your
  23.712 +program's commands might be different; for a GUI interface, you would
  23.713 +use an ``about box''.
  23.714 +
  23.715 +  You should also get your employer (if you work as a programmer) or
  23.716 +school, if any, to sign a ``copyright disclaimer'' for the program, if
  23.717 +necessary. For more information on this, and how to apply and follow the
  23.718 +GNU GPL, see \verb|<http://www.gnu.org/licenses/>|.
  23.719 +
  23.720 +  The GNU General Public License does not permit incorporating your
  23.721 +program into proprietary programs.  If your program is a subroutine
  23.722 +library, you may consider it more useful to permit linking proprietary
  23.723 +applications with the library.  If this is what you want to do, use the
  23.724 +GNU Lesser General Public License instead of this License.  But first,
  23.725 +please read \verb|<http://www.gnu.org/philosophy/why-not-lgpl.html>|.
  23.726 +
  23.727 +\end{footnotesize}
  23.728 +
  23.729 +%* eof *%
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/doc/glpk_faq.txt	Mon Dec 06 13:09:21 2010 +0100
    24.3 @@ -0,0 +1,435 @@
    24.4 +
    24.5 +GNU Linear Programming Kit FAQ
    24.6 +
    24.7 +  Summary: Frequently Asked Questions about the GNU Linear Programming Kit
    24.8 +
    24.9 +  Author: Dr. Harley Mackenzie <hjm@hardsoftware.com>                     
   24.10 +
   24.11 +  Posting-Frequency: Monthly                                              
   24.12 +
   24.13 +  Language: English                                                       
   24.14 +
   24.15 +  $Date: 2004/01/09 05:57:57 $                                            
   24.16 +
   24.17 +  $Revision: 1.6 $                                                        
   24.18 +
   24.19 +
   24.20 +
   24.21 +Introduction
   24.22 +
   24.23 +  Q. What is GPLK?                                                        
   24.24 +
   24.25 +  A. GLPK stands for the GNU Linear Programming Kit. The GLPK package is  
   24.26 +  a set of routines written in ANSI C and organized in the form of a      
   24.27 +  callable library. This package is intended for solving large-scale      
   24.28 +  linear programming (LP), mixed integer linear programming (MIP), and    
   24.29 +  other related problems.                                                 
   24.30 +
   24.31 +  The GLPK package includes the following main components:                
   24.32 +
   24.33 +    * implementation of the simplex method,                                   
   24.34 +
   24.35 +    * implementation of the primal-dual interior point method,                
   24.36 +
   24.37 +    * implementation of the branch-and-bound method,                          
   24.38 +
   24.39 +    * application program interface (API),                                    
   24.40 +
   24.41 +    * GNU MathProg modeling language (a subset of AMPL),                      
   24.42 +
   24.43 +    * GLPSOL, a stand-alone LP/MIP solver.                                    
   24.44 +
   24.45 +
   24.46 +  Q. Who develops and maintains GLPK?                                     
   24.47 +
   24.48 +  A. GLPK is currently developed and maintained by Andrew Makhorin,       
   24.49 +  Department for Applied Informatics, Moscow Aviation Institute, Moscow,  
   24.50 +  Russia. Andrew's email address is <mao@mai2.rcnet.ru> and his postal    
   24.51 +  address is 125871, Russia, Moscow, Volokolamskoye sh., 4, Moscow        
   24.52 +  Aviation Institute, Andrew O. Makhorin                                  
   24.53 +
   24.54 +
   24.55 +  Q. How is GLPK licensed?                                                
   24.56 +
   24.57 +  A. GLPK is currently licensed under the GNU General Public License      
   24.58 +  (GPL). GLPK is free software; you can redistribute it and/or modify it  
   24.59 +  under the terms of the GNU General Public License as published by the   
   24.60 +  Free Software Foundation; either version 2, or (at your option) any     
   24.61 +  later version.                                                          
   24.62 +
   24.63 +  GLPK is not licensed under the Lesser General Public License (LGPL) as  
   24.64 +  distinct from other free LP codes such as lp_solve. The most            
   24.65 +  significant implication is that code that is linked to the GLPK library 
   24.66 +  must be released under the GPL, whereas with the LGPL, code linked to   
   24.67 +  the library does not have to be released under the same license.        
   24.68 +
   24.69 +
   24.70 +  Q. Where is the GLPK home page?                                         
   24.71 +
   24.72 +  The GLPK home page is part of the GNU web site and can found at         
   24.73 +  <http://www.gnu.org/software/glpk/glpk.html>.                           
   24.74 +
   24.75 +
   24.76 +  Q. How do I download and install GLPK?                                  
   24.77 +
   24.78 +  A. The GLPK source distribution can be found in the subdirectory        
   24.79 +  /gnu/glpk/ on your favorite GNU mirror                                  
   24.80 +  <http://www.gnu.org/prep/ftp.html> and can be compiled directly from    
   24.81 +  the source.                                                             
   24.82 +
   24.83 +  The GLPK package (like all other GNU software) is distributed in the    
   24.84 +  form of packed archive. This is one file named 'glpk-x.y.tar.gz', where 
   24.85 +  x is the major version number and y is the minor version number.        
   24.86 +
   24.87 +  In order to prepare the distribution for installation you should:       
   24.88 +
   24.89 +    1. Copy the GLPK distribution file to some subdirectory.                   
   24.90 +
   24.91 +    2. Enter the command 'gzip -d glpk-x.y.tar.gz' in order to unpack the      
   24.92 +       distribution file. After unpacking the name of the distribution file    
   24.93 +       will be automatically changed to 'glpk-x.y.tar'.                        
   24.94 +
   24.95 +    3. Enter the command 'tar -x < glpk-x.y.tar' in order to unarchive the     
   24.96 +       distribution. After this operation the subdirectory 'glpk-x.y' which is 
   24.97 +       the GLPK distribution will have been automatically created.             
   24.98 +
   24.99 +  After you have unpacked and unarchived GLPK distribution you should     
  24.100 +  configure the package, and compiled the application. The result of      
  24.101 +  compilation is:                                                         
  24.102 +
  24.103 +    * the file 'libglpk.a', which is a library archive containing object code 
  24.104 +      for all GLPK routines; and                                              
  24.105 +
  24.106 +    * the program 'glpsol', which is a stand-alone LP/MIP solver.             
  24.107 +
  24.108 +  Complete compilation and installation instructions are included in the  
  24.109 +  INSTALL file included with the distribution.                            
  24.110 +
  24.111 +  The distribution includes make files for the Microsoft Visual C/C++     
  24.112 +  version 6 and Borland C/C++ version 5 and by default compiles and links 
  24.113 +  a glpk*.lib library file, a glpk*.dll DLL file and an glpsol.exe        
  24.114 +  application file. A GNU Windows 4.1 binary, source and documentation    
  24.115 +  compiled using the mingw32 C/C++ compiler is also available from        
  24.116 +  <http://gnuwin32.sourceforge.net/packages/glpk.htm>.                    
  24.117 +
  24.118 +
  24.119 +  Q. Is there a GLPK mailing list or newsgroup?                           
  24.120 +
  24.121 +  A. GLPK has two mailing lists: <help-glpk@gnu.org> and                  
  24.122 +  <bug-glpk@gnu.org>.                                                     
  24.123 +
  24.124 +  The main discussion list is <help-glpk@gnu.org>, and is used to discuss 
  24.125 +  all aspects of GLPK, including its development and porting. There is    
  24.126 +  also a special list used for reporting bugs at <bug-glpk@gnu.org>.      
  24.127 +
  24.128 +  To subscribe to any GLPK mailing list, send an empty mail with a        
  24.129 +  Subject: header line of just "subscribe" to the relevant -request list. 
  24.130 +  For example, to subscribe yourself to the main list, you would send     
  24.131 +  mail to <help-glpk-request@gnu.org> with no body and a Subject: header  
  24.132 +  line of just "subscribe".                                               
  24.133 +
  24.134 +  Another way to subscribe to the GLP mailing lists is to visit the web   
  24.135 +  pages <http://mail.gnu.org/mailman/listinfo/help-glpk> and              
  24.136 +  <http://mail.gnu.org/mailman/listinfo/bug-glpk>.                        
  24.137 +
  24.138 +  Currently there are no newsgroups dedicated to GLPK.                    
  24.139 +
  24.140 +
  24.141 +  Q. Who maintains this FAQ and how do I contribute to this FAQ?          
  24.142 +
  24.143 +  A. The present maintainer of this FAQ is Dr. Harley Mackenzie, HARD     
  24.144 +  software, although the content of the FAQ is derived from many sources  
  24.145 +  such as GLPK documentation, GLPK email archives and original content.   
  24.146 +
  24.147 +  Harley's email address is <hjm@hardsoftware.com> and his postal address 
  24.148 +  is c/o HARD software, PO Box 8004, Newtown, Victoria 3220, Australia.   
  24.149 +
  24.150 +  All contributions to this FAQ, such as questions and (preferably)       
  24.151 +  answers should be sent to the <hjm@hardsoftware.com> email address.     
  24.152 +  This FAQ is copyright Harley Mackenzie 2003 and is released under the   
  24.153 +  same license, terms and conditions as GLPK, that is, GPL version 2 or   
  24.154 +  later.                                                                  
  24.155 +
  24.156 +  Contributions are not directly referenced in the body of the FAQ as     
  24.157 +  this would become unmanageable and messy, but rather as a list of       
  24.158 +  contributors to this FAQ. If you are the author of any information      
  24.159 +  included in this FAQ and you do not want your content to be included,   
  24.160 +  please contact the FAQ maintainer and your material will be removed.    
  24.161 +  Also if you have not been correctly included as a contributor to this   
  24.162 +  FAQ, your details have changed, or you do not want your name listed in  
  24.163 +  the list of contributors, please contact the FAQ maintainer for         
  24.164 +  correction.                                                             
  24.165 +
  24.166 +
  24.167 +  Q. Where can I download this FAQ?                                       
  24.168 +
  24.169 +  The latest version of the GLPK FAQ is available to download from        
  24.170 +  <http://www.hardsoftware.com/downloads.php#GLPK+FAQ> in the following   
  24.171 +  formats:                                                                
  24.172 +
  24.173 +    * DocBook                                                                 
  24.174 +
  24.175 +    * Formatted text                                                          
  24.176 +
  24.177 +    * Adobe PDF                                                               
  24.178 +
  24.179 +
  24.180 +  Q. Who are the FAQ contributors?                                        
  24.181 +
  24.182 +  A. The FAQ contents were created from the following sources:            
  24.183 +
  24.184 +    * Michael Hennebry                                                        
  24.185 +
  24.186 +    * http://www-unix.mcs.anl.gov/otc/Guide/faq/linear-programming-faq.html   
  24.187 +
  24.188 +    * Harley Mackenzie, HARD software Pty. Ltd.                               
  24.189 +
  24.190 +    * Andrew Makhorin, Department for Applied Informatics, Moscow Aviation    
  24.191 +      Institute                                                               
  24.192 +
  24.193 +
  24.194 +GLPK functions & features
  24.195 +
  24.196 +  Q. What is the current state of GLPK development?                       
  24.197 +
  24.198 +  A. GLPK is a work in progress and is presently under continual          
  24.199 +  development. As of the current version 4.3, GLPK is a simplex-based     
  24.200 +  solver is able to handle problems with up to 100,000 constraints. In    
  24.201 +  particular, it successfully solves all instances from netlib (see the   
  24.202 +  file bench.txt included in the GLPK distribution). The interior-point   
  24.203 +  solver is not very robust as it is unable to handle dense columns,      
  24.204 +  sometimes terminates due to numeric instability or slow convergence.    
  24.205 +
  24.206 +  The Mixed Integer Programming (MIP) solver currently is based on        
  24.207 +  branch-and-bound, so it is unable to solve hard or very large problems  
  24.208 +  with a probable practical limit of 100-200 integer variables. However,  
  24.209 +  sometimes it is able to solve larger problems of up to 1000 integer     
  24.210 +  variables, although the size that depends on properties of particular   
  24.211 +  problem.                                                                
  24.212 +
  24.213 +
  24.214 +  Q. How does GLPK compare with other LP codes?                           
  24.215 +
  24.216 +  A. I think that on very large-scale instances CPLEX 8.0 dual simplex is 
  24.217 +  10-100 times faster than the GLPK simplex solver and, of course, much   
  24.218 +  more robust. In many cases GLPK is faster and more robust than lp_solve 
  24.219 +  4.0 for pure LPs as well as MIP's. See the bench.txt file in the GLPK   
  24.220 +  distribution doc directory for GLPK netlib benchmark results.           
  24.221 +
  24.222 +  You can find benchmarks for some LP and MIP solvers such as CPLEX,      
  24.223 +  GLPK, lp_solve, and OSL on Hans Mittelmann's webpage at                 
  24.224 +  <http://plato.asu.edu/bench.html>.                                      
  24.225 +
  24.226 +
  24.227 +  Q. What are the differences between AMPL and GNU MathProg?              
  24.228 +
  24.229 +  A. The subset of AMPL implemented in MathProg approximately corresponds 
  24.230 +  to AMPL status in 1990, because it is mainly based on the paper Robert  
  24.231 +  Fourer, David M Gay and Brian W Kernighan (1990), "A Modeling Language  
  24.232 +  for Mathematical Programming", Management Science, Vol 36, pp. 519-554  
  24.233 +  and is available at                                                     
  24.234 +  <http://users.iems.nwu.edu/~4er/WRITINGS/amplmod.pdf>.                  
  24.235 +
  24.236 +  The GNU MathProg translator was developed as part of GLPK. However, GNU 
  24.237 +  MathProg can be easily used in other applications as there is a set of  
  24.238 +  MathProg interface routines designed for use in other applications.     
  24.239 +
  24.240 +
  24.241 +  Q. What input file formats does GLPK support?                           
  24.242 +
  24.243 +  A. GLPK presently can read input and output LP model files in three     
  24.244 +  supported formats:                                                      
  24.245 +
  24.246 +    * MPS format - which is a column oriented and widely supported file       
  24.247 +      format but has poor human readability.                                  
  24.248 +
  24.249 +    * CPLEX format - which is an easily readable row oriented format.         
  24.250 +
  24.251 +    * GNU MathProg - which is an AMPL like mathematical modeling language.    
  24.252 +
  24.253 +
  24.254 +  Q. What interfaces are available for GLPK?                              
  24.255 +
  24.256 +  A. The GLPK package is in fact a C API that can be either by statically 
  24.257 +  or dynamically linked directly with many programming systems.           
  24.258 +
  24.259 +  Presently there are three contributed external interfaces included with 
  24.260 +  the GLPK package:                                                       
  24.261 +
  24.262 +    * GLPK Java Native Interface (JNI)                                        
  24.263 +
  24.264 +    * GLPK Delphi Interface (DELI)                                            
  24.265 +
  24.266 +    * GLPKMEX Matlab MEX interface                                            
  24.267 +
  24.268 +  There is an unofficial Microsoft Visual Basic, Tcl/Tk and Java GLPK     
  24.269 +  interface available at                                                  
  24.270 +  <http://gottfried.lindner.bei.t-online.de/glpk.htm>.                    
  24.271 +
  24.272 +  There are other language interfaces under development, including a Perl 
  24.273 +  interface currently being developed by the FAQ maintainer, Dr. Harley   
  24.274 +  Mackenzie <hjm@hardsoftware.com>.                                       
  24.275 +
  24.276 +
  24.277 +  Q. Where can I find some examples?                                      
  24.278 +
  24.279 +  A. The GLPK package distribution contains many examples written in GNU  
  24.280 +  MathProg (*.mod), C API calls (*.c), CPLEX input file format (*.lpt),   
  24.281 +  MPS format (*.mps) as well as some specific Traveling Salesman examples 
  24.282 +  (*.tsp).                                                                
  24.283 +
  24.284 +  All of the examples can be found in the GLPK distribution examples      
  24.285 +  sub-directory.                                                          
  24.286 +
  24.287 +
  24.288 +  Q. What are the future plans for GLPK?                                  
  24.289 +
  24.290 +  A. Developments planned for GLPK include improving the existing key     
  24.291 +  GLPK components, such as developing a more robust and more efficient    
  24.292 +  implementation of the simplex-based and interior-point solvers. Future  
  24.293 +  GLPK enhancements planned are implementing a branch-and-cut solver, a   
  24.294 +  MIP pre-processor, post-optimal and sensitivity analysis and possibly   
  24.295 +  network simplex and quadratic programming solvers.                      
  24.296 +
  24.297 +
  24.298 +  Q. How do I report a GLPK bug?                                          
  24.299 +
  24.300 +  A. If you think you have found a bug in GLPK, then you should send as   
  24.301 +  complete a report as possible to <bug-glpk@gnu.org>.                    
  24.302 +
  24.303 +
  24.304 +  Q. How do I contribute to the GLPK development?                         
  24.305 +
  24.306 +  A. At present new GLPK development patches should be emailed to Andrew  
  24.307 +  Makhorin <mao@mai2.rcnet.ru >, with sufficient documentation and test   
  24.308 +  code to explain the nature of the patch, how to install it and the      
  24.309 +  implications of its use. Before commencing any major GLPK development   
  24.310 +  for inclusion in the GLPK distribution, it would be a good idea to      
  24.311 +  discuss the idea on the GLPK mailing list.                              
  24.312 +
  24.313 +
  24.314 +  Q. How do I compile and link a GLPK application on a UNIX platform?     
  24.315 +
  24.316 +  A. To compile a GLPK application on a UNIX platform, then compiler must 
  24.317 +  be able to include the GLPK include files and link to the GLPK library. 
  24.318 +  For example, on a system where the GLPK system is installed:            
  24.319 +
  24.320 +  gcc mylp.c -o mylp -lglpk                                               
  24.321 +
  24.322 +  or specify the include files and libglpk.a explicitly, if GLPK is not   
  24.323 +  installed.                                                              
  24.324 +
  24.325 +
  24.326 +  Q. How do I compile and link a GLPK application on a Win32 platform?    
  24.327 +
  24.328 +  A. On a Win32 platform, GLPK is implemented either as a Win32 Dynamic   
  24.329 +  Link Library (DLL) or can be statically linked to the glpk*.lib file.   
  24.330 +  As with the UNIX instructions, a GLPK application must set a path to    
  24.331 +  the GLPK include files and also reference the GLPK library if           
  24.332 +  statically linked.                                                      
  24.333 +
  24.334 +
  24.335 +  Q. How do I limit the GLPK execution time?                              
  24.336 +
  24.337 +  A. You can limit the computing time by setting the control parameter    
  24.338 +  LPX_K_TMLIM via the API routine lpx_set_real_parm . At present there is 
  24.339 +  no way of limiting the execution time of glpsol without changing the    
  24.340 +  source and recompiling a specific version.                              
  24.341 +
  24.342 +
  24.343 +GLPK Linear Programming
  24.344 +
  24.345 +  Q. What is Linear Programming and how does it work?                     
  24.346 +
  24.347 +  A. Linear Programming is a mathematical technique that is a generic     
  24.348 +  method for solving certain systems of equations with linear terms. The  
  24.349 +  real power of LP's are that they have many practical applications and   
  24.350 +  have proven to be a powerful and robust tool.                           
  24.351 +
  24.352 +  The best single source of information on LP's is the Linear Programming 
  24.353 +  FAQ                                                                     
  24.354 +  <http://www-unix.mcs.anl.gov/otc/Guide/faq/linear-programming-faq.html> 
  24.355 +  that has information on LP's and MIP's, includes a comprehensive list   
  24.356 +  of available LP software and has many LP references for further study.  
  24.357 +
  24.358 +
  24.359 +  Q. How do I determine the stability of an LP solution?                  
  24.360 +
  24.361 +  A. You can perform sensitivity analysis by specifying the --bounds      
  24.362 +  option for glpsol as:                                                   
  24.363 +
  24.364 +  glpsol ... --bounds filename                                            
  24.365 +
  24.366 +  in which case the solver writes results of the analysis to the          
  24.367 +  specified filename in plain text format. The corresponding API routine  
  24.368 +  is lpx_print_sens_bnds() .                                              
  24.369 +
  24.370 +
  24.371 +  Q. How do I determine which constraints are causing infeasibility?      
  24.372 +
  24.373 +  A straightforward way to find such a set of constraints is to drop      
  24.374 +  constraints one at a time. If dropping a constraint results in a        
  24.375 +  solvable problem, pick it up and go on to the next constraint. After    
  24.376 +  applying phase 1 to an infeasible problem, all basic satisfied          
  24.377 +  constraints may be dropped.                                             
  24.378 +
  24.379 +  If the problem has a feasible dual, then running the dual simplex       
  24.380 +  method is a more direct approach. After the last pivot, the nonbasic    
  24.381 +  constraints and one of the violated constraints will constitute a       
  24.382 +  minimal set. The GLPK simplex table routines will allow you to pick a   
  24.383 +  correct constraint from the violated ones.                              
  24.384 +
  24.385 +  Note that the GLPK pre-solver needs to be turned off for the preceding  
  24.386 +  technique to work, otherwise GLPK does not keep the basis of an         
  24.387 +  infeasible solution.                                                    
  24.388 +
  24.389 +  Also a more detailed methodology has been posted on the mail list       
  24.390 +  archive at                                                              
  24.391 +  <http://mail.gnu.org/archive/html/help-glpk/2003-09/msg00017.html>.     
  24.392 +
  24.393 +
  24.394 +  Q. What is the difference between checks and constraints?               
  24.395 +
  24.396 +  A. Check statements are intended to check that all data specified by    
  24.397 +  the user of the model are correct, mainly in the data section of a      
  24.398 +  MathProg model. For example, if some parameter means the number of      
  24.399 +  nodes in a network, it must be positive integer, that is just the       
  24.400 +  condition to be checked in the check statement (although in this case   
  24.401 +  such condition may be also checked directly in the parameter            
  24.402 +  statement). Note that check statements are performed when the           
  24.403 +  translator is generating the model, so they cannot include variables.   
  24.404 +
  24.405 +  Constraints are conditions that are expressed in terms of variables and 
  24.406 +  resolved by the solver after the model has been completely generated.   
  24.407 +  If all data specified in the model are correct a priori, check          
  24.408 +  statements are not needed and can be omitted, while constraints are     
  24.409 +  essential components of the model and therefore cannot be omitted.      
  24.410 +
  24.411 +
  24.412 +GLPK Integer Programming 
  24.413 +
  24.414 +  Q. What is Integer Programming and how does it work?                    
  24.415 +
  24.416 +  A. Integer LP models are ones whose variables are constrained to take   
  24.417 +  integer or whole number (as opposed to fractional) values. It may not   
  24.418 +  be obvious that integer programming is a very much harder problem than  
  24.419 +  ordinary linear programming, but that is nonetheless the case, in both  
  24.420 +  theory and practice.                                                    
  24.421 +
  24.422 +
  24.423 +  Q. What is the Integer Optimization Suite (IOS)?                        
  24.424 +
  24.425 +  A. IOS is a framework to implement implicit enumeration methods based   
  24.426 +  on LP relaxation (like branch-and-bound and branch-and-cut). Currently  
  24.427 +  IOS includes only basic features (the enumeration tree, API routines,   
  24.428 +  and the driver) and is not completely documented.                       
  24.429 +
  24.430 +
  24.431 +  Q. I have just changed an LP to a MIP and now it doesn't work?          
  24.432 +
  24.433 +  A. If you have an existing LP that is working and you change to an MIP  
  24.434 +  and receive a "lpx_integer: optimal solution of LP relaxation required" 
  24.435 +  204 (==LPX_E_FAULT) error, you probably have not called the LP solution 
  24.436 +  method lpx_simplex() before lpx_integer() . The MIP routines use the LP 
  24.437 +  solution as part of the MIP solution methodology.                       
  24.438 +
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/doc/gmpl.tex	Mon Dec 06 13:09:21 2010 +0100
    25.3 @@ -0,0 +1,4653 @@
    25.4 +%* gmpl.tex *%
    25.5 +
    25.6 +%***********************************************************************
    25.7 +%  This code is part of GLPK (GNU Linear Programming Kit).
    25.8 +%
    25.9 +%  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
   25.10 +%  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
   25.11 +%  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
   25.12 +%  E-mail: <mao@gnu.org>.
   25.13 +%
   25.14 +%  GLPK is free software: you can redistribute it and/or modify it
   25.15 +%  under the terms of the GNU General Public License as published by
   25.16 +%  the Free Software Foundation, either version 3 of the License, or
   25.17 +%  (at your option) any later version.
   25.18 +%
   25.19 +%  GLPK is distributed in the hope that it will be useful, but WITHOUT
   25.20 +%  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   25.21 +%  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
   25.22 +%  License for more details.
   25.23 +%
   25.24 +%  You should have received a copy of the GNU General Public License
   25.25 +%  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
   25.26 +%***********************************************************************
   25.27 +
   25.28 +\documentclass[10pt]{article}
   25.29 +\usepackage[dvipdfm,linktocpage,colorlinks,linkcolor=blue]{hyperref}
   25.30 +
   25.31 +\begin{document}
   25.32 +
   25.33 +\thispagestyle{empty}
   25.34 +
   25.35 +\begin{center}
   25.36 +
   25.37 +\vspace*{1in}
   25.38 +
   25.39 +\begin{huge}
   25.40 +\sf\bfseries Modeling Language GNU MathProg
   25.41 +\end{huge}
   25.42 +
   25.43 +\vspace{0.5in}
   25.44 +
   25.45 +\begin{LARGE}
   25.46 +\sf Language Reference
   25.47 +\end{LARGE}
   25.48 +
   25.49 +\vspace{0.5in}
   25.50 +
   25.51 +\begin{LARGE}
   25.52 +\sf for GLPK Version 4.45
   25.53 +\end{LARGE}
   25.54 +
   25.55 +\vspace{0.5in}
   25.56 +\begin{Large}
   25.57 +\sf (DRAFT, December 2010)
   25.58 +\end{Large}
   25.59 +
   25.60 +\end{center}
   25.61 +
   25.62 +\newpage
   25.63 +
   25.64 +\vspace*{1in}
   25.65 +
   25.66 +\vfill
   25.67 +
   25.68 +\noindent
   25.69 +The GLPK package is part of the GNU Project released under the aegis of
   25.70 +GNU.
   25.71 +
   25.72 +\medskip\noindent
   25.73 +Copyright \copyright{} 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
   25.74 +2008, 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
   25.75 +Moscow Aviation Institute, Moscow, Russia. All rights reserved.
   25.76 +
   25.77 +\medskip\noindent
   25.78 +Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
   25.79 +MA 02110-1301, USA.
   25.80 +
   25.81 +\medskip\noindent
   25.82 +Permission is granted to make and distribute verbatim copies of this
   25.83 +manual provided the copyright notice and this permission notice are
   25.84 +preserved on all copies.
   25.85 +
   25.86 +\medskip\noindent
   25.87 +Permission is granted to copy and distribute modified versions of this
   25.88 +manual under the conditions for verbatim copying, provided also that
   25.89 +the entire resulting derived work is distributed under the terms of
   25.90 +a permission notice identical to this one.
   25.91 +
   25.92 +\medskip\noindent
   25.93 +Permission is granted to copy and distribute translations of this
   25.94 +manual into another language, under the above conditions for modified
   25.95 +versions.
   25.96 +
   25.97 +\newpage
   25.98 +
   25.99 +\tableofcontents
  25.100 +
  25.101 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  25.102 +
  25.103 +\newpage
  25.104 +
  25.105 +\section{Introduction}
  25.106 +
  25.107 +{\it GNU MathProg} is a modeling language intended for describing
  25.108 +linear mathematical programming models.\footnote{The GNU MathProg
  25.109 +language is a subset of the AMPL language. Its GLPK implementation is
  25.110 +mainly based on the paper: {\it Robert Fourer}, {\it David M. Gay}, and
  25.111 +{\it Brian W. Kernighan}, ``A Modeling Language for Mathematical
  25.112 +Programming.'' {\it Management Science} 36 (1990)\linebreak pp. 519-54.}
  25.113 +
  25.114 +Model descriptions written in the GNU MathProg language consist of
  25.115 +a set of statements and data blocks constructed by the user from the
  25.116 +language elements described in this document.
  25.117 +
  25.118 +In a process called {\it translation}, a program called the {\it model
  25.119 +translator} analyzes the model description and translates it into
  25.120 +internal data structures, which may be then used either for generating
  25.121 +mathematical programming problem instance or directly by a program
  25.122 +called the {\it solver} to obtain numeric solution of the problem.
  25.123 +
  25.124 +\subsection{Linear programming problem}
  25.125 +\label{problem}
  25.126 +
  25.127 +In MathProg the linear programming (LP) problem is stated as follows:
  25.128 +
  25.129 +\medskip
  25.130 +
  25.131 +\noindent\hspace{.7in}minimize (or maximize)
  25.132 +$$z=c_1x_1+c_2x_2+\dots+c_nx_n+c_0\eqno(1.1)$$
  25.133 +\noindent\hspace{.7in}subject to linear constraints
  25.134 +$$
  25.135 +\begin{array}{l@{\ }c@{\ }r@{\ }c@{\ }r@{\ }c@{\ }r@{\ }c@{\ }l}
  25.136 +L_1&\leq&a_{11}x_1&+&a_{12}x_2&+\dots+&a_{1n}x_n&\leq&U_1\\
  25.137 +L_2&\leq&a_{21}x_1&+&a_{22}x_2&+\dots+&a_{2n}x_n&\leq&U_2\\
  25.138 +\multicolumn{9}{c}{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .}\\
  25.139 +L_m&\leq&a_{m1}x_1&+&a_{m2}x_2&+\dots+&a_{mn}x_n&\leq&U_m\\
  25.140 +\end{array}\eqno(1.2)
  25.141 +$$
  25.142 +\noindent\hspace{.7in}and bounds of variables
  25.143 +$$
  25.144 +\begin{array}{l@{\ }c@{\ }c@{\ }c@{\ }l}
  25.145 +l_1&\leq&x_1&\leq&u_1\\
  25.146 +l_2&\leq&x_2&\leq&u_2\\
  25.147 +\multicolumn{5}{c}{.\ \ .\ \ .\ \ .\ \ .}\\
  25.148 +l_n&\leq&x_n&\leq&u_n\\
  25.149 +\end{array}\eqno(1.3)
  25.150 +$$
  25.151 +where $x_1$, $x_2$, \dots, $x_n$ are variables; $z$ is the objective
  25.152 +function; $c_1$, $c_2$, \dots, $c_n$ are objective coefficients; $c_0$
  25.153 +is the constant term (``shift'') of the objective function; $a_{11}$,
  25.154 +$a_{12}$, \dots, $a_{mn}$ are constraint coefficients; $L_1$, $L_2$,
  25.155 +\dots, $L_m$ are lower constraint bounds; $U_1$, $U_2$, \dots, $U_m$
  25.156 +are upper constraint bounds; $l_1$, $l_2$, \dots, $l_n$ are lower
  25.157 +bounds of variables; $u_1$, $u_2$, \dots, $u_n$ are upper bounds of
  25.158 +variables.
  25.159 +
  25.160 +Bounds of variables and constraint bounds can be finite as well as
  25.161 +infinite. Besides, lower bounds can be equal to corresponding upper
  25.162 +bounds. Thus, the following types of variables and constraints are
  25.163 +allowed:
  25.164 +
  25.165 +\newpage
  25.166 +
  25.167 +\begin{tabular}{@{}r@{\ }c@{\ }c@{\ }c@{\ }l@{\hspace*{38pt}}l}
  25.168 +$-\infty$&$<$&$x$&$<$&$+\infty$&Free (unbounded) variable\\
  25.169 +$l$&$\leq$&$x$&$<$&$+\infty$&Variable with lower bound\\
  25.170 +$-\infty$&$<$&$x$&$\leq$&$u$&Variable with upper bound\\
  25.171 +$l$&$\leq$&$x$&$\leq$&$u$&Double-bounded variable\\
  25.172 +$l$&$=$&$x$&=&$u$&Fixed variable\\
  25.173 +\end{tabular}
  25.174 +
  25.175 +\bigskip
  25.176 +
  25.177 +\begin{tabular}{@{}r@{\ }c@{\ }c@{\ }c@{\ }ll}
  25.178 +$-\infty$&$<$&$\sum a_jx_j$&$<$&$+\infty$&Free (unbounded) linear
  25.179 +form\\
  25.180 +$L$&$\leq$&$\sum a_jx_j$&$<$&$+\infty$&Inequality constraint ``greater
  25.181 +than or equal to''\\
  25.182 +$-\infty$&$<$&$\sum a_jx_j$&$\leq$&$U$&Inequality constraint ``less
  25.183 +than or equal to''\\
  25.184 +$L$&$\leq$&$\sum a_jx_j$&$\leq$&$U$&Double-bounded inequality
  25.185 +constraint\\
  25.186 +$L$&$=$&$\sum a_jx_j$&=&$U$&Equality constraint\\
  25.187 +\end{tabular}
  25.188 +
  25.189 +\bigskip
  25.190 +
  25.191 +In addition to pure LP problems MathProg also allows mixed integer
  25.192 +linear programming (MIP) problems, where some or all variables are
  25.193 +restricted to be integer or binary.
  25.194 +
  25.195 +\subsection{Model objects}
  25.196 +
  25.197 +In MathProg the model is described in terms of sets, parameters,
  25.198 +variables, constraints, and objectives, which are called {\it model
  25.199 +objects}.
  25.200 +
  25.201 +The user introduces particular model objects using the language
  25.202 +statements. Each model object is provided with a symbolic name that
  25.203 +uniquely identifies the object and is intended for referencing purposes.
  25.204 +
  25.205 +Model objects, including sets, can be multidimensional arrays built
  25.206 +over indexing sets. Formally, $n$-dimensional array $A$ is the mapping:
  25.207 +$$A:\Delta\rightarrow\Xi,\eqno(1.4)$$
  25.208 +where $\Delta\subseteq S_1\times\dots\times S_n$ is a subset of the
  25.209 +Cartesian product of indexing sets,\linebreak $\Xi$ is a set of array members.
  25.210 +In MathProg the set $\Delta$ is called the {\it subscript domain}. Its
  25.211 +members are $n$-tuples $(i_1,\dots,i_n)$, where $i_1\in S_1$, \dots,
  25.212 +$i_n\in S_n$.
  25.213 +
  25.214 +If $n=0$, the Cartesian product above has exactly one member (namely,
  25.215 +\linebreak 0-tuple), so it is convenient to think scalar objects as
  25.216 +0-dimensional arrays having one member.
  25.217 +
  25.218 +The type of array members is determined by the type of corresponding
  25.219 +model object as follows:
  25.220 +
  25.221 +\medskip
  25.222 +
  25.223 +\noindent\hfil
  25.224 +\begin{tabular}{@{}ll@{}}
  25.225 +Model object&Array member\\
  25.226 +\hline
  25.227 +Set&Elemental plain set\\
  25.228 +Parameter&Number or symbol\\
  25.229 +Variable&Elemental variable\\
  25.230 +Constraint&Elemental constraint\\
  25.231 +Objective&Elemental objective\\
  25.232 +\end{tabular}
  25.233 +
  25.234 +\medskip
  25.235 +
  25.236 +In order to refer to a particular object member the object should be
  25.237 +provided with {\it subscripts}. For example, if $a$ is a 2-dimensional
  25.238 +parameter defined over $I\times J$, a reference to its particular
  25.239 +member can be written as $a[i,j]$, where $i\in I$ and $j\in J$. It is
  25.240 +understood that scalar objects being 0-dimensional need no subscripts.
  25.241 +
  25.242 +\subsection{Structure of model description}
  25.243 +
  25.244 +It is sometimes desirable to write a model which, at various points,
  25.245 +may require different data for each problem instance to be solved using
  25.246 +that model. For this reason in MathProg the model description consists
  25.247 +of two parts: the {\it model section} and the {\it data section}.
  25.248 +
  25.249 +The model section is a main part of the model description that contains
  25.250 +declarations of model objects and is common for all problems based on
  25.251 +the corresponding model.
  25.252 +
  25.253 +The data section is an optional part of the model description that
  25.254 +contains data specific for a particular problem instance.
  25.255 +
  25.256 +Depending on what is more convenient the model and data sections can be
  25.257 +placed either in one file or in two separate files. The latter feature
  25.258 +allows having arbitrary number of different data sections to be used
  25.259 +with the same model section.
  25.260 +
  25.261 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  25.262 +
  25.263 +\newpage
  25.264 +
  25.265 +\section{Coding model description}
  25.266 +\label{coding}
  25.267 +
  25.268 +The model description is coded in plain text format using ASCII
  25.269 +character set. Characters valid in the model description are the
  25.270 +following:
  25.271 +
  25.272 +\begin{itemize}
  25.273 +\item alphabetic characters:\\
  25.274 +\verb|A B C D E F G H I J K L M N O P Q R S T U V W X Y Z|\\
  25.275 +\verb|a b c d e f g h i j k l m n o p q r s t u v w x y z _|
  25.276 +\item numeric characters:\\
  25.277 +\verb|0 1 2 3 4 5 6 7 8 9|
  25.278 +\item special characters:\\
  25.279 +\verb?! " # & ' ( ) * + , - . / : ; < = > [ ] ^ { | }?
  25.280 +\item white-space characters:\\
  25.281 +\verb|SP HT CR NL VT FF|
  25.282 +\end{itemize}
  25.283 +
  25.284 +Within string literals and comments any ASCII characters (except
  25.285 +control characters) are valid.
  25.286 +
  25.287 +White-space characters are non-significant. They can be used freely
  25.288 +between lexical units to improve readability of the model description.
  25.289 +They are also used to separate lexical units from each other if there
  25.290 +is no other way to do that.
  25.291 +
  25.292 +Syntactically model description is a sequence of lexical units in the
  25.293 +following categories:
  25.294 +
  25.295 +\begin{itemize}
  25.296 +\item symbolic names;
  25.297 +\item numeric literals;
  25.298 +\item string literals;
  25.299 +\item keywords;
  25.300 +\item delimiters;
  25.301 +\item comments.
  25.302 +\end{itemize}
  25.303 +
  25.304 +The lexical units of the language are discussed below.
  25.305 +
  25.306 +\subsection{Symbolic names}
  25.307 +
  25.308 +A {\it symbolic name} consists of alphabetic and numeric characters,
  25.309 +the first of which must be alphabetic. All symbolic names are distinct
  25.310 +(case sensitive).
  25.311 +
  25.312 +\medskip
  25.313 +
  25.314 +\noindent{\bf Examples}
  25.315 +
  25.316 +\medskip
  25.317 +
  25.318 +\noindent\verb|alpha123|
  25.319 +
  25.320 +\noindent\verb|This_is_a_name|
  25.321 +
  25.322 +\noindent\verb|_P123_abc_321|
  25.323 +
  25.324 +\newpage
  25.325 +
  25.326 +Symbolic names are used to identify model objects (sets, parameters,
  25.327 +variables, constraints, objectives) and dummy indices.
  25.328 +
  25.329 +All symbolic names (except names of dummy indices) must be unique, i.e.
  25.330 +the model description must have no objects with identical names.
  25.331 +Symbolic names of dummy indices must be unique within the scope, where
  25.332 +they are valid.
  25.333 +
  25.334 +\subsection{Numeric literals}
  25.335 +
  25.336 +A {\it numeric literal} has the form {\it xx}{\tt E}{\it syy}, where
  25.337 +{\it xx} is a number with optional decimal point, {\it s} is the sign
  25.338 +{\tt+} or {\tt-}, {\it yy} is a decimal exponent. The letter {\tt E} is
  25.339 +case insensitive and can be coded as {\tt e}.
  25.340 +
  25.341 +\medskip
  25.342 +
  25.343 +\noindent{\bf Examples}
  25.344 +
  25.345 +\medskip
  25.346 +
  25.347 +\noindent\verb|123|
  25.348 +
  25.349 +\noindent\verb|3.14159|
  25.350 +
  25.351 +\noindent\verb|56.E+5|
  25.352 +
  25.353 +\noindent\verb|.78|
  25.354 +
  25.355 +\noindent\verb|123.456e-7|
  25.356 +
  25.357 +\medskip
  25.358 +
  25.359 +Numeric literals are used to represent numeric quantities. They have
  25.360 +obvious fixed meaning.
  25.361 +
  25.362 +\subsection{String literals}
  25.363 +
  25.364 +A {\it string literal} is a sequence of arbitrary characters enclosed
  25.365 +either in single quotes or in double quotes. Both these forms are
  25.366 +equivalent.
  25.367 +
  25.368 +If the single quote is part of a string literal enclosed in single
  25.369 +quotes, it must be coded twice. Analogously, if the double quote is
  25.370 +part of a string literal enclosed in double quotes, it must be coded
  25.371 +twice.
  25.372 +
  25.373 +\medskip
  25.374 +
  25.375 +\noindent{\bf Examples}
  25.376 +
  25.377 +\medskip
  25.378 +
  25.379 +\noindent\verb|'This is a string'|
  25.380 +
  25.381 +\noindent\verb|"This is another string"|
  25.382 +
  25.383 +\noindent\verb|'1 + 2 = 3'|
  25.384 +
  25.385 +\noindent\verb|'That''s all'|
  25.386 +
  25.387 +\noindent\verb|"She said: ""No"""|
  25.388 +
  25.389 +\medskip
  25.390 +
  25.391 +String literals are used to represent symbolic quantities.
  25.392 +
  25.393 +\subsection{Keywords}
  25.394 +
  25.395 +A {\it keyword} is a sequence of alphabetic characters and possibly
  25.396 +some special characters.
  25.397 +
  25.398 +All keywords fall into two categories: {\it reserved keywords}, which
  25.399 +cannot be used as symbolic names, and {\it non-reserved keywords},
  25.400 +which being recognized by context can be used as symbolic names.
  25.401 +
  25.402 +\newpage
  25.403 +
  25.404 +The reserved keywords are the following:
  25.405 +
  25.406 +\medskip
  25.407 +
  25.408 +\noindent\hfil
  25.409 +\begin{tabular}{@{}p{.7in}p{.7in}p{.7in}p{.7in}@{}}
  25.410 +{\tt and}&{\tt else}&{\tt mod}&{\tt union}\\
  25.411 +{\tt by}&{\tt if}&{\tt not}&{\tt within}\\
  25.412 +{\tt cross}&{\tt in}&{\tt or}\\
  25.413 +{\tt diff}&{\tt inter}&{\tt symdiff}\\
  25.414 +{\tt div}&{\tt less}&{\tt then}\\
  25.415 +\end{tabular}
  25.416 +
  25.417 +\medskip
  25.418 +
  25.419 +Non-reserved keywords are described in following sections.
  25.420 +
  25.421 +All the keywords have fixed meaning, which will be explained on
  25.422 +discussion of corresponding syntactic constructions, where the keywords
  25.423 +are used.
  25.424 +
  25.425 +\subsection{Delimiters}
  25.426 +
  25.427 +A {\it delimiter} is either a single special character or a sequence of
  25.428 +two special characters as follows:
  25.429 +
  25.430 +\medskip
  25.431 +
  25.432 +\noindent\hfil
  25.433 +\begin{tabular}{@{}p{.3in}p{.3in}p{.3in}p{.3in}p{.3in}p{.3in}@{}}
  25.434 +{\tt+}&{\tt\textasciicircum}&{\tt==}&{\tt!}&{\tt:}&{\tt)}\\
  25.435 +{\tt-}&{\tt\&}&{\tt>=}&{\tt\&\&}&{\tt;}&{\tt[}\\
  25.436 +{\tt*}&{\tt<}&{\tt>}&{\tt||}&{\tt:=}&{\tt|}\\
  25.437 +{\tt/}&{\tt<=}&{\tt<>}&{\tt.}&{\tt..}&{\tt\{}\\
  25.438 +{\tt**}&{\tt=}&{\tt!=}&{\tt,}&{\tt(}&{\tt\}}\\
  25.439 +\end{tabular}
  25.440 +
  25.441 +\medskip
  25.442 +
  25.443 +If the delimiter consists of two characters, there must be no spaces
  25.444 +between the characters.
  25.445 +
  25.446 +All the delimiters have fixed meaning, which will be explained on
  25.447 +discussion corresponding syntactic constructions, where the delimiters
  25.448 +are used.
  25.449 +
  25.450 +\subsection{Comments}
  25.451 +
  25.452 +For documenting purposes the model description can be provided with
  25.453 +{\it comments}, which may have two different forms. The first form is
  25.454 +a {\it single-line comment}, which begins with the character {\tt\#}
  25.455 +and extends until end of line. The second form is a {\it comment
  25.456 +sequence}, which is a sequence of any characters enclosed within
  25.457 +{\tt/*} and {\tt*/}.
  25.458 +
  25.459 +\medskip
  25.460 +
  25.461 +\noindent{\bf Examples}
  25.462 +
  25.463 +\medskip
  25.464 +
  25.465 +\noindent\verb|param n := 10; # This is a comment|
  25.466 +
  25.467 +\noindent\verb|/* This is another comment */|
  25.468 +
  25.469 +\medskip
  25.470 +
  25.471 +Comments are ignored by the model translator and can appear anywhere in
  25.472 +the model description, where white-space characters are allowed.
  25.473 +
  25.474 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  25.475 +
  25.476 +\newpage
  25.477 +
  25.478 +\section{Expressions}
  25.479 +
  25.480 +An {\it expression} is a rule for computing a value. In model
  25.481 +description expressions are used as constituents of certain statements.
  25.482 +
  25.483 +In general case expressions consist of operands and operators.
  25.484 +
  25.485 +Depending on the type of the resultant value all expressions fall into
  25.486 +the following categories:
  25.487 +
  25.488 +\begin{itemize}
  25.489 +\item numeric expressions;
  25.490 +\item symbolic expressions;
  25.491 +\item indexing expressions;
  25.492 +\item set expressions;
  25.493 +\item logical expressions;
  25.494 +\item linear expressions.
  25.495 +\end{itemize}
  25.496 +
  25.497 +\subsection{Numeric expressions}
  25.498 +
  25.499 +A {\it numeric expression} is a rule for computing a single numeric
  25.500 +value represented as a floating-point number.
  25.501 +
  25.502 +The primary numeric expression may be a numeric literal, dummy index,
  25.503 +unsubscripted parameter, subscripted parameter, built-in function
  25.504 +reference, iterated numeric expression, conditional numeric expression,
  25.505 +or another numeric expression enclosed in parentheses.
  25.506 +
  25.507 +\medskip
  25.508 +
  25.509 +\noindent{\bf Examples}
  25.510 +
  25.511 +\medskip
  25.512 +
  25.513 +\noindent
  25.514 +\begin{tabular}{@{}ll@{}}
  25.515 +\verb|1.23|&(numeric literal)\\
  25.516 +\verb|j|&(dummy index)\\
  25.517 +\verb|time|&(unsubscripted parameter)\\
  25.518 +\verb|a['May 2003',j+1]|&(subscripted parameter)\\
  25.519 +\verb|abs(b[i,j])|&(function reference)\\
  25.520 +\verb|sum{i in S diff T} alpha[i] * b[i,j]|&(iterated expression)\\
  25.521 +\verb|if i in I then 2 * p else q[i+1]|&(conditional expression)\\
  25.522 +\verb|(b[i,j] + .5 * c)|&(parenthesized expression)\\
  25.523 +\end{tabular}
  25.524 +
  25.525 +\medskip
  25.526 +
  25.527 +More general numeric expressions containing two or more primary numeric
  25.528 +expressions may be constructed by using certain arithmetic operators.
  25.529 +
  25.530 +\medskip
  25.531 +
  25.532 +\noindent{\bf Examples}
  25.533 +
  25.534 +\medskip
  25.535 +
  25.536 +\noindent\verb|j+1|
  25.537 +
  25.538 +\noindent\verb|2 * a[i-1,j+1] - b[i,j]|
  25.539 +
  25.540 +\noindent\verb|sum{j in J} a[i,j] * x[j] + sum{k in K} b[i,k] * x[k]|
  25.541 +
  25.542 +\noindent\verb|(if i in I then 2 * p else q[i+1]) / (a[i,j] + 1.5)|
  25.543 +
  25.544 +\subsubsection{Numeric literals}
  25.545 +
  25.546 +If the primary numeric expression is a numeric literal, the resultant
  25.547 +value is obvious.
  25.548 +
  25.549 +\subsubsection{Dummy indices}
  25.550 +
  25.551 +If the primary numeric expression is a dummy index, the resultant value
  25.552 +is current value assigned to that dummy index.
  25.553 +
  25.554 +\subsubsection{Unsubscripted parameters}
  25.555 +
  25.556 +If the primary numeric expression is an unsubscripted parameter (which
  25.557 +must be 0-dimensional), the resultant value is the value of that
  25.558 +parameter.
  25.559 +
  25.560 +\subsubsection{Subscripted parameters}
  25.561 +
  25.562 +The primary numeric expression, which refers to a subscripted parameter,
  25.563 +has the following syntactic form:
  25.564 +
  25.565 +\medskip
  25.566 +
  25.567 +\noindent\hfil
  25.568 +{\it name}{\tt[}$i_1${\tt,} $i_2${\tt,} \dots{\tt,} $i_n${\tt]}
  25.569 +
  25.570 +\medskip
  25.571 +
  25.572 +\noindent where {\it name} is the symbolic name of the parameter,
  25.573 +$i_1$, $i_2$, \dots, $i_n$ are subscripts.
  25.574 +
  25.575 +Each subscript must be a numeric or symbolic expression. The number of
  25.576 +subscripts in the subscript list must be the same as the dimension of
  25.577 +the parameter with which the subscript list is associated.
  25.578 +
  25.579 +Actual values of subscript expressions are used to identify
  25.580 +a particular member of the parameter that determines the resultant
  25.581 +value of the primary expression.
  25.582 +
  25.583 +\subsubsection{Function references}
  25.584 +
  25.585 +In MathProg there exist the following built-in functions which may be
  25.586 +used in numeric expressions:
  25.587 +
  25.588 +\medskip
  25.589 +
  25.590 +\begin{tabular}{@{}p{96pt}p{222pt}@{}}
  25.591 +{\tt abs(}$x${\tt)}&$|x|$, absolute value of $x$\\
  25.592 +{\tt atan(}$x${\tt)}&$\arctan x$, principal value of the arc tangent of
  25.593 +$x$ (in radians)\\
  25.594 +{\tt atan(}$y${\tt,} $x${\tt)}&$\arctan y/x$, principal value of the
  25.595 +arc tangent of $y/x$ (in radians). In this case the signs of both
  25.596 +arguments $y$ and $x$ are used to determine the quadrant of the
  25.597 +resultant value\\
  25.598 +{\tt card(}$X${\tt)}&$|X|$, cardinality (the number of elements) of
  25.599 +set $X$\\
  25.600 +{\tt ceil(}$x${\tt)}&$\lceil x\rceil$, smallest integer not less than
  25.601 +$x$ (``ceiling of $x$'')\\
  25.602 +{\tt cos(}$x${\tt)}&$\cos x$, cosine of $x$ (in radians)\\
  25.603 +{\tt exp(}$x${\tt)}&$e^x$, base-$e$ exponential of $x$\\
  25.604 +{\tt floor(}$x${\tt)}&$\lfloor x\rfloor$, largest integer not greater
  25.605 +than $x$ (``floor of $x$'')\\
  25.606 +\end{tabular}
  25.607 +
  25.608 +\begin{tabular}{@{}p{96pt}p{222pt}@{}}
  25.609 +{\tt gmtime()}&the number of seconds elapsed since 00:00:00~Jan~1, 1970,
  25.610 +Coordinated Universal Time (for details see Subsection \ref{gmtime},
  25.611 +page \pageref{gmtime})\\
  25.612 +{\tt length(}$s${\tt)}&$|s|$, length of character string $s$\\
  25.613 +{\tt log(}$x${\tt)}&$\log x$, natural logarithm of $x$\\
  25.614 +{\tt log10(}$x${\tt)}&$\log_{10}x$, common (decimal) logarithm of $x$\\
  25.615 +{\tt max(}$x_1${\tt,} $x_2${\tt,} \dots{\tt,} $x_n${\tt)}&the largest
  25.616 +of values $x_1$, $x_2$, \dots, $x_n$\\
  25.617 +{\tt min(}$x_1${\tt,} $x_2${\tt,} \dots{\tt,} $x_n${\tt)}&the smallest
  25.618 +of values $x_1$, $x_2$, \dots, $x_n$\\
  25.619 +{\tt round(}$x${\tt)}&rounding $x$ to nearest integer\\
  25.620 +{\tt round(}$x${\tt,} $n${\tt)}&rounding $x$ to $n$ fractional decimal
  25.621 +digits\\
  25.622 +{\tt sin(}$x${\tt)}&$\sin x$, sine of $x$ (in radians)\\
  25.623 +{\tt sqrt(}$x${\tt)}&$\sqrt{x}$, non-negative square root of $x$\\
  25.624 +{\tt str2time(}$s${\tt,} $f${\tt)}&converting character string $s$ to
  25.625 +calendar time (for details see Subsection \ref{str2time}, page
  25.626 +\pageref{str2time})\\
  25.627 +{\tt trunc(}$x${\tt)}&truncating $x$ to nearest integer\\
  25.628 +{\tt trunc(}$x${\tt,} $n${\tt)}&truncating $x$ to $n$ fractional
  25.629 +decimal digits\\
  25.630 +{\tt Irand224()}&generating pseudo-random integer uniformly distributed
  25.631 +in $[0,2^{24})$\\
  25.632 +{\tt Uniform01()}&generating pseudo-random number uniformly distributed
  25.633 +in $[0,1)$\\
  25.634 +{\tt Uniform(}$a${\tt,} $b${\tt)}&generating pseudo-random number
  25.635 +uniformly distributed in $[a,b)$\\
  25.636 +{\tt Normal01()}&generating Gaussian pseudo-random variate with
  25.637 +$\mu=0$ and $\sigma=1$\\
  25.638 +{\tt Normal(}$\mu${\tt,} $\sigma${\tt)}&generating Gaussian
  25.639 +pseudo-random variate with given $\mu$ and $\sigma$\\
  25.640 +\end{tabular}
  25.641 +
  25.642 +\medskip
  25.643 +
  25.644 +Arguments of all built-in functions, except {\tt card}, {\tt length},
  25.645 +and {\tt str2time}, must be numeric expressions. The argument of
  25.646 +{\tt card} must be a set expression. The argument of {\tt length} and
  25.647 +both arguments of {\tt str2time} must be symbolic expressions.
  25.648 +
  25.649 +The resultant value of the numeric expression, which is a function
  25.650 +reference, is the result of applying the function to its argument(s).
  25.651 +
  25.652 +Note that each pseudo-random generator function has a latent argument
  25.653 +(i.e. some internal state), which is changed whenever the function has
  25.654 +been applied. Thus, if the function is applied repeatedly even to
  25.655 +identical arguments, due to the side effect different resultant values
  25.656 +are always produced.
  25.657 +
  25.658 +\subsubsection{Iterated expressions}
  25.659 +\label{itexpr}
  25.660 +
  25.661 +An {\it iterated numeric expression} is a primary numeric expression,
  25.662 +which has the following syntactic form:
  25.663 +
  25.664 +\medskip
  25.665 +
  25.666 +\noindent\hfil
  25.667 +{\it iterated-operator indexing-expression integrand}
  25.668 +
  25.669 +\medskip
  25.670 +
  25.671 +\noindent where {\it iterated-operator} is the symbolic name of the
  25.672 +iterated operator to be performed (see below), {\it indexing-expression}
  25.673 +is an indexing expression which introduces dummy indices and controls
  25.674 +iterating, {\it integrand} is a numeric expression that participates in
  25.675 +the operation.
  25.676 +
  25.677 +In MathProg there exist four iterated operators, which may be used in
  25.678 +numeric expressions:
  25.679 +
  25.680 +\medskip
  25.681 +
  25.682 +\noindent\hfil
  25.683 +\begin{tabular}{@{}lll@{}}
  25.684 +{\tt sum}&summation&$\displaystyle\sum_{(i_1,\dots,i_n)\in\Delta}
  25.685 +f(i_1,\dots,i_n)$\\
  25.686 +{\tt prod}&production&$\displaystyle\prod_{(i_1,\dots,i_n)\in\Delta}
  25.687 +f(i_1,\dots,i_n)$\\
  25.688 +{\tt min}&minimum&$\displaystyle\min_{(i_1,\dots,i_n)\in\Delta}
  25.689 +f(i_1,\dots,i_n)$\\
  25.690 +{\tt max}&maximum&$\displaystyle\max_{(i_1,\dots,i_n)\in\Delta}
  25.691 +f(i_1,\dots,i_n)$\\
  25.692 +\end{tabular}
  25.693 +
  25.694 +\medskip
  25.695 +
  25.696 +\noindent where $i_1$, \dots, $i_n$ are dummy indices introduced in
  25.697 +the indexing expression, $\Delta$ is the domain, a set of $n$-tuples
  25.698 +specified by the indexing expression which defines particular values
  25.699 +assigned to the dummy indices on performing the iterated operation,
  25.700 +$f(i_1,\dots,i_n)$ is the integrand, a numeric expression whose
  25.701 +resultant value depends on the dummy indices.
  25.702 +
  25.703 +The resultant value of an iterated numeric expression is the result of
  25.704 +applying of the iterated operator to its integrand over all $n$-tuples
  25.705 +contained in the domain.
  25.706 +
  25.707 +\subsubsection{Conditional expressions}
  25.708 +\label{ifthen}
  25.709 +
  25.710 +A {\it conditional numeric expression} is a primary numeric expression,
  25.711 +which has one of the following two syntactic forms:
  25.712 +
  25.713 +\medskip
  25.714 +
  25.715 +\noindent\hfil
  25.716 +{\tt if} $b$ {\tt then} $x$ {\tt else} $y$
  25.717 +
  25.718 +\medskip
  25.719 +
  25.720 +\noindent\hspace{126.5pt}
  25.721 +{\tt if} $b$ {\tt then} $x$
  25.722 +
  25.723 +\medskip
  25.724 +
  25.725 +\noindent where $b$ is an logical expression, $x$ and $y$ are numeric
  25.726 +expressions.
  25.727 +
  25.728 +The resultant value of the conditional expression depends on the value
  25.729 +of the logical expression that follows the keyword {\tt if}. If it
  25.730 +takes on the value {\it true}, the value of the conditional expression
  25.731 +is the value of the expression that follows the keyword {\tt then}.
  25.732 +Otherwise, if the logical expression takes on the value {\it false},
  25.733 +the value of the conditional expression is the value of the expression
  25.734 +that follows the keyword {\it else}. If the second, reduced form of the
  25.735 +conditional expression is used and the logical expression takes on the
  25.736 +value {\it false}, the resultant value of the conditional expression is
  25.737 +zero.
  25.738 +
  25.739 +\subsubsection{Parenthesized expressions}
  25.740 +
  25.741 +Any numeric expression may be enclosed in parentheses that
  25.742 +syntactically makes it a primary numeric expression.
  25.743 +
  25.744 +Parentheses may be used in numeric expressions, as in algebra, to
  25.745 +specify the desired order in which operations are to be performed.
  25.746 +Where parentheses are used, the expression within the parentheses is
  25.747 +evaluated before the resultant value is used.
  25.748 +
  25.749 +The resultant value of the parenthesized expression is the same as the
  25.750 +value of the expression enclosed within parentheses.
  25.751 +
  25.752 +\subsubsection{Arithmetic operators}
  25.753 +
  25.754 +In MathProg there exist the following arithmetic operators, which may
  25.755 +be used in numeric expressions:
  25.756 +
  25.757 +\medskip
  25.758 +
  25.759 +\begin{tabular}{@{}p{96pt}p{222pt}@{}}
  25.760 +{\tt +} $x$&unary plus\\
  25.761 +{\tt -} $x$&unary minus\\
  25.762 +$x$ {\tt +} $y$&addition\\
  25.763 +$x$ {\tt -} $y$&subtraction\\
  25.764 +$x$ {\tt less} $y$&positive difference (if $x<y$ then 0 else $x-y$)\\
  25.765 +$x$ {\tt *} $y$&multiplication\\
  25.766 +$x$ {\tt /} $y$&division\\
  25.767 +$x$ {\tt div} $y$&quotient of exact division\\
  25.768 +$x$ {\tt mod} $y$&remainder of exact division\\
  25.769 +$x$ {\tt **} $y$, $x$ {\tt\textasciicircum} $y$&exponentiation (raising
  25.770 +to power)\\
  25.771 +\end{tabular}
  25.772 +
  25.773 +\medskip
  25.774 +
  25.775 +\noindent where $x$ and $y$ are numeric expressions.
  25.776 +
  25.777 +If the expression includes more than one arithmetic operator, all
  25.778 +operators are performed from left to right according to the hierarchy
  25.779 +of operations (see below) with the only exception that the
  25.780 +exponentiaion operators are performed from right to left.
  25.781 +
  25.782 +The resultant value of the expression, which contains arithmetic
  25.783 +operators, is the result of applying the operators to their operands.
  25.784 +
  25.785 +\subsubsection{Hierarchy of operations}
  25.786 +\label{hierarchy}
  25.787 +
  25.788 +The following list shows the hierarchy of operations in numeric
  25.789 +expressions:
  25.790 +
  25.791 +\medskip
  25.792 +
  25.793 +\noindent\hfil
  25.794 +\begin{tabular}{@{}ll@{}}
  25.795 +Operation&Hierarchy\\
  25.796 +\hline
  25.797 +Evaluation of functions ({\tt abs}, {\tt ceil}, etc.)&1st\\
  25.798 +Exponentiation ({\tt**}, {\tt\textasciicircum})&2nd\\
  25.799 +Unary plus and minus ({\tt+}, {\tt-})&3rd\\
  25.800 +Multiplication and division ({\tt*}, {\tt/}, {\tt div}, {\tt mod})&4th\\
  25.801 +Iterated operations ({\tt sum}, {\tt prod}, {\tt min}, {\tt max})&5th\\
  25.802 +Addition and subtraction ({\tt+}, {\tt-}, {\tt less})&6th\\
  25.803 +Conditional evaluation ({\tt if} \dots {\tt then} \dots {\tt else})&
  25.804 +7th\\
  25.805 +\end{tabular}
  25.806 +
  25.807 +\medskip
  25.808 +
  25.809 +This hierarchy is used to determine which of two consecutive operations
  25.810 +is performed first. If the first operator is higher than or equal to
  25.811 +the second, the first operation is performed. If it is not, the second
  25.812 +operator is compared to the third, etc. When the end of the expression
  25.813 +is reached, all of the remaining operations are performed in the
  25.814 +reverse order.
  25.815 +
  25.816 +\newpage
  25.817 +
  25.818 +\subsection{Symbolic expressions}
  25.819 +
  25.820 +A {\it symbolic expression} is a rule for computing a single symbolic
  25.821 +value represented as a character string.
  25.822 +
  25.823 +The primary symbolic expression may be a string literal, dummy index,
  25.824 +unsubscripted parameter, subscripted parameter, built-in function
  25.825 +reference, conditional symbolic expression, or another symbolic
  25.826 +expression enclosed in parentheses.
  25.827 +
  25.828 +It is also allowed to use a numeric expression as the primary symbolic
  25.829 +expression, in which case the resultant value of the numeric expression
  25.830 +is automatically converted to the symbolic type.
  25.831 +
  25.832 +\medskip
  25.833 +
  25.834 +\noindent{\bf Examples}
  25.835 +
  25.836 +\medskip
  25.837 +
  25.838 +\noindent
  25.839 +\begin{tabular}{@{}ll@{}}
  25.840 +\verb|'May 2003'|&(string literal)\\
  25.841 +\verb|j|&(dummy index)\\
  25.842 +\verb|p|&(unsubscripted parameter)\\
  25.843 +\verb|s['abc',j+1]|&(subscripted parameter)\\
  25.844 +\verb|substr(name[i],k+1,3)|&(function reference)\\
  25.845 +\verb|if i in I then s[i,j] else t[i+1]|&(conditional expression)\\
  25.846 +\verb|((10 * b[i,j]) & '.bis')|&(parenthesized expression)\\
  25.847 +\end{tabular}
  25.848 +
  25.849 +\medskip
  25.850 +
  25.851 +More general symbolic expressions containing two or more primary
  25.852 +symbolic expressions may be constructed by using the concatenation
  25.853 +operator.
  25.854 +
  25.855 +\medskip
  25.856 +
  25.857 +\noindent{\bf Examples}
  25.858 +
  25.859 +\medskip
  25.860 +
  25.861 +\noindent\verb|'abc[' & i & ',' & j & ']'|
  25.862 +
  25.863 +\noindent\verb|"from " & city[i] & " to " & city[j]|
  25.864 +
  25.865 +\medskip
  25.866 +
  25.867 +The principles of evaluation of symbolic expressions are completely
  25.868 +analogous to the ones given for numeric expressions (see above).
  25.869 +
  25.870 +\subsubsection{Function references}
  25.871 +
  25.872 +In MathProg there exist the following built-in functions which may be
  25.873 +used in symbolic expressions:
  25.874 +
  25.875 +\medskip
  25.876 +
  25.877 +\begin{tabular}{@{}p{96pt}p{222pt}@{}}
  25.878 +{\tt substr(}$s${\tt,} $x${\tt)}&substring of $s$ starting from
  25.879 +position $x$\\
  25.880 +{\tt substr(}$s${\tt,} $x${\tt,} $y${\tt)}&substring of $s$ starting
  25.881 +from position $x$ and having length $y$\\
  25.882 +{\tt time2str(}$t${\tt,} $f${\tt)}&converting calendar time to
  25.883 +character string (for details see Subsection \ref{time2str}, page
  25.884 +\pageref{time2str})\\
  25.885 +\end{tabular}
  25.886 +
  25.887 +\medskip
  25.888 +
  25.889 +The first argument of {\tt substr} must be a symbolic expression while
  25.890 +its second and optional third arguments must be numeric expressions.
  25.891 +
  25.892 +The first argument of {\tt time2str} must be a numeric expression, and
  25.893 +its second argument must be a symbolic expression.
  25.894 +
  25.895 +The resultant value of the symbolic expression, which is a function
  25.896 +reference, is the result of applying the function to its arguments.
  25.897 +
  25.898 +\subsubsection{Symbolic operators}
  25.899 +
  25.900 +Currently in MathProg there exists the only symbolic operator:
  25.901 +
  25.902 +\medskip
  25.903 +
  25.904 +\noindent\hfil
  25.905 +{\tt s \& t}
  25.906 +
  25.907 +\medskip
  25.908 +
  25.909 +\noindent where $s$ and $t$ are symbolic expressions. This operator
  25.910 +means concatenation of its two symbolic operands, which are character
  25.911 +strings.
  25.912 +
  25.913 +\subsubsection{Hierarchy of operations}
  25.914 +
  25.915 +The following list shows the hierarchy of operations in symbolic
  25.916 +expressions:
  25.917 +
  25.918 +\medskip
  25.919 +
  25.920 +\noindent\hfil
  25.921 +\begin{tabular}{@{}ll@{}}
  25.922 +Operation&Hierarchy\\
  25.923 +\hline
  25.924 +Evaluation of numeric operations&1st-7th\\
  25.925 +Concatenation ({\tt\&})&8th\\
  25.926 +Conditional evaluation ({\tt if} \dots {\tt then} \dots {\tt else})&
  25.927 +7th\\
  25.928 +\end{tabular}
  25.929 +
  25.930 +\medskip
  25.931 +
  25.932 +This hierarchy has the same meaning as was explained above for numeric
  25.933 +expressions (see Subsection \ref{hierarchy}, page \pageref{hierarchy}).
  25.934 +
  25.935 +\subsection{Indexing expressions and dummy indices}
  25.936 +\label{indexing}
  25.937 +
  25.938 +An {\it indexing expression} is an auxiliary construction, which
  25.939 +specifies a plain set of $n$-tuples and introduces dummy indices. It
  25.940 +has two syntactic forms:
  25.941 +
  25.942 +\medskip
  25.943 +
  25.944 +\noindent\hspace{73.5pt}
  25.945 +{\tt\{} {\it entry}$_1${\tt,} {\it entry}$_2${\tt,} \dots{\tt,}
  25.946 +{\it entry}$_m$ {\tt\}}
  25.947 +
  25.948 +\medskip
  25.949 +
  25.950 +\noindent\hfil
  25.951 +{\tt\{} {\it entry}$_1${\tt,} {\it entry}$_2${\tt,} \dots{\tt,}
  25.952 +{\it entry}$_m$ {\tt:} {\it predicate} {\tt\}}
  25.953 +
  25.954 +\medskip
  25.955 +
  25.956 +\noindent where {\it entry}{$_1$}, {\it entry}{$_2$}, \dots,
  25.957 +{\it entry}{$_m$} are indexing entries, {\it predicate} is a logical
  25.958 +expression that specifies an optional predicate (logical condition).
  25.959 +
  25.960 +Each {\it indexing entry} in the indexing expression has one of the
  25.961 +following three forms:
  25.962 +
  25.963 +\medskip
  25.964 +
  25.965 +\noindent\hspace{123pt}
  25.966 +$i$ {\tt in} $S$
  25.967 +
  25.968 +\medskip
  25.969 +
  25.970 +\noindent\hfil
  25.971 +{\tt(}$i_1${\tt,} $i_2${\tt,} \dots{\tt,}$i_n${\tt)} {\tt in} $S$
  25.972 +
  25.973 +\medskip
  25.974 +
  25.975 +\noindent\hspace{123pt}
  25.976 +$S$
  25.977 +
  25.978 +\medskip
  25.979 +
  25.980 +\noindent where $i_1$, $i_2$, \dots, $i_n$ are indices, $S$ is a set
  25.981 +expression (discussed in the next section) that specifies the basic set.
  25.982 +
  25.983 +The number of indices in the indexing entry must be the same as the
  25.984 +dimension of the basic set $S$, i.e. if $S$ consists of 1-tuples, the
  25.985 +first form must be used, and if $S$ consists of $n$-tuples, where
  25.986 +$n>1$, the second form must be used.
  25.987 +
  25.988 +If the first form of the indexing entry is used, the index $i$ can be
  25.989 +a dummy index only (see below). If the second form is used, the indices
  25.990 +$i_1$, $i_2$, \dots, $i_n$ can be either dummy indices or some numeric
  25.991 +or symbolic expressions, where at least one index must be a dummy index.
  25.992 +The third, reduced form of the indexing entry has the same effect as if
  25.993 +there were $i$ (if $S$ is 1-dimensional) or $i_1$, $i_2$, \dots, $i_n$
  25.994 +(if $S$ is $n$-dimensional) all specified as dummy indices.
  25.995 +
  25.996 +A {\it dummy index} is an auxiliary model object, which acts like an
  25.997 +individual variable. Values assigned to dummy indices are components of
  25.998 +$n$-tuples from basic sets, i.e. some numeric and symbolic quantities.
  25.999 +
 25.1000 +For referencing purposes dummy indices can be provided with symbolic
 25.1001 +names. However, unlike other model objects (sets, parameters, etc.)
 25.1002 +dummy indices need not be explicitly declared. Each {\it undeclared}
 25.1003 +symbolic name being used in the indexing position of an indexing entry
 25.1004 +is recognized as the symbolic name of corresponding dummy index.
 25.1005 +
 25.1006 +Symbolic names of dummy indices are valid only within the scope of the
 25.1007 +indexing expression, where the dummy indices were introduced. Beyond
 25.1008 +the scope the dummy indices are completely inaccessible, so the same
 25.1009 +symbolic names may be used for other purposes, in particular, to
 25.1010 +represent dummy indices in other indexing expressions.
 25.1011 +
 25.1012 +The scope of indexing expression, where implicit declarations of dummy
 25.1013 +indices are valid, depends on the context, in which the indexing
 25.1014 +expression is used:
 25.1015 +
 25.1016 +\begin{enumerate}
 25.1017 +\item If the indexing expression is used in iterated operator, its
 25.1018 +scope extends until the end of the integrand.
 25.1019 +\item If the indexing expression is used as a primary set expression,
 25.1020 +its scope extends until the end of that indexing expression.
 25.1021 +\item If the indexing expression is used to define the subscript domain
 25.1022 +in declarations of some model objects, its scope extends until the end
 25.1023 +of the corresponding statement.
 25.1024 +\end{enumerate}
 25.1025 +
 25.1026 +The indexing mechanism implemented by means of indexing expressions is
 25.1027 +best explained by some examples discussed below.
 25.1028 +
 25.1029 +Let there be given three sets:
 25.1030 +
 25.1031 +\medskip
 25.1032 +
 25.1033 +\noindent\hspace{33.5pt}
 25.1034 +$A=\{4,7,9\}$,
 25.1035 +
 25.1036 +\medskip
 25.1037 +
 25.1038 +\noindent\hfil
 25.1039 +$B=\{(1,Jan),(1,Feb),(2,Mar),(2,Apr),(3,May),(3,Jun)\}$,
 25.1040 +
 25.1041 +\medskip
 25.1042 +
 25.1043 +\noindent\hspace{33.5pt}
 25.1044 +$C=\{a,b,c\}$,
 25.1045 +
 25.1046 +\medskip
 25.1047 +
 25.1048 +\noindent where $A$ and $C$ consist of 1-tuples (singlets), $B$
 25.1049 +consists of 2-tuples (doublets). Consider the following indexing
 25.1050 +expression:
 25.1051 +
 25.1052 +\medskip
 25.1053 +
 25.1054 +\noindent\hfil
 25.1055 +{\tt\{i in A, (j,k) in B, l in C\}}
 25.1056 +
 25.1057 +\medskip
 25.1058 +
 25.1059 +\noindent where {\tt i}, {\tt j}, {\tt k}, and {\tt l} are dummy
 25.1060 +indices.
 25.1061 +
 25.1062 +Although MathProg is not a procedural language, for any indexing
 25.1063 +expression an equivalent algorithmic description can be given. In
 25.1064 +particular, the algorithmic description of the indexing expression
 25.1065 +above could look like follows:
 25.1066 +
 25.1067 +\medskip
 25.1068 +
 25.1069 +\noindent\hfil
 25.1070 +\begin{tabular}{@{}l@{}}
 25.1071 +{\bf for all} $i\in A$ {\bf do}\\
 25.1072 +\hspace{12pt}{\bf for all} $(j,k)\in B$ {\bf do}\\
 25.1073 +\hspace{24pt}{\bf for all} $l\in C$ {\bf do}\\
 25.1074 +\hspace{36pt}{\it action};\\
 25.1075 +\end{tabular}
 25.1076 +
 25.1077 +\newpage
 25.1078 +
 25.1079 +\noindent where the dummy indices $i$, $j$, $k$, $l$ are consecutively
 25.1080 +assigned corresponding components of $n$-tuples from the basic sets $A$,
 25.1081 +$B$, $C$, and {\it action} is some action that depends on the context,
 25.1082 +where the indexing expression is used. For example, if the action were
 25.1083 +printing current values of dummy indices, the printout would look like
 25.1084 +follows:
 25.1085 +
 25.1086 +\medskip
 25.1087 +
 25.1088 +\noindent\hfil
 25.1089 +\begin{tabular}{@{}llll@{}}
 25.1090 +$i=4$&$j=1$&$k=Jan$&$l=a$\\
 25.1091 +$i=4$&$j=1$&$k=Jan$&$l=b$\\
 25.1092 +$i=4$&$j=1$&$k=Jan$&$l=c$\\
 25.1093 +$i=4$&$j=1$&$k=Feb$&$l=a$\\
 25.1094 +$i=4$&$j=1$&$k=Feb$&$l=b$\\
 25.1095 +\multicolumn{4}{c}{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .}\\
 25.1096 +$i=9$&$j=3$&$k=Jun$&$l=b$\\
 25.1097 +$i=9$&$j=3$&$k=Jun$&$l=c$\\
 25.1098 +\end{tabular}
 25.1099 +
 25.1100 +\medskip
 25.1101 +
 25.1102 +Let the example indexing expression be used in the following iterated
 25.1103 +operation:
 25.1104 +
 25.1105 +\medskip
 25.1106 +
 25.1107 +\noindent\hfil
 25.1108 +{\tt sum\{i in A, (j,k) in B, l in C\} p[i,j,k,l]}
 25.1109 +
 25.1110 +\medskip
 25.1111 +
 25.1112 +\noindent where {\tt p} is a 4-dimensional numeric parameter or some
 25.1113 +numeric expression whose resultant value depends on {\tt i}, {\tt j},
 25.1114 +{\tt k}, and {\tt l}. In this case the action is summation, so the
 25.1115 +resultant value of the primary numeric expression is:
 25.1116 +$$\sum_{i\in A,(j,k)\in B,l\in C}(p_{ijkl}).$$
 25.1117 +
 25.1118 +Now let the example indexing expression be used as a primary set
 25.1119 +expression. In this case the action is gathering all 4-tuples
 25.1120 +(quadruplets) of the form $(i,j,k,l)$ in one set, so the resultant
 25.1121 +value of such operation is simply the Cartesian product of the basic
 25.1122 +sets:
 25.1123 +$$A\times B\times C=\{(i,j,k,l):i\in A,(j,k)\in B,l\in C\}.$$
 25.1124 +Note that in this case the same indexing expression might be written in
 25.1125 +the reduced form:
 25.1126 +
 25.1127 +\medskip
 25.1128 +
 25.1129 +\noindent\hfil
 25.1130 +{\tt\{A, B, C\}}
 25.1131 +
 25.1132 +\medskip
 25.1133 +
 25.1134 +\noindent because the dummy indices $i$, $j$, $k$, and $l$ are not
 25.1135 +referenced and therefore their symbolic names need not be specified.
 25.1136 +
 25.1137 +Finally, let the example indexing expression be used as the subscript
 25.1138 +domain in the declaration of a 4-dimensional model object, say,
 25.1139 +a numeric parameter:
 25.1140 +
 25.1141 +\medskip
 25.1142 +
 25.1143 +\noindent\hfil
 25.1144 +{\tt param p\{i in A, (j,k) in B, l in C\}} \dots {\tt;}
 25.1145 +
 25.1146 +\medskip
 25.1147 +
 25.1148 +\noindent In this case the action is generating the parameter members,
 25.1149 +where each member has the form $p[i,j,k,l]$.
 25.1150 +
 25.1151 +As was said above, some indices in the second form of indexing entries
 25.1152 +may be numeric or symbolic expressions, not only dummy indices. In this
 25.1153 +case resultant values of such expressions play role of some logical
 25.1154 +conditions to select only that $n$-tuples from the Cartesian product of
 25.1155 +basic sets that satisfy these conditions.
 25.1156 +
 25.1157 +Consider, for example, the following indexing expression:
 25.1158 +
 25.1159 +\medskip
 25.1160 +
 25.1161 +\noindent\hfil
 25.1162 +{\tt\{i in A, (i-1,k) in B, l in C\}}
 25.1163 +
 25.1164 +\medskip
 25.1165 +
 25.1166 +\noindent where {\tt i}, {\tt k}, {\tt l} are dummy indices, and
 25.1167 +{\tt i-1} is a numeric expression. The algorithmic decsription of this
 25.1168 +indexing expression is the following:
 25.1169 +
 25.1170 +\medskip
 25.1171 +
 25.1172 +\noindent\hfil
 25.1173 +\begin{tabular}{@{}l@{}}
 25.1174 +{\bf for all} $i\in A$ {\bf do}\\
 25.1175 +\hspace{12pt}{\bf for all} $(j,k)\in B$ {\bf and} $j=i-1$ {\bf do}\\
 25.1176 +\hspace{24pt}{\bf for all} $l\in C$ {\bf do}\\
 25.1177 +\hspace{36pt}{\it action};\\
 25.1178 +\end{tabular}
 25.1179 +
 25.1180 +\medskip
 25.1181 +
 25.1182 +\noindent Thus, if this indexing expression were used as a primary set
 25.1183 +expression, the resultant set would be the following:
 25.1184 +$$\{(4,May,a),(4,May,b),(4,May,c),(4,Jun,a),(4,Jun,b),(4,Jun,c)\}.$$
 25.1185 +Should note that in this case the resultant set consists of 3-tuples,
 25.1186 +not of 4-tuples, because in the indexing expression there is no dummy
 25.1187 +index that corresponds to the first component of 2-tuples from the set
 25.1188 +$B$.
 25.1189 +
 25.1190 +The general rule is: the number of components of $n$-tuples defined by
 25.1191 +an indexing expression is the same as the number of dummy indices in
 25.1192 +that expression, where the correspondence between dummy indices and
 25.1193 +components on $n$-tuples in the resultant set is positional, i.e. the
 25.1194 +first dummy index corresponds to the first component, the second dummy
 25.1195 +index corresponds to the second component, etc.
 25.1196 +
 25.1197 +In some cases it is needed to select a subset from the Cartesian
 25.1198 +product of some sets. This may be attained by using an optional logical
 25.1199 +predicate, which is specified in the indexing expression.
 25.1200 +
 25.1201 +Consider, for example, the following indexing expression:
 25.1202 +
 25.1203 +\medskip
 25.1204 +
 25.1205 +\noindent\hfil
 25.1206 +{\tt\{i in A, (j,k) in B, l in C: i <= 5 and k <> 'Mar'\}}
 25.1207 +
 25.1208 +\medskip
 25.1209 +
 25.1210 +\noindent where the logical expression following the colon is a
 25.1211 +predicate. The algorithmic description of this indexing expression is
 25.1212 +the following:
 25.1213 +
 25.1214 +\medskip
 25.1215 +
 25.1216 +\noindent\hfil
 25.1217 +\begin{tabular}{@{}l@{}}
 25.1218 +{\bf for all} $i\in A$ {\bf do}\\
 25.1219 +\hspace{12pt}{\bf for all} $(j,k)\in B$ {\bf do}\\
 25.1220 +\hspace{24pt}{\bf for all} $l\in C$ {\bf do}\\
 25.1221 +\hspace{36pt}{\bf if} $i\leq 5$ {\bf and} $l\neq`Mar'$ {\bf then}\\
 25.1222 +\hspace{48pt}{\it action};\\
 25.1223 +\end{tabular}
 25.1224 +
 25.1225 +\medskip
 25.1226 +
 25.1227 +\noindent Thus, if this indexing expression were used as a primary set
 25.1228 +expression, the resultant set would be the following:
 25.1229 +$$\{(4,1,Jan,a),(4,1,Feb,a),(4,2,Apr,a),\dots,(4,3,Jun,c)\}.$$
 25.1230 +
 25.1231 +If no predicate is specified in the indexing expression, one, which
 25.1232 +takes on the value {\it true}, is assumed.
 25.1233 +
 25.1234 +\subsection{Set expressions}
 25.1235 +
 25.1236 +A {\it set expression} is a rule for computing an elemental set, i.e.
 25.1237 +a collection of $n$-tuples, where components of $n$-tuples are numeric
 25.1238 +and symbolic quantities.
 25.1239 +
 25.1240 +The primary set expression may be a literal set, unsubscripted set,
 25.1241 +subscripted set, ``arithmetic'' set, indexing expression, iterated set
 25.1242 +expression, conditional set expression, or another set expression
 25.1243 +enclosed in parentheses.
 25.1244 +
 25.1245 +\medskip
 25.1246 +
 25.1247 +\noindent{\bf Examples}
 25.1248 +
 25.1249 +\medskip
 25.1250 +
 25.1251 +\noindent
 25.1252 +\begin{tabular}{@{}ll@{}}
 25.1253 +\verb|{(123,'aa'), (i,'bb'), (j-1,'cc')}|&(literal set)\\
 25.1254 +\verb|I|&(unsubscripted set)\\
 25.1255 +\verb|S[i-1,j+1]|&(subscripted set)\\
 25.1256 +\verb|1..t-1 by 2|&(``arithmetic'' set)\\
 25.1257 +\verb|{t in 1..T, (t+1,j) in S: (t,j) in F}|&(indexing expression)\\
 25.1258 +\verb|setof{i in I, j in J}(i+1,j-1)|&(iterated expression)\\
 25.1259 +\verb|if i < j then S[i] else F diff S[j]|&(conditional expression)\\
 25.1260 +\verb|(1..10 union 21..30)|&(parenthesized expression)\\
 25.1261 +\end{tabular}
 25.1262 +
 25.1263 +\medskip
 25.1264 +
 25.1265 +More general set expressions containing two or more primary set
 25.1266 +expressions may be constructed by using certain set operators.
 25.1267 +
 25.1268 +\medskip
 25.1269 +
 25.1270 +\noindent{\bf Examples}
 25.1271 +
 25.1272 +\medskip
 25.1273 +
 25.1274 +\noindent\verb|(A union B) inter (I cross J)|
 25.1275 +
 25.1276 +\noindent
 25.1277 +\verb|1..10 cross (if i < j then {'a', 'b', 'c'} else {'d', 'e', 'f'})|
 25.1278 +
 25.1279 +\subsubsection{Literal sets}
 25.1280 +
 25.1281 +A {\it literal set} is a primary set expression, which has the
 25.1282 +following two syntactic forms:
 25.1283 +
 25.1284 +\medskip
 25.1285 +
 25.1286 +\noindent\hspace{39pt}
 25.1287 +{\tt\{}$e_1${\tt,} $e_2${\tt,} \dots{\tt,} $e_m${\tt\}}
 25.1288 +
 25.1289 +\medskip
 25.1290 +
 25.1291 +\noindent\hfil
 25.1292 +{\tt\{(}$e_{11}${\tt,} \dots{\tt,} $e_{1n}${\tt),}
 25.1293 +{\tt(}$e_{21}${\tt,} \dots{\tt,} $e_{2n}${\tt),} \dots{\tt,}
 25.1294 +{\tt(}$e_{m1}${\tt,} \dots{\tt,} $e_{mn}${\tt)\}}
 25.1295 +
 25.1296 +\medskip
 25.1297 +
 25.1298 +\noindent where $e_1$, \dots, $e_m$, $e_{11}$, \dots, $e_{mn}$ are
 25.1299 +numeric or symbolic expressions.
 25.1300 +
 25.1301 +If the first form is used, the resultant set consists of 1-tuples
 25.1302 +(singlets) enumerated within the curly braces. It is allowed to specify
 25.1303 +an empty set as {\tt\{\ \}}, which has no 1-tuples. If the second form
 25.1304 +is used, the resultant set consists of $n$-tuples enumerated within the
 25.1305 +curly braces, where a particular $n$-tuple consists of corresponding
 25.1306 +components enumerated within the parentheses. All $n$-tuples must have
 25.1307 +the same number of components.
 25.1308 +
 25.1309 +\subsubsection{Unsubscripted sets}
 25.1310 +
 25.1311 +If the primary set expression is an unsubscripted set (which must be
 25.1312 +0-dimen\-sional), the resultant set is an elemental set associated with
 25.1313 +the corresponding set object.
 25.1314 +
 25.1315 +\newpage
 25.1316 +
 25.1317 +\subsubsection{Subscripted sets}
 25.1318 +
 25.1319 +The primary set expression, which refers to a subscripted set, has the
 25.1320 +following syntactic form:
 25.1321 +
 25.1322 +\medskip
 25.1323 +
 25.1324 +\noindent\hfil
 25.1325 +{\it name}{\tt[}$i_1${\tt,} $i_2${\tt,} \dots{\tt,} $i_n${\tt]}
 25.1326 +
 25.1327 +\medskip
 25.1328 +
 25.1329 +\noindent where {\it name} is the symbolic name of the set object,
 25.1330 +$i_1$, $i_2$, \dots, $i_n$ are subscripts.
 25.1331 +
 25.1332 +Each subscript must be a numeric or symbolic expression. The number of
 25.1333 +subscripts in the subscript list must be the same as the dimension of
 25.1334 +the set object with which the subscript list is associated.
 25.1335 +
 25.1336 +Actual values of subscript expressions are used to identify a
 25.1337 +particular member of the set object that determines the resultant set.
 25.1338 +
 25.1339 +\subsubsection{``Arithmetic'' sets}
 25.1340 +
 25.1341 +The primary set expression, which is an ``arithmetic'' set, has the
 25.1342 +following two syntactic forms:
 25.1343 +
 25.1344 +\medskip
 25.1345 +
 25.1346 +\noindent\hfil
 25.1347 +$t_0$ {\tt..} $t_1$ {\tt by} $\delta t$
 25.1348 +
 25.1349 +\medskip
 25.1350 +
 25.1351 +\noindent\hspace{138.5pt}
 25.1352 +$t_0$ {\tt..} $t_1$
 25.1353 +
 25.1354 +\medskip
 25.1355 +
 25.1356 +\noindent where $t_0$, $t_1$, and $\delta t$ are numeric expressions
 25.1357 +(the value of $\delta t$ must not be zero). The second form is
 25.1358 +equivalent to the first form, where $\delta t=1$.
 25.1359 +
 25.1360 +If $\delta t>0$, the resultant set is determined as follows:
 25.1361 +$$\{t:\exists k\in{\cal Z}(t=t_0+k\delta t,\ t_0\leq t\leq t_1)\}.$$
 25.1362 +Otherwise, if $\delta t<0$, the resultant set is determined as follows:
 25.1363 +$$\{t:\exists k\in{\cal Z}(t=t_0+k\delta t,\ t_1\leq t\leq t_0)\}.$$
 25.1364 +
 25.1365 +\subsubsection{Indexing expressions}
 25.1366 +
 25.1367 +If the primary set expression is an indexing expression, the resultant
 25.1368 +set is determined as described above in Subsection \ref{indexing}, page
 25.1369 +\pageref{indexing}.
 25.1370 +
 25.1371 +\subsubsection{Iterated expressions}
 25.1372 +
 25.1373 +An {\it iterated set expression} is a primary set expression, which has
 25.1374 +the following syntactic form:
 25.1375 +
 25.1376 +\medskip
 25.1377 +
 25.1378 +\noindent\hfil
 25.1379 +{\tt setof} {\it indexing-expression} {\it integrand}
 25.1380 +
 25.1381 +\medskip
 25.1382 +
 25.1383 +\noindent where {\it indexing-expression} is an indexing expression,
 25.1384 +which introduces dummy indices and controls iterating, {\it integrand}
 25.1385 +is either a single numeric or symbolic expression or a list of numeric
 25.1386 +and symbolic expressions separated by commae and enclosed in
 25.1387 +parentheses.
 25.1388 +
 25.1389 +If the integrand is a single numeric or symbolic expression, the
 25.1390 +resultant set consists of 1-tuples and is determined as follows:
 25.1391 +$$\{x:(i_1,\dots,i_n)\in\Delta\},$$
 25.1392 +\noindent where $x$ is a value of the integrand, $i_1$, \dots, $i_n$
 25.1393 +are dummy indices introduced in the indexing expression, $\Delta$ is
 25.1394 +the domain, a set of $n$-tuples specified by the indexing expression,
 25.1395 +which defines particular values assigned to the dummy indices on
 25.1396 +performing the iterated operation.
 25.1397 +
 25.1398 +If the integrand is a list containing $m$ numeric and symbolic
 25.1399 +expressions, the resultant set consists of $m$-tuples and is determined
 25.1400 +as follows:
 25.1401 +$$\{(x_1,\dots,x_m):(i_1,\dots,i_n)\in\Delta\},$$
 25.1402 +where $x_1$, \dots, $x_m$ are values of the expressions in the
 25.1403 +integrand list, $i_1$, \dots, $i_n$ and $\Delta$ have the same meaning
 25.1404 +as above.
 25.1405 +
 25.1406 +\subsubsection{Conditional expressions}
 25.1407 +
 25.1408 +A {\it conditional set expression} is a primary set expression that has
 25.1409 +the following syntactic form:
 25.1410 +
 25.1411 +\medskip
 25.1412 +
 25.1413 +\noindent\hfil
 25.1414 +{\tt if} $b$ {\tt then} $X$ {\tt else} $Y$
 25.1415 +
 25.1416 +\medskip
 25.1417 +
 25.1418 +\noindent where $b$ is an logical expression, $X$ and $Y$ are set
 25.1419 +expressions, which must define sets of the same dimension.
 25.1420 +
 25.1421 +The resultant value of the conditional expression depends on the value
 25.1422 +of the logical expression that follows the keyword {\tt if}. If it
 25.1423 +takes on the value {\it true}, the resultant set is the value of the
 25.1424 +expression that follows the keyword {\tt then}. Otherwise, if the
 25.1425 +logical expression takes on the value {\it false}, the resultant set is
 25.1426 +the value of the expression that follows the keyword {\tt else}.
 25.1427 +
 25.1428 +\subsubsection{Parenthesized expressions}
 25.1429 +
 25.1430 +Any set expression may be enclosed in parentheses that syntactically
 25.1431 +makes it a primary set expression.
 25.1432 +
 25.1433 +Parentheses may be used in set expressions, as in algebra, to specify
 25.1434 +the desired order in which operations are to be performed. Where
 25.1435 +parentheses are used, the expression within the parentheses is
 25.1436 +evaluated before the resultant value is used.
 25.1437 +
 25.1438 +The resultant value of the parenthesized expression is the same as the
 25.1439 +value of the expression enclosed within parentheses.
 25.1440 +
 25.1441 +\subsubsection{Set operators}
 25.1442 +
 25.1443 +In MathProg there exist the following set operators, which may be used
 25.1444 +in set expressions:
 25.1445 +
 25.1446 +\medskip
 25.1447 +
 25.1448 +\begin{tabular}{@{}p{96pt}p{222pt}@{}}
 25.1449 +$X$ {\tt union} $Y$&union $X\cup Y$\\
 25.1450 +$X$ {\tt diff} $Y$&difference $X\backslash Y$\\
 25.1451 +$X$ {\tt symdiff} $Y$&symmetric difference $X\oplus Y$\\
 25.1452 +$X$ {\tt inter} $Y$&intersection $X\cap Y$\\
 25.1453 +$X$ {\tt cross} $Y$&cross (Cartesian) product $X\times Y$\\
 25.1454 +\end{tabular}
 25.1455 +
 25.1456 +\medskip
 25.1457 +
 25.1458 +\noindent where $X$ and Y are set expressions, which must define sets
 25.1459 +of the identical dimension (except the Cartesian product).
 25.1460 +
 25.1461 +If the expression includes more than one set operator, all operators
 25.1462 +are performed from left to right according to the hierarchy of
 25.1463 +operations (see below).
 25.1464 +
 25.1465 +The resultant value of the expression, which contains set operators, is
 25.1466 +the result of applying the operators to their operands.
 25.1467 +
 25.1468 +The dimension of the resultant set, i.e. the dimension of $n$-tuples,
 25.1469 +of which the resultant set consists of, is the same as the dimension of
 25.1470 +the operands, except the Cartesian product, where the dimension of the
 25.1471 +resultant set is the sum of the dimensions of its operands.
 25.1472 +
 25.1473 +\subsubsection{Hierarchy of operations}
 25.1474 +
 25.1475 +The following list shows the hierarchy of operations in set
 25.1476 +expressions:
 25.1477 +
 25.1478 +\medskip
 25.1479 +
 25.1480 +\noindent\hfil
 25.1481 +\begin{tabular}{@{}ll@{}}
 25.1482 +Operation&Hierarchy\\
 25.1483 +\hline
 25.1484 +Evaluation of numeric operations&1st-7th\\
 25.1485 +Evaluation of symbolic operations&8th-9th\\
 25.1486 +Evaluation of iterated or ``arithmetic'' set ({\tt setof}, {\tt..})&
 25.1487 +10th\\
 25.1488 +Cartesian product ({\tt cross})&11th\\
 25.1489 +Intersection ({\tt inter})&12th\\
 25.1490 +Union and difference ({\tt union}, {\tt diff}, {\tt symdiff})&13th\\
 25.1491 +Conditional evaluation ({\tt if} \dots {\tt then} \dots {\tt else})&
 25.1492 +14th\\
 25.1493 +\end{tabular}
 25.1494 +
 25.1495 +\medskip
 25.1496 +
 25.1497 +This hierarchy has the same meaning as was explained above for numeric
 25.1498 +expressions (see Subsection \ref{hierarchy}, page \pageref{hierarchy}).
 25.1499 +
 25.1500 +\subsection{Logical expressions}
 25.1501 +
 25.1502 +A {\it logical expression} is a rule for computing a single logical
 25.1503 +value, which can be either {\it true} or {\it false}.
 25.1504 +
 25.1505 +The primary logical expression may be a numeric expression, relational
 25.1506 +expression, iterated logical expression, or another logical expression
 25.1507 +enclosed in parentheses.
 25.1508 +
 25.1509 +\medskip
 25.1510 +
 25.1511 +\noindent{\bf Examples}
 25.1512 +
 25.1513 +\medskip
 25.1514 +
 25.1515 +\noindent
 25.1516 +\begin{tabular}{@{}ll@{}}
 25.1517 +\verb|i+1|&(numeric expression)\\
 25.1518 +\verb|a[i,j] < 1.5|&(relational expression)\\
 25.1519 +\verb|s[i+1,j-1] <> 'Mar'|&(relational expression)\\
 25.1520 +\verb|(i+1,'Jan') not in I cross J|&(relational expression)\\
 25.1521 +\verb|S union T within A[i] inter B[j]|&(relational expression)\\
 25.1522 +\verb|forall{i in I, j in J} a[i,j] < .5 * b|&(iterated expression)\\
 25.1523 +\verb|(a[i,j] < 1.5 or b[i] >= a[i,j])|&(parenthesized expression)\\
 25.1524 +\end{tabular}
 25.1525 +
 25.1526 +\medskip
 25.1527 +
 25.1528 +More general logical expressions containing two or more primary logical
 25.1529 +expressions may be constructed by using certain logical operators.
 25.1530 +
 25.1531 +\newpage
 25.1532 +
 25.1533 +\noindent{\bf Examples}
 25.1534 +
 25.1535 +\medskip
 25.1536 +
 25.1537 +\noindent\verb|not (a[i,j] < 1.5 or b[i] >= a[i,j]) and (i,j) in S|
 25.1538 +
 25.1539 +\noindent\verb|(i,j) in S or (i,j) not in T diff U|
 25.1540 +
 25.1541 +\subsubsection{Numeric expressions}
 25.1542 +
 25.1543 +The resultant value of the primary logical expression, which is a
 25.1544 +numeric expression, is {\it true}, if the resultant value of the
 25.1545 +numeric expression is non-zero. Otherwise the resultant value of the
 25.1546 +logical expression is {\it false}.
 25.1547 +
 25.1548 +\subsubsection{Relational operators}
 25.1549 +
 25.1550 +In MathProg there exist the following relational operators, which may
 25.1551 +be used in logical expressions:
 25.1552 +
 25.1553 +\medskip
 25.1554 +
 25.1555 +\begin{tabular}{@{}ll@{}}
 25.1556 +$x$ {\tt<} $y$&test on $x<y$\\
 25.1557 +$x$ {\tt<=} $y$&test on $x\leq y$\\
 25.1558 +$x$ {\tt=} $y$, $x$ {\tt==} $y$&test on $x=y$\\
 25.1559 +$x$ {\tt>=} $y$&test on $x\geq y$\\
 25.1560 +$x$ {\tt>} $y$&test on $x>y$\\
 25.1561 +$x$ {\tt<>} $y$, $x$ {\tt!=} $y$&test on $x\neq y$\\
 25.1562 +$x$ {\tt in} $Y$&test on $x\in Y$\\
 25.1563 +{\tt(}$x_1${\tt,}\dots{\tt,}$x_n${\tt)} {\tt in} $Y$&test on
 25.1564 +$(x_1,\dots,x_n)\in Y$\\
 25.1565 +$x$ {\tt not} {\tt in} $Y$, $x$ {\tt!in} $Y$&test on $x\not\in Y$\\
 25.1566 +{\tt(}$x_1${\tt,}\dots{\tt,}$x_n${\tt)} {\tt not} {\tt in} $Y$,
 25.1567 +{\tt(}$x_1${\tt,}\dots{\tt,}$x_n${\tt)} {\tt !in} $Y$&test on
 25.1568 +$(x_1,\dots,x_n)\not\in Y$\\
 25.1569 +$X$ {\tt within} $Y$&test on $X\subseteq Y$\\
 25.1570 +$X$ {\tt not} {\tt within} $Y$, $X$ {\tt !within} $Y$&test on
 25.1571 +$X\not\subseteq Y$\\
 25.1572 +\end{tabular}
 25.1573 +
 25.1574 +\medskip
 25.1575 +
 25.1576 +\noindent where $x$, $x_1$, \dots, $x_n$, $y$ are numeric or symbolic
 25.1577 +expressions, $X$ and $Y$ are set expression.
 25.1578 +
 25.1579 +{\it Notes:}
 25.1580 +
 25.1581 +1. In the operations {\tt in}, {\tt not in}, and {\tt !in} the
 25.1582 +number of components in the first operands must be the same as the
 25.1583 +dimension of the second operand.
 25.1584 +
 25.1585 +2. In the operations {\tt within}, {\tt not within}, and {\tt !within}
 25.1586 +both operands must have identical dimension.
 25.1587 +
 25.1588 +All the relational operators listed above have their conventional
 25.1589 +mathematical meaning. The resultant value is {\it true}, if
 25.1590 +corresponding relation is satisfied for its operands, otherwise
 25.1591 +{\it false}. (Note that symbolic values are ordered lexicographically,
 25.1592 +and any numeric value precedes any symbolic value.)
 25.1593 +
 25.1594 +\subsubsection{Iterated expressions}
 25.1595 +
 25.1596 +An {\it iterated logical expression} is a primary logical expression,
 25.1597 +which has the following syntactic form:
 25.1598 +
 25.1599 +\medskip
 25.1600 +
 25.1601 +\noindent\hfil
 25.1602 +{\it iterated-operator} {\it indexing-expression} {\it integrand}
 25.1603 +
 25.1604 +\medskip
 25.1605 +
 25.1606 +\noindent where {\it iterated-operator} is the symbolic name of the
 25.1607 +iterated operator to be performed (see below), {\it indexing-expression}
 25.1608 +is an indexing expression which introduces dummy indices and controls
 25.1609 +iterating, {\it integrand} is a numeric expression that participates in
 25.1610 +the operation.
 25.1611 +
 25.1612 +In MathProg there exist two iterated operators, which may be used in
 25.1613 +logical expressions:
 25.1614 +
 25.1615 +\medskip
 25.1616 +
 25.1617 +\noindent\hfil
 25.1618 +\begin{tabular}{@{}lll@{}}
 25.1619 +{\tt forall}&$\forall$-quantification&$\displaystyle
 25.1620 +\forall(i_1,\dots,i_n)\in\Delta[f(i_1,\dots,i_n)],$\\
 25.1621 +{\tt exists}&$\exists$-quantification&$\displaystyle
 25.1622 +\exists(i_1,\dots,i_n)\in\Delta[f(i_1,\dots,i_n)],$\\
 25.1623 +\end{tabular}
 25.1624 +
 25.1625 +\medskip
 25.1626 +
 25.1627 +\noindent where $i_1$, \dots, $i_n$ are dummy indices introduced in
 25.1628 +the indexing expression, $\Delta$ is the domain, a set of $n$-tuples
 25.1629 +specified by the indexing expression which defines particular values
 25.1630 +assigned to the dummy indices on performing the iterated operation,
 25.1631 +$f(i_1,\dots,i_n)$ is the integrand, a logical expression whose
 25.1632 +resultant value depends on the dummy indices.
 25.1633 +
 25.1634 +For $\forall$-quantification the resultant value of the iterated
 25.1635 +logical expression is {\it true}, if the value of the integrand is
 25.1636 +{\it true} for all $n$-tuples contained in the domain, otherwise
 25.1637 +{\it false}.
 25.1638 +
 25.1639 +For $\exists$-quantification the resultant value of the iterated
 25.1640 +logical expression is {\it false}, if the value of the integrand is
 25.1641 +{\it false} for all $n$-tuples contained in the domain, otherwise
 25.1642 +{\it true}.
 25.1643 +
 25.1644 +\subsubsection{Parenthesized expressions}
 25.1645 +
 25.1646 +Any logical expression may be enclosed in parentheses that
 25.1647 +syntactically makes it a primary logical expression.
 25.1648 +
 25.1649 +Parentheses may be used in logical expressions, as in algebra, to
 25.1650 +specify the desired order in which operations are to be performed.
 25.1651 +Where parentheses are used, the expression within the parentheses is
 25.1652 +evaluated before the resultant value is used.
 25.1653 +
 25.1654 +The resultant value of the parenthesized expression is the same as the
 25.1655 +value of the expression enclosed within parentheses.
 25.1656 +
 25.1657 +\subsubsection{Logical operators}
 25.1658 +
 25.1659 +In MathProg there exist the following logical operators, which may be
 25.1660 +used in logical expressions:
 25.1661 +
 25.1662 +\medskip
 25.1663 +
 25.1664 +\begin{tabular}{@{}p{96pt}p{222pt}@{}}
 25.1665 +{\tt not} $x$, {\tt!}$x$&negation $\neg\ x$\\
 25.1666 +$x$ {\tt and} $y$, $x$ {\tt\&\&} $y$&conjunction (logical ``and'')
 25.1667 +$x\;\&\;y$\\
 25.1668 +$x$ {\tt or} $y$, $x$ {\tt||} $y$&disjunction (logical ``or'')
 25.1669 +$x\vee y$\\
 25.1670 +\end{tabular}
 25.1671 +
 25.1672 +\medskip
 25.1673 +
 25.1674 +\noindent where $x$ and $y$ are logical expressions.
 25.1675 +
 25.1676 +If the expression includes more than one logical operator, all
 25.1677 +operators are performed from left to right according to the hierarchy
 25.1678 +of the operations (see below). The resultant value of the expression,
 25.1679 +which contains logical operators, is the result of applying the
 25.1680 +operators to their operands.
 25.1681 +
 25.1682 +\subsubsection{Hierarchy of operations}
 25.1683 +
 25.1684 +The following list shows the hierarchy of operations in logical
 25.1685 +expressions:
 25.1686 +
 25.1687 +\medskip
 25.1688 +
 25.1689 +\noindent\hfil
 25.1690 +\begin{tabular}{@{}ll@{}}
 25.1691 +Operation&Hierarchy\\
 25.1692 +\hline
 25.1693 +Evaluation of numeric operations&1st-7th\\
 25.1694 +Evaluation of symbolic operations&8th-9th\\
 25.1695 +Evaluation of set operations&10th-14th\\
 25.1696 +Relational operations ({\tt<}, {\tt<=}, etc.)&15th\\
 25.1697 +Negation ({\tt not}, {\tt!})&16th\\
 25.1698 +Conjunction ({\tt and}, {\tt\&\&})&17th\\
 25.1699 +$\forall$- and $\exists$-quantification ({\tt forall}, {\tt exists})&
 25.1700 +18th\\
 25.1701 +Disjunction ({\tt or}, {\tt||})&19th\\
 25.1702 +\end{tabular}
 25.1703 +
 25.1704 +\medskip
 25.1705 +
 25.1706 +This hierarchy has the same meaning as was explained above for numeric
 25.1707 +expressions (see Subsection \ref{hierarchy}, page \pageref{hierarchy}).
 25.1708 +
 25.1709 +\subsection{Linear expressions}
 25.1710 +
 25.1711 +An {\it linear expression} is a rule for computing so called
 25.1712 +a {\it linear form} or simply a {\it formula}, which is a linear (or
 25.1713 +affine) function of elemental variables.
 25.1714 +
 25.1715 +The primary linear expression may be an unsubscripted variable,
 25.1716 +subscripted variable, iterated linear expression, conditional linear
 25.1717 +expression, or another linear expression enclosed in parentheses.
 25.1718 +
 25.1719 +It is also allowed to use a numeric expression as the primary linear
 25.1720 +expression, in which case the resultant value of the numeric expression
 25.1721 +is automatically converted to a formula that includes the constant term
 25.1722 +only.
 25.1723 +
 25.1724 +\medskip
 25.1725 +
 25.1726 +\noindent{\bf Examples}
 25.1727 +
 25.1728 +\medskip
 25.1729 +
 25.1730 +\noindent
 25.1731 +\begin{tabular}{@{}ll@{}}
 25.1732 +\verb|z|&(unsubscripted variable)\\
 25.1733 +\verb|x[i,j]|&(subscripted variable)\\
 25.1734 +\verb|sum{j in J} (a[i] * x[i,j] + 3 * y)|&(iterated expression)\\
 25.1735 +\verb|if i in I then x[i,j] else 1.5 * z + 3|&(conditional expression)\\
 25.1736 +\verb|(a[i,j] * x[i,j] + y[i-1] + .1)|&(parenthesized expression)\\
 25.1737 +\end{tabular}
 25.1738 +
 25.1739 +\medskip
 25.1740 +
 25.1741 +More general linear expressions containing two or more primary linear
 25.1742 +expressions may be constructed by using certain arithmetic operators.
 25.1743 +
 25.1744 +\medskip
 25.1745 +
 25.1746 +\noindent{\bf Examples}
 25.1747 +
 25.1748 +\medskip
 25.1749 +
 25.1750 +\noindent\verb|2 * x[i-1,j+1] + 3.5 * y[k] + .5 * z|
 25.1751 +
 25.1752 +\noindent\verb|(- x[i,j] + 3.5 * y[k]) / sum{t in T} abs(d[i,j,t])|
 25.1753 +
 25.1754 +\subsubsection{Unsubscripted variables}
 25.1755 +
 25.1756 +If the primary linear expression is an unsubscripted variable (which
 25.1757 +must be 0-dimensional), the resultant formula is that unsubscripted
 25.1758 +variable.
 25.1759 +
 25.1760 +\subsubsection{Subscripted variables}
 25.1761 +
 25.1762 +The primary linear expression, which refers to a subscripted variable,
 25.1763 +has the following syntactic form:
 25.1764 +
 25.1765 +\medskip
 25.1766 +
 25.1767 +\noindent\hfil
 25.1768 +{\it name}{\tt[}$i_1${\tt,} $i_2${\tt,} \dots{\tt,} $i_n${\tt]}
 25.1769 +
 25.1770 +\medskip
 25.1771 +
 25.1772 +\noindent where {\it name} is the symbolic name of the model variable,
 25.1773 +$i_1$, $i_2$, \dots, $i_n$ are subscripts.
 25.1774 +
 25.1775 +Each subscript must be a numeric or symbolic expression. The number of
 25.1776 +subscripts in the subscript list must be the same as the dimension of
 25.1777 +the model variable with which the subscript list is associated.
 25.1778 +
 25.1779 +Actual values of the subscript expressions are used to identify a
 25.1780 +particular member of the model variable that determines the resultant
 25.1781 +formula, which is an elemental variable associated with corresponding
 25.1782 +member.
 25.1783 +
 25.1784 +\subsubsection{Iterated expressions}
 25.1785 +
 25.1786 +An {\it iterated linear expression} is a primary linear expression,
 25.1787 +which has the following syntactic form:
 25.1788 +
 25.1789 +\medskip
 25.1790 +
 25.1791 +\noindent\hfil
 25.1792 +{\tt sum} {\it indexing-expression} {\it integrand}
 25.1793 +
 25.1794 +\medskip
 25.1795 +
 25.1796 +\noindent where {\it indexing-expression} is an indexing expression,
 25.1797 +which introduces dummy indices and controls iterating, {\it integrand}
 25.1798 +is a linear expression that participates in the operation.
 25.1799 +
 25.1800 +The iterated linear expression is evaluated exactly in the same way as
 25.1801 +the iterated numeric expression (see Subection \ref{itexpr}, page
 25.1802 +\pageref{itexpr}) with exception that the integrand participated in the
 25.1803 +summation is a formula, not a numeric value.
 25.1804 +
 25.1805 +\subsubsection{Conditional expressions}
 25.1806 +
 25.1807 +A {\it conditional linear expression} is a primary linear expression,
 25.1808 +which has one of the following two syntactic forms:
 25.1809 +
 25.1810 +\medskip
 25.1811 +
 25.1812 +\noindent\hfil
 25.1813 +{\tt if} $b$ {\tt then} $f$ {\tt else} $g$
 25.1814 +
 25.1815 +\medskip
 25.1816 +
 25.1817 +\noindent\hspace{127pt}
 25.1818 +{\tt if} $b$ {\tt then} $f$
 25.1819 +
 25.1820 +\medskip
 25.1821 +
 25.1822 +\noindent where $b$ is an logical expression, $f$ and $g$ are linear
 25.1823 +expressions.
 25.1824 +
 25.1825 +The conditional linear expression is evaluated exactly in the same way
 25.1826 +as the conditional numeric expression (see Subsection \ref{ifthen},
 25.1827 +page \pageref{ifthen}) with exception that operands participated in the
 25.1828 +operation are formulae, not numeric values.
 25.1829 +
 25.1830 +\subsubsection{Parenthesized expressions}
 25.1831 +
 25.1832 +Any linear expression may be enclosed in parentheses that syntactically
 25.1833 +makes it a primary linear expression.
 25.1834 +
 25.1835 +Parentheses may be used in linear expressions, as in algebra, to
 25.1836 +specify the desired order in which operations are to be performed.
 25.1837 +Where parentheses are used, the expression within the parentheses is
 25.1838 +evaluated before the resultant formula is used.
 25.1839 +
 25.1840 +The resultant value of the parenthesized expression is the same as the
 25.1841 +value of the expression enclosed within parentheses.
 25.1842 +
 25.1843 +\subsubsection{Arithmetic operators}
 25.1844 +
 25.1845 +In MathProg there exists the following arithmetic operators, which may
 25.1846 +be used in linear expressions:
 25.1847 +
 25.1848 +\medskip
 25.1849 +
 25.1850 +\begin{tabular}{@{}p{96pt}p{222pt}@{}}
 25.1851 +{\tt+} $f$&unary plus\\
 25.1852 +{\tt-} $f$&unary minus\\
 25.1853 +$f$ {\tt+} $g$&addition\\
 25.1854 +$f$ {\tt-} $g$&subtraction\\
 25.1855 +$x$ {\tt*} $f$, $f$ {\tt*} $x$&multiplication\\
 25.1856 +$f$ {\tt/} $x$&division
 25.1857 +\end{tabular}
 25.1858 +
 25.1859 +\medskip
 25.1860 +
 25.1861 +\noindent where $f$ and $g$ are linear expressions, $x$ is a numeric
 25.1862 +expression (more precisely, a linear expression containing only the
 25.1863 +constant term).
 25.1864 +
 25.1865 +If the expression includes more than one arithmetic operator, all
 25.1866 +operators are performed from left to right according to the hierarchy
 25.1867 +of operations (see below). The resultant value of the expression, which
 25.1868 +contains arithmetic operators, is the result of applying the operators
 25.1869 +to their operands.
 25.1870 +
 25.1871 +\subsubsection{Hierarchy of operations}
 25.1872 +
 25.1873 +The hierarchy of arithmetic operations used in linear expressions is
 25.1874 +the same as for numeric expressions (see Subsection \ref{hierarchy},
 25.1875 +page \pageref{hierarchy}).
 25.1876 +
 25.1877 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 25.1878 +
 25.1879 +\newpage
 25.1880 +
 25.1881 +\section{Statements}
 25.1882 +
 25.1883 +{\it Statements} are basic units of the model description. In MathProg
 25.1884 +all statements are divided into two categories: declaration statements
 25.1885 +and functional statements.
 25.1886 +
 25.1887 +{\it Declaration statements} (set statement, parameter statement,
 25.1888 +variable statement, constraint statement, and objective statement) are
 25.1889 +used to declare model objects of certain kinds and define certain
 25.1890 +properties of such objects.
 25.1891 +
 25.1892 +{\it Functional statements} (solve statement, check statement, display
 25.1893 +statement, printf statement, loop statement) are intended for
 25.1894 +performing some specific actions.
 25.1895 +
 25.1896 +Note that declaration statements may follow in arbitrary order, which
 25.1897 +does not affect the result of translation. However, any model object
 25.1898 +must be declared before it is referenced in other statements.
 25.1899 +
 25.1900 +\subsection{Set statement}
 25.1901 +
 25.1902 +\medskip
 25.1903 +
 25.1904 +\framebox[345pt][l]{
 25.1905 +\parbox[c][24pt]{345pt}{
 25.1906 +\hspace{6pt} {\tt set} {\it name} {\it alias} {\it domain} {\tt,}
 25.1907 +{\it attrib} {\tt,} \dots {\tt,} {\it attrib} {\tt;}
 25.1908 +}}
 25.1909 +
 25.1910 +\setlength{\leftmargini}{60pt}
 25.1911 +
 25.1912 +\begin{description}
 25.1913 +\item[{\rm Where:}\hspace*{23pt}] {\it name} is a symbolic name of the
 25.1914 +set;
 25.1915 +\item[\hspace*{54pt}] {\it alias} is an optional string literal, which
 25.1916 +specifies an alias of the set;
 25.1917 +\item[\hspace*{54pt}] {\it domain} is an optional indexing expression,
 25.1918 +which specifies a subscript domain of the set;
 25.1919 +\item[\hspace*{54pt}] {\it attrib}, \dots, {\it attrib} are optional
 25.1920 +attributes of the set. (Commae preceding attributes may be omitted.)
 25.1921 +\end{description}
 25.1922 +
 25.1923 +\noindent Optional attributes:
 25.1924 +
 25.1925 +\begin{description}
 25.1926 +\item[{\tt dimen} $n$\hspace*{19pt}] specifies the dimension of
 25.1927 +$n$-tuples, which the set consists of;
 25.1928 +\item[{\tt within} {\it expression}]\hspace*{0pt}\\
 25.1929 +specifies a superset which restricts the set or all its members
 25.1930 +(elemental sets) to be within that superset;
 25.1931 +\item[{\tt:=} {\it expression}]\hspace*{0pt}\\
 25.1932 +specifies an elemental set assigned to the set or its members;
 25.1933 +\item[{\tt default} {\it expression}]\hspace*{0pt}\\
 25.1934 +specifies an elemental set assigned to the set or its members whenever
 25.1935 +no appropriate data are available in the data section.
 25.1936 +\end{description}
 25.1937 +
 25.1938 +\newpage
 25.1939 +
 25.1940 +\noindent{\bf Examples}
 25.1941 +
 25.1942 +\begin{verbatim}
 25.1943 +set V;
 25.1944 +set E within V cross V;
 25.1945 +set step{s in 1..maxiter} dimen 2 := if s = 1 then E else
 25.1946 +   step[s-1] union setof{k in V, (i,k) in step[s-1], (k,j)
 25.1947 +   in step[s-1]}(i,j);
 25.1948 +set A{i in I, j in J}, within B[i+1] cross C[j-1], within
 25.1949 +   D diff E, default {('abc',123), (321,'cba')};
 25.1950 +\end{verbatim}
 25.1951 +
 25.1952 +The set statement declares a set. If the subscript domain is not
 25.1953 +specified, the set is a simple set, otherwise it is an array of
 25.1954 +elemental sets.
 25.1955 +
 25.1956 +The {\tt dimen} attribute specifies the dimension of $n$-tuples, which
 25.1957 +the set (if it is a simple set) or its members (if the set is an array
 25.1958 +of elemental sets) consist of, where $n$ must be unsigned integer from
 25.1959 +1 to 20. At most one {\tt dimen} attribute can be specified. If the
 25.1960 +{\tt dimen} attribute is not specified, the dimension of\linebreak
 25.1961 +$n$-tuples is implicitly determined by other attributes (for example,
 25.1962 +if there is a set expression that follows {\tt:=} or the keyword
 25.1963 +{\tt default}, the dimension of $n$-tuples of corresponding elemental
 25.1964 +set is used). If no dimension information is available, {\tt dimen 1}
 25.1965 +is assumed.
 25.1966 +
 25.1967 +The {\tt within} attribute specifies a set expression whose resultant
 25.1968 +value is a superset used to restrict the set (if it is a simple set) or
 25.1969 +its members (if the set is an array of elemental sets) to be within
 25.1970 +that superset. Arbitrary number of {\tt within} attributes may be
 25.1971 +specified in the same set statement.
 25.1972 +
 25.1973 +The assign ({\tt:=}) attribute specifies a set expression used to
 25.1974 +evaluate elemental set(s) assigned to the set (if it is a simple set)
 25.1975 +or its members (if the set is an array of elemental sets). If the
 25.1976 +assign attribute is specified, the set is {\it computable} and
 25.1977 +therefore needs no data to be provided in the data section. If the
 25.1978 +assign attribute is not specified, the set must be provided with data
 25.1979 +in the data section. At most one assign or default attribute can be
 25.1980 +specified for the same set.
 25.1981 +
 25.1982 +The {\tt default} attribute specifies a set expression used to evaluate
 25.1983 +elemental set(s) assigned to the set (if it is a simple set) or its
 25.1984 +members (if the set is an array of elemental sets) whenever
 25.1985 +no appropriate data are available in the data section. If neither
 25.1986 +assign nor default attribute is specified, missing data will cause an
 25.1987 +error.
 25.1988 +
 25.1989 +\subsection{Parameter statement}
 25.1990 +
 25.1991 +\medskip
 25.1992 +
 25.1993 +\framebox[345pt][l]{
 25.1994 +\parbox[c][24pt]{345pt}{
 25.1995 +\hspace{6pt} {\tt param} {\it name} {\it alias} {\it domain} {\tt,}
 25.1996 +{\it attrib} {\tt,} \dots {\tt,} {\it attrib} {\tt;}
 25.1997 +}}
 25.1998 +
 25.1999 +\setlength{\leftmargini}{60pt}
 25.2000 +
 25.2001 +\begin{description}
 25.2002 +\item[{\rm Where:}\hspace*{23pt}] {\it name} is a symbolic name of the
 25.2003 +parameter;
 25.2004 +\item[\hspace*{54pt}] {\it alias} is an optional string literal, which
 25.2005 +specifies an alias of the parameter;
 25.2006 +\item[\hspace*{54pt}] {\it domain} is an optional indexing expression,
 25.2007 +which specifies a subscript domain of the parameter;
 25.2008 +\item[\hspace*{54pt}] {\it attrib}, \dots, {\it attrib} are optional
 25.2009 +attributes of the parameter. (Commae preceding attributes may be
 25.2010 +omitted.)
 25.2011 +\end{description}
 25.2012 +
 25.2013 +\noindent Optional attributes:
 25.2014 +
 25.2015 +\begin{description}
 25.2016 +\item[{\tt integer}\hspace*{18.5pt}] specifies that the parameter is
 25.2017 +integer;
 25.2018 +\item[{\tt binary}\hspace*{24pt}] specifies that the parameter is
 25.2019 +binary;
 25.2020 +\item[{\tt symbolic}\hspace*{13.5pt}] specifies that the parameter is
 25.2021 +symbolic;
 25.2022 +\item[{\it relation expression}]\hspace*{0pt}\\
 25.2023 +(where {\it relation} is one of: {\tt<}, {\tt<=}, {\tt=}, {\tt==},
 25.2024 +{\tt>=}, {\tt>}, {\tt<>}, {\tt!=})\\
 25.2025 +specifies a condition that restricts the parameter or its members to
 25.2026 +satisfy that condition;
 25.2027 +\item[{\tt in} {\it expression}]\hspace*{0pt}\\
 25.2028 +specifies a superset that restricts the parameter or its members to be
 25.2029 +in that superset;
 25.2030 +\item[{\tt:=} {\it expression}]\hspace*{0pt}\\
 25.2031 +specifies a value assigned to the parameter or its members;
 25.2032 +\item[{\tt default} {\it expression}]\hspace*{0pt}\\
 25.2033 +specifies a value assigned to the parameter or its members whenever
 25.2034 +no appropriate data are available in the data section.
 25.2035 +\end{description}
 25.2036 +
 25.2037 +\noindent{\bf Examples}
 25.2038 +
 25.2039 +\begin{verbatim}
 25.2040 +param units{raw, prd} >= 0;
 25.2041 +param profit{prd, 1..T+1};
 25.2042 +param N := 20, integer, >= 0, <= 100;
 25.2043 +param comb 'n choose k' {n in 0..N, k in 0..n} :=
 25.2044 +   if k = 0 or k = n then 1 else comb[n-1,k-1] + comb[n-1,k];
 25.2045 +param p{i in I, j in J}, integer, >= 0, <= i+j,
 25.2046 +   in A[i] symdiff B[j], in C[i,j], default 0.5 * (i + j);
 25.2047 +param month symbolic default 'May' in {'Mar', 'Apr', 'May'};
 25.2048 +\end{verbatim}
 25.2049 +
 25.2050 +The parameter statement declares a parameter. If a subscript domain is
 25.2051 +not specified, the parameter is a simple (scalar) parameter, otherwise
 25.2052 +it is a $n$-dimensional array.
 25.2053 +
 25.2054 +The type attributes {\tt integer}, {\tt binary}, and {\tt symbolic}
 25.2055 +qualify the type of values that can be assigned to the parameter as
 25.2056 +shown below:
 25.2057 +
 25.2058 +\medskip
 25.2059 +
 25.2060 +\noindent\hfil
 25.2061 +\begin{tabular}{@{}ll@{}}
 25.2062 +Type attribute&Assigned values\\
 25.2063 +\hline
 25.2064 +(not specified)&Any numeric values\\
 25.2065 +{\tt integer}&Only integer numeric values\\
 25.2066 +{\tt binary}&Either 0 or 1\\
 25.2067 +{\tt symbolic}&Any numeric and symbolic values\\
 25.2068 +\end{tabular}
 25.2069 +
 25.2070 +\newpage
 25.2071 +
 25.2072 +The {\tt symbolic} attribute cannot be specified along with other type
 25.2073 +attributes. Being specified it must precede all other attributes.
 25.2074 +
 25.2075 +The condition attribute specifies an optional condition that restricts
 25.2076 +values assigned to the parameter to satisfy that condition. This
 25.2077 +attribute has the following syntactic forms:
 25.2078 +
 25.2079 +\medskip
 25.2080 +
 25.2081 +\begin{tabular}{@{}ll@{}}
 25.2082 +{\tt<} $v$&check for $x<v$\\
 25.2083 +{\tt<=} $v$&check for $x\leq v$\\
 25.2084 +{\tt=} $v$, {\tt==} $v$&check for $x=v$\\
 25.2085 +{\tt>=} $v$&check for $x\geq v$\\
 25.2086 +{\tt>} $v$&check for $x\geq v$\\
 25.2087 +{\tt<>} $v$, {\tt!=} $v$&check for $x\neq v$\\
 25.2088 +\end{tabular}
 25.2089 +
 25.2090 +\medskip
 25.2091 +
 25.2092 +\noindent where $x$ is a value assigned to the parameter, $v$ is the
 25.2093 +resultant value of a numeric or symbolic expression specified in the
 25.2094 +condition attribute. Arbitrary number of condition attributes can be
 25.2095 +specified for the same parameter. If a value being assigned to the
 25.2096 +parameter during model evaluation violates at least one of specified
 25.2097 +conditions, an error is raised. (Note that symbolic values are ordered
 25.2098 +lexicographically, and any numeric value precedes any symbolic value.)
 25.2099 +
 25.2100 +The {\tt in} attribute is similar to the condition attribute and
 25.2101 +specifies a set expression whose resultant value is a superset used to
 25.2102 +restrict numeric or symbolic values assigned to the parameter to be in
 25.2103 +that superset. Arbitrary number of the {\tt in} attributes can be
 25.2104 +specified for the same parameter. If a value being assigned to the
 25.2105 +parameter during model evaluation is not in at least one of specified
 25.2106 +supersets, an error is raised.
 25.2107 +
 25.2108 +The assign ({\tt:=}) attribute specifies a numeric or symbolic
 25.2109 +expression used to compute a value assigned to the parameter (if it is
 25.2110 +a simple parameter) or its member (if the parameter is an array). If
 25.2111 +the assign attribute is specified, the parameter is {\it computable}
 25.2112 +and therefore needs no data to be provided in the data section. If the
 25.2113 +assign attribute is not specified, the parameter must be provided with
 25.2114 +data in the data section. At most one assign or {\tt default} attribute
 25.2115 +can be specified for the same parameter.
 25.2116 +
 25.2117 +The {\tt default} attribute specifies a numeric or symbolic expression
 25.2118 +used to compute a value assigned to the parameter or its member
 25.2119 +whenever no appropriate data are available in the data section. If
 25.2120 +neither assign nor {\tt default} attribute is specified, missing data
 25.2121 +will cause an error.
 25.2122 +
 25.2123 +\subsection{Variable statement}
 25.2124 +
 25.2125 +\medskip
 25.2126 +
 25.2127 +\framebox[345pt][l]{
 25.2128 +\parbox[c][24pt]{345pt}{
 25.2129 +\hspace{6pt} {\tt var} {\it name} {\it alias} {\it domain} {\tt,}
 25.2130 +{\it attrib} {\tt,} \dots {\tt,} {\it attrib} {\tt;}
 25.2131 +}}
 25.2132 +
 25.2133 +\setlength{\leftmargini}{60pt}
 25.2134 +
 25.2135 +\begin{description}
 25.2136 +\item[{\rm Where:}\hspace*{23pt}] {\it name} is a symbolic name of the
 25.2137 +variable;
 25.2138 +\item[\hspace*{54pt}] {\it alias} is an optional string literal, which
 25.2139 +specifies an alias of the variable;
 25.2140 +\item[\hspace*{54pt}] {\it domain} is an optional indexing expression,
 25.2141 +which specifies a subscript domain of the variable;
 25.2142 +\item[\hspace*{54pt}] {\it attrib}, \dots, {\it attrib} are optional
 25.2143 +attributes of the variable. (Commae preceding attributes may be
 25.2144 +omitted.)
 25.2145 +\end{description}
 25.2146 +
 25.2147 +\noindent Optional attributes:
 25.2148 +
 25.2149 +\begin{description}
 25.2150 +\item[{\tt integer}\hspace*{18.5pt}] restricts the variable to be
 25.2151 +integer;
 25.2152 +\item[{\tt binary}\hspace*{24pt}] restricts the variable to be binary;
 25.2153 +\item[{\tt>=} {\it expression}]\hspace*{0pt}\\
 25.2154 +specifies an lower bound of the variable;
 25.2155 +\item[{\tt<=} {\it expression}]\hspace*{0pt}\\
 25.2156 +specifies an upper bound of the variable;
 25.2157 +\item[{\tt=} {\it expression}]\hspace*{0pt}\\
 25.2158 +specifies a fixed value of the variable;
 25.2159 +\end{description}
 25.2160 +
 25.2161 +\noindent{\bf Examples}
 25.2162 +
 25.2163 +\begin{verbatim}
 25.2164 +var x >= 0;
 25.2165 +var y{I,J};
 25.2166 +var make{p in prd}, integer, >= commit[p], <= market[p];
 25.2167 +var store{raw, 1..T+1} >= 0;
 25.2168 +var z{i in I, j in J} >= i+j;
 25.2169 +\end{verbatim}
 25.2170 +
 25.2171 +The variable statement declares a variable. If a subscript domain is
 25.2172 +not specified, the variable is a simple (scalar) variable, otherwise it
 25.2173 +is a $n$-dimensional array of elemental variables.
 25.2174 +
 25.2175 +Elemental variable(s) associated with the model variable (if it is a
 25.2176 +simple variable) or its members (if it is an array) correspond to the
 25.2177 +variables in the LP/MIP problem formulation (see Subsection
 25.2178 +\ref{problem}, page \pageref{problem}). Note that only elemental
 25.2179 +variables actually referenced in some constraints and/or objectives are
 25.2180 +included in the LP/MIP problem instance to be generated.
 25.2181 +
 25.2182 +The type attributes {\tt integer} and {\tt binary} restrict the
 25.2183 +variable to be integer or binary, respectively. If no type attribute is
 25.2184 +specified, the variable is continuous. If all variables in the model
 25.2185 +are continuous, the corresponding problem is of LP class. If there is
 25.2186 +at least one integer or binary variable, the problem is of MIP class.
 25.2187 +
 25.2188 +The lower bound ({\tt>=}) attribute specifies a numeric expression for
 25.2189 +computing an lower bound of the variable. At most one lower bound can
 25.2190 +be specified. By default all variables (except binary ones) have no
 25.2191 +lower bound, so if a variable is required to be non-negative, its zero
 25.2192 +lower bound should be explicitly specified.
 25.2193 +
 25.2194 +The upper bound ({\tt<=}) attribute specifies a numeric expression for
 25.2195 +computing an upper bound of the variable. At most one upper bound
 25.2196 +attribute can be specified.
 25.2197 +
 25.2198 +The fixed value ({\tt=}) attribute specifies a numeric expression for
 25.2199 +computing a value, at which the variable is fixed. This attribute
 25.2200 +cannot be specified along with the bound attributes.
 25.2201 +
 25.2202 +\subsection{Constraint statement}
 25.2203 +
 25.2204 +\medskip
 25.2205 +
 25.2206 +\framebox[345pt][l]{
 25.2207 +\parbox[c][96pt]{345pt}{
 25.2208 +\hspace{6pt} {\tt s.t.} {\it name} {\it alias} {\it domain} {\tt:}
 25.2209 +{\it expression} {\tt,} {\tt=} {\it expression} {\tt;}
 25.2210 +
 25.2211 +\medskip
 25.2212 +
 25.2213 +\hspace{6pt} {\tt s.t.} {\it name} {\it alias} {\it domain} {\tt:}
 25.2214 +{\it expression} {\tt,} {\tt<=} {\it expression} {\tt;}
 25.2215 +
 25.2216 +\medskip
 25.2217 +
 25.2218 +\hspace{6pt} {\tt s.t.} {\it name} {\it alias} {\it domain} {\tt:}
 25.2219 +{\it expression} {\tt,} {\tt>=} {\it expression} {\tt;}
 25.2220 +
 25.2221 +\medskip
 25.2222 +
 25.2223 +\hspace{6pt} {\tt s.t.} {\it name} {\it alias} {\it domain} {\tt:}
 25.2224 +{\it expression} {\tt,} {\tt<=} {\it expression} {\tt,} {\tt<=}
 25.2225 +{\it expression} {\tt;}
 25.2226 +
 25.2227 +\medskip
 25.2228 +
 25.2229 +\hspace{6pt} {\tt s.t.} {\it name} {\it alias} {\it domain} {\tt:}
 25.2230 +{\it expression} {\tt,} {\tt>=} {\it expression} {\tt,} {\tt>=}
 25.2231 +{\it expression} {\tt;}
 25.2232 +}}
 25.2233 +
 25.2234 +\setlength{\leftmargini}{60pt}
 25.2235 +
 25.2236 +\begin{description}
 25.2237 +\item[{\rm Where:}\hspace*{23pt}] {\it name} is a symbolic name of the
 25.2238 +constraint;
 25.2239 +\item[\hspace*{54pt}] {\it alias} is an optional string literal, which
 25.2240 +specifies an alias of the constraint;
 25.2241 +\item[\hspace*{54pt}] {\it domain} is an optional indexing expression,
 25.2242 +which specifies a subscript domain of the constraint;
 25.2243 +\item[\hspace*{54pt}] {\it expression} is a linear expression used to
 25.2244 +compute a component of the constraint. (Commae following expressions
 25.2245 +may be omitted.)
 25.2246 +\end{description}
 25.2247 +
 25.2248 +\begin{description}
 25.2249 +\item[{\rm Note:}\hspace*{31pt}] The keyword {\tt s.t.} may be written
 25.2250 +as {\tt subject to} or as {\tt subj to}, or may be omitted at all.
 25.2251 +\end{description}
 25.2252 +
 25.2253 +\noindent{\bf Examples}
 25.2254 +
 25.2255 +\begin{verbatim}
 25.2256 +s.t. r: x + y + z, >= 0, <= 1;
 25.2257 +limit{t in 1..T}: sum{j in prd} make[j,t] <= max_prd;
 25.2258 +subject to balance{i in raw, t in 1..T}: store[i,t+1] -
 25.2259 +   store[i,t] - sum{j in prd} units[i,j] * make[j,t];
 25.2260 +subject to rlim 'regular-time limit' {t in time}:
 25.2261 +sum{p in prd} pt[p] * rprd[p,t] <= 1.3 * dpp[t] * crews[t];
 25.2262 +\end{verbatim}
 25.2263 +
 25.2264 +The constraint statement declares a constraint. If a subscript domain
 25.2265 +is not specified, the constraint is a simple (scalar) constraint,
 25.2266 +otherwise it is a $n$-dimensional array of elemental constraints.
 25.2267 +
 25.2268 +Elemental constraint(s) associated with the model constraint (if it is
 25.2269 +a simple constraint) or its members (if it is an array) correspond to
 25.2270 +the linear constraints in the LP/MIP problem formulation (see
 25.2271 +Subsection \ref{problem}, page \pageref{problem}).
 25.2272 +
 25.2273 +If the constraint has the form of equality or single inequality, i.e.
 25.2274 +includes two expressions, one of which follows the colon and other
 25.2275 +follows the relation sign {\tt=}, {\tt<=}, or {\tt>=}, both expressions
 25.2276 +in the statement can be linear expressions. If the constraint has the
 25.2277 +form of double inequality, i.e. includes three expressions, the middle
 25.2278 +expression can be a linear expression while the leftmost and rightmost
 25.2279 +ones can be only numeric expressions.
 25.2280 +
 25.2281 +Generating the model is, roughly speaking, generating its constraints,
 25.2282 +which are always evaluated for the entire subscript domain. Evaluation
 25.2283 +of the constraints leads, in turn, to evaluation of other model objects
 25.2284 +such as sets, parameters, and variables.
 25.2285 +
 25.2286 +Constructing an actual linear constraint included in the problem
 25.2287 +instance, which (constraint) corresponds to a particular elemental
 25.2288 +constraint, is performed as follows.
 25.2289 +
 25.2290 +If the constraint has the form of equality or single inequality,
 25.2291 +evaluation of both linear expressions gives two resultant linear forms:
 25.2292 +$$\begin{array}{r@{\ }c@{\ }r@{\ }c@{\ }r@{\ }c@{\ }r@{\ }c@{\ }r}
 25.2293 +f&=&a_1x_1&+&a_2x_2&+\dots+&a_nx_n&+&a_0,\\
 25.2294 +g&=&b_1x_1&+&a_2x_2&+\dots+&a_nx_n&+&b_0,\\
 25.2295 +\end{array}$$
 25.2296 +where $x_1$, $x_2$, \dots, $x_n$ are elemental variables; $a_1$, $a_2$,
 25.2297 +\dots, $a_n$, $b_1$, $b_2$, \dots, $b_n$ are numeric coefficients;
 25.2298 +$a_0$ and $b_0$ are constant terms. Then all linear terms of $f$ and
 25.2299 +$g$ are carried to the left-hand side, and the constant terms are
 25.2300 +carried to the right-hand side, that gives the final elemental
 25.2301 +constraint in the standard form:
 25.2302 +$$(a_1-b_1)x_1+(a_2-b_2)x_2+\dots+(a_n-b_n)x_n\left\{
 25.2303 +\begin{array}{@{}c@{}}=\\\leq\\\geq\\\end{array}\right\}b_0-a_0.$$
 25.2304 +
 25.2305 +If the constraint has the form of double inequality, evaluation of the
 25.2306 +middle linear expression gives the resultant linear form:
 25.2307 +$$f=a_1x_1+a_2x_2+\dots+a_nx_n+a_0,$$
 25.2308 +and evaluation of the leftmost and rightmost numeric expressions gives
 25.2309 +two numeric values $l$ and $u$, respectively. Then the constant term of
 25.2310 +the linear form is carried to both left-hand and right-handsides that
 25.2311 +gives the final elemental constraint in the standard form:
 25.2312 +$$l-a_0\leq a_1x_1+a_2x_2+\dots+a_nx_n\leq u-a_0.$$
 25.2313 +
 25.2314 +\subsection{Objective statement}
 25.2315 +
 25.2316 +\medskip
 25.2317 +
 25.2318 +\framebox[345pt][l]{
 25.2319 +\parbox[c][44pt]{345pt}{
 25.2320 +\hspace{6pt} {\tt minimize} {\it name} {\it alias} {\it domain} {\tt:}
 25.2321 +{\it expression} {\tt;}
 25.2322 +
 25.2323 +\medskip
 25.2324 +
 25.2325 +\hspace{6pt} {\tt maximize} {\it name} {\it alias} {\it domain} {\tt:}
 25.2326 +{\it expression} {\tt;}
 25.2327 +}}
 25.2328 +
 25.2329 +\setlength{\leftmargini}{60pt}
 25.2330 +
 25.2331 +\begin{description}
 25.2332 +\item[{\rm Where:}\hspace*{23pt}] {\it name} is a symbolic name of the
 25.2333 +objective;
 25.2334 +\item[\hspace*{54pt}] {\it alias} is an optional string literal, which
 25.2335 +specifies an alias of the objective;
 25.2336 +\item[\hspace*{54pt}] {\it domain} is an optional indexing expression,
 25.2337 +which specifies a subscript domain of the objective;
 25.2338 +\item[\hspace*{54pt}] {\it expression} is a linear expression used to
 25.2339 +compute the linear form of the objective.
 25.2340 +\end{description}
 25.2341 +
 25.2342 +\noindent{\bf Examples}
 25.2343 +
 25.2344 +\begin{verbatim}
 25.2345 +minimize obj: x + 1.5 * (y + z);
 25.2346 +maximize total_profit: sum{p in prd} profit[p] * make[p];
 25.2347 +\end{verbatim}
 25.2348 +
 25.2349 +The objective statement declares an objective. If a subscript domain is
 25.2350 +not specified, the objective is a simple (scalar) objective. Otherwise
 25.2351 +it is a $n$-dimensional array of elemental objectives.
 25.2352 +
 25.2353 +Elemental objective(s) associated with the model objective (if it is a
 25.2354 +simple objective) or its members (if it is an array) correspond to
 25.2355 +general linear constraints in the LP/MIP problem formulation (see
 25.2356 +Subsection \ref{problem}, page \pageref{problem}). However, unlike
 25.2357 +constraints the corresponding linear forms are free (unbounded).
 25.2358 +
 25.2359 +Constructing an actual linear constraint included in the problem
 25.2360 +instance, which (constraint) corresponds to a particular elemental
 25.2361 +constraint, is performed as follows. The linear expression specified in
 25.2362 +the objective statement is evaluated that, gives the resultant linear
 25.2363 +form:
 25.2364 +$$f=a_1x_1+a_2x_2+\dots+a_nx_n+a_0,$$
 25.2365 +where $x_1$, $x_2$, \dots, $x_n$ are elemental variables; $a_1$, $a_2$,
 25.2366 +\dots, $a_n$ are numeric coefficients; $a_0$ is the constant term. Then
 25.2367 +the linear form is used to construct the final elemental constraint in
 25.2368 +the standard form:
 25.2369 +$$-\infty<a_1x_1+a_2x_2+\dots+a_nx_n+a_0<+\infty.$$
 25.2370 +
 25.2371 +As a rule the model description contains only one objective statement
 25.2372 +that defines the objective function used in the problem instance.
 25.2373 +However, it is allowed to declare arbitrary number of objectives, in
 25.2374 +which case the actual objective function is the first objective
 25.2375 +encountered in the model description. Other objectives are also
 25.2376 +included in the problem instance, but they do not affect the objective
 25.2377 +function.
 25.2378 +
 25.2379 +\subsection{Solve statement}
 25.2380 +
 25.2381 +\medskip
 25.2382 +
 25.2383 +\framebox[345pt][l]{
 25.2384 +\parbox[c][24pt]{345pt}{
 25.2385 +\hspace{6pt} {\tt solve} {\tt;}
 25.2386 +}}
 25.2387 +
 25.2388 +\setlength{\leftmargini}{60pt}
 25.2389 +
 25.2390 +\begin{description}
 25.2391 +\item[{\rm Note:}\hspace*{31pt}] The solve statement is optional and
 25.2392 +can be used only once. If no solve statement is used, one is assumed at
 25.2393 +the end of the model section.
 25.2394 +\end{description}
 25.2395 +
 25.2396 +The solve statement causes the model to be solved, that means computing
 25.2397 +numeric values of all model variables. This allows using variables in
 25.2398 +statements below the solve statement in the same way as if they were
 25.2399 +numeric parameters.
 25.2400 +
 25.2401 +Note that the variable, constraint, and objective statements cannot be
 25.2402 +used below the solve statement, i.e. all principal components of the
 25.2403 +model must be declared above the solve statement.
 25.2404 +
 25.2405 +\subsection{Check statement}
 25.2406 +
 25.2407 +\medskip
 25.2408 +
 25.2409 +\framebox[345pt][l]{
 25.2410 +\parbox[c][24pt]{345pt}{
 25.2411 +\hspace{6pt} {\tt check} {\it domain} {\tt:} {\it expression} {\tt;}
 25.2412 +}}
 25.2413 +
 25.2414 +\setlength{\leftmargini}{60pt}
 25.2415 +
 25.2416 +\begin{description}
 25.2417 +\item[{\rm Where:}\hspace*{23pt}] {\it domain} is an optional indexing
 25.2418 +expression, which specifies a subscript domain of the check statement;
 25.2419 +\item[\hspace*{54pt}] {\it expression} is an logical expression which
 25.2420 +specifies the logical condition to be checked. (The colon preceding
 25.2421 +{\it expression} may be omitted.)
 25.2422 +\end{description}
 25.2423 +
 25.2424 +\noindent{\bf Examples}
 25.2425 +
 25.2426 +\begin{verbatim}
 25.2427 +check: x + y <= 1 and x >= 0 and y >= 0;
 25.2428 +check sum{i in ORIG} supply[i] = sum{j in DEST} demand[j];
 25.2429 +check{i in I, j in 1..10}: S[i,j] in U[i] union V[j];
 25.2430 +\end{verbatim}
 25.2431 +
 25.2432 +The check statement allows checking the resultant value of an logical
 25.2433 +expression specified in the statement. If the value is {\it false}, an
 25.2434 +error is reported.
 25.2435 +
 25.2436 +If the subscript domain is not specified, the check is performed only
 25.2437 +once. Specifying the subscript domain allows performing multiple checks
 25.2438 +for every\linebreak $n$-tuple in the domain set. In the latter case the
 25.2439 +logical expression may include dummy indices introduced in
 25.2440 +corresponding indexing expression.
 25.2441 +
 25.2442 +\subsection{Display statement}
 25.2443 +
 25.2444 +\medskip
 25.2445 +
 25.2446 +\framebox[345pt][l]{
 25.2447 +\parbox[c][24pt]{345pt}{
 25.2448 +\hspace{6pt} {\tt display} {\it domain} {\tt:} {\it item} {\tt,}
 25.2449 +\dots {\tt,} {\it item} {\tt;}
 25.2450 +}}
 25.2451 +
 25.2452 +\setlength{\leftmargini}{60pt}
 25.2453 +
 25.2454 +\begin{description}
 25.2455 +\item[{\rm Where:}\hspace*{23pt}] {\it domain} is an optional indexing
 25.2456 +expression, which specifies a subscript domain of the check statement;
 25.2457 +\item[\hspace*{54pt}] {\it item}, \dots, {\it item} are items to be
 25.2458 +displayed. (The colon preceding the first item may be omitted.)
 25.2459 +\end{description}
 25.2460 +
 25.2461 +\noindent{\bf Examples}
 25.2462 +
 25.2463 +\begin{verbatim}
 25.2464 +display: 'x =', x, 'y =', y, 'z =', z;
 25.2465 +display sqrt(x ** 2 + y ** 2 + z ** 2);
 25.2466 +display{i in I, j in J}: i, j, a[i,j], b[i,j];
 25.2467 +\end{verbatim}
 25.2468 +
 25.2469 +\newpage
 25.2470 +
 25.2471 +The display statement evaluates all items specified in the statement
 25.2472 +and writes their values to the terminal in plain text format.
 25.2473 +
 25.2474 +If a subscript domain is not specified, items are evaluated and then
 25.2475 +displayed only once. Specifying the subscript domain causes items to be
 25.2476 +evaluated and displayed for every $n$-tuple in the domain set. In the
 25.2477 +latter case items may include dummy indices introduced in corresponding
 25.2478 +indexing expression.
 25.2479 +
 25.2480 +An item to be displayed can be a model object (set, parameter, variable,
 25.2481 +constraint, objective) or an expression.
 25.2482 +
 25.2483 +If the item is a computable object (i.e. a set or parameter provided
 25.2484 +with the assign attribute), the object is evaluated over the entire
 25.2485 +domain and then its content (i.e. the content of the object array) is
 25.2486 +displayed. Otherwise, if the item is not a computable object, only its
 25.2487 +current content (i.e. members actually generated during the model
 25.2488 +evaluation) is displayed.
 25.2489 +
 25.2490 +If the item is an expression, the expression is evaluated and its
 25.2491 +resultant value is displayed.
 25.2492 +
 25.2493 +\subsection{Printf statement}
 25.2494 +
 25.2495 +\medskip
 25.2496 +
 25.2497 +\framebox[345pt][l]{
 25.2498 +\parbox[c][60pt]{345pt}{
 25.2499 +\hspace{6pt} {\tt printf} {\it domain} {\tt:} {\it format} {\tt,}
 25.2500 +{\it expression} {\tt,} \dots {\tt,} {\it expression} {\tt;}
 25.2501 +
 25.2502 +\medskip
 25.2503 +
 25.2504 +\hspace{6pt} {\tt printf} {\it domain} {\tt:} {\it format} {\tt,}
 25.2505 +{\it expression} {\tt,} \dots {\tt,} {\it expression} {\tt>}
 25.2506 +{\it filename} {\tt;}
 25.2507 +
 25.2508 +\medskip
 25.2509 +
 25.2510 +\hspace{6pt} {\tt printf} {\it domain} {\tt:} {\it format} {\tt,}
 25.2511 +{\it expression} {\tt,} \dots {\tt,} {\it expression} {\tt>>}
 25.2512 +{\it filename} {\tt;}
 25.2513 +}}
 25.2514 +
 25.2515 +\setlength{\leftmargini}{60pt}
 25.2516 +
 25.2517 +\begin{description}
 25.2518 +\item[{\rm Where:}\hspace*{23pt}] {\it domain} is an optional indexing
 25.2519 +expression, which specifies a subscript domain of the printf statement;
 25.2520 +\item[\hspace*{54pt}] {\it format} is a symbolic expression whose value
 25.2521 +specifies a format control string. (The colon preceding the format
 25.2522 +expression may be omitted.)
 25.2523 +\item[\hspace*{54pt}] {\it expression}, \dots, {\it expression} are
 25.2524 +zero or more expressions whose values have to be formatted and printed.
 25.2525 +Each expression must be of numeric, symbolic, or logical type.
 25.2526 +\item[\hspace*{54pt}] {\it filename} is a symbolic expression whose
 25.2527 +value specifies a name of a text file, to which the output is
 25.2528 +redirected. The flag {\tt>} means creating a new empty file while the
 25.2529 +flag {\tt>>} means appending the output to an existing file. If no file
 25.2530 +name is specified, the output is written to the terminal.
 25.2531 +\end{description}
 25.2532 +
 25.2533 +\noindent{\bf Examples}
 25.2534 +
 25.2535 +\begin{verbatim}
 25.2536 +printf 'Hello, world!\n';
 25.2537 +printf: "x = %.3f; y = %.3f; z = %.3f\n",
 25.2538 +   x, y, z > "result.txt";
 25.2539 +printf{i in I, j in J}: "flow from %s to %s is %d\n",
 25.2540 +   i, j, x[i,j] >> result_file & ".txt";
 25.2541 +\end{verbatim}
 25.2542 +
 25.2543 +\newpage
 25.2544 +
 25.2545 +\begin{verbatim}
 25.2546 +printf{i in I} 'total flow from %s is %g\n',
 25.2547 +   i, sum{j in J} x[i,j];
 25.2548 +printf{k in K} "x[%s] = " & (if x[k] < 0 then "?" else "%g"),
 25.2549 +   k, x[k];
 25.2550 +\end{verbatim}
 25.2551 +
 25.2552 +The printf statement is similar to the display statement, however, it
 25.2553 +allows formatting data to be written.
 25.2554 +
 25.2555 +If a subscript domain is not specified, the printf statement is
 25.2556 +executed only once. Specifying a subscript domain causes executing the
 25.2557 +printf statement for every $n$-tuple in the domain set. In the latter
 25.2558 +case the format and expression may include dummy indices introduced in
 25.2559 +corresponding indexing expression.
 25.2560 +
 25.2561 +The format control string is a value of the symbolic expression
 25.2562 +{\it format} specified in the printf statement. It is composed of zero
 25.2563 +or more directives as follows: ordinary characters (not {\tt\%}), which
 25.2564 +are copied unchanged to the output stream, and conversion
 25.2565 +specifications, each of which causes evaluating corresponding
 25.2566 +expression specified in the printf statement, formatting it, and
 25.2567 +writing its resultant value to the output stream.
 25.2568 +
 25.2569 +Conversion specifications that may be used in the format control string
 25.2570 +are the following: {\tt d}, {\tt i}, {\tt f}, {\tt F}, {\tt e}, {\tt E},
 25.2571 +{\tt g}, {\tt G}, and {\tt s}. These specifications have the same
 25.2572 +syntax and semantics as in the C programming language.
 25.2573 +
 25.2574 +\subsection{For statement}
 25.2575 +
 25.2576 +\medskip
 25.2577 +
 25.2578 +\framebox[345pt][l]{
 25.2579 +\parbox[c][44pt]{345pt}{
 25.2580 +\hspace{6pt} {\tt for} {\it domain} {\tt:} {\it statement} {\tt;}
 25.2581 +
 25.2582 +\medskip
 25.2583 +
 25.2584 +\hspace{6pt} {\tt for} {\it domain} {\tt:} {\tt\{} {\it statement}
 25.2585 +\dots {\it statement} {\tt\}} {\tt;}
 25.2586 +}}
 25.2587 +
 25.2588 +\setlength{\leftmargini}{60pt}
 25.2589 +
 25.2590 +\begin{description}
 25.2591 +\item[{\rm Where:}\hspace*{23pt}] {\it domain} is an indexing
 25.2592 +expression which specifies a subscript domain of the for statement.
 25.2593 +(The colon following the indexing expression may be omitted.)
 25.2594 +\item[\hspace*{54pt}] {\it statement} is a statement, which should be
 25.2595 +executed under control of the for statement;
 25.2596 +\item[\hspace*{54pt}] {\it statement}, \dots, {\it statement} is a
 25.2597 +sequence of statements (enclosed in curly braces), which should be
 25.2598 +executed under control of the for statement.
 25.2599 +\end{description}
 25.2600 +
 25.2601 +\begin{description}
 25.2602 +\item[{\rm Note:}\hspace*{31pt}] Only the following statements can be
 25.2603 +used within the for statement: check, display, printf, and another for.
 25.2604 +\end{description}
 25.2605 +
 25.2606 +\noindent{\bf Examples}
 25.2607 +
 25.2608 +\begin{verbatim}
 25.2609 +for {(i,j) in E: i != j}
 25.2610 +{  printf "flow from %s to %s is %g\n", i, j, x[i,j];
 25.2611 +   check x[i,j] >= 0;
 25.2612 +}
 25.2613 +\end{verbatim}
 25.2614 +
 25.2615 +\newpage
 25.2616 +
 25.2617 +\begin{verbatim}
 25.2618 +for {i in 1..n}
 25.2619 +{  for {j in 1..n} printf " %s", if x[i,j] then "Q" else ".";
 25.2620 +   printf("\n");
 25.2621 +}
 25.2622 +for {1..72} printf("*");
 25.2623 +\end{verbatim}
 25.2624 +
 25.2625 +The for statement causes a statement or a sequence of statements
 25.2626 +specified as part of the for statement to be executed for every
 25.2627 +$n$-tuple in the domain set. Thus, statements within the for statement
 25.2628 +may include dummy indices introduced in corresponding indexing
 25.2629 +expression.
 25.2630 +
 25.2631 +\subsection{Table statement}
 25.2632 +
 25.2633 +\medskip
 25.2634 +
 25.2635 +\framebox[345pt][l]{
 25.2636 +\parbox[c][68pt]{345pt}{
 25.2637 +\hspace{6pt} {\tt table} {\it name} {\it alias} {\tt IN} {\it driver}
 25.2638 +{\it arg} \dots {\it arg} {\tt:}
 25.2639 +
 25.2640 +\hspace{6pt} {\tt\ \ \ \ \ } {\it set} {\tt<-} {\tt[} {\it fld} {\tt,}
 25.2641 +\dots {\tt,} {\it fld} {\tt]} {\tt,} {\it par} {\tt\textasciitilde}
 25.2642 +{\it fld} {\tt,} \dots {\tt,} {\it par} {\tt\textasciitilde} {\it fld}
 25.2643 +{\tt;}
 25.2644 +
 25.2645 +\medskip
 25.2646 +
 25.2647 +\hspace{6pt} {\tt table} {\it name} {\it alias} {\it domain} {\tt OUT}
 25.2648 +{\it driver} {\it arg} \dots {\it arg} {\tt:}
 25.2649 +
 25.2650 +\hspace{6pt} {\tt\ \ \ \ \ } {\it expr} {\tt\textasciitilde} {\it fld}
 25.2651 +{\tt,} \dots {\tt,} {\it expr} {\tt\textasciitilde} {\it fld} {\tt;}
 25.2652 +}}
 25.2653 +
 25.2654 +\setlength{\leftmargini}{60pt}
 25.2655 +
 25.2656 +\begin{description}
 25.2657 +\item[{\rm Where:}\hspace*{23pt}] {\it name} is a symbolic name of the
 25.2658 +table;
 25.2659 +\item[\hspace*{54pt}] {\it alias} is an optional string literal, which
 25.2660 +specifies an alias of the table;
 25.2661 +\item[\hspace*{54pt}] {\it domain} is an indexing expression, which
 25.2662 +specifies a subscript domain of the (output) table;
 25.2663 +\item[\hspace*{54pt}] {\tt IN} means reading data from the input table;
 25.2664 +\item[\hspace*{54pt}] {\tt OUT} means writing data to the output table;
 25.2665 +\item[\hspace*{54pt}] {\it driver} is a symbolic expression, which
 25.2666 +specifies the driver used to access the table (for details see Section
 25.2667 +\ref{drivers}, page \pageref{drivers});
 25.2668 +\item[\hspace*{54pt}] {\it arg} is an optional symbolic expression,
 25.2669 +which is an argument pass\-ed to the table driver. This symbolic
 25.2670 +expression must not include dummy indices specified in the domain;
 25.2671 +\item[\hspace*{54pt}] {\it set} is the name of an optional simple set
 25.2672 +called {\it control set}. It can be omitted along with the delimiter
 25.2673 +{\tt<-};
 25.2674 +\item[\hspace*{54pt}] {\it fld} is a field name. Within square brackets
 25.2675 +at least one field should be specified. The field name following
 25.2676 +a parameter name or expression is optional and can be omitted along
 25.2677 +with the delimiter {\tt\textasciitilde}, in which case the name of
 25.2678 +corresponding model object is used as the field name;
 25.2679 +\item[\hspace*{54pt}] {\it par} is a symbolic name of a model parameter;
 25.2680 +\item[\hspace*{54pt}] {\it expr} is a numeric or symbolic expression.
 25.2681 +\end{description}
 25.2682 +
 25.2683 +\newpage
 25.2684 +
 25.2685 +\noindent{\bf Examples}
 25.2686 +
 25.2687 +\begin{verbatim}
 25.2688 +table data IN "CSV" "data.csv":
 25.2689 +   S <- [FROM,TO], d~DISTANCE, c~COST;
 25.2690 +table result{(f,t) in S} OUT "CSV" "result.csv":
 25.2691 +   f~FROM, t~TO, x[f,t]~FLOW;
 25.2692 +\end{verbatim}
 25.2693 +
 25.2694 +The table statement allows reading data from a table into model
 25.2695 +objects such as sets and (non-scalar) parameters as well as writing
 25.2696 +data from the model to a table.
 25.2697 +
 25.2698 +\subsubsection{Table structure}
 25.2699 +
 25.2700 +A {\it data table} is an (unordered) set of {\it records}, where each
 25.2701 +record consists of the same number of {\it fields}, and each field is
 25.2702 +provided with a unique symbolic name called the {\it field name}. For
 25.2703 +example:
 25.2704 +
 25.2705 +\bigskip
 25.2706 +
 25.2707 +\begin{tabular}{@{\hspace*{38mm}}c@{\hspace*{11mm}}c@{\hspace*{10mm}}c
 25.2708 +@{\hspace*{9mm}}c}
 25.2709 +First&Second&&Last\\
 25.2710 +field&field&.\ \ .\ \ .&field\\
 25.2711 +$\downarrow$&$\downarrow$&&$\downarrow$\\
 25.2712 +\end{tabular}
 25.2713 +
 25.2714 +\begin{tabular}{ll@{}}
 25.2715 +Table header&$\rightarrow$\\
 25.2716 +First record&$\rightarrow$\\
 25.2717 +Second record&$\rightarrow$\\
 25.2718 +\\
 25.2719 +\hfil .\ \ .\ \ .\\
 25.2720 +\\
 25.2721 +Last record&$\rightarrow$\\
 25.2722 +\end{tabular}
 25.2723 +\begin{tabular}{|l|l|c|c|}
 25.2724 +\hline
 25.2725 +{\tt FROM}&{\tt TO}&{\tt DISTANCE}&{\tt COST}\\
 25.2726 +\hline
 25.2727 +{\tt Seattle}  &{\tt New-York}&{\tt 2.5}&{\tt 0.12}\\
 25.2728 +{\tt Seattle}  &{\tt Chicago} &{\tt 1.7}&{\tt 0.08}\\
 25.2729 +{\tt Seattle}  &{\tt Topeka}  &{\tt 1.8}&{\tt 0.09}\\
 25.2730 +{\tt San-Diego}&{\tt New-York}&{\tt 2.5}&{\tt 0.15}\\
 25.2731 +{\tt San-Diego}&{\tt Chicago} &{\tt 1.8}&{\tt 0.10}\\
 25.2732 +{\tt San-Diego}&{\tt Topeka}  &{\tt 1.4}&{\tt 0.07}\\
 25.2733 +\hline
 25.2734 +\end{tabular}
 25.2735 +
 25.2736 +\subsubsection{Reading data from input table}
 25.2737 +
 25.2738 +The input table statement causes reading data from the specified table
 25.2739 +record by record.
 25.2740 +
 25.2741 +Once a next record has been read, numeric or symbolic values of fields,
 25.2742 +whose names are enclosed in square brackets in the table statement, are
 25.2743 +gathered into $n$-tuple, and if the control set is specified in the
 25.2744 +table statement, this $n$-tuple is added to it. Besides, a numeric or
 25.2745 +symbolic value of each field associated with a model parameter is
 25.2746 +assigned to the parameter member identified by subscripts, which are
 25.2747 +components of the $n$-tuple just read.
 25.2748 +
 25.2749 +For example, the following input table statement:
 25.2750 +
 25.2751 +\medskip
 25.2752 +
 25.2753 +\noindent\hfil
 25.2754 +\verb|table data IN "...": S <- [FROM,TO], d~DISTANCE, c~COST;|
 25.2755 +
 25.2756 +\medskip
 25.2757 +
 25.2758 +\noindent
 25.2759 +causes reading values of four fields named {\tt FROM}, {\tt TO},
 25.2760 +{\tt DISTANCE}, and {\tt COST} from each record of the specified table.
 25.2761 +Values of fields {\tt FROM} and {\tt TO} give a pair $(f,t)$, which is
 25.2762 +added to the control set {\tt S}. The value of field {\tt DISTANCE} is
 25.2763 +assigned to parameter member ${\tt d}[f,t]$, and the value of field
 25.2764 +{\tt COST} is assigned to parameter member ${\tt c}[f,t]$.
 25.2765 +
 25.2766 +Note that the input table may contain extra fields whose names are not
 25.2767 +specified in the table statement, in which case values of these fields
 25.2768 +on reading the table are ignored.
 25.2769 +
 25.2770 +\subsubsection{Writing data to output table}
 25.2771 +
 25.2772 +The output table statement causes writing data to the specified table.
 25.2773 +Note that some drivers (namely, CSV and xBASE) destroy the output table
 25.2774 +before writing data, i.e. delete all its existing records.
 25.2775 +
 25.2776 +Each $n$-tuple in the specified domain set generates one record written
 25.2777 +to the output table. Values of fields are numeric or symbolic values of
 25.2778 +corresponding expressions specified in the table statement. These
 25.2779 +expressions are evaluated for each $n$-tuple in the domain set and,
 25.2780 +thus, may include dummy indices introduced in the corresponding indexing
 25.2781 +expression.
 25.2782 +
 25.2783 +For example, the following output table statement:
 25.2784 +
 25.2785 +\medskip
 25.2786 +
 25.2787 +\noindent
 25.2788 +\verb|   table result{(f,t) in S} OUT "...": f~FROM, t~TO, x[f,t]~FLOW;|
 25.2789 +
 25.2790 +\medskip
 25.2791 +
 25.2792 +\noindent
 25.2793 +causes writing records, by one record for each pair $(f,t)$ in set
 25.2794 +{\tt S}, to the output table, where each record consists of three
 25.2795 +fields named {\tt FROM}, {\tt TO}, and {\tt FLOW}. The values written
 25.2796 +to fields {\tt FROM} and {\tt TO} are current values of dummy indices
 25.2797 +{\tt f} and {\tt t}, and the value written to field {\tt FLOW} is
 25.2798 +a value of member ${\tt x}[f,t]$ of corresponding subscripted parameter
 25.2799 +or variable.
 25.2800 +
 25.2801 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 25.2802 +
 25.2803 +\newpage
 25.2804 +
 25.2805 +\section{Model data}
 25.2806 +
 25.2807 +{\it Model data} include elemental sets, which are ``values'' of model
 25.2808 +sets, and numeric and symbolic values of model parameters.
 25.2809 +
 25.2810 +In MathProg there are two different ways to saturate model sets and
 25.2811 +parameters with data. One way is simply providing necessary data using
 25.2812 +the assign attribute. However, in many cases it is more practical to
 25.2813 +separate the model itself and particular data needed for the model. For
 25.2814 +the latter reason in MathProg there is another way, when the model
 25.2815 +description is divided into two parts: model section and data section.
 25.2816 +
 25.2817 +A {\it model section} is a main part of the model description that
 25.2818 +contains declarations of all model objects and is common for all
 25.2819 +problems based on that model.
 25.2820 +
 25.2821 +A {\it data section} is an optional part of the model description that
 25.2822 +contains model data specific for a particular problem.
 25.2823 +
 25.2824 +In MathProg model and data sections can be placed either in one text
 25.2825 +file or in two separate text files.
 25.2826 +
 25.2827 +1. If both model and data sections are placed in one file, the file is
 25.2828 +composed as follows:
 25.2829 +
 25.2830 +\bigskip
 25.2831 +
 25.2832 +\noindent\hfil
 25.2833 +\framebox{\begin{tabular}{l}
 25.2834 +{\it statement}{\tt;}\\
 25.2835 +{\it statement}{\tt;}\\
 25.2836 +\hfil.\ \ .\ \ .\\
 25.2837 +{\it statement}{\tt;}\\
 25.2838 +{\tt data;}\\
 25.2839 +{\it data block}{\tt;}\\
 25.2840 +{\it data block}{\tt;}\\
 25.2841 +\hfil.\ \ .\ \ .\\
 25.2842 +{\it data block}{\tt;}\\
 25.2843 +{\tt end;}
 25.2844 +\end{tabular}}
 25.2845 +
 25.2846 +\bigskip
 25.2847 +
 25.2848 +2. If the model and data sections are placed in two separate files, the
 25.2849 +files are composed as follows:
 25.2850 +
 25.2851 +\bigskip
 25.2852 +
 25.2853 +\noindent\hfil
 25.2854 +\begin{tabular}{@{}c@{}}
 25.2855 +\framebox{\begin{tabular}{l}
 25.2856 +{\it statement}{\tt;}\\
 25.2857 +{\it statement}{\tt;}\\
 25.2858 +\hfil.\ \ .\ \ .\\
 25.2859 +{\it statement}{\tt;}\\
 25.2860 +{\tt end;}\\
 25.2861 +\end{tabular}}\\
 25.2862 +\\\\Model file\\
 25.2863 +\end{tabular}
 25.2864 +\hspace{32pt}
 25.2865 +\begin{tabular}{@{}c@{}}
 25.2866 +\framebox{\begin{tabular}{l}
 25.2867 +{\tt data;}\\
 25.2868 +{\it data block}{\tt;}\\
 25.2869 +{\it data block}{\tt;}\\
 25.2870 +\hfil.\ \ .\ \ .\\
 25.2871 +{\it data block}{\tt;}\\
 25.2872 +{\tt end;}\\
 25.2873 +\end{tabular}}\\
 25.2874 +\\Data file\\
 25.2875 +\end{tabular}
 25.2876 +
 25.2877 +\bigskip
 25.2878 +
 25.2879 +\begin{description}
 25.2880 +\item[{\rm Note:}\hspace*{31pt}] If the data section is placed in a
 25.2881 +separate file, the keyword {\tt data} is optional and may be omitted
 25.2882 +along with the semicolon that follows it.
 25.2883 +\end{description}
 25.2884 +
 25.2885 +\subsection{Coding data section}
 25.2886 +
 25.2887 +The {\it data section} is a sequence of data blocks in various formats,
 25.2888 +which are discussed in following subsections. The order, in which data
 25.2889 +blocks follow in the data section, may be arbitrary, not necessarily
 25.2890 +the same, in which corresponding model objects follow in the model
 25.2891 +section.
 25.2892 +
 25.2893 +The rules of coding the data section are commonly the same as the rules
 25.2894 +of coding the model description (see Subsection \ref{coding}, page
 25.2895 +\pageref{coding}), i.e. data blocks are composed from basic lexical
 25.2896 +units such as symbolic names, numeric and string literals, keywords,
 25.2897 +delimiters, and comments. However, for the sake of convenience and
 25.2898 +improving readability there is one deviation from the common rule: if
 25.2899 +a string literal consists of only alphanumeric characters (including
 25.2900 +the underscore character), the signs {\tt+} and {\tt-}, and/or the
 25.2901 +decimal point, it may be coded without bordering by (single or double)
 25.2902 +quotes.
 25.2903 +
 25.2904 +All numeric and symbolic material provided in the data section is coded
 25.2905 +in the form of numbers and symbols, i.e. unlike the model section
 25.2906 +no expressions are allowed in the data section. Nevertheless, the signs
 25.2907 +{\tt+} and {\tt-} can precede numeric literals to allow coding signed
 25.2908 +numeric quantities, in which case there must be no white-space
 25.2909 +characters between the sign and following numeric literal (if there is
 25.2910 +at least one white-space, the sign and following numeric literal are
 25.2911 +recognized as two different lexical units).
 25.2912 +
 25.2913 +\subsection{Set data block}
 25.2914 +
 25.2915 +\medskip
 25.2916 +
 25.2917 +\framebox[345pt][l]{
 25.2918 +\parbox[c][44pt]{345pt}{
 25.2919 +\hspace{6pt} {\tt set} {\it name} {\tt,} {\it record} {\tt,} \dots
 25.2920 +{\tt,} {\it record} {\tt;}
 25.2921 +
 25.2922 +\medskip
 25.2923 +
 25.2924 +\hspace{6pt} {\tt set} {\it name} {\tt[} {\it symbol} {\tt,} \dots
 25.2925 +{\tt,} {\it symbol} {\tt]} {\tt,} {\it record} {\tt,} \dots {\tt,}
 25.2926 +{\it record} {\tt;}
 25.2927 +}}
 25.2928 +
 25.2929 +\setlength{\leftmargini}{60pt}
 25.2930 +
 25.2931 +\begin{description}
 25.2932 +\item[{\rm Where:}\hspace*{23pt}] {\it name} is a symbolic name of the
 25.2933 +set;
 25.2934 +\item[\hspace*{54pt}] {\it symbol}, \dots, {\it symbol} are subscripts,
 25.2935 +which specify a particular member of the set (if the set is an array,
 25.2936 +i.e. a set of sets);
 25.2937 +\item[\hspace*{54pt}] {\it record}, \dots, {\it record} are data
 25.2938 +records.
 25.2939 +\end{description}
 25.2940 +
 25.2941 +\begin{description}
 25.2942 +\item[{\rm Note:}\hspace*{31pt}] Commae preceding data records may be
 25.2943 +omitted.
 25.2944 +\end{description}
 25.2945 +
 25.2946 +\noindent Data records:
 25.2947 +
 25.2948 +\begin{description}
 25.2949 +\item[{\tt :=}\hspace*{45pt}] is a non-significant data record, which
 25.2950 +may be used freely to improve readability;
 25.2951 +\item[{\tt(} {\it slice} {\tt)}\hspace*{18.5pt}] specifies a slice;
 25.2952 +\item[{\it simple-data}\hspace*{5.5pt}] specifies set data in the
 25.2953 +simple format;
 25.2954 +\item[{\tt:} {\it matrix-data}]\hspace*{0pt}\\
 25.2955 +specifies set data in the matrix format;
 25.2956 +\item[{\tt(tr)} {\tt:} {\it matrix-data}]\hspace*{0pt}\\
 25.2957 +specifies set data in the transposed matrix format. (In this case the
 25.2958 +colon following the keyword {\tt(tr)} may be omitted.)
 25.2959 +\end{description}
 25.2960 +
 25.2961 +\noindent{\bf Examples}
 25.2962 +
 25.2963 +\begin{verbatim}
 25.2964 +set month := Jan Feb Mar Apr May Jun;
 25.2965 +set month "Jan", "Feb", "Mar", "Apr", "May", "Jun";
 25.2966 +set A[3,Mar] := (1,2) (2,3) (4,2) (3,1) (2,2) (4,4) (3,4);
 25.2967 +set A[3,'Mar'] := 1 2 2 3 4 2 3 1 2 2 4 4 2 4;
 25.2968 +set A[3,'Mar'] : 1 2 3 4 :=
 25.2969 +               1 - + - -
 25.2970 +               2 - + + -
 25.2971 +               3 + - - +
 25.2972 +               4 - + - + ;
 25.2973 +set B := (1,2,3) (1,3,2) (2,3,1) (2,1,3) (1,2,2) (1,1,1) (2,1,1);
 25.2974 +set B := (*,*,*) 1 2 3, 1 3 2, 2 3 1, 2 1 3, 1 2 2, 1 1 1, 2 1 1;
 25.2975 +set B := (1,*,2) 3 2 (2,*,1) 3 1 (1,2,3) (2,1,3) (1,1,1);
 25.2976 +set B := (1,*,*) : 1 2 3 :=
 25.2977 +                 1 + - -
 25.2978 +                 2 - + +
 25.2979 +                 3 - + -
 25.2980 +         (2,*,*) : 1 2 3 :=
 25.2981 +                 1 + - +
 25.2982 +                 2 - - -
 25.2983 +                 3 + - - ;
 25.2984 +\end{verbatim}
 25.2985 +
 25.2986 +\noindent(In these examples {\tt month} is a simple set of singlets,
 25.2987 +{\tt A} is a 2-dimensional array of doublets, and {\tt B} is a simple
 25.2988 +set of triplets. Data blocks for the same set are equivalent in the
 25.2989 +sense that they specify the same data in different formats.)
 25.2990 +
 25.2991 +\medskip
 25.2992 +
 25.2993 +The {\it set data block} is used to specify a complete elemental set,
 25.2994 +which is assigned to a set (if it is a simple set) or one of its
 25.2995 +members (if the set is an array of sets).\footnote{There is another way
 25.2996 +to specify data for a simple set along with data for parameters. This
 25.2997 +feature is discussed in the next subsection.}
 25.2998 +
 25.2999 +Data blocks can be specified only for non-computable sets, i.e. for
 25.3000 +sets, which have no assign ({\tt:=}) attribute in the corresponding set
 25.3001 +statements.
 25.3002 +
 25.3003 +If the set is a simple set, only its symbolic name should be specified
 25.3004 +in the header of the data block. Otherwise, if the set is a
 25.3005 +$n$-dimensional array, its symbolic name should be provided with a
 25.3006 +complete list of subscripts separated by commae and enclosed in square
 25.3007 +brackets to specify a particular member of the set array. The number of
 25.3008 +subscripts must be the same as the dimension of the set array, where
 25.3009 +each subscript must be a number or symbol.
 25.3010 +
 25.3011 +An elemental set defined in the set data block is coded as a sequence
 25.3012 +of data records described below.\footnote{{\it Data record} is simply a
 25.3013 +technical term. It does not mean that data records have any special
 25.3014 +formatting.}
 25.3015 +
 25.3016 +\newpage
 25.3017 +
 25.3018 +\subsubsection{Assign data record}
 25.3019 +
 25.3020 +The {\it assign} ({\tt:=}) {\it data record} is a non-signficant
 25.3021 +element. It may be used for improving readability of data blocks.
 25.3022 +
 25.3023 +\subsubsection{Slice data record}
 25.3024 +
 25.3025 +The {\it slice data record} is a control record, which specifies a
 25.3026 +{\it slice} of the elemental set defined in the data block. It has the
 25.3027 +following syntactic form:
 25.3028 +
 25.3029 +\medskip
 25.3030 +
 25.3031 +\noindent\hfil
 25.3032 +{\tt(} $s_1$ {\tt,} $s_2$ {\tt,} \dots {\tt,} $s_n$ {\tt)}
 25.3033 +
 25.3034 +\medskip
 25.3035 +
 25.3036 +\noindent where $s_1$, $s_2$, \dots, $s_n$ are components of the slice.
 25.3037 +
 25.3038 +Each component of the slice can be a number or symbol or the asterisk
 25.3039 +({\tt*}). The number of components in the slice must be the same as the
 25.3040 +dimension of $n$-tuples in the elemental set to be defined. For
 25.3041 +instance, if the elemental set contains 4-tuples (quadruplets), the
 25.3042 +slice must have four components. The number of asterisks in the slice
 25.3043 +is called the {\it slice dimension}.
 25.3044 +
 25.3045 +The effect of using slices is the following. If a $m$-dimensional slice
 25.3046 +(i.e. a slice having $m$ asterisks) is specified in the data block, all
 25.3047 +subsequent data records must specify tuples of the dimension $m$.
 25.3048 +Whenever a $m$-tuple is encountered, each asterisk in the slice is
 25.3049 +replaced by corresponding components of the $m$-tuple that gives the
 25.3050 +resultant $n$-tuple, which is included in the elemental set to be
 25.3051 +defined. For example, if the slice $(a,*,1,2,*)$ is in effect, and
 25.3052 +2-tuple $(3,b)$ is encountered in a subsequent data record, the
 25.3053 +resultant 5-tuple included in the elemental set is $(a,3,1,2,b)$.
 25.3054 +
 25.3055 +The slice having no asterisks itself defines a complete $n$-tuple,
 25.3056 +which is included in the elemental set.
 25.3057 +
 25.3058 +Being once specified the slice effects until either a new slice or the
 25.3059 +end of data block is encountered. Note that if no slice is specified in
 25.3060 +the data block, one, components of which are all asterisks, is assumed.
 25.3061 +
 25.3062 +\subsubsection{Simple data record}
 25.3063 +
 25.3064 +The {\it simple data record} defines one $n$-tuple in a simple format
 25.3065 +and has the following syntactic form:
 25.3066 +
 25.3067 +\medskip
 25.3068 +
 25.3069 +\noindent\hfil
 25.3070 +$t_1$ {\tt,} $t_2$ {\tt,} \dots {\tt,} $t_n$
 25.3071 +
 25.3072 +\medskip
 25.3073 +
 25.3074 +\noindent where $t_1$, $t_2$, \dots, $t_n$ are components of the
 25.3075 +$n$-tuple. Each component can be a number or symbol. Commae between
 25.3076 +components are optional and may be omitted.
 25.3077 +
 25.3078 +\subsubsection{Matrix data record}
 25.3079 +
 25.3080 +The {\it matrix data record} defines several 2-tuples (doublets) in
 25.3081 +a matrix format and has the following syntactic form:
 25.3082 +
 25.3083 +\newpage
 25.3084 +
 25.3085 +$$\begin{array}{cccccc}
 25.3086 +\mbox{{\tt:}}&c_1&c_2&\dots&c_n&\mbox{{\tt:=}}\\
 25.3087 +r_1&a_{11}&a_{12}&\dots&a_{1n}&\\
 25.3088 +r_2&a_{21}&a_{22}&\dots&a_{2n}&\\
 25.3089 +\multicolumn{5}{c}{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .}&\\
 25.3090 +r_m&a_{m1}&a_{m2}&\dots&a_{mn}&\\
 25.3091 +\end{array}$$
 25.3092 +where $r_1$, $r_2$, \dots, $r_m$ are numbers and/or symbols
 25.3093 +corresponding to rows of the matrix; $c_1$, $c_2$, \dots, $c_n$ are
 25.3094 +numbers and/or symbols corresponding to columns of the matrix, $a_{11}$,
 25.3095 +$a_{12}$, \dots, $a_{mn}$ are matrix elements, which can be either
 25.3096 +{\tt+} or {\tt-}. (In this data record the delimiter {\tt:} preceding
 25.3097 +the column list and the delimiter {\tt:=} following the column list
 25.3098 +cannot be omitted.)
 25.3099 +
 25.3100 +Each element $a_{ij}$ of the matrix data block (where $1\leq i\leq m$,
 25.3101 +$1\leq j\leq n$) corresponds to 2-tuple $(r_i,c_j)$. If $a_{ij}$ is the
 25.3102 +plus sign ({\tt+}), that 2-tuple (or a longer $n$-tuple, if a slice is
 25.3103 +used) is included in the elemental set. Otherwise, if $a_{ij}$ is the
 25.3104 +minus sign ({\tt-}), that 2-tuple is not included in the elemental set.
 25.3105 +
 25.3106 +Since the matrix data record defines 2-tuples, either the elemental set
 25.3107 +must consist of 2-tuples or the slice currently used must be
 25.3108 +2-dimensional.
 25.3109 +
 25.3110 +\subsubsection{Transposed matrix data record}
 25.3111 +
 25.3112 +The {\it transposed matrix data record} has the following syntactic
 25.3113 +form:
 25.3114 +$$\begin{array}{cccccc}
 25.3115 +\mbox{{\tt(tr) :}}&c_1&c_2&\dots&c_n&\mbox{{\tt:=}}\\
 25.3116 +r_1&a_{11}&a_{12}&\dots&a_{1n}&\\
 25.3117 +r_2&a_{21}&a_{22}&\dots&a_{2n}&\\
 25.3118 +\multicolumn{5}{c}{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .}&\\
 25.3119 +r_m&a_{m1}&a_{m2}&\dots&a_{mn}&\\
 25.3120 +\end{array}$$
 25.3121 +(In this case the delimiter {\tt:} following the keyword {\tt(tr)} is
 25.3122 +optional and may be omitted.)
 25.3123 +
 25.3124 +This data record is completely analogous to the matrix data record (see
 25.3125 +above) with only exception that in this case each element $a_{ij}$ of
 25.3126 +the matrix corresponds to 2-tuple $(c_j,r_i)$ rather than $(r_i,c_j)$.
 25.3127 +
 25.3128 +Being once specified the {\tt(tr)} indicator affects all subsequent
 25.3129 +data records until either a slice or the end of data block is
 25.3130 +encountered.
 25.3131 +
 25.3132 +\subsection{Parameter data block}
 25.3133 +
 25.3134 +\medskip
 25.3135 +
 25.3136 +\framebox[345pt][l]{
 25.3137 +\parbox[c][80pt]{345pt}{
 25.3138 +\hspace{6pt} {\tt param} {\it name} {\tt,} {\it record} {\tt,} \dots
 25.3139 +{\tt,} {\it record} {\tt;}
 25.3140 +
 25.3141 +\medskip
 25.3142 +
 25.3143 +\hspace{6pt} {\tt param} {\it name} {\tt default} {\it value} {\tt,}
 25.3144 +{\it record} {\tt,} \dots {\tt,} {\it record} {\tt;}
 25.3145 +
 25.3146 +\medskip
 25.3147 +
 25.3148 +\hspace{6pt} {\tt param} {\tt:} {\it tabbing-data} {\tt;}
 25.3149 +
 25.3150 +\medskip
 25.3151 +
 25.3152 +\hspace{6pt} {\tt param} {\tt default} {\it value} {\tt:}
 25.3153 +{\it tabbing-data} {\tt;}
 25.3154 +}}
 25.3155 +
 25.3156 +\newpage
 25.3157 +
 25.3158 +\setlength{\leftmargini}{60pt}
 25.3159 +
 25.3160 +\begin{description}
 25.3161 +\item[{\rm Where:}\hspace*{23pt}] {\it name} is a symbolic name of the
 25.3162 +parameter;
 25.3163 +\item[\hspace*{54pt}] {\it value} is an optional default value of the
 25.3164 +parameter;
 25.3165 +\item[\hspace*{54pt}] {\it record}, \dots, {\it record} are data
 25.3166 +records;
 25.3167 +\item[\hspace*{54pt}] {\it tabbing-data} specifies parameter data in
 25.3168 +the tabbing format.
 25.3169 +\end{description}
 25.3170 +
 25.3171 +\begin{description}
 25.3172 +\item[{\rm Note:}\hspace*{31pt}] Commae preceding data records may be
 25.3173 +omitted.
 25.3174 +\end{description}
 25.3175 +
 25.3176 +\noindent Data records:
 25.3177 +
 25.3178 +\begin{description}
 25.3179 +\item[{\tt :=}\hspace*{45pt}] is a non-significant data record, which
 25.3180 +may be used freely to improve readability;
 25.3181 +\item[{\tt[} {\it slice} {\tt]}\hspace*{18.5pt}] specifies a slice;
 25.3182 +\item[{\it plain-data}\hspace*{11pt}] specifies parameter data in the
 25.3183 +plain format;
 25.3184 +\item[{\tt:} {\it tabular-data}]\hspace*{0pt}\\
 25.3185 +specifies parameter data in the tabular format;
 25.3186 +\item[{\tt(tr)} {\tt:} {\it tabular-data}]\hspace*{0pt}\\
 25.3187 +specifies set data in the transposed tabular format. (In this case the
 25.3188 +colon following the keyword {\tt(tr)} may be omitted.)
 25.3189 +\end{description}
 25.3190 +
 25.3191 +\noindent{\bf Examples}
 25.3192 +
 25.3193 +\begin{verbatim}
 25.3194 +param T := 4;
 25.3195 +param month := 1 'Jan' 2 'Feb' 3 'Mar' 4 'Apr' 5 'May';
 25.3196 +param month := [1] Jan, [2] Feb, [3] Mar, [4] Apr, [5] May;
 25.3197 +param day := [Sun] 0, [Mon] 1, [Tue] 2, [Wed] 3, [Thu] 4,
 25.3198 +             [Fri] 5, [Sat] 6;
 25.3199 +param init_stock := iron 7.32 nickel 35.8;
 25.3200 +param init_stock [*] iron 7.32, nickel 35.8;
 25.3201 +param cost [iron] .025 [nickel] .03;
 25.3202 +param value := iron -.1, nickel .02;
 25.3203 +param       : init_stock cost value :=
 25.3204 +      iron       7.32    .025  -.1
 25.3205 +      nickel    35.8     .03    .02 ;
 25.3206 +param : raw : init_stock cost value :=
 25.3207 +      iron       7.32    .025  -.1
 25.3208 +      nickel    35.8     .03    .02 ;
 25.3209 +param demand default 0 (tr)
 25.3210 +       :  FRA  DET  LAN  WIN  STL  FRE  LAF :=
 25.3211 +   bands  300   .   100   75   .   225  250
 25.3212 +   coils  500  750  400  250   .   850  500
 25.3213 +   plate  100   .    .    50  200   .   250 ;
 25.3214 +\end{verbatim}
 25.3215 +
 25.3216 +\newpage
 25.3217 +
 25.3218 +\begin{verbatim}
 25.3219 +param trans_cost :=
 25.3220 +   [*,*,bands]:  FRA  DET  LAN  WIN  STL  FRE  LAF :=
 25.3221 +         GARY     30   10    8   10   11   71    6
 25.3222 +         CLEV     22    7   10    7   21   82   13
 25.3223 +         PITT     19   11   12   10   25   83   15
 25.3224 +   [*,*,coils]:  FRA  DET  LAN  WIN  STL  FRE  LAF :=
 25.3225 +         GARY     39   14   11   14   16   82    8
 25.3226 +         CLEV     27    9   12    9   26   95   17
 25.3227 +         PITT     24   14   17   13   28   99   20
 25.3228 +   [*,*,plate]:  FRA  DET  LAN  WIN  STL  FRE  LAF :=
 25.3229 +         GARY     41   15   12   16   17   86    8
 25.3230 +         CLEV     29    9   13    9   28   99   18
 25.3231 +         PITT     26   14   17   13   31  104   20 ;
 25.3232 +\end{verbatim}
 25.3233 +
 25.3234 +The {\it parameter data block} is used to specify complete data for a
 25.3235 +parameter (or parameters, if data are specified in the tabbing format).
 25.3236 +
 25.3237 +Data blocks can be specified only for non-computable parameters, i.e.
 25.3238 +for parameters, which have no assign ({\tt:=}) attribute in the
 25.3239 +corresponding parameter statements.
 25.3240 +
 25.3241 +Data defined in the parameter data block are coded as a sequence of
 25.3242 +data records described below. Additionally the data block can be
 25.3243 +provided with the optional {\tt default} attribute, which specifies a
 25.3244 +default numeric or symbolic value of the parameter (parameters). This
 25.3245 +default value is assigned to the parameter or its members, if
 25.3246 +no appropriate value is defined in the parameter data block. The
 25.3247 +{\tt default} attribute cannot be used, if it is already specified in
 25.3248 +the corresponding parameter statement.
 25.3249 +
 25.3250 +\subsubsection{Assign data record}
 25.3251 +
 25.3252 +The {\it assign} ({\tt:=}) {\it data record} is a non-signficant
 25.3253 +element. It may be used for improving readability of data blocks.
 25.3254 +
 25.3255 +\subsubsection{Slice data record}
 25.3256 +
 25.3257 +The {\it slice data record} is a control record, which specifies a
 25.3258 +{\it slice} of the parameter array. It has the following syntactic form:
 25.3259 +
 25.3260 +\medskip
 25.3261 +
 25.3262 +\noindent\hfil
 25.3263 +{\tt[} $s_1$ {\tt,} $s_2$ {\tt,} \dots {\tt,} $s_n$ {\tt]}
 25.3264 +
 25.3265 +\medskip
 25.3266 +
 25.3267 +\noindent where $s_1$, $s_2$, \dots, $s_n$ are components of the slice.
 25.3268 +
 25.3269 +Each component of the slice can be a number or symbol or the asterisk
 25.3270 +({\tt*}). The number of components in the slice must be the same as the
 25.3271 +dimension of the parameter. For instance, if the parameter is a
 25.3272 +4-dimensional array, the slice must have four components. The number of
 25.3273 +asterisks in the slice is called the {\it slice dimension}.
 25.3274 +
 25.3275 +The effect of using slices is the following. If a $m$-dimensional slice
 25.3276 +(i.e. a slice having $m$ asterisks) is specified in the data block, all
 25.3277 +subsequent data records must specify subscripts of the parameter
 25.3278 +members as if the parameter were $m$-dimensional, not $n$-dimensional.
 25.3279 +
 25.3280 +Whenever $m$ subscripts are encountered, each asterisk in the slice is
 25.3281 +replaced by corresponding subscript that gives $n$ subscripts, which
 25.3282 +define the actual parameter member. For example, if the slice
 25.3283 +$[a,*,1,2,*]$ is in effect, and subscripts 3 and $b$ are encountered in
 25.3284 +a subsequent data record, the complete subscript list used to choose a
 25.3285 +parameter member is $[a,3,1,2,b]$.
 25.3286 +
 25.3287 +It is allowed to specify a slice having no asterisks. Such slice itself
 25.3288 +defines a complete subscript list, in which case the next data record
 25.3289 +should define only a single value of corresponding parameter member.
 25.3290 +
 25.3291 +Being once specified the slice effects until either a new slice or the
 25.3292 +end of data block is encountered. Note that if no slice is specified in
 25.3293 +the data block, one, components of which are all asterisks, is assumed.
 25.3294 +
 25.3295 +\subsubsection{Plain data record}
 25.3296 +
 25.3297 +The {\it plain data record} defines a subscript list and a single value
 25.3298 +in the plain format. This record has the following syntactic form:
 25.3299 +
 25.3300 +\medskip
 25.3301 +
 25.3302 +\noindent\hfil
 25.3303 +$t_1$ {\tt,} $t_2$ {\tt,} \dots {\tt,} $t_n$ {\tt,} $v$
 25.3304 +
 25.3305 +\medskip
 25.3306 +
 25.3307 +\noindent where $t_1$, $t_2$, \dots, $t_n$ are subscripts, and $v$ is a
 25.3308 +value. Each subscript as well as the value can be a number or symbol.
 25.3309 +Commae following subscripts are optional and may be omitted.
 25.3310 +
 25.3311 +In case of 0-dimensional parameter or slice the plain data record has
 25.3312 +no subscripts and consists of a single value only.
 25.3313 +
 25.3314 +\subsubsection{Tabular data record}
 25.3315 +
 25.3316 +The {\it tabular data record} defines several values, where each value
 25.3317 +is provided with two subscripts. This record has the following
 25.3318 +syntactic form:
 25.3319 +$$\begin{array}{cccccc}
 25.3320 +\mbox{{\tt:}}&c_1&c_2&\dots&c_n&\mbox{{\tt:=}}\\
 25.3321 +r_1&a_{11}&a_{12}&\dots&a_{1n}&\\
 25.3322 +r_2&a_{21}&a_{22}&\dots&a_{2n}&\\
 25.3323 +\multicolumn{5}{c}{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .}&\\
 25.3324 +r_m&a_{m1}&a_{m2}&\dots&a_{mn}&\\
 25.3325 +\end{array}$$
 25.3326 +where $r_1$, $r_2$, \dots, $r_m$ are numbers and/or symbols
 25.3327 +corresponding to rows of the table; $c_1$, $c_2$, \dots, $c_n$ are
 25.3328 +numbers and/or symbols corresponding to columns of the table, $a_{11}$,
 25.3329 +$a_{12}$, \dots, $a_{mn}$ are table elements. Each element can be a
 25.3330 +number or symbol or the single decimal point ({\tt.}). (In this data
 25.3331 +record the delimiter {\tt:} preceding the column list and the delimiter
 25.3332 +{\tt:=} following the column list cannot be omitted.)
 25.3333 +
 25.3334 +Each element $a_{ij}$ of the tabular data block ($1\leq i\leq m$,
 25.3335 +$1\leq j\leq n$) defines two subscripts, where the first subscript is
 25.3336 +$r_i$, and the second one is $c_j$. These subscripts are used in
 25.3337 +conjunction with the current slice to form the complete subscript list
 25.3338 +that identifies a particular member of the parameter array. If $a_{ij}$
 25.3339 +is a number or symbol, this value is assigned to the parameter member.
 25.3340 +However, if $a_{ij}$ is the single decimal point, the member is
 25.3341 +assigned a default value specified either in the parameter data block
 25.3342 +or in the parameter statement, or, if no default value is specified,
 25.3343 +the member remains undefined.
 25.3344 +
 25.3345 +Since the tabular data record provides two subscripts for each value,
 25.3346 +either the parameter or the slice currently used must be 2-dimensional.
 25.3347 +
 25.3348 +\subsubsection{Transposed tabular data record}
 25.3349 +
 25.3350 +The {\it transposed tabular data record} has the following syntactic
 25.3351 +form:
 25.3352 +$$\begin{array}{cccccc}
 25.3353 +\mbox{{\tt(tr) :}}&c_1&c_2&\dots&c_n&\mbox{{\tt:=}}\\
 25.3354 +r_1&a_{11}&a_{12}&\dots&a_{1n}&\\
 25.3355 +r_2&a_{21}&a_{22}&\dots&a_{2n}&\\
 25.3356 +\multicolumn{5}{c}{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .}&\\
 25.3357 +r_m&a_{m1}&a_{m2}&\dots&a_{mn}&\\
 25.3358 +\end{array}$$
 25.3359 +(In this case the delimiter {\tt:} following the keyword {\tt(tr)} is
 25.3360 +optional and may be omitted.)
 25.3361 +
 25.3362 +This data record is completely analogous to the tabular data record
 25.3363 +(see above) with only exception that the first subscript defined by
 25.3364 +element $a_{ij}$ is $c_j$ while the second one is $r_i$.
 25.3365 +
 25.3366 +Being once specified the {\tt(tr)} indicator affects all subsequent
 25.3367 +data records until either a slice or the end of data block is
 25.3368 +encountered.
 25.3369 +
 25.3370 +\subsubsection{Tabbing data format}
 25.3371 +
 25.3372 +The parameter data block in the {\it tabbing format} has the following
 25.3373 +syntactic form:
 25.3374 +$$\begin{array}{p{12pt}@{\ }l@{\ }c@{\ }l@{\ }c@{\ }l@{\ }r@{\ }l@{\ }c
 25.3375 +@{\ }l@{\ }c@{\ }l@{\ }l}
 25.3376 +\multicolumn{7}{@{}c@{}}{\mbox{\tt param}\ \mbox{\tt default}\ \mbox
 25.3377 +{\it value}\ \mbox{\tt:}\ \mbox{\it s}\ \mbox{\tt:}}&
 25.3378 +p_1&\mbox{\tt,}&p_2&\mbox{\tt,} \dots \mbox{\tt,}&p_k&\mbox{\tt:=}\\
 25.3379 +&t_{11}&\mbox{\tt,}&t_{12}&\mbox{\tt,} \dots \mbox{\tt,}&t_{1n}&
 25.3380 +\mbox{\tt,}&a_{11}&\mbox{\tt,}&a_{12}&\mbox{\tt,} \dots \mbox{\tt,}&
 25.3381 +a_{1k}\\
 25.3382 +&t_{21}&\mbox{\tt,}&t_{22}&\mbox{\tt,} \dots \mbox{\tt,}&t_{2n}&
 25.3383 +\mbox{\tt,}&a_{21}&\mbox{\tt,}&a_{22}&\mbox{\tt,} \dots \mbox{\tt,}&
 25.3384 +a_{2k}\\
 25.3385 +\multicolumn{13}{c}
 25.3386 +{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .}\\
 25.3387 +&t_{m1}&\mbox{\tt,}&t_{m2}&\mbox{\tt,} \dots \mbox{\tt,}&t_{mn}&
 25.3388 +\mbox{\tt,}&a_{m1}&\mbox{\tt,}&a_{m2}&\mbox{\tt,} \dots \mbox{\tt,}&
 25.3389 +a_{mk}&\mbox{\tt;}\\
 25.3390 +\end{array}$$
 25.3391 +
 25.3392 +{\it Notes:}
 25.3393 +
 25.3394 +1. The keyword {\tt default} may be omitted along with a value
 25.3395 +following it.
 25.3396 +
 25.3397 +2. Symbolic name {\tt s} may be omitted along with the colon following
 25.3398 +it.
 25.3399 +
 25.3400 +3. All comae are optional and may be omitted.
 25.3401 +
 25.3402 +\medskip
 25.3403 +
 25.3404 +The data block in the tabbing format shown above is exactly equivalent
 25.3405 +to the following data blocks for $j=1,2,\dots,k$:
 25.3406 +
 25.3407 +\medskip
 25.3408 +
 25.3409 +{\tt set} {\it s} {\tt:=}
 25.3410 +{\tt(}$t_{11}${\tt,}$t_{12}${\tt,}\dots{\tt,}$t_{1n}${\tt)}
 25.3411 +{\tt(}$t_{21}${\tt,}$t_{22}${\tt,}\dots{\tt,}$t_{2n}${\tt)} \dots
 25.3412 +{\tt(}$t_{m1}${\tt,}$t_{m2}${\tt,}\dots{\tt,}$t_{mn}${\tt)} {\tt;}
 25.3413 +
 25.3414 +{\tt param} $p_j$ {\tt default} {\it value} {\tt:=}
 25.3415 +
 25.3416 +$\!${\tt[}$t_{11}${\tt,}$t_{12}${\tt,}\dots{\tt,}$t_{1n}${\tt]}
 25.3417 +$a_{1j}$
 25.3418 +{\tt[}$t_{21}${\tt,}$t_{22}${\tt,}\dots{\tt,}$t_{2n}${\tt]} $a_{2j}$
 25.3419 +\dots
 25.3420 +{\tt[}$t_{m1}${\tt,}$t_{m2}${\tt,}\dots{\tt,}$t_{mn}${\tt]} $a_{mj}$
 25.3421 +{\tt;}
 25.3422 +
 25.3423 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 25.3424 +
 25.3425 +\appendix
 25.3426 +
 25.3427 +\newpage
 25.3428 +
 25.3429 +\section{Using suffixes}
 25.3430 +
 25.3431 +Suffixes can be used to retrieve additional values associated with
 25.3432 +model variables, constraints, and objectives.
 25.3433 +
 25.3434 +A {\it suffix} consists of a period ({\tt.}) followed by a non-reserved
 25.3435 +keyword. For example, if {\tt x} is a two-dimensional variable,
 25.3436 +{\tt x[i,j].lb} is a numeric value equal to the lower bound of
 25.3437 +elemental variable {\tt x[i,j]}, which (value) can be used everywhere
 25.3438 +in expressions like a numeric parameter.
 25.3439 +
 25.3440 +For model variables suffixes have the following meaning:
 25.3441 +
 25.3442 +\medskip
 25.3443 +
 25.3444 +\begin{tabular}{@{}p{96pt}p{222pt}@{}}
 25.3445 +{\tt.lb}&lower bound\\
 25.3446 +{\tt.ub}&upper bound\\
 25.3447 +{\tt.status}&status in the solution:\\
 25.3448 +&0 --- undefined\\
 25.3449 +&1 --- basic\\
 25.3450 +&2 --- non-basic on lower bound\\
 25.3451 +&3 --- non-basic on upper bound\\
 25.3452 +&4 --- non-basic free (unbounded) variable\\
 25.3453 +&5 --- non-basic fixed variable\\
 25.3454 +{\tt.val}&primal value in the solution\\
 25.3455 +{\tt.dual}&dual value (reduced cost) in the solution\\
 25.3456 +\end{tabular}
 25.3457 +
 25.3458 +\medskip
 25.3459 +
 25.3460 +For model constraints and objectives suffixes have the following
 25.3461 +meaning:
 25.3462 +
 25.3463 +\medskip
 25.3464 +
 25.3465 +\begin{tabular}{@{}p{96pt}p{222pt}@{}}
 25.3466 +{\tt.lb}&lower bound of the linear form\\
 25.3467 +{\tt.ub}&upper bound of the linear form\\
 25.3468 +{\tt.status}&status in the solution:\\
 25.3469 +&0 --- undefined\\
 25.3470 +&1 --- non-active\\
 25.3471 +&2 --- active on lower bound\\
 25.3472 +&3 --- active on upper bound\\
 25.3473 +&4 --- active free (unbounded) row\\
 25.3474 +&5 --- active equality constraint\\
 25.3475 +{\tt.val}&primal value of the linear form in the solution\\
 25.3476 +{\tt.dual}&dual value (reduced cost) of the linear form in the
 25.3477 +solution\\
 25.3478 +\end{tabular}
 25.3479 +
 25.3480 +\medskip
 25.3481 +
 25.3482 +Note that suffixes {\tt.status}, {\tt.val}, and {\tt.dual} can be used
 25.3483 +only below the solve statement.
 25.3484 +
 25.3485 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 25.3486 +
 25.3487 +\newpage
 25.3488 +
 25.3489 +\section{Date and time functions}
 25.3490 +
 25.3491 +\noindent\hfil
 25.3492 +by Andrew Makhorin \verb|<mao@gnu.org>|
 25.3493 +
 25.3494 +\noindent\hfil
 25.3495 +and Heinrich Schuchardt \verb|<heinrich.schuchardt@gmx.de>|
 25.3496 +
 25.3497 +\subsection{Obtaining current calendar time}
 25.3498 +\label{gmtime}
 25.3499 +
 25.3500 +To obtain the current calendar time in MathProg there exists the
 25.3501 +function {\tt gmtime}. It has no arguments and returns the number of
 25.3502 +seconds elapsed since 00:00:00 on January 1, 1970, Coordinated
 25.3503 +Universal Time (UTC). For example:
 25.3504 +
 25.3505 +\medskip
 25.3506 +
 25.3507 +\verb|   param utc := gmtime();|
 25.3508 +
 25.3509 +\medskip
 25.3510 +
 25.3511 +MathProg has no function to convert UTC time returned by the function
 25.3512 +{\tt gmtime} to {\it local} calendar times. Thus, if you need to
 25.3513 +determine the current local calendar time, you have to add to the UTC
 25.3514 +time returned the time offset from UTC expressed in seconds. For
 25.3515 +example, the time in Berlin during the winter is one hour ahead of UTC
 25.3516 +that corresponds to the time offset +1 hour = +3600 secs, so the
 25.3517 +current winter calendar time in Berlin may be determined as follows:
 25.3518 +
 25.3519 +\medskip
 25.3520 +
 25.3521 +\verb|   param now := gmtime() + 3600;|
 25.3522 +
 25.3523 +\medskip
 25.3524 +
 25.3525 +\noindent Similarly, the summer time in Chicago (Central Daylight Time)
 25.3526 +is five hours behind UTC, so the corresponding current local calendar
 25.3527 +time may be determined as follows:
 25.3528 +
 25.3529 +\medskip
 25.3530 +
 25.3531 +\verb|   param now := gmtime() - 5 * 3600;|
 25.3532 +
 25.3533 +\medskip
 25.3534 +
 25.3535 +Note that the value returned by {\tt gmtime} is volatile, i.e. being
 25.3536 +called several times this function may return different values.
 25.3537 +
 25.3538 +\subsection{Converting character string to calendar time}
 25.3539 +\label{str2time}
 25.3540 +
 25.3541 +The function {\tt str2time(}{\it s}{\tt,} {\it f}{\tt)} converts a
 25.3542 +character string (timestamp) specified by its first argument {\it s},
 25.3543 +which must be a symbolic expression, to the calendar time suitable for
 25.3544 +arithmetic calculations. The conversion is controlled by the specified
 25.3545 +format string {\it f} (the second argument), which also must be a
 25.3546 +symbolic expression.
 25.3547 +
 25.3548 +The result of conversion returned by {\tt str2time} has the same
 25.3549 +meaning as values returned by the function {\tt gmtime} (see Subsection
 25.3550 +\ref{gmtime}, page \pageref{gmtime}). Note that {\tt str2time} does
 25.3551 +{\tt not} correct the calendar time returned for the local timezone,
 25.3552 +i.e. being applied to 00:00:00 on January 1, 1970 it always returns 0.
 25.3553 +
 25.3554 +For example, the model statements:
 25.3555 +
 25.3556 +\medskip
 25.3557 +
 25.3558 +\verb|   param s, symbolic, := "07/14/98 13:47";|
 25.3559 +
 25.3560 +\verb|   param t := str2time(s, "%m/%d/%y %H:%M");|
 25.3561 +
 25.3562 +\verb|   display t;|
 25.3563 +
 25.3564 +\medskip
 25.3565 +
 25.3566 +\noindent produce the following printout:
 25.3567 +
 25.3568 +\medskip
 25.3569 +
 25.3570 +\verb|   t = 900424020|
 25.3571 +
 25.3572 +\medskip
 25.3573 +
 25.3574 +\noindent where the calendar time printed corresponds to 13:47:00 on
 25.3575 +July 14, 1998.
 25.3576 +
 25.3577 +\newpage
 25.3578 +
 25.3579 +The format string passed to the function {\tt str2time} consists of
 25.3580 +conversion specifiers and ordinary characters. Each conversion
 25.3581 +specifier begins with a percent ({\tt\%}) character followed by a
 25.3582 +letter.
 25.3583 +
 25.3584 +The following conversion specifiers may be used in the format string:
 25.3585 +
 25.3586 +\medskip
 25.3587 +
 25.3588 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3589 +{\tt\%b}&The abbreviated month name (case insensitive). At least three
 25.3590 +first letters of the month name must appear in the input string.\\
 25.3591 +\end{tabular}
 25.3592 +
 25.3593 +\medskip
 25.3594 +
 25.3595 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3596 +{\tt\%d}&The day of the month as a decimal number (range 1 to 31).
 25.3597 +Leading zero is permitted, but not required.\\
 25.3598 +\end{tabular}
 25.3599 +
 25.3600 +\medskip
 25.3601 +
 25.3602 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3603 +{\tt\%h}&The same as {\tt\%b}.\\
 25.3604 +\end{tabular}
 25.3605 +
 25.3606 +\medskip
 25.3607 +
 25.3608 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3609 +{\tt\%H}&The hour as a decimal number, using a 24-hour clock (range 0
 25.3610 +to 23). Leading zero is permitted, but not required.\\
 25.3611 +\end{tabular}
 25.3612 +
 25.3613 +\medskip
 25.3614 +
 25.3615 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3616 +{\tt\%m}&The month as a decimal number (range 1 to 12). Leading zero is
 25.3617 +permitted, but not required.\\
 25.3618 +\end{tabular}
 25.3619 +
 25.3620 +\medskip
 25.3621 +
 25.3622 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3623 +{\tt\%M}&The minute as a decimal number (range 0 to 59). Leading zero
 25.3624 +is permitted, but not required.\\
 25.3625 +\end{tabular}
 25.3626 +
 25.3627 +\medskip
 25.3628 +
 25.3629 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3630 +{\tt\%S}&The second as a decimal number (range 0 to 60). Leading zero
 25.3631 +is permitted, but not required.\\
 25.3632 +\end{tabular}
 25.3633 +
 25.3634 +\medskip
 25.3635 +
 25.3636 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3637 +{\tt\%y}&The year without a century as a decimal number (range 0 to 99).
 25.3638 +Leading zero is permitted, but not required. Input values in the range
 25.3639 +0 to 68 are considered as the years 2000 to 2068 while the values 69 to
 25.3640 +99 as the years 1969 to 1999.\\
 25.3641 +\end{tabular}
 25.3642 +
 25.3643 +\medskip
 25.3644 +
 25.3645 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3646 +{\tt\%z}&The offset from GMT in ISO 8601 format.\\
 25.3647 +\end{tabular}
 25.3648 +
 25.3649 +\medskip
 25.3650 +
 25.3651 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3652 +{\tt\%\%}&A literal {\tt\%} character.\\
 25.3653 +\end{tabular}
 25.3654 +
 25.3655 +\medskip
 25.3656 +
 25.3657 +All other (ordinary) characters in the format string must have a
 25.3658 +matching character in the input string to be converted. Exceptions are
 25.3659 +spaces in the input string which can match zero or more space
 25.3660 +characters in the format string.
 25.3661 +
 25.3662 +If some date and/or time component(s) are missing in the format and,
 25.3663 +therefore, in the input string, the function {\tt str2time} uses their
 25.3664 +default values corresponding to 00:00:00 on January 1, 1970, that is,
 25.3665 +the default value of the year is 1970, the default value of the month
 25.3666 +is January, etc.
 25.3667 +
 25.3668 +The function {\tt str2time} is applicable to all calendar times in the
 25.3669 +range 00:00:00 on January 1, 0001 to 23:59:59 on December 31, 4000 of
 25.3670 +the Gregorian calendar.
 25.3671 +
 25.3672 +\subsection{Converting calendar time to character string}
 25.3673 +\label{time2str}
 25.3674 +
 25.3675 +The function {\tt time2str(}{\it t}{\tt,} {\it f}{\tt)} converts the
 25.3676 +calendar time specified by its first argument {\it t}, which must be a
 25.3677 +numeric expression, to a character string (symbolic value). The
 25.3678 +conversion is controlled by the specified format string {\it f} (the
 25.3679 +second argument), which must be a symbolic expression.
 25.3680 +
 25.3681 +The calendar time passed to {\tt time2str} has the same meaning as
 25.3682 +values returned by the function {\tt gmtime} (see Subsection
 25.3683 +\ref{gmtime}, page \pageref{gmtime}). Note that {\tt time2str} does
 25.3684 +{\it not} correct the specified calendar time for the local timezone,
 25.3685 +i.e. the calendar time 0 always corresponds to 00:00:00 on January 1,
 25.3686 +1970.
 25.3687 +
 25.3688 +For example, the model statements:
 25.3689 +
 25.3690 +\medskip
 25.3691 +
 25.3692 +\verb|   param s, symbolic, := time2str(gmtime(), "%FT%TZ");|
 25.3693 +
 25.3694 +\verb|   display s;|
 25.3695 +
 25.3696 +\medskip
 25.3697 +
 25.3698 +\noindent may produce the following printout:
 25.3699 +
 25.3700 +\medskip
 25.3701 +
 25.3702 +\verb|   s = '2008-12-04T00:23:45Z'|
 25.3703 +
 25.3704 +\medskip
 25.3705 +
 25.3706 +\noindent which is a timestamp in the ISO format.
 25.3707 +
 25.3708 +The format string passed to the function {\tt time2str} consists of
 25.3709 +conversion specifiers and ordinary characters. Each conversion
 25.3710 +specifier begins with a percent ({\tt\%}) character followed by a
 25.3711 +letter.
 25.3712 +
 25.3713 +The following conversion specifiers may be used in the format string:
 25.3714 +
 25.3715 +\medskip
 25.3716 +
 25.3717 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3718 +{\tt\%a}&The abbreviated (2-character) weekday name.\\
 25.3719 +\end{tabular}
 25.3720 +
 25.3721 +\medskip
 25.3722 +
 25.3723 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3724 +{\tt\%A}&The full weekday name.\\
 25.3725 +\end{tabular}
 25.3726 +
 25.3727 +\medskip
 25.3728 +
 25.3729 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3730 +{\tt\%b}&The abbreviated (3-character) month name.\\
 25.3731 +\end{tabular}
 25.3732 +
 25.3733 +\medskip
 25.3734 +
 25.3735 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3736 +{\tt\%B}&The full month name.\\
 25.3737 +\end{tabular}
 25.3738 +
 25.3739 +\medskip
 25.3740 +
 25.3741 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3742 +{\tt\%C}&The century of the year, that is the greatest integer not
 25.3743 +greater than the year divided by 100.\\
 25.3744 +\end{tabular}
 25.3745 +
 25.3746 +\medskip
 25.3747 +
 25.3748 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3749 +{\tt\%d}&The day of the month as a decimal number (range 01 to 31).\\
 25.3750 +\end{tabular}
 25.3751 +
 25.3752 +\medskip
 25.3753 +
 25.3754 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3755 +{\tt\%D}&The date using the format \verb|%m/%d/%y|.\\
 25.3756 +\end{tabular}
 25.3757 +
 25.3758 +\medskip
 25.3759 +
 25.3760 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3761 +{\tt\%e}&The day of the month like with \verb|%d|, but padded with
 25.3762 +blank rather than zero.\\
 25.3763 +\end{tabular}
 25.3764 +
 25.3765 +\medskip
 25.3766 +
 25.3767 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3768 +{\tt\%F}&The date using the format \verb|%Y-%m-%d|.\\
 25.3769 +\end{tabular}
 25.3770 +
 25.3771 +\medskip
 25.3772 +
 25.3773 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3774 +{\tt\%g}&The year corresponding to the ISO week number, but without the
 25.3775 +century (range 00 to 99). This has the same format and value as
 25.3776 +\verb|%y|, except that if the ISO week number (see \verb|%V|) belongs
 25.3777 +to the previous or next year, that year is used instead.\\
 25.3778 +\end{tabular}
 25.3779 +
 25.3780 +\medskip
 25.3781 +
 25.3782 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3783 +{\tt\%G}&The year corresponding to the ISO week number. This has the
 25.3784 +same format and value as \verb|%Y|, except that if the ISO week number
 25.3785 +(see \verb|%V|) belongs to the previous or next year, that year is used
 25.3786 +instead.
 25.3787 +\end{tabular}
 25.3788 +
 25.3789 +\medskip
 25.3790 +
 25.3791 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3792 +{\tt\%h}&The same as \verb|%b|.\\
 25.3793 +\end{tabular}
 25.3794 +
 25.3795 +\medskip
 25.3796 +
 25.3797 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3798 +{\tt\%H}&The hour as a decimal number, using a 24-hour clock (range 00
 25.3799 +to 23).\\
 25.3800 +\end{tabular}
 25.3801 +
 25.3802 +\medskip
 25.3803 +
 25.3804 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3805 +{\tt\%I}&The hour as a decimal number, using a 12-hour clock (range 01
 25.3806 +to 12).\\
 25.3807 +\end{tabular}
 25.3808 +
 25.3809 +\medskip
 25.3810 +
 25.3811 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3812 +{\tt\%j}&The day of the year as a decimal number (range 001 to 366).\\
 25.3813 +\end{tabular}
 25.3814 +
 25.3815 +\medskip
 25.3816 +
 25.3817 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3818 +{\tt\%k}&The hour as a decimal number, using a 24-hour clock like
 25.3819 +\verb|%H|, but padded with blank rather than zero.\\
 25.3820 +\end{tabular}
 25.3821 +
 25.3822 +\medskip
 25.3823 +
 25.3824 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3825 +{\tt\%l}&The hour as a decimal number, using a 12-hour clock like
 25.3826 +\verb|%I|, but padded with blank rather than zero.
 25.3827 +\end{tabular}
 25.3828 +
 25.3829 +\medskip
 25.3830 +
 25.3831 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3832 +{\tt\%m}&The month as a decimal number (range 01 to 12).\\
 25.3833 +\end{tabular}
 25.3834 +
 25.3835 +\medskip
 25.3836 +
 25.3837 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3838 +{\tt\%M}&The minute as a decimal number (range 00 to 59).\\
 25.3839 +\end{tabular}
 25.3840 +
 25.3841 +\medskip
 25.3842 +
 25.3843 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3844 +{\tt\%p}&Either {\tt AM} or {\tt PM}, according to the given time value.
 25.3845 +Midnight is treated as {\tt AM} and noon as {\tt PM}.\\
 25.3846 +\end{tabular}
 25.3847 +
 25.3848 +\medskip
 25.3849 +
 25.3850 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3851 +{\tt\%P}&Either {\tt am} or {\tt pm}, according to the given time value.
 25.3852 +Midnight is treated as {\tt am} and noon as {\tt pm}.\\
 25.3853 +\end{tabular}
 25.3854 +
 25.3855 +\medskip
 25.3856 +
 25.3857 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3858 +{\tt\%R}&The hour and minute in decimal numbers using the format
 25.3859 +\verb|%H:%M|.\\
 25.3860 +\end{tabular}
 25.3861 +
 25.3862 +\medskip
 25.3863 +
 25.3864 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3865 +{\tt\%S}&The second as a decimal number (range 00 to 59).\\
 25.3866 +\end{tabular}
 25.3867 +
 25.3868 +\medskip
 25.3869 +
 25.3870 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3871 +{\tt\%T}&The time of day in decimal numbers using the format
 25.3872 +\verb|%H:%M:%S|.\\
 25.3873 +\end{tabular}
 25.3874 +
 25.3875 +\medskip
 25.3876 +
 25.3877 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3878 +{\tt\%u}&The day of the week as a decimal number (range 1 to 7), Monday
 25.3879 +being 1.\\
 25.3880 +\end{tabular}
 25.3881 +
 25.3882 +\medskip
 25.3883 +
 25.3884 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3885 +{\tt\%U}&The week number of the current year as a decimal number (range
 25.3886 +00 to 53), starting with the first Sunday as the first day of the first
 25.3887 +week. Days preceding the first Sunday in the year are considered to be
 25.3888 +in week 00.
 25.3889 +\end{tabular}
 25.3890 +
 25.3891 +\medskip
 25.3892 +
 25.3893 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3894 +{\tt\%V}&The ISO week number as a decimal number (range 01 to 53). ISO
 25.3895 +weeks start with Monday and end with Sunday. Week 01 of a year is the
 25.3896 +first week which has the majority of its days in that year; this is
 25.3897 +equivalent to the week containing January 4. Week 01 of a year can
 25.3898 +contain days from the previous year. The week before week 01 of a year
 25.3899 +is the last week (52 or 53) of the previous year even if it contains
 25.3900 +days from the new year. In other word, if 1 January is Monday, Tuesday,
 25.3901 +Wednesday or Thursday, it is in week 01; if 1 January is Friday,
 25.3902 +Saturday or Sunday, it is in week 52 or 53 of the previous year.\\
 25.3903 +\end{tabular}
 25.3904 +
 25.3905 +\medskip
 25.3906 +
 25.3907 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3908 +{\tt\%w}&The day of the week as a decimal number (range 0 to 6), Sunday
 25.3909 +being 0.\\
 25.3910 +\end{tabular}
 25.3911 +
 25.3912 +\medskip
 25.3913 +
 25.3914 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3915 +{\tt\%W}&The week number of the current year as a decimal number (range
 25.3916 +00 to 53), starting with the first Monday as the first day of the first
 25.3917 +week. Days preceding the first Monday in the year are considered to be
 25.3918 +in week 00.\\
 25.3919 +\end{tabular}
 25.3920 +
 25.3921 +\medskip
 25.3922 +
 25.3923 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3924 +{\tt\%y}&The year without a century as a decimal number (range 00 to
 25.3925 +99), that is the year modulo 100.\\
 25.3926 +\end{tabular}
 25.3927 +
 25.3928 +\medskip
 25.3929 +
 25.3930 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3931 +{\tt\%Y}&The year as a decimal number, using the Gregorian calendar.\\
 25.3932 +\end{tabular}
 25.3933 +
 25.3934 +\medskip
 25.3935 +
 25.3936 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
 25.3937 +{\tt\%\%}&A literal \verb|%| character.\\
 25.3938 +\end{tabular}
 25.3939 +
 25.3940 +\medskip
 25.3941 +
 25.3942 +All other (ordinary) characters in the format string are simply copied
 25.3943 +to the resultant string.
 25.3944 +
 25.3945 +The first argument (calendar time) passed to the function {\tt time2str}
 25.3946 +must be in the range from $-62135596800$ to $+64092211199$ that
 25.3947 +corresponds to the period from 00:00:00 on January 1, 0001 to 23:59:59
 25.3948 +on December 31, 4000 of the Gregorian calendar.
 25.3949 +
 25.3950 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 25.3951 +
 25.3952 +\newpage
 25.3953 +
 25.3954 +\section{Table drivers}
 25.3955 +\label{drivers}
 25.3956 +
 25.3957 +\noindent\hfil
 25.3958 +by Andrew Makhorin \verb|<mao@gnu.org>|
 25.3959 +
 25.3960 +\noindent\hfil
 25.3961 +and Heinrich Schuchardt \verb|<heinrich.schuchardt@gmx.de>|
 25.3962 +
 25.3963 +\bigskip\bigskip
 25.3964 +
 25.3965 +The {\it table driver} is a program module which provides transmitting
 25.3966 +data between MathProg model objects and data tables.
 25.3967 +
 25.3968 +Currently the GLPK package has four table drivers:
 25.3969 +
 25.3970 +\setlength{\leftmargini}{2.5em}
 25.3971 +
 25.3972 +\begin{itemize}
 25.3973 +\item built-in CSV table driver;
 25.3974 +\item built-in xBASE table driver;
 25.3975 +\item ODBC table driver;
 25.3976 +\item MySQL table driver.
 25.3977 +\end{itemize}
 25.3978 +
 25.3979 +\subsection{CSV table driver}
 25.3980 +
 25.3981 +The CSV table driver assumes that the data table is represented in the
 25.3982 +form of a plain text file in the CSV (comma-separated values) file
 25.3983 +format as described below.
 25.3984 +
 25.3985 +To choose the CSV table driver its name in the table statement should
 25.3986 +be specified as \verb|"CSV"|, and the only argument should specify the
 25.3987 +name of a plain text file containing the table. For example:
 25.3988 +
 25.3989 +\medskip
 25.3990 +
 25.3991 +\verb|   table data IN "CSV" "data.csv": ... ;|
 25.3992 +
 25.3993 +\medskip
 25.3994 +
 25.3995 +The filename suffix may be arbitrary, however, it is recommended to use
 25.3996 +the suffix `\verb|.csv|'.
 25.3997 +
 25.3998 +On reading input tables the CSV table driver provides an implicit field
 25.3999 +named \verb|RECNO|, which contains the current record number. This
 25.4000 +field can be specified in the input table statement as if there were
 25.4001 +the actual field having the name \verb|RECNO| in the CSV file. For
 25.4002 +example:
 25.4003 +
 25.4004 +\medskip
 25.4005 +
 25.4006 +\verb|   table list IN "CSV" "list.csv": num <- [RECNO], ... ;|
 25.4007 +
 25.4008 +\subsubsection*{CSV format\footnote{This material is based on the RFC
 25.4009 +document 4180.}}
 25.4010 +
 25.4011 +The CSV (comma-separated values) format is a plain text file format
 25.4012 +defined as follows.
 25.4013 +
 25.4014 +1. Each record is located on a separate line, delimited by a line
 25.4015 +break. For example:
 25.4016 +
 25.4017 +\medskip
 25.4018 +
 25.4019 +\verb|   aaa,bbb,ccc\n|
 25.4020 +
 25.4021 +\verb|   xxx,yyy,zzz\n|
 25.4022 +
 25.4023 +\medskip
 25.4024 +
 25.4025 +\noindent
 25.4026 +where \verb|\n| means the control character \verb|LF| ({\tt 0x0A}).
 25.4027 +
 25.4028 +\newpage
 25.4029 +
 25.4030 +2. The last record in the file may or may not have an ending line
 25.4031 +break. For example:
 25.4032 +
 25.4033 +\medskip
 25.4034 +
 25.4035 +\verb|   aaa,bbb,ccc\n|
 25.4036 +
 25.4037 +\verb|   xxx,yyy,zzz|
 25.4038 +
 25.4039 +\medskip
 25.4040 +
 25.4041 +3. There should be a header line appearing as the first line of the
 25.4042 +file in the same format as normal record lines. This header should
 25.4043 +contain names corresponding to the fields in the file. The number of
 25.4044 +field names in the header line should be the same as the number of
 25.4045 +fields in the records of the file. For example:
 25.4046 +
 25.4047 +\medskip
 25.4048 +
 25.4049 +\verb|   name1,name2,name3\n|
 25.4050 +
 25.4051 +\verb|   aaa,bbb,ccc\n|
 25.4052 +
 25.4053 +\verb|   xxx,yyy,zzz\n|
 25.4054 +
 25.4055 +\medskip
 25.4056 +
 25.4057 +4. Within the header and each record there may be one or more fields
 25.4058 +separated by commas. Each line should contain the same number of fields
 25.4059 +throughout the file. Spaces are considered as part of a field and
 25.4060 +therefore not ignored. The last field in the record should not be
 25.4061 +followed by a comma. For example:
 25.4062 +
 25.4063 +\medskip
 25.4064 +
 25.4065 +\verb|   aaa,bbb,ccc\n|
 25.4066 +
 25.4067 +\medskip
 25.4068 +
 25.4069 +5. Fields may or may not be enclosed in double quotes. For example:
 25.4070 +
 25.4071 +\medskip
 25.4072 +
 25.4073 +\verb|   "aaa","bbb","ccc"\n|
 25.4074 +
 25.4075 +\verb|   zzz,yyy,xxx\n|
 25.4076 +
 25.4077 +\medskip
 25.4078 +
 25.4079 +6. If a field is enclosed in double quotes, each double quote which is
 25.4080 +part of the field should be coded twice. For example:
 25.4081 +
 25.4082 +\medskip
 25.4083 +
 25.4084 +\verb|   "aaa","b""bb","ccc"\n|
 25.4085 +
 25.4086 +\medskip
 25.4087 +
 25.4088 +\noindent{\bf Example}
 25.4089 +
 25.4090 +\begin{verbatim}
 25.4091 +FROM,TO,DISTANCE,COST
 25.4092 +Seattle,New-York,2.5,0.12
 25.4093 +Seattle,Chicago,1.7,0.08
 25.4094 +Seattle,Topeka,1.8,0.09
 25.4095 +San-Diego,New-York,2.5,0.15
 25.4096 +San-Diego,Chicago,1.8,0.10
 25.4097 +San-Diego,Topeka,1.4,0.07
 25.4098 +\end{verbatim}
 25.4099 +
 25.4100 +\subsection{xBASE table driver}
 25.4101 +
 25.4102 +The xBASE table driver assumes that the data table is stored in the
 25.4103 +.dbf file format.
 25.4104 +
 25.4105 +To choose the xBASE table driver its name in the table statement should
 25.4106 +be specified as \verb|"xBASE"|, and the first argument should specify
 25.4107 +the name of a .dbf file containing the table. For the output table there
 25.4108 +should be the second argument defining the table format in the form
 25.4109 +\verb|"FF...F"|, where \verb|F| is either {\tt C({\it n})},
 25.4110 +which specifies a character field of length $n$, or
 25.4111 +{\tt N({\it n}{\rm [},{\it p}{\rm ]})}, which specifies a numeric field
 25.4112 +of length $n$ and precision $p$ (by default $p$ is 0).
 25.4113 +
 25.4114 +The following is a simple example which illustrates creating and
 25.4115 +reading a .dbf file:
 25.4116 +
 25.4117 +\begin{verbatim}
 25.4118 +table tab1{i in 1..10} OUT "xBASE" "foo.dbf"
 25.4119 +   "N(5)N(10,4)C(1)C(10)": 2*i+1 ~ B, Uniform(-20,+20) ~ A,
 25.4120 +   "?" ~ FOO, "[" & i & "]" ~ C;
 25.4121 +set S, dimen 4;
 25.4122 +table tab2 IN "xBASE" "foo.dbf": S <- [B, C, RECNO, A];
 25.4123 +display S;
 25.4124 +end;
 25.4125 +\end{verbatim}
 25.4126 +
 25.4127 +\subsection{ODBC table driver}
 25.4128 +
 25.4129 +The ODBC table driver allows connecting to SQL databases using an
 25.4130 +implementation of the ODBC interface based on the Call Level Interface
 25.4131 +(CLI).\footnote{The corresponding software standard is defined in
 25.4132 +ISO/IEC 9075-3:2003.}
 25.4133 +
 25.4134 +\paragraph{Debian GNU/Linux.}
 25.4135 +Under Debian GNU/Linux the ODBC table driver uses the iODBC
 25.4136 +package,\footnote{See {\tt<http://www.iodbc.org/>}.} which should be
 25.4137 +installed before building the GLPK package. The installation can be
 25.4138 +effected with the following command:
 25.4139 +
 25.4140 +\begin{verbatim}
 25.4141 +sudo apt-get install libiodbc2-dev
 25.4142 +\end{verbatim}
 25.4143 +
 25.4144 +Note that on configuring the GLPK package to enable using the iODBC
 25.4145 +library the option `\verb|--enable-odbc|' should be passed to the
 25.4146 +configure script.
 25.4147 +
 25.4148 +The individual databases must be entered for systemwide usage in
 25.4149 +\linebreak \verb|/etc/odbc.ini| and \verb|/etc/odbcinst.ini|. Database
 25.4150 +connections to be used by a single user are specified by files in the
 25.4151 +home directory (\verb|.odbc.ini| and \verb|.odbcinst.ini|).
 25.4152 +
 25.4153 +\paragraph{Microsoft Windows.}
 25.4154 +Under Microsoft Windows the ODBC table driver uses the Microsoft ODBC
 25.4155 +library. To enable this feature the symbol:
 25.4156 +
 25.4157 +\begin{verbatim}
 25.4158 +#define ODBC_DLNAME "odbc32.dll"
 25.4159 +\end{verbatim}
 25.4160 +
 25.4161 +\noindent
 25.4162 +should be defined in the GLPK configuration file `\verb|config.h|'.
 25.4163 +
 25.4164 +Data sources can be created via the Administrative Tools from the
 25.4165 +Control Panel.
 25.4166 +
 25.4167 +\bigskip
 25.4168 +
 25.4169 +To choose the ODBC table driver its name in the table statement should
 25.4170 +be specified as \verb|'ODBC'| or \verb|'iODBC'|.
 25.4171 +
 25.4172 +The argument list is specified as follows.
 25.4173 +
 25.4174 +The first argument is the connection string passed to the ODBC library,
 25.4175 +for example:
 25.4176 +
 25.4177 +\verb|'DSN=glpk;UID=user;PWD=password'|, or
 25.4178 +
 25.4179 +\verb|'DRIVER=MySQL;DATABASE=glpkdb;UID=user;PWD=password'|.
 25.4180 +
 25.4181 +Different parts of the string are separated by semicolons. Each part
 25.4182 +consists of a pair {\it fieldname} and {\it value} separated by the
 25.4183 +equal sign. Allowable fieldnames depend on the ODBC library. Typically
 25.4184 +the following fieldnames are allowed:
 25.4185 +
 25.4186 +\verb|DATABASE | database;
 25.4187 +
 25.4188 +\verb|DRIVER   | ODBC driver;
 25.4189 +
 25.4190 +\verb|DSN      | name of a data source;
 25.4191 +
 25.4192 +\verb|FILEDSN  | name of a file data source;
 25.4193 +
 25.4194 +\verb|PWD      | user password;
 25.4195 +
 25.4196 +\verb|SERVER   | database;
 25.4197 +
 25.4198 +\verb|UID      | user name.
 25.4199 +
 25.4200 +The second argument and all following are considered to be SQL
 25.4201 +statements
 25.4202 +
 25.4203 +SQL statements may be spread over multiple arguments.  If the last
 25.4204 +character of an argument is a semicolon this indicates the end of
 25.4205 +a SQL statement.
 25.4206 +
 25.4207 +The arguments of a SQL statement are concatenated separated by space.
 25.4208 +The eventual trailing semicolon will be removed.
 25.4209 +
 25.4210 +All but the last SQL statement will be executed directly.
 25.4211 +
 25.4212 +For IN-table the last SQL statement can be a SELECT command starting
 25.4213 +with the capitalized letters \verb|'SELECT '|. If the string does not
 25.4214 +start with \verb|'SELECT '| it is considered to be a table name and a
 25.4215 +SELECT statement is automatically generated.
 25.4216 +
 25.4217 +For OUT-table the last SQL statement can contain one or multiple
 25.4218 +question marks. If it contains a question mark it is considered a
 25.4219 +template for the write routine. Otherwise the string is considered a
 25.4220 +table name and an INSERT template is automatically generated.
 25.4221 +
 25.4222 +The writing routine uses the template with the question marks and
 25.4223 +replaces the first question mark by the first output parameter, the
 25.4224 +second question mark by the second output parameter and so forth. Then
 25.4225 +the SQL command is issued.
 25.4226 +
 25.4227 +The following is an example of the output table statement:
 25.4228 +
 25.4229 +\begin{small}
 25.4230 +\begin{verbatim}
 25.4231 +table ta { l in LOCATIONS } OUT
 25.4232 +   'ODBC'
 25.4233 +   'DSN=glpkdb;UID=glpkuser;PWD=glpkpassword'
 25.4234 +   'DROP TABLE IF EXISTS result;'
 25.4235 +   'CREATE TABLE result ( ID INT, LOC VARCHAR(255), QUAN DOUBLE );'
 25.4236 +   'INSERT INTO result 'VALUES ( 4, ?, ? )' :
 25.4237 +   l ~ LOC, quantity[l] ~ QUAN;
 25.4238 +\end{verbatim}
 25.4239 +\end{small}
 25.4240 +
 25.4241 +\noindent
 25.4242 +Alternatively it could be written as follows:
 25.4243 +
 25.4244 +\begin{small}
 25.4245 +\begin{verbatim}
 25.4246 +table ta { l in LOCATIONS } OUT
 25.4247 +   'ODBC'
 25.4248 +   'DSN=glpkdb;UID=glpkuser;PWD=glpkpassword'
 25.4249 +   'DROP TABLE IF EXISTS result;'
 25.4250 +   'CREATE TABLE result ( ID INT, LOC VARCHAR(255), QUAN DOUBLE );'
 25.4251 +   'result' :
 25.4252 +   l ~ LOC, quantity[l] ~ QUAN, 4 ~ ID;
 25.4253 +\end{verbatim}
 25.4254 +\end{small}
 25.4255 +
 25.4256 +Using templates with `\verb|?|' supports not only INSERT, but also
 25.4257 +UPDATE, DELETE, etc. For example:
 25.4258 +
 25.4259 +\begin{small}
 25.4260 +\begin{verbatim}
 25.4261 +table ta { l in LOCATIONS } OUT
 25.4262 +   'ODBC'
 25.4263 +   'DSN=glpkdb;UID=glpkuser;PWD=glpkpassword'
 25.4264 +   'UPDATE result SET DATE = ' & date & ' WHERE ID = 4;'
 25.4265 +   'UPDATE result SET QUAN = ? WHERE LOC = ? AND ID = 4' :
 25.4266 +   quantity[l], l;
 25.4267 +\end{verbatim}
 25.4268 +\end{small}
 25.4269 +
 25.4270 +\subsection{MySQL table driver}
 25.4271 +
 25.4272 +The MySQL table driver allows connecting to MySQL databases.
 25.4273 +
 25.4274 +\paragraph{Debian GNU/Linux.}
 25.4275 +Under Debian GNU/Linux the MySQL table\linebreak driver uses the MySQL
 25.4276 +package,\footnote{For download development files see
 25.4277 +{\tt<http://dev.mysql.com/downloads/mysql/>}.} which should be installed
 25.4278 +before building the GLPK package. The installation can be effected with
 25.4279 +the following command:
 25.4280 +
 25.4281 +\begin{verbatim}
 25.4282 +sudo apt-get install libmysqlclient15-dev
 25.4283 +\end{verbatim}
 25.4284 +
 25.4285 +Note that on configuring the GLPK package to enable using the MySQL
 25.4286 +library the option `\verb|--enable-mysql|' should be passed to the
 25.4287 +configure script.
 25.4288 +
 25.4289 +\paragraph{Microsoft Windows.}
 25.4290 +Under Microsoft Windows the MySQL table driver also uses the MySQL
 25.4291 +library. To enable this feature the symbol:
 25.4292 +
 25.4293 +\begin{verbatim}
 25.4294 +#define MYSQL_DLNAME "libmysql.dll"
 25.4295 +\end{verbatim}
 25.4296 +
 25.4297 +\noindent
 25.4298 +should be defined in the GLPK configuration file `\verb|config.h|'.
 25.4299 +
 25.4300 +\bigskip
 25.4301 +
 25.4302 +To choose the MySQL table driver its name in the table statement should
 25.4303 +be specified as \verb|'MySQL'|.
 25.4304 +
 25.4305 +The argument list is specified as follows.
 25.4306 +
 25.4307 +The first argument specifies how to connect the data base in the DSN
 25.4308 +style, for example:
 25.4309 +
 25.4310 +\verb|'Database=glpk;UID=glpk;PWD=gnu'|.
 25.4311 +
 25.4312 +Different parts of the string are separated by semicolons. Each part
 25.4313 +consists of a pair {\it fieldname} and {\it value} separated by the
 25.4314 +equal sign. The following fieldnames are allowed:
 25.4315 +
 25.4316 +\verb|Server   | server running the database (defaulting to localhost);
 25.4317 +
 25.4318 +\verb|Database | name of the database;
 25.4319 +
 25.4320 +\verb|UID      | user name;
 25.4321 +
 25.4322 +\verb|PWD      | user password;
 25.4323 +
 25.4324 +\verb|Port     | port used by the server (defaulting to 3306).
 25.4325 +
 25.4326 +The second argument and all following are considered to be SQL
 25.4327 +statements
 25.4328 +
 25.4329 +SQL statements may be spread over multiple arguments.  If the last
 25.4330 +character of an argument is a semicolon this indicates the end of
 25.4331 +a SQL statement.
 25.4332 +
 25.4333 +The arguments of a SQL statement are concatenated separated by space.
 25.4334 +The eventual trailing semicolon will be removed.
 25.4335 +
 25.4336 +All but the last SQL statement will be executed directly.
 25.4337 +
 25.4338 +For IN-table the last SQL statement can be a SELECT command starting
 25.4339 +with the capitalized letters \verb|'SELECT '|. If the string does not
 25.4340 +start with \verb|'SELECT '| it is considered to be a table name and a
 25.4341 +SELECT statement is automatically generated.
 25.4342 +
 25.4343 +For OUT-table the last SQL statement can contain one or multiple
 25.4344 +question marks. If it contains a question mark it is considered a
 25.4345 +template for the write routine. Otherwise the string is considered a
 25.4346 +table name and an INSERT template is automatically generated.
 25.4347 +
 25.4348 +The writing routine uses the template with the question marks and
 25.4349 +replaces the first question mark by the first output parameter, the
 25.4350 +second question mark by the second output parameter and so forth. Then
 25.4351 +the SQL command is issued.
 25.4352 +
 25.4353 +The following is an example of the output table statement:
 25.4354 +
 25.4355 +\begin{small}
 25.4356 +\begin{verbatim}
 25.4357 +table ta { l in LOCATIONS } OUT
 25.4358 +   'MySQL'
 25.4359 +   'Database=glpkdb;UID=glpkuser;PWD=glpkpassword'
 25.4360 +   'DROP TABLE IF EXISTS result;'
 25.4361 +   'CREATE TABLE result ( ID INT, LOC VARCHAR(255), QUAN DOUBLE );'
 25.4362 +   'INSERT INTO result VALUES ( 4, ?, ? )' :
 25.4363 +   l ~ LOC, quantity[l] ~ QUAN;
 25.4364 +\end{verbatim}
 25.4365 +\end{small}
 25.4366 +
 25.4367 +\noindent
 25.4368 +Alternatively it could be written as follows:
 25.4369 +
 25.4370 +\begin{small}
 25.4371 +\begin{verbatim}
 25.4372 +table ta { l in LOCATIONS } OUT
 25.4373 +   'MySQL'
 25.4374 +   'Database=glpkdb;UID=glpkuser;PWD=glpkpassword'
 25.4375 +   'DROP TABLE IF EXISTS result;'
 25.4376 +   'CREATE TABLE result ( ID INT, LOC VARCHAR(255), QUAN DOUBLE );'
 25.4377 +   'result' :
 25.4378 +   l ~ LOC, quantity[l] ~ QUAN, 4 ~ ID;
 25.4379 +\end{verbatim}
 25.4380 +\end{small}
 25.4381 +
 25.4382 +Using templates with `\verb|?|' supports not only INSERT, but also
 25.4383 +UPDATE, DELETE, etc. For example:
 25.4384 +
 25.4385 +\begin{small}
 25.4386 +\begin{verbatim}
 25.4387 +table ta { l in LOCATIONS } OUT
 25.4388 +   'MySQL'
 25.4389 +   'Database=glpkdb;UID=glpkuser;PWD=glpkpassword'
 25.4390 +   'UPDATE result SET DATE = ' & date & ' WHERE ID = 4;'
 25.4391 +   'UPDATE result SET QUAN = ? WHERE LOC = ? AND ID = 4' :
 25.4392 +   quantity[l], l;
 25.4393 +\end{verbatim}
 25.4394 +\end{small}
 25.4395 +
 25.4396 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 25.4397 +
 25.4398 +\newpage
 25.4399 +
 25.4400 +\section{Solving models with glpsol}
 25.4401 +
 25.4402 +The GLPK package\footnote{{\tt http://www.gnu.org/software/glpk/}}
 25.4403 +includes the program {\tt glpsol}, which is a stand-alone LP/MIP solver.
 25.4404 +This program can be launched from the command line or from the shell to
 25.4405 +solve models written in the GNU MathProg modeling language.
 25.4406 +
 25.4407 +In order to tell the solver that the input file contains a model
 25.4408 +description, you need to specify the option \verb|--model| in the
 25.4409 +command line. For example:
 25.4410 +
 25.4411 +\medskip
 25.4412 +
 25.4413 +\verb|   glpsol --model foo.mod|
 25.4414 +
 25.4415 +\medskip
 25.4416 +
 25.4417 +Sometimes it is necessary to use the data section placed in a separate
 25.4418 +file, in which case you may use the following command:
 25.4419 +
 25.4420 +\medskip
 25.4421 +
 25.4422 +\verb|   glpsol --model foo.mod --data foo.dat|
 25.4423 +
 25.4424 +\medskip
 25.4425 +
 25.4426 +\noindent Note that if the model file also contains the data section,
 25.4427 +that section is ignored.
 25.4428 +
 25.4429 +If the model description contains some display and/or printf statements,
 25.4430 +by default the output is sent to the terminal. In order to redirect the
 25.4431 +output to a file you may use the following command:
 25.4432 +
 25.4433 +\medskip
 25.4434 +
 25.4435 +\verb|   glpsol --model foo.mod --display foo.out|
 25.4436 +
 25.4437 +\medskip
 25.4438 +
 25.4439 +If you need to look at the problem, which has been generated by the
 25.4440 +model translator, you may use the option \verb|--wlp| as follows:
 25.4441 +
 25.4442 +\medskip
 25.4443 +
 25.4444 +\verb|   glpsol --model foo.mod --wlp foo.lp|
 25.4445 +
 25.4446 +\medskip
 25.4447 +
 25.4448 +\noindent in which case the problem data is written to file
 25.4449 +\verb|foo.lp| in CPLEX LP format suitable for visual analysis.
 25.4450 +
 25.4451 +Sometimes it is needed merely to check the model description not
 25.4452 +solving the generated problem instance. In this case you may specify
 25.4453 +the option \verb|--check|, for example:
 25.4454 +
 25.4455 +\medskip
 25.4456 +
 25.4457 +\verb|   glpsol --check --model foo.mod --wlp foo.lp|
 25.4458 +
 25.4459 +\medskip
 25.4460 +
 25.4461 +In order to write a numeric solution obtained by the solver you may use
 25.4462 +the following command:
 25.4463 +
 25.4464 +\medskip
 25.4465 +
 25.4466 +\verb|   glpsol --model foo.mod --output foo.sol|
 25.4467 +
 25.4468 +\medskip
 25.4469 +
 25.4470 +\noindent in which case the solution is written to file \verb|foo.sol|
 25.4471 +in a plain text format.
 25.4472 +
 25.4473 +The complete list of the \verb|glpsol| options can be found in the
 25.4474 +reference manual included in the GLPK distribution.
 25.4475 +
 25.4476 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 25.4477 +
 25.4478 +\newpage
 25.4479 +
 25.4480 +\section{Example model description}
 25.4481 +
 25.4482 +\subsection{Model description written in MathProg}
 25.4483 +
 25.4484 +Below here is a complete example of the model description written in
 25.4485 +the GNU MathProg modeling language.
 25.4486 +
 25.4487 +\begin{small}
 25.4488 +\begin{verbatim}
 25.4489 +# A TRANSPORTATION PROBLEM
 25.4490 +#
 25.4491 +# This problem finds a least cost shipping schedule that meets
 25.4492 +# requirements at markets and supplies at factories.
 25.4493 +#
 25.4494 +#  References:
 25.4495 +#              Dantzig G B, "Linear Programming and Extensions."
 25.4496 +#              Princeton University Press, Princeton, New Jersey, 1963,
 25.4497 +#              Chapter 3-3.
 25.4498 +
 25.4499 +set I;
 25.4500 +/* canning plants */
 25.4501 +
 25.4502 +set J;
 25.4503 +/* markets */
 25.4504 +
 25.4505 +param a{i in I};
 25.4506 +/* capacity of plant i in cases */
 25.4507 +
 25.4508 +param b{j in J};
 25.4509 +/* demand at market j in cases */
 25.4510 +
 25.4511 +param d{i in I, j in J};
 25.4512 +/* distance in thousands of miles */
 25.4513 +
 25.4514 +param f;
 25.4515 +/* freight in dollars per case per thousand miles */
 25.4516 +
 25.4517 +param c{i in I, j in J} := f * d[i,j] / 1000;
 25.4518 +/* transport cost in thousands of dollars per case */
 25.4519 +
 25.4520 +var x{i in I, j in J} >= 0;
 25.4521 +/* shipment quantities in cases */
 25.4522 +
 25.4523 +minimize cost: sum{i in I, j in J} c[i,j] * x[i,j];
 25.4524 +/* total transportation costs in thousands of dollars */
 25.4525 +
 25.4526 +s.t. supply{i in I}: sum{j in J} x[i,j] <= a[i];
 25.4527 +/* observe supply limit at plant i */
 25.4528 +
 25.4529 +s.t. demand{j in J}: sum{i in I} x[i,j] >= b[j];
 25.4530 +/* satisfy demand at market j */
 25.4531 +
 25.4532 +data;
 25.4533 +
 25.4534 +set I := Seattle San-Diego;
 25.4535 +
 25.4536 +set J := New-York Chicago Topeka;
 25.4537 +
 25.4538 +param a := Seattle     350
 25.4539 +           San-Diego   600;
 25.4540 +
 25.4541 +param b := New-York    325
 25.4542 +           Chicago     300
 25.4543 +           Topeka      275;
 25.4544 +
 25.4545 +param d :              New-York   Chicago   Topeka :=
 25.4546 +           Seattle     2.5        1.7       1.8
 25.4547 +           San-Diego   2.5        1.8       1.4  ;
 25.4548 +
 25.4549 +param f := 90;
 25.4550 +
 25.4551 +end;
 25.4552 +\end{verbatim}
 25.4553 +\end{small}
 25.4554 +
 25.4555 +\subsection{Generated LP problem instance}
 25.4556 +
 25.4557 +Below here is the result of the translation of the example model
 25.4558 +produced by the solver \verb|glpsol| and written in CPLEX LP format
 25.4559 +with the option \verb|--wlp|.
 25.4560 +
 25.4561 +\begin{small}
 25.4562 +\begin{verbatim}
 25.4563 +\* Problem: transp *\
 25.4564 +
 25.4565 +Minimize
 25.4566 + cost: + 0.225 x(Seattle,New~York) + 0.153 x(Seattle,Chicago)
 25.4567 + + 0.162 x(Seattle,Topeka) + 0.225 x(San~Diego,New~York)
 25.4568 + + 0.162 x(San~Diego,Chicago) + 0.126 x(San~Diego,Topeka)
 25.4569 +
 25.4570 +Subject To
 25.4571 + supply(Seattle): + x(Seattle,New~York) + x(Seattle,Chicago)
 25.4572 + + x(Seattle,Topeka) <= 350
 25.4573 + supply(San~Diego): + x(San~Diego,New~York) + x(San~Diego,Chicago)
 25.4574 + + x(San~Diego,Topeka) <= 600
 25.4575 + demand(New~York): + x(Seattle,New~York) + x(San~Diego,New~York) >= 325
 25.4576 + demand(Chicago): + x(Seattle,Chicago) + x(San~Diego,Chicago) >= 300
 25.4577 + demand(Topeka): + x(Seattle,Topeka) + x(San~Diego,Topeka) >= 275
 25.4578 +
 25.4579 +End
 25.4580 +\end{verbatim}
 25.4581 +\end{small}
 25.4582 +
 25.4583 +\subsection{Optimal LP solution}
 25.4584 +
 25.4585 +Below here is the optimal solution of the generated LP problem instance
 25.4586 +found by the solver \verb|glpsol| and written in plain text format
 25.4587 +with the option \verb|--output|.
 25.4588 +
 25.4589 +\newpage
 25.4590 +
 25.4591 +\begin{small}
 25.4592 +\begin{verbatim}
 25.4593 +Problem:    transp
 25.4594 +Rows:       6
 25.4595 +Columns:    6
 25.4596 +Non-zeros:  18
 25.4597 +Status:     OPTIMAL
 25.4598 +Objective:  cost = 153.675 (MINimum)
 25.4599 +
 25.4600 +No.   Row name   St   Activity    Lower bound  Upper bound   Marginal
 25.4601 +--- ------------ -- ------------ ------------ ------------ ------------
 25.4602 +  1 cost         B       153.675
 25.4603 +  2 supply[Seattle]
 25.4604 +                 B           300                       350
 25.4605 +  3 supply[San-Diego]
 25.4606 +                 NU          600                       600        < eps
 25.4607 +  4 demand[New-York]
 25.4608 +                 NL          325          325                     0.225
 25.4609 +  5 demand[Chicago]
 25.4610 +                 NL          300          300                     0.153
 25.4611 +  6 demand[Topeka]
 25.4612 +                 NL          275          275                     0.126
 25.4613 +
 25.4614 +No. Column name  St   Activity    Lower bound  Upper bound   Marginal
 25.4615 +--- ------------ -- ------------ ------------ ------------ ------------
 25.4616 +  1 x[Seattle,New-York]
 25.4617 +                 B             0            0
 25.4618 +  2 x[Seattle,Chicago]
 25.4619 +                 B           300            0
 25.4620 +  3 x[Seattle,Topeka]
 25.4621 +                 NL            0            0                     0.036
 25.4622 +  4 x[San-Diego,New-York]
 25.4623 +                 B           325            0
 25.4624 +  5 x[San-Diego,Chicago]
 25.4625 +                 NL            0            0                     0.009
 25.4626 +  6 x[San-Diego,Topeka]
 25.4627 +                 B           275            0
 25.4628 +
 25.4629 +End of output
 25.4630 +\end{verbatim}
 25.4631 +\end{small}
 25.4632 +
 25.4633 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 25.4634 +
 25.4635 +\newpage
 25.4636 +
 25.4637 +\setcounter{secnumdepth}{-1}
 25.4638 +
 25.4639 +\section{Acknowledgment}
 25.4640 +
 25.4641 +The authors would like to thank the following people, who kindly read,
 25.4642 +commented, and corrected the draft of this document:
 25.4643 +
 25.4644 +\medskip
 25.4645 +
 25.4646 +\noindent Juan Carlos Borras \verb|<borras@cs.helsinki.fi>|
 25.4647 +
 25.4648 +\medskip
 25.4649 +
 25.4650 +\noindent Harley Mackenzie \verb|<hjm@bigpond.com>|
 25.4651 +
 25.4652 +\medskip
 25.4653 +
 25.4654 +\noindent Robbie Morrison \verb|<robbie@actrix.co.nz>|
 25.4655 +
 25.4656 +\end{document}
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/doc/graphs.tex	Mon Dec 06 13:09:21 2010 +0100
    26.3 @@ -0,0 +1,3935 @@
    26.4 +%* graphs.tex *%
    26.5 +
    26.6 +%***********************************************************************
    26.7 +%  This code is part of GLPK (GNU Linear Programming Kit).
    26.8 +%
    26.9 +%  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
   26.10 +%  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
   26.11 +%  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
   26.12 +%  E-mail: <mao@gnu.org>.
   26.13 +%
   26.14 +%  GLPK is free software: you can redistribute it and/or modify it
   26.15 +%  under the terms of the GNU General Public License as published by
   26.16 +%  the Free Software Foundation, either version 3 of the License, or
   26.17 +%  (at your option) any later version.
   26.18 +%
   26.19 +%  GLPK is distributed in the hope that it will be useful, but WITHOUT
   26.20 +%  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   26.21 +%  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
   26.22 +%  License for more details.
   26.23 +%
   26.24 +%  You should have received a copy of the GNU General Public License
   26.25 +%  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
   26.26 +%***********************************************************************
   26.27 +
   26.28 +\documentclass[11pt]{report}
   26.29 +\usepackage{amssymb}
   26.30 +\usepackage[dvipdfm,linktocpage,colorlinks,linkcolor=blue,
   26.31 +urlcolor=blue]{hyperref}
   26.32 +\usepackage[all]{xy}
   26.33 +
   26.34 +\renewcommand\contentsname{\sf\bfseries Contents}
   26.35 +\renewcommand\chaptername{\sf\bfseries Chapter}
   26.36 +\renewcommand\appendixname{\sf\bfseries Appendix}
   26.37 +
   26.38 +\begin{document}
   26.39 +
   26.40 +\thispagestyle{empty}
   26.41 +
   26.42 +\begin{center}
   26.43 +
   26.44 +\vspace*{1in}
   26.45 +
   26.46 +\begin{huge}
   26.47 +\sf\bfseries GNU Linear Programming Kit
   26.48 +\end{huge}
   26.49 +
   26.50 +\vspace{0.5in}
   26.51 +
   26.52 +\begin{LARGE}
   26.53 +\sf Graph and Network Routines
   26.54 +\end{LARGE}
   26.55 +
   26.56 +\vspace{0.5in}
   26.57 +
   26.58 +\begin{LARGE}
   26.59 +\sf for GLPK Version 4.45
   26.60 +\end{LARGE}
   26.61 +
   26.62 +\vspace{0.5in}
   26.63 +\begin{Large}
   26.64 +\sf (DRAFT, December 2010)
   26.65 +\end{Large}
   26.66 +\end{center}
   26.67 +
   26.68 +\newpage
   26.69 +
   26.70 +\vspace*{1in}
   26.71 +
   26.72 +\vfill
   26.73 +
   26.74 +\noindent
   26.75 +The GLPK package is part of the GNU Project released under the aegis of
   26.76 +GNU.
   26.77 +
   26.78 +\medskip \noindent
   26.79 +Copyright \copyright{} 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
   26.80 +2008, 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
   26.81 +Moscow Aviation Institute, Moscow, Russia. All rights reserved.
   26.82 +
   26.83 +\medskip \noindent
   26.84 +Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
   26.85 +02110-1301, USA.
   26.86 +
   26.87 +\medskip \noindent
   26.88 +Permission is granted to make and distribute verbatim copies of this
   26.89 +manual provided the copyright notice and this permission notice are
   26.90 +preserved on all copies.
   26.91 +
   26.92 +\medskip \noindent
   26.93 +Permission is granted to copy and distribute modified versions of this
   26.94 +manual under the conditions for verbatim copying, provided also that the
   26.95 +entire resulting derived work is distributed under the terms of
   26.96 +a permission notice identical to this one.
   26.97 +
   26.98 +\medskip \noindent
   26.99 +Permission is granted to copy and distribute translations of this manual
  26.100 +into another language, under the above conditions for modified versions.
  26.101 +
  26.102 +\tableofcontents
  26.103 +
  26.104 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  26.105 +
  26.106 +\chapter{Basic Graph API Routines}
  26.107 +
  26.108 +\section{Graph program object}
  26.109 +
  26.110 +In GLPK the base program object used to represent graphs and networks
  26.111 +is a directed graph (digraph).
  26.112 +
  26.113 +Formally, {\it digraph} (or simply, {\it graph}) is a pair $G=(V,A)$,
  26.114 +where $V$ is a set of {\it vertices}, and $A$ is a set
  26.115 +{\it arcs}.\footnote{$A$ may be a multiset.} Each arc $a\in A$ is an
  26.116 +ordered pair of vertices $a=(x,y)$, where $x\in V$ is called {\it tail
  26.117 +vertex} of arc $a$, and $y\in V$ is called its {\it head vertex}.
  26.118 +
  26.119 +Representation of a graph in the program includes three structs defined
  26.120 +by typedef in the header \verb|glpk.h|:
  26.121 +
  26.122 +\medskip
  26.123 +
  26.124 +$\bullet$ \verb|glp_graph|, which represents the graph in a whole,
  26.125 +
  26.126 +$\bullet$ \verb|glp_vertex|, which represents a vertex of the graph, and
  26.127 +
  26.128 +$\bullet$ \verb|glp_arc|, which represents an arc of the graph.
  26.129 +
  26.130 +\medskip
  26.131 +
  26.132 +All these three structs are ``semi-opaque'', i.e. the application
  26.133 +program can directly access their fields through pointers, however,
  26.134 +changing the fields directly is not allowed---all changes should be
  26.135 +performed only with appropriate GLPK API routines.
  26.136 +
  26.137 +\newpage
  26.138 +
  26.139 +\newenvironment{comment}
  26.140 +{\addtolength{\leftskip}{17pt}\noindent}
  26.141 +{\par\addtolength{\leftskip}{-17pt}}
  26.142 +
  26.143 +\noindent
  26.144 +{\bf glp\_graph.} The struct \verb|glp_graph| has the following
  26.145 +fields available to the application program:
  26.146 +
  26.147 +\medskip
  26.148 +
  26.149 +\noindent
  26.150 +\verb|char *name;|
  26.151 +
  26.152 +\begin{comment}Symbolic name assigned to the graph. It is a pointer to
  26.153 +a null terminated character string of length from 1 to 255 characters.
  26.154 +If no name is assigned to the graph, this field contains \verb|NULL|.
  26.155 +\end{comment}
  26.156 +
  26.157 +\medskip
  26.158 +
  26.159 +\noindent
  26.160 +\verb|int nv;|
  26.161 +
  26.162 +\begin{comment}The number of vertices in the graph, $nv\geq 0$.
  26.163 +\end{comment}
  26.164 +
  26.165 +\medskip
  26.166 +
  26.167 +\noindent
  26.168 +\verb|int na;|
  26.169 +
  26.170 +\begin{comment}The number of arcs in the graph, $na\geq 0$.
  26.171 +\end{comment}
  26.172 +
  26.173 +\medskip
  26.174 +
  26.175 +\noindent
  26.176 +\verb|glp_vertex **v;|
  26.177 +
  26.178 +\begin{comment}Pointer to an array containing the list of vertices.
  26.179 +Element $v[0]$ is not used. Element $v[i]$, $1\leq i\leq nv$, is a
  26.180 +pointer to $i$-th vertex of the graph. Note that on adding new vertices
  26.181 +to the graph the field $v$ may be altered due to reallocation. However,
  26.182 +pointers $v[i]$ are not changed while corresponding vertices exist in
  26.183 +the graph.
  26.184 +\end{comment}
  26.185 +
  26.186 +\medskip
  26.187 +
  26.188 +\noindent
  26.189 +\verb|int v_size;|
  26.190 +
  26.191 +\begin{comment}Size of vertex data blocks, in bytes,
  26.192 +$0\leq v\_size\leq 256$. (See also the field \verb|data| in the struct
  26.193 +\verb|glp_vertex|.)
  26.194 +\end{comment}
  26.195 +
  26.196 +\medskip
  26.197 +
  26.198 +\noindent
  26.199 +\verb|int a_size;|
  26.200 +
  26.201 +\begin{comment}Size of arc data blocks, in bytes,
  26.202 +$0\leq v\_size\leq 256$. (See also the field \verb|data| in the struct
  26.203 +\verb|glp_arc|.)
  26.204 +\end{comment}
  26.205 +
  26.206 +\bigskip
  26.207 +
  26.208 +\noindent
  26.209 +{\bf glp\_vertex.} The struct \verb|glp_vertex| has the following
  26.210 +fields available to the application program:
  26.211 +
  26.212 +\medskip
  26.213 +
  26.214 +\noindent
  26.215 +\verb|int i;|
  26.216 +
  26.217 +\begin{comment}Ordinal number of the vertex, $1\leq i\leq nv$. Note
  26.218 +that element $v[i]$ in the struct \verb|glp_graph| points to the vertex,
  26.219 +whose ordinal number is $i$.
  26.220 +\end{comment}
  26.221 +
  26.222 +\medskip
  26.223 +
  26.224 +\noindent
  26.225 +\verb|char *name;|
  26.226 +
  26.227 +\begin{comment}Symbolic name assigned to the vertex. It is a pointer to
  26.228 +a null terminated character string of length from 1 to 255 characters.
  26.229 +If no name is assigned to the vertex, this field contains \verb|NULL|.
  26.230 +\end{comment}
  26.231 +
  26.232 +\medskip
  26.233 +
  26.234 +\noindent
  26.235 +\verb|void *data;|
  26.236 +
  26.237 +\begin{comment}Pointer to a data block associated with the vertex. This
  26.238 +data block is automatically allocated on creating a new vertex and freed
  26.239 +on deleting the vertex. If $v\_size=0$, the block is not allocated, and
  26.240 +this field contains \verb|NULL|.
  26.241 +\end{comment}
  26.242 +
  26.243 +\medskip
  26.244 +
  26.245 +\noindent
  26.246 +\verb|void *temp;|
  26.247 +
  26.248 +\begin{comment}Working pointer, which may be used freely for any
  26.249 +purposes. The application program can change this field directly.
  26.250 +\end{comment}
  26.251 +
  26.252 +\medskip
  26.253 +
  26.254 +\noindent
  26.255 +\verb|glp_arc *in;|
  26.256 +
  26.257 +\begin{comment}Pointer to the (unordered) list of incoming arcs. If the
  26.258 +vertex has no incoming arcs, this field contains \verb|NULL|.
  26.259 +\end{comment}
  26.260 +
  26.261 +\medskip
  26.262 +
  26.263 +\noindent
  26.264 +\verb|glp_arc *out;|
  26.265 +
  26.266 +\begin{comment}Pointer to the (unordered) list of outgoing arcs. If the
  26.267 +vertex has no outgoing arcs, this field contains \verb|NULL|.
  26.268 +\end{comment}
  26.269 +
  26.270 +\bigskip
  26.271 +
  26.272 +\noindent
  26.273 +{\bf glp\_arc.} The struct \verb|glp_arc| has the following fields
  26.274 +available to the application program:
  26.275 +
  26.276 +\medskip
  26.277 +
  26.278 +\noindent
  26.279 +\verb|glp_vertex *tail;|
  26.280 +
  26.281 +\begin{comment}Pointer to a vertex, which is tail endpoint of the arc.
  26.282 +\end{comment}
  26.283 +
  26.284 +\medskip
  26.285 +
  26.286 +\noindent
  26.287 +\verb|glp_vertex *head;|
  26.288 +
  26.289 +\begin{comment}Pointer to a vertex, which is head endpoint of the arc.
  26.290 +\end{comment}
  26.291 +
  26.292 +\medskip
  26.293 +
  26.294 +\noindent
  26.295 +\verb|void *data;|
  26.296 +
  26.297 +\begin{comment}Pointer to a data block associated with the arc. This
  26.298 +data block is automatically allocated on creating a new arc and freed on
  26.299 +deleting the arc. If $v\_size=0$, the block is not allocated, and this
  26.300 +field contains \verb|NULL|.
  26.301 +\end{comment}
  26.302 +
  26.303 +\medskip
  26.304 +
  26.305 +\noindent
  26.306 +\verb|void *temp;|
  26.307 +
  26.308 +\begin{comment}Working pointer, which may be used freely for any
  26.309 +purposes. The application program can change this field directly.
  26.310 +\end{comment}
  26.311 +
  26.312 +\medskip
  26.313 +
  26.314 +\noindent
  26.315 +\verb|glp_arc *t_next;|
  26.316 +
  26.317 +\begin{comment}Pointer to another arc, which has the same tail endpoint
  26.318 +as this one. \verb|NULL| in this field indicates the end of the list of
  26.319 +outgoing arcs.
  26.320 +\end{comment}
  26.321 +
  26.322 +\medskip
  26.323 +
  26.324 +\noindent
  26.325 +\verb|glp_arc *h_next;|
  26.326 +
  26.327 +\begin{comment}Pointer to another arc, which has the same head endpoint
  26.328 +as this one. \verb|NULL| in this field indicates the end of the list of
  26.329 +incoming arcs.
  26.330 +\end{comment}
  26.331 +
  26.332 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  26.333 +
  26.334 +\newpage
  26.335 +
  26.336 +\section{Graph creating and modifying routines}
  26.337 +
  26.338 +\subsection{glp\_create\_graph---create graph}
  26.339 +
  26.340 +\subsubsection*{Synopsis}
  26.341 +
  26.342 +\begin{verbatim}
  26.343 +glp_graph *glp_create_graph(int v_size, int a_size);
  26.344 +\end{verbatim}
  26.345 +
  26.346 +\subsubsection*{Description}
  26.347 +
  26.348 +The routine \verb|glp_create_graph| creates a new graph, which
  26.349 +initially is\linebreak empty, i.e. has no vertices and arcs.
  26.350 +
  26.351 +The parameter \verb|v_size| specifies the size of vertex data blocks,
  26.352 +in bytes, $0\leq v\_size\leq 256$.
  26.353 +
  26.354 +The parameter \verb|a_size| specifies the size of arc data blocks, in
  26.355 +bytes, $0\leq a\_size\leq 256$.
  26.356 +
  26.357 +\subsubsection*{Returns}
  26.358 +
  26.359 +The routine returns a pointer to the graph created.
  26.360 +
  26.361 +\subsection{glp\_set\_graph\_name---assign (change) graph name}
  26.362 +
  26.363 +\subsubsection*{Synopsis}
  26.364 +
  26.365 +\begin{verbatim}
  26.366 +void glp_set_graph_name(glp_graph *G, const char *name);
  26.367 +\end{verbatim}
  26.368 +
  26.369 +\subsubsection*{Description}
  26.370 +
  26.371 +The routine \verb|glp_set_graph_name| assigns a symbolic name specified
  26.372 +by the character string \verb|name| (1 to 255 chars) to the graph.
  26.373 +
  26.374 +If the parameter \verb|name| is \verb|NULL| or an empty string, the
  26.375 +routine erases the existing symbolic name of the graph.
  26.376 +
  26.377 +\newpage
  26.378 +
  26.379 +\subsection{glp\_add\_vertices---add new vertices to graph}
  26.380 +
  26.381 +\subsubsection*{Synopsis}
  26.382 +
  26.383 +\begin{verbatim}
  26.384 +int glp_add_vertices(glp_graph *G, int nadd);
  26.385 +\end{verbatim}
  26.386 +
  26.387 +\subsubsection*{Description}
  26.388 +
  26.389 +The routine \verb|glp_add_vertices| adds \verb|nadd| vertices to the
  26.390 +specified graph. New vertices are always added to the end of the vertex
  26.391 +list, so ordinal numbers of existing vertices remain unchanged. Note
  26.392 +that this operation may change the field \verb|v| in the struct
  26.393 +\verb|glp_graph| (pointer to the vertex array) due to reallocation.
  26.394 +
  26.395 +Being added each new vertex is isolated, i.e. has no incident arcs.
  26.396 +
  26.397 +If the size of vertex data blocks specified on creating the graph is
  26.398 +non-zero, the routine also allocates a memory block of that size for
  26.399 +each new vertex added, fills it by binary zeros, and stores a pointer to
  26.400 +it in the field \verb|data| of the struct \verb|glp_vertex|. Otherwise,
  26.401 +if the block size is zero, the field \verb|data| is set to \verb|NULL|.
  26.402 +
  26.403 +\subsubsection*{Returns}
  26.404 +
  26.405 +The routine \verb|glp_add_vertices| returns the ordinal number of the
  26.406 +first new vertex added to the graph.
  26.407 +
  26.408 +\subsection{glp\_set\_vertex\_name---assign (change) vertex name}
  26.409 +
  26.410 +\subsubsection*{Synopsis}
  26.411 +
  26.412 +\begin{verbatim}
  26.413 +void glp_set_vertex_name(glp_graph *G, int i, const char *name);
  26.414 +\end{verbatim}
  26.415 +
  26.416 +\subsubsection*{Description}
  26.417 +
  26.418 +The routine \verb|glp_set_vertex_name| assigns a given symbolic name
  26.419 +(1 up to 255 characters) to \verb|i|-th vertex of the specified graph.
  26.420 +
  26.421 +If the parameter \verb|name| is \verb|NULL| or empty string, the
  26.422 +routine erases an existing name of \verb|i|-th vertex.
  26.423 +
  26.424 +\newpage
  26.425 +
  26.426 +\subsection{glp\_add\_arc---add new arc to graph}
  26.427 +
  26.428 +\subsubsection*{Synopsis}
  26.429 +
  26.430 +\begin{verbatim}
  26.431 +glp_arc *glp_add_arc(glp_graph *G, int i, int j);
  26.432 +\end{verbatim}
  26.433 +
  26.434 +\subsubsection*{Description}
  26.435 +
  26.436 +The routine \verb|glp_add_arc| adds one new arc to the specified graph.
  26.437 +
  26.438 +The parameters \verb|i| and \verb|j| specify the ordinal numbers of,
  26.439 +resp., tail and head endpoints (vertices) of the arc. Note that
  26.440 +self-loops and multiple arcs are allowed.
  26.441 +
  26.442 +If the size of arc data blocks specified on creating the graph is
  26.443 +non-zero, the routine also allocates a memory block of that size, fills
  26.444 +it by binary zeros, and stores a pointer to it in the field \verb|data|
  26.445 +of the struct \verb|glp_arc|. Otherwise, if the block size is zero, the
  26.446 +field \verb|data| is set to \verb|NULL|.
  26.447 +
  26.448 +\subsection{glp\_del\_vertices---delete vertices from graph}
  26.449 +
  26.450 +\subsubsection*{Synopsis}
  26.451 +
  26.452 +\begin{verbatim}
  26.453 +void glp_del_vertices(glp_graph *G, int ndel, const int num[]);
  26.454 +\end{verbatim}
  26.455 +
  26.456 +\subsubsection*{Description}
  26.457 +
  26.458 +The routine \verb|glp_del_vertices| deletes vertices along with all
  26.459 +incident arcs from the specified graph. Ordinal numbers of vertices to
  26.460 +be deleted should be placed in locations \verb|num[1]|, \dots,
  26.461 +\verb|num[ndel]|, \verb|ndel| $>0$.
  26.462 +
  26.463 +Note that deleting vertices involves changing ordinal numbers of other
  26.464 +vertices remaining in the graph. New ordinal numbers of the remaining
  26.465 +vertices are assigned under the assumption that the original order of
  26.466 +vertices is not changed.
  26.467 +
  26.468 +\subsection{glp\_del\_arc---delete arc from graph}
  26.469 +
  26.470 +\subsubsection*{Synopsis}
  26.471 +
  26.472 +\begin{verbatim}
  26.473 +void glp_del_arc(glp_graph *G, glp_arc *a);
  26.474 +\end{verbatim}
  26.475 +
  26.476 +\subsubsection*{Description}
  26.477 +
  26.478 +The routine \verb|glp_del_arc| deletes an arc from the specified graph.
  26.479 +The arc to be deleted must exist.
  26.480 +
  26.481 +\subsection{glp\_erase\_graph---erase graph content}
  26.482 +
  26.483 +\subsubsection*{Synopsis}
  26.484 +
  26.485 +\begin{verbatim}
  26.486 +void glp_erase_graph(glp_graph *G, int v_size, int a_size);
  26.487 +\end{verbatim}
  26.488 +
  26.489 +\subsubsection*{Description}
  26.490 +
  26.491 +The routine \verb|glp_erase_graph| erases the content of the specified
  26.492 +graph. The effect of this operation is the same as if the graph would be
  26.493 +deleted with the routine \verb|glp_delete_graph| and then created anew
  26.494 +with the routine \verb|glp_create_graph|, with exception that the handle
  26.495 +(pointer) to the graph remains valid.
  26.496 +
  26.497 +The parameters \verb|v_size| and \verb|a_size| have the same meaning as
  26.498 +for the routine \verb|glp_create_graph|.
  26.499 +
  26.500 +\subsection{glp\_delete\_graph---delete graph}
  26.501 +
  26.502 +\subsubsection*{Synopsis}
  26.503 +
  26.504 +\begin{verbatim}
  26.505 +void glp_delete_graph(glp_graph *G);
  26.506 +\end{verbatim}
  26.507 +
  26.508 +\subsubsection*{Description}
  26.509 +
  26.510 +The routine \verb|glp_delete_graph| deletes the specified graph and
  26.511 +frees all the memory allocated to this program object.
  26.512 +
  26.513 +\newpage
  26.514 +
  26.515 +\section{Graph searching routines}
  26.516 +
  26.517 +\subsection{glp\_create\_v\_index---create vertex name index}
  26.518 +
  26.519 +\subsubsection*{Synopsis}
  26.520 +
  26.521 +\begin{verbatim}
  26.522 +void glp_create_v_index(glp_graph *G);
  26.523 +\end{verbatim}
  26.524 +
  26.525 +\subsubsection*{Description}
  26.526 +
  26.527 +The routine \verb|glp_create_v_index| creates the name index for the
  26.528 +specified graph. The name index is an auxiliary data structure, which
  26.529 +is intended to quickly (i.e. for logarithmic time) find vertices by
  26.530 +their names.
  26.531 +
  26.532 +This routine can be called at any time. If the name index already
  26.533 +exists, the routine does nothing.
  26.534 +
  26.535 +\subsection{glp\_find\_vertex---find vertex by its name}
  26.536 +
  26.537 +\subsubsection*{Synopsis}
  26.538 +
  26.539 +\begin{verbatim}
  26.540 +int glp_find_vertex(glp_graph *G, const char *name);
  26.541 +\end{verbatim}
  26.542 +
  26.543 +\subsubsection*{Returns}
  26.544 +
  26.545 +The routine \verb|glp_find_vertex| returns the ordinal number of
  26.546 +a vertex, which is assigned (by the routine \verb|glp_set_vertex_name|)
  26.547 +the specified symbolic \verb|name|. If no such vertex exists, the
  26.548 +routine returns 0.
  26.549 +
  26.550 +\subsection{glp\_delete\_v\_index---delete vertex name index}
  26.551 +
  26.552 +\subsubsection*{Synopsis}
  26.553 +
  26.554 +\begin{verbatim}
  26.555 +void glp_delete_v_index(glp_graph *G);
  26.556 +\end{verbatim}
  26.557 +
  26.558 +\subsubsection*{Description}
  26.559 +
  26.560 +The routine \verb|glp_delete_v_index| deletes the name index previously
  26.561 +created by the routine \verb|glp_create_v_index| and frees the memory
  26.562 +allocated to this auxiliary data structure.
  26.563 +
  26.564 +This routine can be called at any time. If the name index does not
  26.565 +exist, the routine does nothing.
  26.566 +
  26.567 +\newpage
  26.568 +
  26.569 +\section{Graph reading/writing routines}
  26.570 +
  26.571 +\subsection{glp\_read\_graph---read graph from plain text file}
  26.572 +
  26.573 +\subsubsection*{Synopsis}
  26.574 +
  26.575 +\begin{verbatim}
  26.576 +int glp_read_graph(glp_graph *G, const char *fname);
  26.577 +\end{verbatim}
  26.578 +
  26.579 +\subsubsection*{Description}
  26.580 +
  26.581 +The routine \verb|glp_read_graph| reads a graph from a plain text file,
  26.582 +whose name is specified by the parameter \verb|fname|. Note that before
  26.583 +reading data the current content of the graph object is completely
  26.584 +erased with the routine \verb|glp_erase_graph|.
  26.585 +
  26.586 +For the file format see description of the routine
  26.587 +\verb|glp_write_graph|.
  26.588 +
  26.589 +\subsubsection*{Returns}
  26.590 +
  26.591 +If the operation was successful, the routine returns zero. Otherwise
  26.592 +it prints an error message and returns non-zero.
  26.593 +
  26.594 +\subsection{glp\_write\_graph---write graph to plain text file}
  26.595 +
  26.596 +\subsubsection*{Synopsis}
  26.597 +
  26.598 +\begin{verbatim}
  26.599 +int glp_write_graph(glp_graph *G, const char *fname);
  26.600 +\end{verbatim}
  26.601 +
  26.602 +\subsubsection*{Description}
  26.603 +
  26.604 +The routine \verb|glp_write_graph| writes the graph to a plain text
  26.605 +file, whose name is specified by the parameter \verb|fname|.
  26.606 +
  26.607 +\subsubsection*{Returns}
  26.608 +
  26.609 +If the operation was successful, the routine returns zero. Otherwise
  26.610 +it prints an error message and returns non-zero.
  26.611 +
  26.612 +\subsubsection*{File format}
  26.613 +
  26.614 +The file created by the routine \verb|glp_write_graph| is a plain text
  26.615 +file, which contains the following information:
  26.616 +
  26.617 +\begin{verbatim}
  26.618 +   nv na
  26.619 +   i[1] j[1]
  26.620 +   i[2] j[2]
  26.621 +   . . .
  26.622 +   i[na] j[na]
  26.623 +\end{verbatim}
  26.624 +
  26.625 +\noindent
  26.626 +where:
  26.627 +
  26.628 +\noindent
  26.629 +\verb|nv| is the number of vertices (nodes);
  26.630 +
  26.631 +\noindent
  26.632 +\verb|na| is the number of arcs;
  26.633 +
  26.634 +\noindent
  26.635 +\verb|i[k]|, $k=1,\dots,na$, is the index of tail vertex of arc $k$;
  26.636 +
  26.637 +\noindent
  26.638 +\verb|j[k]|, $k=1,\dots,na$, is the index of head vertex of arc $k$.
  26.639 +
  26.640 +\subsection{glp\_read\_ccdata---read graph from text file in DIMACS
  26.641 +clique/coloring format}
  26.642 +
  26.643 +\subsubsection*{Synopsis}
  26.644 +
  26.645 +\begin{verbatim}
  26.646 +int glp_read_ccdata(glp_graph *G, int v_wgt,
  26.647 +      const char *fname);
  26.648 +\end{verbatim}
  26.649 +
  26.650 +\subsubsection*{Description}
  26.651 +
  26.652 +The routine {\it glp\_read\_ccdata} reads a graph from a text file in
  26.653 +DIMACS clique/coloring format. (Though this format is originally
  26.654 +designed to represent data for the minimal vertex coloring and maximal
  26.655 +clique problems, it may be used to represent general undirected and
  26.656 +directed graphs, because the routine allows reading self-loops and
  26.657 +multiple edges/arcs keeping the order of vertices specified for each
  26.658 +edge/arc of the graph.)
  26.659 +
  26.660 +The parameter $G$ specifies the graph object to be read in. Note that
  26.661 +before reading data the current content of the graph object is
  26.662 +completely erased with the routine {\it glp\_erase\_graph}.
  26.663 +
  26.664 +The parameter {\it v\_wgt} specifies an offset of the field of type
  26.665 +{\bf double} in the vertex data block, to which the routine stores the
  26.666 +vertex weight. If {\it v\_wgt} $<0$, the vertex weights are not stored.
  26.667 +
  26.668 +The character string {\it fname} specifies the name of a text file to
  26.669 +be read in. (If the file name ends with the suffix `\verb|.gz|', the
  26.670 +file is assumed to be compressed, in which case the routine decompresses
  26.671 +it ``on the fly''.)
  26.672 +
  26.673 +\subsubsection*{Returns}
  26.674 +
  26.675 +If the operation was successful, the routine returns zero. Otherwise,
  26.676 +it prints an error message and returns non-zero.
  26.677 +
  26.678 +\subsubsection*{DIMACS clique/coloring format\footnote{This material is
  26.679 +based on the paper ``Clique and Coloring Problems Graph Format'', which
  26.680 +is publically available at
  26.681 +{\tt http://dimacs.rutgers.edu/Challenges/}.}}
  26.682 +
  26.683 +The DIMACS input file is a plain ASCII text file. It contains
  26.684 +{\it lines} of several types described below. A line is terminated with
  26.685 +an end-of-line character. Fields in each line are separated by at least
  26.686 +one blank space. Each line begins with a one-character designator to
  26.687 +identify the line type.
  26.688 +
  26.689 +Note that DIMACS requires all numerical quantities to be integers in
  26.690 +the range $[-2^{31},2^{31}-1]$ while GLPK allows the quantities to be
  26.691 +floating-point numbers.
  26.692 +
  26.693 +\paragraph{Comment lines.} Comment lines give human-readable information
  26.694 +about the file and are ignored by programs. Comment lines can appear
  26.695 +anywhere in the file. Each comment line begins with a lower-case
  26.696 +character \verb|c|.
  26.697 +
  26.698 +\begin{verbatim}
  26.699 +   c This is a comment line
  26.700 +\end{verbatim}
  26.701 +
  26.702 +\paragraph{Problem line.} There is one problem line per data file. The
  26.703 +problem line must appear before any node or edge descriptor lines. It
  26.704 +has the following format:
  26.705 +
  26.706 +\begin{verbatim}
  26.707 +   p edge NODES EDGES
  26.708 +\end{verbatim}
  26.709 +
  26.710 +\noindent
  26.711 +The lower-case letter \verb|p| signifies that this is a problem line.
  26.712 +The four-character problem designator \verb|edge| identifies the file
  26.713 +as containing data for the minimal vertex coloring or maximal clique
  26.714 +problem. The \verb|NODES| field contains an integer value specifying
  26.715 +the number of vertices in the graph. The \verb|EDGES| field contains an
  26.716 +integer value specifying the number of edges (arcs) in the graph.
  26.717 +
  26.718 +\paragraph{Vertex descriptors.} These lines give the weight assigned to
  26.719 +a vertex of the graph. There is one vertex descriptor line for each
  26.720 +vertex, with the following format. Vertices without a descriptor take on
  26.721 +a default value of 1.
  26.722 +
  26.723 +\begin{verbatim}
  26.724 +   n ID VALUE
  26.725 +\end{verbatim}
  26.726 +
  26.727 +\noindent
  26.728 +The lower-case character \verb|n| signifies that this is a vertex
  26.729 +descriptor line. The \verb|ID| field gives a vertex identification
  26.730 +number, an integer between 1 and $n$, where $n$ is the number of
  26.731 +vertices in the graph. The \verb|VALUE| field gives a vertex weight,
  26.732 +which can either positive or negative (or zero).
  26.733 +
  26.734 +\paragraph{Edge descriptors.} There is one edge descriptor line for
  26.735 +each edge (arc) of the graph, each with the following format:
  26.736 +
  26.737 +\begin{verbatim}
  26.738 +   e I J
  26.739 +\end{verbatim}
  26.740 +
  26.741 +\noindent
  26.742 +The lower-case character \verb|e| signifies that this is an edge
  26.743 +descriptor line. For an edge (arc) $(i,j)$ the fields \verb|I| and
  26.744 +\verb|J| specify its endpoints.
  26.745 +
  26.746 +\paragraph{Example.} The following example of an undirected graph:
  26.747 +
  26.748 +\bigskip
  26.749 +
  26.750 +\noindent\hfil
  26.751 +\xymatrix %@C=32pt
  26.752 +{&{v_1}\ar@{-}[ldd]\ar@{-}[dd]\ar@{-}[rd]\ar@{-}[rr]&&{v_2}\ar@{-}[ld]
  26.753 +\ar@{-}[dd]\ar@{-}[rdd]&\\
  26.754 +&&{v_7}\ar@{-}[ld]\ar@{-}[rd]&&\\
  26.755 +{v_6}\ar@{-}[r]\ar@{-}[rdd]&{v_{10}}\ar@{-}[rr]\ar@{-}[rd]\ar@{-}[dd]&&
  26.756 +{v_8}\ar@{-}[ld]\ar@{-}[dd]\ar@{-}[r]&{v_3}\ar@{-}[ldd]\\
  26.757 +&&{v_9}\ar@{-}[ld]\ar@{-}[rd]&&\\
  26.758 +&{v_5}\ar@{-}[rr]&&{v_4}&\\
  26.759 +}
  26.760 +
  26.761 +\bigskip
  26.762 +
  26.763 +\noindent
  26.764 +might be coded in DIMACS clique/coloring format as follows:
  26.765 +
  26.766 +\begin{footnotesize}
  26.767 +\begin{verbatim}
  26.768 +c sample.col
  26.769 +c
  26.770 +c This is an example of the vertex coloring problem data
  26.771 +c in DIMACS format.
  26.772 +c
  26.773 +p edge 10 21
  26.774 +c
  26.775 +e 1 2
  26.776 +e 1 6
  26.777 +e 1 7
  26.778 +e 1 10
  26.779 +e 2 3
  26.780 +e 2 7
  26.781 +e 2 8
  26.782 +e 3 4
  26.783 +e 3 8
  26.784 +e 4 5
  26.785 +e 4 8
  26.786 +e 4 9
  26.787 +e 5 6
  26.788 +e 5 9
  26.789 +e 5 10
  26.790 +e 6 10
  26.791 +e 7 8
  26.792 +e 7 10
  26.793 +e 8 9
  26.794 +e 8 10
  26.795 +e 9 10
  26.796 +c
  26.797 +c eof
  26.798 +\end{verbatim}
  26.799 +\end{footnotesize}
  26.800 +
  26.801 +\subsection{glp\_write\_ccdata---write graph to text file in DIMACS
  26.802 +clique/coloring format}
  26.803 +
  26.804 +\subsubsection*{Synopsis}
  26.805 +
  26.806 +\begin{verbatim}
  26.807 +int glp_write_ccdata(glp_graph *G, int v_wgt,
  26.808 +      const char *fname);
  26.809 +\end{verbatim}
  26.810 +
  26.811 +\subsection*{Description}
  26.812 +
  26.813 +The routine {\it glp\_write\_ccdata} writes the graph object specified
  26.814 +by the parameter $G$ to a text file in DIMACS clique/coloring format.
  26.815 +(Though this format is originally designed to represent data for the
  26.816 +minimal vertex coloring and maximal clique problems, it may be used to
  26.817 +represent general undirected and directed graphs, because the routine
  26.818 +allows writing self-loops and multiple edges/arcs keeping the order of
  26.819 +vertices specified for each edge/arc of the graph.)
  26.820 +
  26.821 +The parameter {\it v\_wgt} specifies an offset of the field of type
  26.822 +{\bf double} in the vertex data block, which contains the vertex weight.
  26.823 +If {\it v\_wgt} $<0$, it is assumed that the weight of each vertex is 1.
  26.824 +
  26.825 +The character string {\it fname} specifies a name of the text file to be
  26.826 +written out. (If the file name ends with suffix `\verb|.gz|', the file
  26.827 +is assumed to be compressed, in which case the routine performs
  26.828 +automatic compression on writing it.)
  26.829 +
  26.830 +\subsubsection*{Returns}
  26.831 +
  26.832 +If the operation was successful, the routine returns zero. Otherwise,
  26.833 +it prints an error message and returns non-zero.
  26.834 +
  26.835 +\newpage
  26.836 +
  26.837 +\section{Graph analysis routines}
  26.838 +
  26.839 +\subsection{glp\_weak\_comp---find all weakly connected components of
  26.840 +graph}
  26.841 +
  26.842 +\subsubsection*{Synopsis}
  26.843 +
  26.844 +\begin{verbatim}
  26.845 +int glp_weak_comp(glp_graph *G, int v_num);
  26.846 +\end{verbatim}
  26.847 +
  26.848 +\subsubsection*{Description}
  26.849 +
  26.850 +The routine \verb|glp_weak_comp| finds all weakly connected components
  26.851 +of the specified graph.
  26.852 +
  26.853 +The parameter \verb|v_num| specifies an offset of the field of type
  26.854 +\verb|int| in the vertex data block, to which the routine stores the
  26.855 +number of a weakly connected component containing that vertex. If
  26.856 +\verb|v_num| $<0$, no component numbers are stored.
  26.857 +
  26.858 +The components are numbered in arbitrary order from 1 to \verb|nc|,
  26.859 +where \verb|nc| is the total number of components found,
  26.860 +$0\leq$ \verb|nc| $\leq|V|$.
  26.861 +
  26.862 +\subsubsection*{Returns}
  26.863 +
  26.864 +The routine returns \verb|nc|, the total number of components found.
  26.865 +
  26.866 +\subsection{glp\_strong\_comp---find all strongly connected components
  26.867 +of graph}
  26.868 +
  26.869 +\subsubsection*{Synopsis}
  26.870 +
  26.871 +\begin{verbatim}
  26.872 +int glp_strong_comp(glp_graph *G, int v_num);
  26.873 +\end{verbatim}
  26.874 +
  26.875 +\subsubsection*{Description}
  26.876 +
  26.877 +The routine \verb|glp_strong_comp| finds all strongly connected
  26.878 +components of the specified graph.
  26.879 +
  26.880 +The parameter \verb|v_num| specifies an offset of the field of type
  26.881 +\verb|int| in the vertex data block, to which the routine stores the
  26.882 +number of a strongly connected component containing that vertex. If
  26.883 +\verb|v_num| $<0$, no component numbers are stored.
  26.884 +
  26.885 +The components are numbered in arbitrary order from 1 to \verb|nc|,
  26.886 +where \verb|nc| is the total number of components found,
  26.887 +$0\leq$ \verb|nc| $\leq|V|$. However, the component numbering has the
  26.888 +property that for every arc $(i\rightarrow j)$ in the graph the
  26.889 +condition $num(i)\geq num(j)$ holds.
  26.890 +
  26.891 +\subsubsection*{Returns}
  26.892 +
  26.893 +The routine returns \verb|nc|, the total number of components found.
  26.894 +
  26.895 +\subsubsection*{References}
  26.896 +
  26.897 +I.~S.~Duff, J.~K.~Reid, Algorithm 529: Permutations to block triangular
  26.898 +form, ACM Trans. on Math. Softw. 4 (1978), 189-92.
  26.899 +
  26.900 +\subsubsection*{Example}
  26.901 +
  26.902 +The following program reads a graph from a plain text file
  26.903 +`\verb|graph.txt|' and finds all its strongly connected components.
  26.904 +
  26.905 +\begin{footnotesize}
  26.906 +\begin{verbatim}
  26.907 +#include <stddef.h>
  26.908 +#include <stdio.h>
  26.909 +#include <stdlib.h>
  26.910 +#include <glpk.h>
  26.911 +
  26.912 +typedef struct { int num; } v_data;
  26.913 +
  26.914 +#define vertex(v) ((v_data *)((v)->data))
  26.915 +
  26.916 +int main(void)
  26.917 +{     glp_graph *G;
  26.918 +      int i, nc;
  26.919 +      G = glp_create_graph(sizeof(v_data), 0);
  26.920 +      glp_read_graph(G, "graph.txt");
  26.921 +      nc = glp_strong_comp(G, offsetof(v_data, num));
  26.922 +      printf("nc = %d\n", nc);
  26.923 +      for (i = 1; i <= G->nv; i++)
  26.924 +         printf("num[%d] = %d\n", i, vertex(G->v[i])->num);
  26.925 +      glp_delete_graph(G);
  26.926 +      return 0;
  26.927 +}
  26.928 +\end{verbatim}
  26.929 +\end{footnotesize}
  26.930 +
  26.931 +\noindent
  26.932 +If the file `\verb|graph.txt|' contains the graph shown below:
  26.933 +
  26.934 +\bigskip
  26.935 +
  26.936 +\noindent\hfil
  26.937 +\xymatrix
  26.938 +{1\ar[r]&2\ar[r]&3\ar[r]\ar[dd]&4\ar[dd]\\
  26.939 +5\ar[u]&6\ar[l]\\
  26.940 +7\ar[u]&&8\ar[lu]\ar[ll]\ar[r]&9\ar[r]&10\ar[r]\ar[d]&11\ar[d]\\
  26.941 +12\ar[u]\ar[rru]\ar@/_/[rr]&&13\ar[ll]\ar[u]\ar[rr]&&14\ar[lu]&15\ar[l]
  26.942 +\\
  26.943 +}
  26.944 +
  26.945 +\bigskip\bigskip
  26.946 +
  26.947 +\noindent
  26.948 +the program output may look like follows:
  26.949 +
  26.950 +\begin{footnotesize}
  26.951 +\begin{verbatim}
  26.952 +Reading graph from `graph.txt'...
  26.953 +Graph has 15 vertices and 30 arcs
  26.954 +31 lines were read
  26.955 +nc = 4
  26.956 +num[1] = 3
  26.957 +num[2] = 3
  26.958 +num[3] = 3
  26.959 +num[4] = 2
  26.960 +num[5] = 3
  26.961 +num[6] = 3
  26.962 +num[7] = 3
  26.963 +num[8] = 3
  26.964 +num[9] = 1
  26.965 +num[10] = 1
  26.966 +num[11] = 1
  26.967 +num[12] = 4
  26.968 +num[13] = 4
  26.969 +num[14] = 1
  26.970 +num[15] = 1
  26.971 +\end{verbatim}
  26.972 +\end{footnotesize}
  26.973 +
  26.974 +\subsection{glp\_top\_sort---topological sorting of acyclic digraph}
  26.975 +
  26.976 +\subsubsection*{Synopsis}
  26.977 +
  26.978 +\begin{verbatim}
  26.979 +int glp_top_sort(glp_graph *G, int v_num);
  26.980 +\end{verbatim}
  26.981 +
  26.982 +\subsubsection*{Description}
  26.983 +
  26.984 +The routine \verb|glp_top_sort| performs topological sorting of
  26.985 +vertices of the specified acyclic digraph.
  26.986 +
  26.987 +The parameter \verb|v_num| specifies an offset of the field of type
  26.988 +\verb|int| in the vertex data block, to which the routine stores the
  26.989 +vertex number assigned. If \verb|v_num| $<0$, vertex numbers are not
  26.990 +stored.
  26.991 +
  26.992 +The vertices are numbered from 1 to $n$, where $n$ is the total number
  26.993 +of vertices in the graph. The vertex numbering has the property that
  26.994 +for every arc $(i\rightarrow j)$ in the graph the condition
  26.995 +$num(i)<num(j)$ holds. Special case $num(i)=0$ means that vertex $i$ is
  26.996 +not assigned a number, because the graph is {\it not} acyclic.
  26.997 +
  26.998 +\subsubsection*{Returns}
  26.999 +
 26.1000 +If the graph is acyclic and therefore all the vertices have been
 26.1001 +assigned numbers, the routine \verb|glp_top_sort| returns zero.
 26.1002 +Otherwise, if the graph is not acyclic, the routine returns the number
 26.1003 +of vertices which have not been numbered, i.e. for which $num(i)=0$.
 26.1004 +
 26.1005 +\subsubsection*{Example}
 26.1006 +
 26.1007 +The following program reads a digraph from a plain text file
 26.1008 +`\verb|graph.txt|' and performs topological sorting of its vertices.
 26.1009 +
 26.1010 +\begin{footnotesize}
 26.1011 +\begin{verbatim}
 26.1012 +#include <stddef.h>
 26.1013 +#include <stdio.h>
 26.1014 +#include <stdlib.h>
 26.1015 +#include <glpk.h>
 26.1016 +
 26.1017 +typedef struct { int num; } v_data;
 26.1018 +
 26.1019 +#define vertex(v) ((v_data *)((v)->data))
 26.1020 +
 26.1021 +int main(void)
 26.1022 +{     glp_graph *G;
 26.1023 +      int i, cnt;
 26.1024 +      G = glp_create_graph(sizeof(v_data), 0);
 26.1025 +      glp_read_graph(G, "graph.txt");
 26.1026 +      cnt = glp_top_sort(G, offsetof(v_data, num));
 26.1027 +      printf("cnt = %d\n", cnt);
 26.1028 +      for (i = 1; i <= G->nv; i++)
 26.1029 +         printf("num[%d] = %d\n", i, vertex(G->v[i])->num);
 26.1030 +      glp_delete_graph(G);
 26.1031 +      return 0;
 26.1032 +}
 26.1033 +\end{verbatim}
 26.1034 +\end{footnotesize}
 26.1035 +
 26.1036 +\noindent
 26.1037 +If the file `\verb|graph.txt|' contains the graph shown below:
 26.1038 +
 26.1039 +\bigskip
 26.1040 +
 26.1041 +\noindent\hfil
 26.1042 +\xymatrix @=20pt
 26.1043 +{
 26.1044 +1\ar[rrr]&&&2\ar[r]\ar[rddd]&3\ar[rd]&&&&\\
 26.1045 +&&&4\ar[ru]&&5\ar[r]&6\ar[rd]\ar[dd]&&\\
 26.1046 +7\ar[r]&8\ar[r]&9\ar[ruu]\ar[ru]\ar[r]\ar[rd]&10\ar[rr]\ar[rru]&&
 26.1047 +11\ar[ru]&&12\ar[r]&13\\
 26.1048 +&&&14\ar[r]&15\ar[rrru]\ar[rr]&&16\ar[rru]\ar[rr]&&17\\
 26.1049 +}
 26.1050 +
 26.1051 +\bigskip\bigskip
 26.1052 +
 26.1053 +\noindent
 26.1054 +the program output may look like follows:
 26.1055 +
 26.1056 +\begin{footnotesize}
 26.1057 +\begin{verbatim}
 26.1058 +Reading graph from `graph.txt'...
 26.1059 +Graph has 17 vertices and 23 arcs
 26.1060 +24 lines were read
 26.1061 +cnt = 0
 26.1062 +num[1] = 8
 26.1063 +num[2] = 9
 26.1064 +num[3] = 10
 26.1065 +num[4] = 4
 26.1066 +num[5] = 11
 26.1067 +num[6] = 12
 26.1068 +num[7] = 1
 26.1069 +num[8] = 2
 26.1070 +num[9] = 3
 26.1071 +num[10] = 5
 26.1072 +num[11] = 6
 26.1073 +num[12] = 14
 26.1074 +num[13] = 16
 26.1075 +num[14] = 7
 26.1076 +num[15] = 13
 26.1077 +num[16] = 15
 26.1078 +num[17] = 17
 26.1079 +\end{verbatim}
 26.1080 +\end{footnotesize}
 26.1081 +
 26.1082 +\noindent
 26.1083 +The output corresponds to the following vertex numbering:
 26.1084 +
 26.1085 +\bigskip
 26.1086 +
 26.1087 +\noindent\hfil
 26.1088 +\xymatrix @=20pt
 26.1089 +{
 26.1090 +8\ar[rrr]&&&9\ar[r]\ar[rddd]&10\ar[rd]&&&&\\
 26.1091 +&&&4\ar[ru]&&11\ar[r]&12\ar[rd]\ar[dd]&&\\
 26.1092 +1\ar[r]&2\ar[r]&3\ar[ruu]\ar[ru]\ar[r]\ar[rd]&5\ar[rr]\ar[rru]&&
 26.1093 +6\ar[ru]&&14\ar[r]&16\\
 26.1094 +&&&7\ar[r]&13\ar[rrru]\ar[rr]&&15\ar[rru]\ar[rr]&&17\\
 26.1095 +}
 26.1096 +
 26.1097 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 26.1098 +
 26.1099 +\chapter{Network optimization API routines}
 26.1100 +
 26.1101 +\section{Minimum cost flow problem}
 26.1102 +
 26.1103 +\subsection{Background}
 26.1104 +
 26.1105 +The {\it minimum cost flow problem} (MCFP) is stated as follows. Let
 26.1106 +there be given a directed graph (flow network) $G=(V,A)$, where $V$ is
 26.1107 +a set of vertices (nodes), and $A\subseteq V\times V$ is a set of arcs.
 26.1108 +Let for each node $i\in V$ there be given a quantity $b_i$ having the
 26.1109 +following meaning:
 26.1110 +
 26.1111 +if $b_i>0$, then $|b_i|$ is a {\it supply} at node $i$, which shows
 26.1112 +how many flow units are {\it generated} at node $i$ (or, equivalently,
 26.1113 +entering the network through node $i$ from the outside);
 26.1114 +
 26.1115 +if $b_i<0$, then $|b_i|$ is a {\it demand} at node $i$, which shows how
 26.1116 +many flow units are {\it lost} at node $i$ (or, equivalently, leaving
 26.1117 +the network through node $i$ to the outside);
 26.1118 +
 26.1119 +if $b_i=0$, then $i$ is a {\it transshipment} node, at which the flow
 26.1120 +is conserved, i.e. neither generated nor lost.
 26.1121 +
 26.1122 +Let also for each arc $a=(i,j)\in A$ there be given the following three
 26.1123 +quantities:
 26.1124 +
 26.1125 +$l_{ij}$, a (non-negative) lower bound to the flow through arc $(i,j)$;
 26.1126 +
 26.1127 +$u_{ij}$, an upper bound to the flow through arc $(i,j)$, which is the
 26.1128 +{\it arc capacity};
 26.1129 +
 26.1130 +$c_{ij}$, a per-unit cost of the flow through arc $(i,j)$.
 26.1131 +
 26.1132 +The problem is to find flows $x_{ij}$ through every arc of the network,
 26.1133 +which satisfy the specified bounds and the conservation constraints at
 26.1134 +all nodes, and minimize the total flow cost. Here the conservation
 26.1135 +constraint at a node means that the total flow entering this node
 26.1136 +through its incoming arcs plus the supply at this node must be equal to
 26.1137 +the total flow leaving this node through its outgoing arcs plus the
 26.1138 +demand at this node.
 26.1139 +
 26.1140 +An example of the minimum cost flow problem is shown on Fig.~1.
 26.1141 +
 26.1142 +\bigskip
 26.1143 +
 26.1144 +\noindent\hfil
 26.1145 +\xymatrix @C=48pt
 26.1146 +{_{20}\ar@{~>}[d]&
 26.1147 +v_2\ar[r]|{_{0,10,\$2}}\ar[dd]|{_{0,9,\$3}}&
 26.1148 +v_3\ar[dd]|{_{2,12,\$1}}\ar[r]|{_{0,18,\$0}}&
 26.1149 +v_8\ar[rd]|{_{0,20,\$9}}&\\
 26.1150 +v_1\ar[ru]|{_{0,14,\$0}}\ar[rd]|{_{0,23,\$0}}&&&
 26.1151 +v_6\ar[d]|{_{0,7,\$0}}\ar[u]|{_{4,8,\$0}}&
 26.1152 +v_9\ar@{~>}[d]\\
 26.1153 +&v_4\ar[r]|{_{0,26,\$0}}&
 26.1154 +v_5\ar[luu]|{_{0,11,\$1}}\ar[ru]|{_{0,25,\$5}}\ar[r]|{_{0,4,\$7}}&
 26.1155 +v_7\ar[ru]|{_{0,15,\$3}}&_{20}\\
 26.1156 +}
 26.1157 +
 26.1158 +\medskip
 26.1159 +
 26.1160 +\noindent\hfil
 26.1161 +\begin{tabular}{ccc}
 26.1162 +\xymatrix @C=48pt{v_i\ar[r]|{\ l,u,\$c\ }&v_j\\}&
 26.1163 +\xymatrix{\hbox{\footnotesize supply}\ar@{~>}[r]&v_i\\}&
 26.1164 +\xymatrix{v_i\ar@{~>}[r]&\hbox{\footnotesize demand}\\}\\
 26.1165 +\end{tabular}
 26.1166 +
 26.1167 +\bigskip
 26.1168 +
 26.1169 +\noindent\hfil
 26.1170 +Fig.~1. An example of the minimum cost flow problem.
 26.1171 +
 26.1172 +\bigskip
 26.1173 +
 26.1174 +The minimum cost flow problem can be naturally formulated as the
 26.1175 +following LP problem:
 26.1176 +
 26.1177 +\medskip
 26.1178 +
 26.1179 +\noindent
 26.1180 +\hspace{.5in}minimize
 26.1181 +$$z=\sum_{(i,j)\in A}c_{ij}x_{ij}\eqno(1)$$
 26.1182 +\hspace{.5in}subject to
 26.1183 +$$\sum_{(i,j)\in A}x_{ij}-\sum_{(j,i)\in A}x_{ji}=b_i\ \ \ \hbox
 26.1184 +{for all}\ i\in V\eqno(2)$$
 26.1185 +$$l_{ij}\leq x_{ij}\leq u_{ij}\ \ \ \hbox{for all}\ (i,j)\in A
 26.1186 +\eqno(3)$$
 26.1187 +
 26.1188 +\newpage
 26.1189 +
 26.1190 +\subsection{glp\_read\_mincost---read minimum cost flow problem\\data
 26.1191 +in DIMACS format}
 26.1192 +
 26.1193 +\subsubsection*{Synopsis}
 26.1194 +
 26.1195 +\begin{verbatim}
 26.1196 +int glp_read_mincost(glp_graph *G, int v_rhs, int a_low,
 26.1197 +      int a_cap, int a_cost, const char *fname);
 26.1198 +\end{verbatim}
 26.1199 +
 26.1200 +\subsubsection*{Description}
 26.1201 +
 26.1202 +The routine \verb|glp_read_mincost| reads the minimum cost flow problem
 26.1203 +data from a text file in DIMACS format.
 26.1204 +
 26.1205 +The parameter \verb|G| specifies the graph object, to which the problem
 26.1206 +data have to be stored. Note that before reading data the current
 26.1207 +content of the graph object is completely erased with the routine
 26.1208 +\verb|glp_erase_graph|.
 26.1209 +
 26.1210 +The parameter \verb|v_rhs| specifies an offset of the field of type
 26.1211 +\verb|double| in the vertex data block, to which the routine stores
 26.1212 +$b_i$, the supply/demand value. If \verb|v_rhs| $<0$, the value is not
 26.1213 +stored.
 26.1214 +
 26.1215 +The parameter \verb|a_low| specifies an offset of the field of type
 26.1216 +\verb|double| in the arc data block, to which the routine stores
 26.1217 +$l_{ij}$, the lower bound to the arc flow. If \verb|a_low| $<0$, the
 26.1218 +lower bound is not stored.
 26.1219 +
 26.1220 +The parameter \verb|a_cap| specifies an offset of the field of type
 26.1221 +\verb|double| in the arc data block, to which the routine stores
 26.1222 +$u_{ij}$, the upper bound to the arc flow (the arc capacity). If
 26.1223 +\verb|a_cap| $<0$, the upper bound is not stored.
 26.1224 +
 26.1225 +The parameter \verb|a_cost| specifies an offset of the field of type
 26.1226 +\verb|double| in the arc data block, to which the routine stores
 26.1227 +$c_{ij}$, the per-unit cost of the arc flow. If \verb|a_cost| $<0$, the
 26.1228 +cost is not stored.
 26.1229 +
 26.1230 +The character string \verb|fname| specifies the name of a text file to
 26.1231 +be read in. (If the file name name ends with the suffix `\verb|.gz|',
 26.1232 +the file is assumed to be compressed, in which case the routine
 26.1233 +decompresses it ``on the fly''.)
 26.1234 +
 26.1235 +\subsubsection*{Returns}
 26.1236 +
 26.1237 +If the operation was successful, the routine returns zero. Otherwise,
 26.1238 +it prints an error message and returns non-zero.
 26.1239 +
 26.1240 +\newpage
 26.1241 +
 26.1242 +\subsubsection*{Example}
 26.1243 +
 26.1244 +\begin{footnotesize}
 26.1245 +\begin{verbatim}
 26.1246 +typedef struct
 26.1247 +{     /* vertex data block */
 26.1248 +      ...
 26.1249 +      double rhs;
 26.1250 +      ...
 26.1251 +} v_data;
 26.1252 +
 26.1253 +typedef struct
 26.1254 +{     /* arc data block */
 26.1255 +      ...
 26.1256 +      double low, cap, cost;
 26.1257 +      ...
 26.1258 +} a_data;
 26.1259 +
 26.1260 +int main(void)
 26.1261 +{     glp_graph *G;
 26.1262 +      int ret;
 26.1263 +      G = glp_create_graph(sizeof(v_data), sizeof(a_data));
 26.1264 +      ret = glp_read_mincost(G, offsetof(v_data, rhs),
 26.1265 +         offsetof(a_data, low), offsetof(a_data, cap),
 26.1266 +         offsetof(a_data, cost), "sample.min");
 26.1267 +      if (ret != 0) goto ...
 26.1268 +      ...
 26.1269 +}
 26.1270 +\end{verbatim}
 26.1271 +\end{footnotesize}
 26.1272 +
 26.1273 +\subsubsection*{DIMACS minimum cost flow problem format\footnote{This
 26.1274 +material is based on the paper ``The First DIMACS International
 26.1275 +Algorithm Implementation Challenge: Problem Definitions and
 26.1276 +Specifications'', which is publically available at
 26.1277 +{\tt http://dimacs.rutgers.edu/Challenges/}.}}
 26.1278 +\label{subsecmincost}
 26.1279 +
 26.1280 +The DIMACS input file is a plain ASCII text file. It contains
 26.1281 +{\it lines} of several types described below. A line is terminated with
 26.1282 +an end-of-line character. Fields in each line are separated by at least
 26.1283 +one blank space. Each line begins with a one-character designator to
 26.1284 +identify the line type.
 26.1285 +
 26.1286 +Note that DIMACS requires all numerical quantities to be integers in
 26.1287 +the range $[-2^{31},\ 2^{31}-1]$ while GLPK allows the quantities to be
 26.1288 +floating-point numbers.
 26.1289 +
 26.1290 +\newpage
 26.1291 +
 26.1292 +\paragraph{Comment lines.} Comment lines give human-readable information
 26.1293 +about the file and are ignored by programs. Comment lines can appear
 26.1294 +anywhere in the file. Each comment line begins with a lower-case
 26.1295 +character \verb|c|.
 26.1296 +
 26.1297 +\begin{verbatim}
 26.1298 +   c This is a comment line
 26.1299 +\end{verbatim}
 26.1300 +
 26.1301 +\paragraph{Problem line.} There is one problem line per data file. The
 26.1302 +problem line must appear before any node or arc descriptor lines. It has
 26.1303 +the following format:
 26.1304 +
 26.1305 +\begin{verbatim}
 26.1306 +   p min NODES ARCS
 26.1307 +\end{verbatim}
 26.1308 +
 26.1309 +\noindent
 26.1310 +The lower-case character \verb|p| signifies that this is a problem line.
 26.1311 +The three-character problem designator \verb|min| identifies the file as
 26.1312 +containing specification information for the minimum cost flow problem.
 26.1313 +The \verb|NODES| field contains an integer value specifying the number
 26.1314 +of nodes in the network. The \verb|ARCS| field contains an integer value
 26.1315 +specifying the number of arcs in the network.
 26.1316 +
 26.1317 +\paragraph{Node descriptors.} All node descriptor lines must appear
 26.1318 +before all arc descriptor lines. The node descriptor lines describe
 26.1319 +supply and demand nodes, but not transshipment nodes. That is, only
 26.1320 +nodes with non-zero node supply/demand values appear. There is one node
 26.1321 +descriptor line for each such node, with the following format:
 26.1322 +
 26.1323 +\begin{verbatim}
 26.1324 +   n ID FLOW
 26.1325 +\end{verbatim}
 26.1326 +
 26.1327 +\noindent
 26.1328 +The lower-case character \verb|n| signifies that this is a node
 26.1329 +descriptor line. The \verb|ID| field gives a node identification number,
 26.1330 +an integer between 1 and \verb|NODES|. The \verb|FLOW| field gives the
 26.1331 +amount of supply (if positive) or demand (if negative) at node
 26.1332 +\verb|ID|.
 26.1333 +
 26.1334 +\paragraph{Arc descriptors.} There is one arc descriptor line for each
 26.1335 +arc in the network. Arc descriptor lines are of the following format:
 26.1336 +
 26.1337 +\begin{verbatim}
 26.1338 +   a SRC DST LOW CAP COST
 26.1339 +\end{verbatim}
 26.1340 +
 26.1341 +\noindent
 26.1342 +The lower-case character \verb|a| signifies that this is an arc
 26.1343 +descriptor line. For a directed arc $(i,j)$ the \verb|SRC| field gives
 26.1344 +the identification number $i$ for the tail endpoint, and the \verb|DST|
 26.1345 +field gives the identification number $j$ for the head endpoint.
 26.1346 +Identification numbers are integers between 1 and \verb|NODES|. The
 26.1347 +\verb|LOW| field specifies the minimum amount of flow that can be sent
 26.1348 +along arc $(i,j)$, and the \verb|CAP| field gives the maximum amount of
 26.1349 +flow that can be sent along arc $(i,j)$ in a feasible flow. The
 26.1350 +\verb|COST| field contains the per-unit cost of flow sent along arc
 26.1351 +$(i,j)$.
 26.1352 +
 26.1353 +\paragraph{Example.} Below here is an example of the data file in
 26.1354 +DIMACS format corresponding to the minimum cost flow problem shown on
 26.1355 +Fig~1.
 26.1356 +
 26.1357 +\begin{footnotesize}
 26.1358 +\begin{verbatim}
 26.1359 +c sample.min
 26.1360 +c
 26.1361 +c This is an example of the minimum cost flow problem data
 26.1362 +c in DIMACS format.
 26.1363 +c
 26.1364 +p min 9 14
 26.1365 +c
 26.1366 +n 1 20
 26.1367 +n 9 -20
 26.1368 +c
 26.1369 +a 1 2 0 14 0
 26.1370 +a 1 4 0 23 0
 26.1371 +a 2 3 0 10 2
 26.1372 +a 2 4 0  9 3
 26.1373 +a 3 5 2 12 1
 26.1374 +a 3 8 0 18 0
 26.1375 +a 4 5 0 26 0
 26.1376 +a 5 2 0 11 1
 26.1377 +a 5 6 0 25 5
 26.1378 +a 5 7 0  4 7
 26.1379 +a 6 7 0  7 0
 26.1380 +a 6 8 4  8 0
 26.1381 +a 7 9 0 15 3
 26.1382 +a 8 9 0 20 9
 26.1383 +c
 26.1384 +c eof
 26.1385 +\end{verbatim}
 26.1386 +\end{footnotesize}
 26.1387 +
 26.1388 +\newpage
 26.1389 +
 26.1390 +\subsection{glp\_write\_mincost---write minimum cost flow problem\\data
 26.1391 +in DIMACS format}
 26.1392 +
 26.1393 +\subsubsection*{Synopsis}
 26.1394 +
 26.1395 +\begin{verbatim}
 26.1396 +int glp_write_mincost(glp_graph *G, int v_rhs, int a_low,
 26.1397 +      int a_cap, int a_cost, const char *fname);
 26.1398 +\end{verbatim}
 26.1399 +
 26.1400 +\subsubsection*{Description}
 26.1401 +
 26.1402 +The routine \verb|glp_write_mincost| writes the minimum cost flow
 26.1403 +problem data to a text file in DIMACS format.
 26.1404 +
 26.1405 +The parameter \verb|G| is the graph (network) program object, which
 26.1406 +specifies the minimum cost flow problem instance.
 26.1407 +
 26.1408 +The parameter \verb|v_rhs| specifies an offset of the field of type
 26.1409 +\verb|double| in the vertex data block, which contains $b_i$, the
 26.1410 +supply/demand value. If \verb|v_rhs| $<0$, it is assumed that $b_i=0$
 26.1411 +for all nodes.
 26.1412 +
 26.1413 +The parameter \verb|a_low| specifies an offset of the field of type
 26.1414 +\verb|double| in the arc data block, which contains $l_{ij}$, the lower
 26.1415 +bound to the arc flow. If \verb|a_low| $<0$, it is assumed that
 26.1416 +$l_{ij}=0$ for all arcs.
 26.1417 +
 26.1418 +The parameter \verb|a_cap| specifies an offset of the field of type
 26.1419 +\verb|double| in the arc data block, which contains $u_{ij}$, the upper
 26.1420 +bound to the arc flow (the arc capacity). If the upper bound is
 26.1421 +specified as \verb|DBL_MAX|, it is assumed that $u_{ij}=\infty$, i.e.
 26.1422 +the arc is uncapacitated. If \verb|a_cap| $<0$, it is assumed that
 26.1423 +$u_{ij}=1$ for all arcs.
 26.1424 +
 26.1425 +The parameter \verb|a_cost| specifies an offset of the field of type
 26.1426 +\verb|double| in the arc data block, which contains $c_{ij}$, the
 26.1427 +per-unit cost of the arc flow. If \verb|a_cost| $<0$, it is assumed that
 26.1428 +$c_{ij}=0$ for all arcs.
 26.1429 +
 26.1430 +The character string \verb|fname| specifies a name of the text file to
 26.1431 +be written out. (If the file name ends with suffix `\verb|.gz|', the
 26.1432 +file is assumed to be compressed, in which case the routine performs
 26.1433 +automatic compression on writing it.)
 26.1434 +
 26.1435 +\subsubsection*{Returns}
 26.1436 +
 26.1437 +If the operation was successful, the routine returns zero. Otherwise,
 26.1438 +it prints an error message and returns non-zero.
 26.1439 +
 26.1440 +\newpage
 26.1441 +
 26.1442 +\subsection{glp\_mincost\_lp---convert minimum cost flow problem\\to LP}
 26.1443 +
 26.1444 +\subsubsection*{Synopsis}
 26.1445 +
 26.1446 +\begin{verbatim}
 26.1447 +void glp_mincost_lp(glp_prob *lp, glp_graph *G, int names,
 26.1448 +      int v_rhs, int a_low, int a_cap, int a_cost);
 26.1449 +\end{verbatim}
 26.1450 +
 26.1451 +\subsubsection*{Description}
 26.1452 +
 26.1453 +The routine \verb|glp_mincost_lp| builds LP problem (1)---(3), which
 26.1454 +corresponds to the specified minimum cost flow problem.
 26.1455 +
 26.1456 +The parameter \verb|lp| is the resultant LP problem object to be built.
 26.1457 +Note that on entry its current content is erased with the routine
 26.1458 +\verb|glp_erase_prob|.
 26.1459 +
 26.1460 +The parameter \verb|G| is the graph (network) program object, which
 26.1461 +specifies the minimum cost flow problem instance.
 26.1462 +
 26.1463 +The parameter \verb|names| is a flag. If it is \verb|GLP_ON|, the
 26.1464 +routine uses symbolic names of the graph object components to assign
 26.1465 +symbolic names to the LP problem object components. If the flag is
 26.1466 +\verb|GLP_OFF|, no symbolic names are assigned.
 26.1467 +
 26.1468 +The parameter \verb|v_rhs| specifies an offset of the field of type
 26.1469 +\verb|double| in the vertex data block, which contains $b_i$, the
 26.1470 +supply/demand value. If \verb|v_rhs| $<0$, it is assumed that $b_i=0$
 26.1471 +for all nodes.
 26.1472 +
 26.1473 +The parameter \verb|a_low| specifies an offset of the field of type
 26.1474 +\verb|double| in the arc data block, which contains $l_{ij}$, the lower
 26.1475 +bound to the arc flow. If \verb|a_low| $<0$, it is assumed that
 26.1476 +$l_{ij}=0$ for all arcs.
 26.1477 +
 26.1478 +The parameter \verb|a_cap| specifies an offset of the field of type
 26.1479 +\verb|double| in the arc data block, which contains $u_{ij}$, the upper
 26.1480 +bound to the arc flow (the arc capacity). If the upper bound is
 26.1481 +specified as \verb|DBL_MAX|, it is assumed that $u_{ij}=\infty$, i.e.
 26.1482 +the arc is uncapacitated. If \verb|a_cap| $<0$, it is assumed that
 26.1483 +$u_{ij}=1$ for all arcs.
 26.1484 +
 26.1485 +The parameter \verb|a_cost| specifies an offset of the field of type
 26.1486 +\verb|double| in the arc data block, which contains $c_{ij}$, the
 26.1487 +per-unit cost of the arc flow. If \verb|a_cost| $<0$, it is assumed that
 26.1488 +$c_{ij}=0$ for all arcs.
 26.1489 +
 26.1490 +\subsubsection*{Example}
 26.1491 +
 26.1492 +The example program below reads the minimum cost problem instance in
 26.1493 +DIMACS format from file `\verb|sample.min|', converts the instance to
 26.1494 +LP, and then writes the resultant LP in CPLEX format to file
 26.1495 +`\verb|mincost.lp|'.
 26.1496 +
 26.1497 +\newpage
 26.1498 +
 26.1499 +\begin{footnotesize}
 26.1500 +\begin{verbatim}
 26.1501 +#include <stddef.h>
 26.1502 +#include <glpk.h>
 26.1503 +
 26.1504 +typedef struct { double rhs; } v_data;
 26.1505 +typedef struct { double low, cap, cost; } a_data;
 26.1506 +
 26.1507 +int main(void)
 26.1508 +{     glp_graph *G;
 26.1509 +      glp_prob *lp;
 26.1510 +      G = glp_create_graph(sizeof(v_data), sizeof(a_data));
 26.1511 +      glp_read_mincost(G, offsetof(v_data, rhs),
 26.1512 +         offsetof(a_data, low), offsetof(a_data, cap),
 26.1513 +         offsetof(a_data, cost), "sample.min");
 26.1514 +      lp = glp_create_prob();
 26.1515 +      glp_mincost_lp(lp, G, GLP_ON, offsetof(v_data, rhs),
 26.1516 +         offsetof(a_data, low), offsetof(a_data, cap),
 26.1517 +         offsetof(a_data, cost));
 26.1518 +      glp_delete_graph(G);
 26.1519 +      glp_write_lp(lp, NULL, "mincost.lp");
 26.1520 +      glp_delete_prob(lp);
 26.1521 +      return 0;
 26.1522 +}
 26.1523 +\end{verbatim}
 26.1524 +\end{footnotesize}
 26.1525 +
 26.1526 +If `\verb|sample.min|' is the example data file from the subsection
 26.1527 +describing the routine \verb|glp_read_mincost|, file `\verb|mincost.lp|'
 26.1528 +may look like follows:
 26.1529 +
 26.1530 +\begin{footnotesize}
 26.1531 +\begin{verbatim}
 26.1532 +Minimize
 26.1533 + obj: + 3 x(2,4) + 2 x(2,3) + x(3,5) + 7 x(5,7) + 5 x(5,6)
 26.1534 + + x(5,2) + 3 x(7,9) + 9 x(8,9)
 26.1535 +
 26.1536 +Subject To
 26.1537 + r_1: + x(1,2) + x(1,4) = 20
 26.1538 + r_2: - x(5,2) + x(2,3) + x(2,4) - x(1,2) = 0
 26.1539 + r_3: + x(3,5) + x(3,8) - x(2,3) = 0
 26.1540 + r_4: + x(4,5) - x(2,4) - x(1,4) = 0
 26.1541 + r_5: + x(5,2) + x(5,6) + x(5,7) - x(4,5) - x(3,5) = 0
 26.1542 + r_6: + x(6,7) + x(6,8) - x(5,6) = 0
 26.1543 + r_7: + x(7,9) - x(6,7) - x(5,7) = 0
 26.1544 + r_8: + x(8,9) - x(6,8) - x(3,8) = 0
 26.1545 + r_9: - x(8,9) - x(7,9) = -20
 26.1546 +
 26.1547 +Bounds
 26.1548 + 0 <= x(1,4) <= 23
 26.1549 + 0 <= x(1,2) <= 14
 26.1550 + 0 <= x(2,4) <= 9
 26.1551 + 0 <= x(2,3) <= 10
 26.1552 + 0 <= x(3,8) <= 18
 26.1553 + 2 <= x(3,5) <= 12
 26.1554 + 0 <= x(4,5) <= 26
 26.1555 + 0 <= x(5,7) <= 4
 26.1556 + 0 <= x(5,6) <= 25
 26.1557 + 0 <= x(5,2) <= 11
 26.1558 + 4 <= x(6,8) <= 8
 26.1559 + 0 <= x(6,7) <= 7
 26.1560 + 0 <= x(7,9) <= 15
 26.1561 + 0 <= x(8,9) <= 20
 26.1562 +
 26.1563 +End
 26.1564 +\end{verbatim}
 26.1565 +\end{footnotesize}
 26.1566 +
 26.1567 +\subsection{glp\_mincost\_okalg---solve minimum cost flow problem with
 26.1568 +out-of-kilter algorithm}
 26.1569 +
 26.1570 +\subsubsection*{Synopsis}
 26.1571 +
 26.1572 +\begin{verbatim}
 26.1573 +int glp_mincost_okalg(glp_graph *G, int v_rhs, int a_low,
 26.1574 +      int a_cap, int a_cost, double *sol, int a_x, int v_pi);
 26.1575 +\end{verbatim}
 26.1576 +
 26.1577 +\subsubsection*{Description}
 26.1578 +
 26.1579 +The routine \verb|glp_mincost_okalg| finds optimal solution to the
 26.1580 +minimum cost flow problem with the out-of-kilter
 26.1581 +algorithm.\footnote{GLPK implementation of the out-of-kilter algorithm
 26.1582 +is based on the following book: L.~R.~Ford,~Jr., and D.~R.~Fulkerson,
 26.1583 +``Flows in Networks,'' The RAND Corp., Report R-375-PR (August 1962),
 26.1584 +Chap. III ``Minimal Cost Flow Problems,'' pp.~113-26.} Note that this
 26.1585 +routine requires all the problem data to be integer-valued.
 26.1586 +
 26.1587 +The parameter \verb|G| is a graph (network) program object which
 26.1588 +specifies the minimum cost flow problem instance to be solved.
 26.1589 +
 26.1590 +The parameter \verb|v_rhs| specifies an offset of the field of type
 26.1591 +\verb|double| in the vertex data block, which contains $b_i$, the
 26.1592 +supply/demand value. This value must be integer in the range
 26.1593 +[$-$\verb|INT_MAX|, $+$\verb|INT_MAX|]. If \verb|v_rhs| $<0$, it is
 26.1594 +assumed that $b_i=0$ for all nodes.
 26.1595 +
 26.1596 +The parameter \verb|a_low| specifies an offset of the field of type
 26.1597 +\verb|double| in the arc data block, which contains $l_{ij}$, the lower
 26.1598 +bound to the arc flow. This bound must be integer in the range
 26.1599 +[$0$, \verb|INT_MAX|]. If \verb|a_low| $<0$, it is assumed that
 26.1600 +$l_{ij}=0$ for all arcs.
 26.1601 +
 26.1602 +The parameter \verb|a_cap| specifies an offset of the field of type
 26.1603 +\verb|double| in the arc data block, which contains $u_{ij}$, the upper
 26.1604 +bound to the arc flow (the arc capacity). This bound must be integer in
 26.1605 +the range [$l_{ij}$, \verb|INT_MAX|]. If \verb|a_cap| $<0$, it is
 26.1606 +assumed that $u_{ij}=1$ for all arcs.
 26.1607 +
 26.1608 +The parameter \verb|a_cost| specifies an offset of the field of type
 26.1609 +\verb|double| in the arc data block, which contains $c_{ij}$, the
 26.1610 +per-unit cost of the arc flow. This value must be integer in the range
 26.1611 +[$-$\verb|INT_MAX|, $+$\verb|INT_MAX|]. If \verb|a_cost| $<0$, it is
 26.1612 +assumed that $c_{ij}=0$ for all arcs.
 26.1613 +
 26.1614 +The parameter \verb|sol| specifies a location, to which the routine
 26.1615 +stores the objective value (that is, the total cost) found. If
 26.1616 +\verb|sol| is NULL, the objective value is not stored.
 26.1617 +
 26.1618 +The parameter \verb|a_x| specifies an offset of the field of type
 26.1619 +\verb|double| in the arc data block, to which the routine stores
 26.1620 +$x_{ij}$, the arc flow found. If \verb|a_x| $<0$, the arc flow value is
 26.1621 +not stored.
 26.1622 +
 26.1623 +The parameter \verb|v_pi| specifies an offset of the field of type
 26.1624 +\verb|double| in the vertex data block, to which the routine stores
 26.1625 +$\pi_i$, the node potential, which is the Lagrange multiplier for the
 26.1626 +corresponding flow conservation equality constraint (see (2) in
 26.1627 +Subsection ``Background''). If necessary, the application program may
 26.1628 +use the node potentials to compute $\lambda_{ij}$, reduced costs of the
 26.1629 +arc flows $x_{ij}$, which are the Lagrange multipliers for the arc flow
 26.1630 +bound constraints (see (3) ibid.), using the following formula:
 26.1631 +$$\lambda_{ij}=c_{ij}-(\pi_i-\pi_j),$$
 26.1632 +where $c_{ij}$ is the per-unit cost for arc $(i,j)$.
 26.1633 +
 26.1634 +Note that all solution components (the objective value, arc flows, and
 26.1635 +node potentials) computed by the routine are always integer-valued.
 26.1636 +
 26.1637 +\subsubsection*{Returns}
 26.1638 +
 26.1639 +\def\arraystretch{1}
 26.1640 +
 26.1641 +\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
 26.1642 +0 & Optimal solution found.\\
 26.1643 +\verb|GLP_ENOPFS| & No (primal) feasible solution exists.\\
 26.1644 +\verb|GLP_EDATA| & Unable to start the search, because some problem
 26.1645 +data are either not integer-valued or out of range. This code is also
 26.1646 +returned if the total supply, which is the sum of $b_i$ over all source
 26.1647 +nodes (nodes with $b_i>0$), exceeds \verb|INT_MAX|.\\
 26.1648 +\end{tabular}
 26.1649 +
 26.1650 +\noindent
 26.1651 +\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
 26.1652 +\verb|GLP_ERANGE| & The search was prematurely terminated because of
 26.1653 +integer overflow.\\
 26.1654 +\verb|GLP_EFAIL| & An error has been detected in the program logic.
 26.1655 +(If this code is returned for your problem instance, please report to
 26.1656 +\verb|<bug-glpk@gnu.org>|.)\\
 26.1657 +\end{tabular}
 26.1658 +
 26.1659 +\subsubsection*{Comments}
 26.1660 +
 26.1661 +By design the out-of-kilter algorithm is applicable only to networks,
 26.1662 +where $b_i=0$ for {\it all} nodes, i.e. actually this algorithm finds a
 26.1663 +minimal cost {\it circulation}. Due to this requirement the routine
 26.1664 +\verb|glp_mincost_okalg| converts the original network to a network
 26.1665 +suitable for the out-of-kilter algorithm in the following
 26.1666 +way:\footnote{The conversion is performed internally and does not change
 26.1667 +the original network program object passed to the routine.}
 26.1668 +
 26.1669 +1) it adds two auxiliary nodes $s$ and $t$;
 26.1670 +
 26.1671 +2) for each original node $i$ with $b_i>0$ the routine adds auxiliary
 26.1672 +supply arc $(s\rightarrow i)$, flow $x_{si}$ through which is costless
 26.1673 +($c_{si}=0$) and fixed to $+b_i$ ($l_{si}=u_{si}=+b_i$);
 26.1674 +
 26.1675 +3) for each original node $i$ with $b_i<0$ the routine adds auxiliary
 26.1676 +demand arc $(i\rightarrow t)$, flow $x_{it}$ through which is costless
 26.1677 +($c_{it}=0$) and fixed to $-b_i$ ($l_{it}=u_{it}=-b_i$);
 26.1678 +
 26.1679 +4) finally, the routine adds auxiliary feedback arc $(t\rightarrow s)$,
 26.1680 +flow $x_{ts}$ through which is also costless ($c_{ts}=0$) and fixed to
 26.1681 +$F$ ($l_{ts}=u_{ts}=F$), where $\displaystyle F=\sum_{b_i>0}b_i$ is the
 26.1682 +total supply.
 26.1683 +
 26.1684 +\subsubsection*{Example}
 26.1685 +
 26.1686 +The example program below reads the minimum cost problem instance in
 26.1687 +DIMACS format from file `\verb|sample.min|', solves it by using the
 26.1688 +routine \verb|glp_mincost_okalg|, and writes the solution found to the
 26.1689 +standard output.
 26.1690 +
 26.1691 +\begin{footnotesize}
 26.1692 +\begin{verbatim}
 26.1693 +#include <stddef.h>
 26.1694 +#include <stdio.h>
 26.1695 +#include <stdlib.h>
 26.1696 +#include <glpk.h>
 26.1697 +
 26.1698 +typedef struct { double rhs, pi; } v_data;
 26.1699 +typedef struct { double low, cap, cost, x; } a_data;
 26.1700 +
 26.1701 +#define node(v) ((v_data *)((v)->data))
 26.1702 +#define arc(a)  ((a_data *)((a)->data))
 26.1703 +
 26.1704 +int main(void)
 26.1705 +{     glp_graph *G;
 26.1706 +      glp_vertex *v, *w;
 26.1707 +      glp_arc *a;
 26.1708 +      int i, ret;
 26.1709 +      double sol;
 26.1710 +      G = glp_create_graph(sizeof(v_data), sizeof(a_data));
 26.1711 +      glp_read_mincost(G, offsetof(v_data, rhs),
 26.1712 +         offsetof(a_data, low), offsetof(a_data, cap),
 26.1713 +         offsetof(a_data, cost), "sample.min");
 26.1714 +      ret = glp_mincost_okalg(G, offsetof(v_data, rhs),
 26.1715 +         offsetof(a_data, low), offsetof(a_data, cap),
 26.1716 +         offsetof(a_data, cost), &sol, offsetof(a_data, x),
 26.1717 +         offsetof(v_data, pi));
 26.1718 +      printf("ret = %d; sol = %5g\n", ret, sol);
 26.1719 +      for (i = 1; i <= G->nv; i++)
 26.1720 +      {  v = G->v[i];
 26.1721 +         printf("node %d:    pi = %5g\n", i, node(v)->pi);
 26.1722 +         for (a = v->out; a != NULL; a = a->t_next)
 26.1723 +         {  w = a->head;
 26.1724 +            printf("arc  %d->%d: x  = %5g; lambda = %5g\n",
 26.1725 +               v->i, w->i, arc(a)->x,
 26.1726 +               arc(a)->cost - (node(v)->pi - node(w)->pi));
 26.1727 +         }
 26.1728 +      }
 26.1729 +      glp_delete_graph(G);
 26.1730 +      return 0;
 26.1731 +}
 26.1732 +\end{verbatim}
 26.1733 +\end{footnotesize}
 26.1734 +
 26.1735 +If `\verb|sample.min|' is the example data file from the subsection
 26.1736 +describing the routine \verb|glp_read_mincost|, the output may look like
 26.1737 +follows:
 26.1738 +
 26.1739 +\begin{footnotesize}
 26.1740 +\begin{verbatim}
 26.1741 +Reading min-cost flow problem data from `sample.min'...
 26.1742 +Flow network has 9 nodes and 14 arcs
 26.1743 +24 lines were read
 26.1744 +ret = 0; sol =   213
 26.1745 +node 1:    pi =   -12
 26.1746 +arc  1->4: x  =    13; lambda =     0
 26.1747 +arc  1->2: x  =     7; lambda =     0
 26.1748 +node 2:    pi =   -12
 26.1749 +arc  2->4: x  =     0; lambda =     3
 26.1750 +arc  2->3: x  =     7; lambda =     0
 26.1751 +node 3:    pi =   -14
 26.1752 +arc  3->8: x  =     5; lambda =     0
 26.1753 +arc  3->5: x  =     2; lambda =     3
 26.1754 +node 4:    pi =   -12
 26.1755 +arc  4->5: x  =    13; lambda =     0
 26.1756 +node 5:    pi =   -12
 26.1757 +arc  5->7: x  =     4; lambda =    -1
 26.1758 +arc  5->6: x  =    11; lambda =     0
 26.1759 +arc  5->2: x  =     0; lambda =     1
 26.1760 +node 6:    pi =   -17
 26.1761 +arc  6->8: x  =     4; lambda =     3
 26.1762 +arc  6->7: x  =     7; lambda =    -3
 26.1763 +node 7:    pi =   -20
 26.1764 +arc  7->9: x  =    11; lambda =     0
 26.1765 +node 8:    pi =   -14
 26.1766 +arc  8->9: x  =     9; lambda =     0
 26.1767 +node 9:    pi =   -23
 26.1768 +\end{verbatim}
 26.1769 +\end{footnotesize}
 26.1770 +
 26.1771 +\subsection{glp\_netgen---Klingman's network problem generator}
 26.1772 +
 26.1773 +\subsubsection*{Synopsis}
 26.1774 +
 26.1775 +\begin{verbatim}
 26.1776 +int glp_netgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
 26.1777 +      const int parm[1+15]);
 26.1778 +\end{verbatim}
 26.1779 +
 26.1780 +\subsubsection*{Description}
 26.1781 +
 26.1782 +The routine \verb|glp_netgen| is a GLPK version of the network problem
 26.1783 +generator developed by Dr.~Darwin~Klingman.\footnote{D.~Klingman,
 26.1784 +A.~Napier, and J.~Stutz. NETGEN: A program for generating large scale
 26.1785 +capacitated assignment, transportation, and minimum cost flow networks.
 26.1786 +Management Science 20 (1974), 814-20.} It can create capacitated and
 26.1787 +uncapacitated minimum cost flow (or transshipment), transportation, and
 26.1788 +assignment problems.
 26.1789 +
 26.1790 +The parameter \verb|G| specifies the graph object, to which the
 26.1791 +generated  problem data have to be stored. Note that on entry the graph
 26.1792 +object  is erased with the routine \verb|glp_erase_graph|.
 26.1793 +
 26.1794 +The parameter \verb|v_rhs| specifies an offset of the field of type
 26.1795 +\verb|double| in the vertex data block, to which the routine stores the
 26.1796 +supply or  demand value. If \verb|v_rhs| $<0$, the value is not stored.
 26.1797 +
 26.1798 +The parameter \verb|a_cap| specifies an offset of the field of type
 26.1799 +\verb|double| in the arc data block, to which the routine stores the
 26.1800 +arc capacity. If \verb|a_cap| $<0$, the capacity is not stored.
 26.1801 +
 26.1802 +The parameter \verb|a_cost| specifies an offset of the field of type
 26.1803 +\verb|double| in the arc data block, to which the routine stores the
 26.1804 +per-unit cost if the arc flow. If \verb|a_cost| $<0$, the cost is not
 26.1805 +stored.
 26.1806 +
 26.1807 +The array \verb|parm| contains description of the network to be
 26.1808 +generated:
 26.1809 +
 26.1810 +\begin{tabular}{@{}lll@{}}
 26.1811 +\verb|parm[0] |&             &not used\\
 26.1812 +\verb|parm[1] |&\verb|iseed |&8-digit positive random number seed\\
 26.1813 +\verb|parm[2] |&\verb|nprob |&8-digit problem id number\\
 26.1814 +\verb|parm[3] |&\verb|nodes |&total number of nodes\\
 26.1815 +\verb|parm[4] |&\verb|nsorc |&total number of source nodes\\
 26.1816 +&&(including transshipment nodes)\\
 26.1817 +\verb|parm[5] |&\verb|nsink |&total number of sink nodes\\
 26.1818 +&&(including transshipment nodes)\\
 26.1819 +\verb|parm[6] |&\verb|iarcs |&number of arc\\
 26.1820 +\verb|parm[7] |&\verb|mincst|&minimum cost for arcs\\
 26.1821 +\verb|parm[8] |&\verb|maxcst|&maximum cost for arcs\\
 26.1822 +\verb|parm[9] |&\verb|itsup |&total supply\\
 26.1823 +\end{tabular}
 26.1824 +
 26.1825 +\begin{tabular}{@{}lll@{}}
 26.1826 +\verb|parm[10]|&\verb|ntsorc|&number of transshipment source nodes\\
 26.1827 +\verb|parm[11]|&\verb|ntsink|&number of transshipment sink nodes\\
 26.1828 +\verb|parm[12]|&\verb|iphic |&percentage of skeleton arcs to be given
 26.1829 +the maxi-\\&&mum cost\\
 26.1830 +\verb|parm[13]|&\verb|ipcap |&percentage of arcs to be capacitated\\
 26.1831 +\verb|parm[14]|&\verb|mincap|&minimum upper bound for capacitated arcs\\
 26.1832 +\verb|parm[15]|&\verb|maxcap|&maximum upper bound for capacitated arcs\\
 26.1833 +\end{tabular}
 26.1834 +
 26.1835 +\subsubsection*{Notes}
 26.1836 +
 26.1837 +\noindent\indent
 26.1838 +1. The routine generates a transportation problem if:
 26.1839 +$${\tt nsorc}+{\tt nsink}={\tt nodes},
 26.1840 +\  {\tt ntsorc}=0,\ \mbox{and}\ {\tt ntsink}=0.$$
 26.1841 +
 26.1842 +2. The routine generates an assignment problem if the requirements for
 26.1843 +a transportation problem are met and:
 26.1844 +$${\tt nsorc}={\tt nsink}\ \mbox{and}\ {\tt itsup}={\tt nsorc}.$$
 26.1845 +
 26.1846 +3. The routine always generates connected graphs. So, if the number of
 26.1847 +requested arcs has been reached and the generated instance is not fully
 26.1848 +connected, the routine generates a few remaining arcs to ensure
 26.1849 +connectedness. Thus, the actual number of arcs generated by the routine
 26.1850 +may be greater than the requested number of arcs.
 26.1851 +
 26.1852 +\subsubsection*{Returns}
 26.1853 +
 26.1854 +If the instance was successfully generated, the routine
 26.1855 +\verb|glp_netgen| returns zero; otherwise, if specified parameters are
 26.1856 +inconsistent, the routine returns a non-zero error code.
 26.1857 +
 26.1858 +\subsection{glp\_gridgen---grid-like network problem generator}
 26.1859 +
 26.1860 +\subsubsection*{Synopsis}
 26.1861 +
 26.1862 +\begin{verbatim}
 26.1863 +int glp_gridgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
 26.1864 +      const int parm[1+14]);
 26.1865 +\end{verbatim}
 26.1866 +
 26.1867 +\subsubsection*{Description}
 26.1868 +
 26.1869 +The routine \verb|glp_gridgen| is a GLPK version of the grid-like
 26.1870 +network problem generator developed by Yusin Lee and Jim
 26.1871 +Orlin.\footnote{Y.~Lee and J.~Orlin. GRIDGEN generator., 1991. The
 26.1872 +original code is publically available from
 26.1873 +{\tt<ftp://dimacs.rutgers.edu/pub/netflow/generators/network/gridgen>}.}
 26.1874 +
 26.1875 +The parameter \verb|G| specifies the graph object, to which the
 26.1876 +generated  problem data have to be stored. Note that on entry the graph
 26.1877 +object  is erased with the routine \verb|glp_erase_graph|.
 26.1878 +
 26.1879 +The parameter \verb|v_rhs| specifies an offset of the field of type
 26.1880 +\verb|double| in the vertex data block, to which the routine stores the
 26.1881 +supply or  demand value. If \verb|v_rhs| $<0$, the value is not stored.
 26.1882 +
 26.1883 +The parameter \verb|a_cap| specifies an offset of the field of type
 26.1884 +\verb|double| in the arc data block, to which the routine stores the
 26.1885 +arc capacity. If \verb|a_cap| $<0$, the capacity is not stored.
 26.1886 +
 26.1887 +The parameter \verb|a_cost| specifies an offset of the field of type
 26.1888 +\verb|double| in the arc data block, to which the routine stores the
 26.1889 +per-unit cost if the arc flow. If \verb|a_cost| $<0$, the cost is not
 26.1890 +stored.
 26.1891 +
 26.1892 +The array \verb|parm| contains parameters of the network to be
 26.1893 +generated:
 26.1894 +
 26.1895 +\begin{tabular}{@{}ll@{}}
 26.1896 +\verb|parm[0] |&not used\\
 26.1897 +\verb|parm[1] |&two-ways arcs indicator:\\
 26.1898 +               &1 --- if links in both direction should be generated\\
 26.1899 +               &0 --- otherwise\\
 26.1900 +\verb|parm[2] |&random number seed (a positive integer)\\
 26.1901 +\verb|parm[3] |&number of nodes (the number of nodes generated might
 26.1902 +be\\&slightly different to make the network a grid)\\
 26.1903 +\verb|parm[4] |&grid width\\
 26.1904 +\verb|parm[5] |&number of sources\\
 26.1905 +\verb|parm[6] |&number of sinks\\
 26.1906 +\verb|parm[7] |&average degree\\
 26.1907 +\verb|parm[8] |&total flow\\
 26.1908 +\verb|parm[9] |&distribution of arc costs:\\
 26.1909 +               &1 --- uniform\\
 26.1910 +               &2 --- exponential\\
 26.1911 +\verb|parm[10]|&lower bound for arc cost (uniform)\\
 26.1912 +               &$100\lambda$ (exponential)\\
 26.1913 +\verb|parm[11]|&upper bound for arc cost (uniform)\\
 26.1914 +               &not used (exponential)\\
 26.1915 +\verb|parm[12]|&distribution of arc capacities:\\
 26.1916 +               &1 --- uniform\\
 26.1917 +               &2 --- exponential\\
 26.1918 +\verb|parm[13]|&lower bound for arc capacity (uniform)\\
 26.1919 +               &$100\lambda$ (exponential)\\
 26.1920 +\verb|parm[14]|&upper bound for arc capacity (uniform)\\
 26.1921 +               &not used (exponential)\\
 26.1922 +\end{tabular}
 26.1923 +
 26.1924 +\subsubsection*{Returns}
 26.1925 +
 26.1926 +If the instance was successfully generated, the routine
 26.1927 +\verb|glp_gridgen| returns zero; otherwise, if specified parameters are
 26.1928 +inconsistent, the routine returns a non-zero error code.
 26.1929 +
 26.1930 +\subsubsection*{Comments\footnote{This material is based on comments
 26.1931 +to the original version of GRIDGEN.}}
 26.1932 +
 26.1933 +This network generator generates a grid-like network plus a super node.
 26.1934 +In additional to the arcs connecting the nodes in the grid, there is an
 26.1935 +arc from each supply node to the super node and from the super node to
 26.1936 +each demand node to guarantee feasiblity. These arcs have very high
 26.1937 +costs and very big capacities.
 26.1938 +
 26.1939 +The idea of this network generator is as follows: First, a grid of
 26.1940 +$n_1\times n_2$ is generated. For example, $5\times 3$. The nodes are
 26.1941 +numbered as 1 to 15, and the supernode is numbered as $n_1\times n_2+1$.
 26.1942 +Then arcs between adjacent nodes are generated. For these arcs, the user
 26.1943 +is allowed to specify either to generate two-way arcs or one-way arcs.
 26.1944 +If two-way arcs are to be generated, two arcs, one in each direction,
 26.1945 +will be generated between each adjacent node pairs. Otherwise, only one
 26.1946 +arc will be generated. If this is the case, the arcs will be generated
 26.1947 +in alterntive directions as shown below.
 26.1948 +
 26.1949 +\bigskip
 26.1950 +
 26.1951 +\noindent\hfil
 26.1952 +\xymatrix
 26.1953 +{1\ar[r]\ar[d]&2\ar[r]&3\ar[r]\ar[d]&4\ar[r]&5\ar[d]\\
 26.1954 +6\ar[d]&7\ar[l]\ar[u]&8\ar[l]\ar[d]&9\ar[l]\ar[u]&10\ar[l]\ar[d]\\
 26.1955 +11\ar[r]&12\ar[r]\ar[u]&13\ar[r]&14\ar[r]\ar[u]&15\\
 26.1956 +}
 26.1957 +
 26.1958 +\bigskip
 26.1959 +
 26.1960 +Then the arcs between the super node and the source/sink nodes are added
 26.1961 +as mentioned before. If the number of arcs still doesn't reach the
 26.1962 +requirement, additional arcs will be added by uniformly picking random
 26.1963 +node pairs. There is no checking to prevent multiple arcs between any
 26.1964 +pair of nodes. However, there will be no self-arcs (arcs that poins back
 26.1965 +to its tail node) in the network.
 26.1966 +
 26.1967 +The source and sink nodes are selected uniformly in the network, and
 26.1968 +the imbalances of each source/sink node are also assigned by uniform
 26.1969 +distribution.
 26.1970 +
 26.1971 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 26.1972 +
 26.1973 +\newpage
 26.1974 +
 26.1975 +\section{Maximum flow problem}
 26.1976 +
 26.1977 +\subsection{Background}
 26.1978 +
 26.1979 +The {\it maximum flow problem} (MAXFLOW) is stated as follows. Let
 26.1980 +there be given a directed graph (flow network) $G=(V,A)$, where $V$ is
 26.1981 +a set of vertices (nodes), and $A\subseteq V\times V$ is a set of arcs.
 26.1982 +Let also for each arc $a=(i,j)\in A$ there be given its capacity
 26.1983 +$u_{ij}$. The problem is, for given {\it source} node $s\in V$ and
 26.1984 +{\it sink} node $t\in V$, to find flows $x_{ij}$ through every arc of
 26.1985 +the network, which satisfy the specified arc capacities and the
 26.1986 +conservation constraints at all nodes, and maximize the total flow $F$
 26.1987 +through the network from $s$ to $t$. Here the conservation constraint
 26.1988 +at a node means that the total flow entering this node through its
 26.1989 +incoming arcs (plus $F$, if it is the source node) must be equal to the
 26.1990 +total flow leaving this node through its outgoing arcs (plus $F$, if it
 26.1991 +is the sink node).
 26.1992 +
 26.1993 +An example of the maximum flow problem, where $s=v_1$ and $t=v_9$, is
 26.1994 +shown on Fig.~2.
 26.1995 +
 26.1996 +\bigskip
 26.1997 +
 26.1998 +\noindent\hfil
 26.1999 +\xymatrix @C=48pt
 26.2000 +{_{F}\ar@{~>}[d]&
 26.2001 +v_2\ar[r]|{_{10}}\ar[dd]|{_{9}}&
 26.2002 +v_3\ar[dd]|{_{12}}\ar[r]|{_{18}}&
 26.2003 +v_8\ar[rd]|{_{20}}&\\
 26.2004 +v_1\ar[ru]|{_{14}}\ar[rd]|{_{23}}&&&
 26.2005 +v_6\ar[d]|{_{7}}\ar[u]|{_{8}}&
 26.2006 +v_9\ar@{~>}[d]\\
 26.2007 +&v_4\ar[r]|{_{26}}&
 26.2008 +v_5\ar[luu]|{_{11}}\ar[ru]|{_{25}}\ar[r]|{_{4}}&
 26.2009 +v_7\ar[ru]|{_{15}}&_{F}\\
 26.2010 +}
 26.2011 +
 26.2012 +\bigskip
 26.2013 +
 26.2014 +\noindent\hfil
 26.2015 +Fig.~2. An example of the maximum flow problem.
 26.2016 +
 26.2017 +\bigskip
 26.2018 +
 26.2019 +The maximum flow problem can be naturally formulated as the following
 26.2020 +LP problem:
 26.2021 +
 26.2022 +\medskip
 26.2023 +
 26.2024 +\noindent
 26.2025 +\hspace{.5in}maximize
 26.2026 +$$F\eqno(4)$$
 26.2027 +\hspace{.5in}subject to
 26.2028 +$$\sum_{(i,j)\in A}x_{ij}-\sum_{(j,i)\in A}x_{ji}=\left\{
 26.2029 +\begin{array}{@{\ }rl}
 26.2030 ++F,&\hbox{for}\ i=s\\
 26.2031 + 0,&\hbox{for all}\ i\in V\backslash\{s,t\}\\
 26.2032 +-F,&\hbox{for}\ i=t\\
 26.2033 +\end{array}
 26.2034 +\right.\eqno(5)
 26.2035 +$$
 26.2036 +$$0\leq x_{ij}\leq u_{ij}\ \ \ \hbox{for all}\ (i,j)\in A
 26.2037 +\eqno(6)$$
 26.2038 +
 26.2039 +\medskip
 26.2040 +
 26.2041 +\noindent
 26.2042 +where $F\geq 0$ is an additional variable playing the role of the
 26.2043 +objective.
 26.2044 +
 26.2045 +\newpage
 26.2046 +
 26.2047 +Another LP formulation of the maximum flow problem, which does not
 26.2048 +include the variable $F$, is the following:
 26.2049 +
 26.2050 +\medskip
 26.2051 +
 26.2052 +\noindent
 26.2053 +\hspace{.5in}maximize
 26.2054 +$$z=\sum_{(s,j)\in A}x_{sj}-\sum_{(j,s)\in A}x_{js}\ (=F)\eqno(7)$$
 26.2055 +\hspace{.5in}subject to
 26.2056 +$$\sum_{(i,j)\in A}x_{ij}-\sum_{(j,i)\in A}x_{ji}\left\{
 26.2057 +\begin{array}{@{\ }rl}
 26.2058 +\geq 0,&\hbox{for}\ i=s\\
 26.2059 +=0,&\hbox{for all}\ i\in V\backslash\{s,t\}\\
 26.2060 +\leq 0,&\hbox{for}\ i=t\\
 26.2061 +\end{array}
 26.2062 +\right.\eqno(8)
 26.2063 +$$
 26.2064 +$$0\leq x_{ij}\leq u_{ij}\ \ \ \hbox{for all}\ (i,j)\in A
 26.2065 +\eqno(9)$$
 26.2066 +
 26.2067 +\subsection{glp\_read\_maxflow---read maximum flow problem data\\in
 26.2068 +DIMACS format}
 26.2069 +
 26.2070 +\subsubsection*{Synopsis}
 26.2071 +
 26.2072 +\begin{verbatim}
 26.2073 +int glp_read_maxflow(glp_graph *G, int *s, int *t, int a_cap,
 26.2074 +      const char *fname);
 26.2075 +\end{verbatim}
 26.2076 +
 26.2077 +\subsubsection*{Description}
 26.2078 +
 26.2079 +The routine \verb|glp_read_maxflow| reads the maximum flow problem
 26.2080 +data from a text file in DIMACS format.
 26.2081 +
 26.2082 +The parameter \verb|G| specifies the graph object, to which the problem
 26.2083 +data have to be stored. Note that before reading data the current
 26.2084 +content of the graph object is completely erased with the routine
 26.2085 +\verb|glp_erase_graph|.
 26.2086 +
 26.2087 +The pointer \verb|s| specifies a location, to which the routine stores
 26.2088 +the ordinal number of the source node. If \verb|s| is \verb|NULL|, the
 26.2089 +source node number is not stored.
 26.2090 +
 26.2091 +The pointer \verb|t| specifies a location, to which the routine stores
 26.2092 +the ordinal number of the sink node. If \verb|t| is \verb|NULL|, the
 26.2093 +sink node number is not stored.
 26.2094 +
 26.2095 +The parameter \verb|a_cap| specifies an offset of the field of type
 26.2096 +\verb|double| in the arc data block, to which the routine stores
 26.2097 +$u_{ij}$, the arc capacity. If \verb|a_cap| $<0$, the arc capacity is
 26.2098 +not stored.
 26.2099 +
 26.2100 +The character string \verb|fname| specifies the name of a text file to
 26.2101 +be read in. (If the file name name ends with the suffix `\verb|.gz|',
 26.2102 +the file is assumed to be compressed, in which case the routine
 26.2103 +decompresses it ``on the fly''.)
 26.2104 +
 26.2105 +\subsubsection*{Returns}
 26.2106 +
 26.2107 +If the operation was successful, the routine returns zero. Otherwise,
 26.2108 +it prints an error message and returns non-zero.
 26.2109 +
 26.2110 +\subsubsection*{Example}
 26.2111 +
 26.2112 +\begin{footnotesize}
 26.2113 +\begin{verbatim}
 26.2114 +typedef struct
 26.2115 +{     /* arc data block */
 26.2116 +      ...
 26.2117 +      double cap;
 26.2118 +      ...
 26.2119 +} a_data;
 26.2120 +
 26.2121 +int main(void)
 26.2122 +{     glp_graph *G;
 26.2123 +      int s, t, ret;
 26.2124 +      G = glp_create_graph(..., sizeof(a_data));
 26.2125 +      ret = glp_read_maxflow(G, &s, &t, offsetof(a_data, cap),
 26.2126 +         "sample.max");
 26.2127 +      if (ret != 0) goto ...
 26.2128 +      ...
 26.2129 +}
 26.2130 +\end{verbatim}
 26.2131 +\end{footnotesize}
 26.2132 +
 26.2133 +\subsubsection*{DIMACS maximum flow problem format\footnote{This
 26.2134 +material is based on the paper ``The First DIMACS International
 26.2135 +Algorithm Implementation Challenge: Problem Definitions and
 26.2136 +Specifications'', which is publically available at
 26.2137 +{\tt http://dimacs.rutgers.edu/Challenges/}.}}
 26.2138 +\label{subsecmaxflow}
 26.2139 +
 26.2140 +The DIMACS input file is a plain ASCII text file. It contains
 26.2141 +{\it lines} of several types described below. A line is terminated with
 26.2142 +an end-of-line character. Fields in each line are separated by at least
 26.2143 +one blank space. Each line begins with a one-character designator to
 26.2144 +identify the line type.
 26.2145 +
 26.2146 +Note that DIMACS requires all numerical quantities to be integers in
 26.2147 +the range $[-2^{31},\ 2^{31}-1]$ while GLPK allows the quantities to be
 26.2148 +floating-point numbers.
 26.2149 +
 26.2150 +\paragraph{Comment lines.} Comment lines give human-readable information
 26.2151 +about the file and are ignored by programs. Comment lines can appear
 26.2152 +anywhere in the file. Each comment line begins with a lower-case
 26.2153 +character \verb|c|.
 26.2154 +
 26.2155 +\begin{verbatim}
 26.2156 +   c This is a comment line
 26.2157 +\end{verbatim}
 26.2158 +
 26.2159 +\newpage
 26.2160 +
 26.2161 +\paragraph{Problem line.} There is one problem line per data file. The
 26.2162 +problem line must appear before any node or arc descriptor lines. It has
 26.2163 +the following format:
 26.2164 +
 26.2165 +\begin{verbatim}
 26.2166 +   p max NODES ARCS
 26.2167 +\end{verbatim}
 26.2168 +
 26.2169 +\noindent
 26.2170 +The lower-case character \verb|p| signifies that this is a problem line.
 26.2171 +The three-character problem designator \verb|max| identifies the file as
 26.2172 +containing specification information for the maximum flow problem. The
 26.2173 +\verb|NODES| field contains an integer value specifying the number of
 26.2174 +nodes in the network. The \verb|ARCS| field contains an integer value
 26.2175 +specifying the number of arcs in the network.
 26.2176 +
 26.2177 +\paragraph{Node descriptors.} Two node descriptor lines for the source
 26.2178 +and sink nodes must appear before all arc descriptor lines. They may
 26.2179 +appear in either order, each with the following format:
 26.2180 +
 26.2181 +\begin{verbatim}
 26.2182 +   n ID WHICH
 26.2183 +\end{verbatim}
 26.2184 +
 26.2185 +\noindent
 26.2186 +The lower-case character \verb|n| signifies that this a node descriptor
 26.2187 +line. The \verb|ID| field gives a node identification number, an integer
 26.2188 +between 1 and \verb|NODES|. The \verb|WHICH| field gives either a
 26.2189 +lower-case \verb|s| or \verb|t|, designating the source and sink,
 26.2190 +respectively.
 26.2191 +
 26.2192 +\paragraph{Arc descriptors.} There is one arc descriptor line for each
 26.2193 +arc in the network. Arc descriptor lines are of the following format:
 26.2194 +
 26.2195 +\begin{verbatim}
 26.2196 +   a SRC DST CAP
 26.2197 +\end{verbatim}
 26.2198 +
 26.2199 +\noindent
 26.2200 +The lower-case character \verb|a| signifies that this is an arc
 26.2201 +descriptor line. For a directed arc $(i,j)$ the \verb|SRC| field gives
 26.2202 +the identification number $i$ for the tail endpoint, and the \verb|DST|
 26.2203 +field gives the identification number $j$ for the head endpoint.
 26.2204 +Identification numbers are integers between 1 and \verb|NODES|. The
 26.2205 +\verb|CAP| field gives the arc capacity, i.e. maximum amount of flow
 26.2206 +that can be sent along arc $(i,j)$ in a feasible flow.
 26.2207 +
 26.2208 +\paragraph{Example.} Below here is an example of the data file in
 26.2209 +DIMACS format corresponding to the maximum flow problem shown on Fig~2.
 26.2210 +
 26.2211 +\newpage
 26.2212 +
 26.2213 +\begin{footnotesize}
 26.2214 +\begin{verbatim}
 26.2215 +c sample.max
 26.2216 +c
 26.2217 +c This is an example of the maximum flow problem data
 26.2218 +c in DIMACS format.
 26.2219 +c
 26.2220 +p max 9 14
 26.2221 +c
 26.2222 +n 1 s
 26.2223 +n 9 t
 26.2224 +c
 26.2225 +a 1 2 14
 26.2226 +a 1 4 23
 26.2227 +a 2 3 10
 26.2228 +a 2 4  9
 26.2229 +a 3 5 12
 26.2230 +a 3 8 18
 26.2231 +a 4 5 26
 26.2232 +a 5 2 11
 26.2233 +a 5 6 25
 26.2234 +a 5 7  4
 26.2235 +a 6 7  7
 26.2236 +a 6 8  8
 26.2237 +a 7 9 15
 26.2238 +a 8 9 20
 26.2239 +c
 26.2240 +c eof
 26.2241 +\end{verbatim}
 26.2242 +\end{footnotesize}
 26.2243 +
 26.2244 +\subsection{glp\_write\_maxflow---write maximum flow problem data\\
 26.2245 +in DIMACS format}
 26.2246 +
 26.2247 +\subsubsection*{Synopsis}
 26.2248 +
 26.2249 +\begin{verbatim}
 26.2250 +int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap,
 26.2251 +      const char *fname);
 26.2252 +\end{verbatim}
 26.2253 +
 26.2254 +\subsubsection*{Description}
 26.2255 +
 26.2256 +The routine \verb|glp_write_maxflow| writes the maximum flow problem
 26.2257 +data to a text file in DIMACS format.
 26.2258 +
 26.2259 +The parameter \verb|G| is the graph (network) program object, which
 26.2260 +specifies the maximum flow problem instance.
 26.2261 +
 26.2262 +The parameter \verb|s| specifies the ordinal number of the source node.
 26.2263 +
 26.2264 +The parameter \verb|t| specifies the ordinal number of the sink node.
 26.2265 +
 26.2266 +The parameter \verb|a_cap| specifies an offset of the field of type
 26.2267 +\verb|double| in the arc data block, which contains $u_{ij}$, the upper
 26.2268 +bound to the arc flow (the arc capacity). If the upper bound is
 26.2269 +specified as \verb|DBL_MAX|, it is assumed that $u_{ij}=\infty$, i.e.
 26.2270 +the arc is uncapacitated. If \verb|a_cap| $<0$, it is assumed that
 26.2271 +$u_{ij}=1$ for all arcs.
 26.2272 +
 26.2273 +The character string \verb|fname| specifies a name of the text file to
 26.2274 +be written out. (If the file name ends with suffix `\verb|.gz|', the
 26.2275 +file is assumed to be compressed, in which case the routine performs
 26.2276 +automatic compression on writing it.)
 26.2277 +
 26.2278 +\subsubsection*{Returns}
 26.2279 +
 26.2280 +If the operation was successful, the routine returns zero. Otherwise,
 26.2281 +it prints an error message and returns non-zero.
 26.2282 +
 26.2283 +\subsection{glp\_maxflow\_lp---convert maximum flow problem to LP}
 26.2284 +
 26.2285 +\subsubsection*{Synopsis}
 26.2286 +
 26.2287 +\begin{verbatim}
 26.2288 +void glp_maxflow_lp(glp_prob *lp, glp_graph *G, int names,
 26.2289 +      int s, int t, int a_cap);
 26.2290 +\end{verbatim}
 26.2291 +
 26.2292 +\subsubsection*{Description}
 26.2293 +
 26.2294 +The routine \verb|glp_maxflow_lp| builds LP problem (7)---(9), which
 26.2295 +corresponds to the specified maximum flow problem.
 26.2296 +
 26.2297 +The parameter \verb|lp| is the resultant LP problem object to be built.
 26.2298 +Note that on entry its current content is erased with the routine
 26.2299 +\verb|glp_erase_prob|.
 26.2300 +
 26.2301 +The parameter \verb|G| is the graph (network) program object, which
 26.2302 +specifies the maximum flow problem instance.
 26.2303 +
 26.2304 +The parameter \verb|names| is a flag. If it is \verb|GLP_ON|, the
 26.2305 +routine uses symbolic names of the graph object components to assign
 26.2306 +symbolic names to the LP problem object components. If the flag is
 26.2307 +\verb|GLP_OFF|, no symbolic names are assigned.
 26.2308 +
 26.2309 +The parameter \verb|s| specifies the ordinal number of the source node.
 26.2310 +
 26.2311 +The parameter \verb|t| specifies the ordinal number of the sink node.
 26.2312 +
 26.2313 +The parameter \verb|a_cap| specifies an offset of the field of type
 26.2314 +\verb|double| in the arc data block, which contains $u_{ij}$, the upper
 26.2315 +bound to the arc flow (the arc capacity). If the upper bound is
 26.2316 +specified as \verb|DBL_MAX|, it is assumed that $u_{ij}=\infty$, i.e.
 26.2317 +the arc is uncapacitated. If \verb|a_cap| $<0$, it is assumed that
 26.2318 +$u_{ij}=1$ for all arcs.
 26.2319 +
 26.2320 +\subsubsection*{Example}
 26.2321 +
 26.2322 +The example program below reads the maximum flow problem in DIMACS
 26.2323 +format from file `\verb|sample.max|', converts the instance to LP, and
 26.2324 +then writes the resultant LP in CPLEX format to file
 26.2325 +`\verb|maxflow.lp|'.
 26.2326 +
 26.2327 +\begin{footnotesize}
 26.2328 +\begin{verbatim}
 26.2329 +#include <stddef.h>
 26.2330 +#include <glpk.h>
 26.2331 +
 26.2332 +int main(void)
 26.2333 +{     glp_graph *G;
 26.2334 +      glp_prob *lp;
 26.2335 +      int s, t;
 26.2336 +      G = glp_create_graph(0, sizeof(double));
 26.2337 +      glp_read_maxflow(G, &s, &t, 0, "sample.max");
 26.2338 +      lp = glp_create_prob();
 26.2339 +      glp_maxflow_lp(lp, G, GLP_ON, s, t, 0);
 26.2340 +      glp_delete_graph(G);
 26.2341 +      glp_write_lp(lp, NULL, "maxflow.lp");
 26.2342 +      glp_delete_prob(lp);
 26.2343 +      return 0;
 26.2344 +}
 26.2345 +\end{verbatim}
 26.2346 +\end{footnotesize}
 26.2347 +
 26.2348 +If `\verb|sample.max|' is the example data file from the previous
 26.2349 +subsection, the output `\verb|maxflow.lp|' may look like follows:
 26.2350 +
 26.2351 +\begin{footnotesize}
 26.2352 +\begin{verbatim}
 26.2353 +Maximize
 26.2354 + obj: + x(1,4) + x(1,2)
 26.2355 +
 26.2356 +Subject To
 26.2357 + r_1: + x(1,2) + x(1,4) >= 0
 26.2358 + r_2: - x(5,2) + x(2,3) + x(2,4) - x(1,2) = 0
 26.2359 + r_3: + x(3,5) + x(3,8) - x(2,3) = 0
 26.2360 + r_4: + x(4,5) - x(2,4) - x(1,4) = 0
 26.2361 + r_5: + x(5,2) + x(5,6) + x(5,7) - x(4,5) - x(3,5) = 0
 26.2362 + r_6: + x(6,7) + x(6,8) - x(5,6) = 0
 26.2363 + r_7: + x(7,9) - x(6,7) - x(5,7) = 0
 26.2364 + r_8: + x(8,9) - x(6,8) - x(3,8) = 0
 26.2365 + r_9: - x(8,9) - x(7,9) <= 0
 26.2366 +
 26.2367 +Bounds
 26.2368 + 0 <= x(1,4) <= 23
 26.2369 + 0 <= x(1,2) <= 14
 26.2370 + 0 <= x(2,4) <= 9
 26.2371 + 0 <= x(2,3) <= 10
 26.2372 + 0 <= x(3,8) <= 18
 26.2373 + 0 <= x(3,5) <= 12
 26.2374 + 0 <= x(4,5) <= 26
 26.2375 + 0 <= x(5,7) <= 4
 26.2376 + 0 <= x(5,6) <= 25
 26.2377 + 0 <= x(5,2) <= 11
 26.2378 + 0 <= x(6,8) <= 8
 26.2379 + 0 <= x(6,7) <= 7
 26.2380 + 0 <= x(7,9) <= 15
 26.2381 + 0 <= x(8,9) <= 20
 26.2382 +
 26.2383 +End
 26.2384 +\end{verbatim}
 26.2385 +\end{footnotesize}
 26.2386 +
 26.2387 +\subsection{glp\_maxflow\_ffalg---solve maximum flow problem with
 26.2388 +Ford-Fulkerson algorithm}
 26.2389 +
 26.2390 +\subsubsection*{Synopsis}
 26.2391 +
 26.2392 +\begin{verbatim}
 26.2393 +int glp_maxflow_ffalg(glp_graph *G, int s, int t, int a_cap,
 26.2394 +      double *sol, int a_x, int v_cut);
 26.2395 +\end{verbatim}
 26.2396 +
 26.2397 +\subsubsection*{Description}
 26.2398 +
 26.2399 +The routine \verb|glp_mincost_ffalg| finds optimal solution to the
 26.2400 +maximum flow problem with the Ford-Fulkerson algorithm.\footnote{GLPK
 26.2401 +implementation of the Ford-Fulkerson algorithm is based on the following
 26.2402 +book: L.~R.~Ford,~Jr., and D.~R.~Fulkerson, ``Flows in Networks,'' The
 26.2403 +RAND Corp., Report\linebreak R-375-PR (August 1962), Chap. I
 26.2404 +``Static Maximal Flow,'' pp.~30-33.} Note that this routine requires all
 26.2405 +the problem data to be integer-valued.
 26.2406 +
 26.2407 +The parameter \verb|G| is a graph (network) program object which
 26.2408 +specifies the maximum flow problem instance to be solved.
 26.2409 +
 26.2410 +The parameter $s$ specifies the ordinal number of the source node.
 26.2411 +
 26.2412 +The parameter $t$ specifies the ordinal number of the sink node.
 26.2413 +
 26.2414 +The parameter \verb|a_cap| specifies an offset of the field of type
 26.2415 +\verb|double| in the arc data block, which contains $u_{ij}$, the upper
 26.2416 +bound to the arc flow (the arc capacity). This bound must be integer in
 26.2417 +the range [0, \verb|INT_MAX|]. If \verb|a_cap| $<0$, it is assumed that
 26.2418 +$u_{ij}=1$ for all arcs.
 26.2419 +
 26.2420 +The parameter \verb|sol| specifies a location, to which the routine
 26.2421 +stores the objective value (that is, the total flow from $s$ to $t$)
 26.2422 +found. If \verb|sol| is NULL, the objective value is not stored.
 26.2423 +
 26.2424 +The parameter \verb|a_x| specifies an offset of the field of type
 26.2425 +\verb|double| in the arc data block, to which the routine stores
 26.2426 +$x_{ij}$, the arc flow found. If \verb|a_x| $<0$, the arc flow values
 26.2427 +are not stored.
 26.2428 +
 26.2429 +The parameter \verb|v_cut| specifies an offset of the field of type
 26.2430 +\verb|int| in the vertex data block, to which the routine stores node
 26.2431 +flags corresponding to the optimal solution found: if the node flag is
 26.2432 +1, the node is labelled, and if the node flag is 0, the node is
 26.2433 +unlabelled. The calling program may use these node flags to determine
 26.2434 +the {\it minimal cut}, which is a subset of arcs whose one endpoint is
 26.2435 +labelled and other is not. If \verb|v_cut| $<0$, the node flags are not
 26.2436 +stored.
 26.2437 +
 26.2438 +Note that all solution components (the objective value and arc flows)
 26.2439 +computed by the routine are always integer-valued.
 26.2440 +
 26.2441 +\subsubsection*{Returns}
 26.2442 +
 26.2443 +\def\arraystretch{1}
 26.2444 +
 26.2445 +\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
 26.2446 +0 & Optimal solution found.\\
 26.2447 +\verb|GLP_EDATA| & Unable to start the search, because some problem
 26.2448 +data are either not integer-valued or out of range.\\
 26.2449 +\end{tabular}
 26.2450 +
 26.2451 +\subsubsection*{Example}
 26.2452 +
 26.2453 +The example program shown below reads the maximum flow problem instance
 26.2454 +in DIMACS format from file `\verb|sample.max|', solves it using the
 26.2455 +routine \verb|glp_maxflow_ffalg|, and write the solution found to the
 26.2456 +standard output.
 26.2457 +
 26.2458 +\begin{footnotesize}
 26.2459 +\begin{verbatim}
 26.2460 +#include <stddef.h>
 26.2461 +#include <stdio.h>
 26.2462 +#include <stdlib.h>
 26.2463 +#include <glpk.h>
 26.2464 +
 26.2465 +typedef struct { int cut; } v_data;
 26.2466 +typedef struct { double cap, x; } a_data;
 26.2467 +
 26.2468 +#define node(v) ((v_data *)((v)->data))
 26.2469 +#define arc(a)  ((a_data *)((a)->data))
 26.2470 +
 26.2471 +int main(void)
 26.2472 +{     glp_graph *G;
 26.2473 +      glp_vertex *v, *w;
 26.2474 +      glp_arc *a;
 26.2475 +      int i, s, t, ret;
 26.2476 +      double sol;
 26.2477 +      G = glp_create_graph(sizeof(v_data), sizeof(a_data));
 26.2478 +      glp_read_maxflow(G, &s, &t, offsetof(a_data, cap),
 26.2479 +         "sample.max");
 26.2480 +      ret = glp_maxflow_ffalg(G, s, t, offsetof(a_data, cap),
 26.2481 +         &sol, offsetof(a_data, x), offsetof(v_data, cut));
 26.2482 +      printf("ret = %d; sol = %5g\n", ret, sol);
 26.2483 +      for (i = 1; i <= G->nv; i++)
 26.2484 +      {  v = G->v[i];
 26.2485 +         for (a = v->out; a != NULL; a = a->t_next)
 26.2486 +         {  w = a->head;
 26.2487 +            printf("x[%d->%d] = %5g (%d)\n", v->i, w->i,
 26.2488 +               arc(a)->x, node(v)->cut ^ node(w)->cut);
 26.2489 +         }
 26.2490 +      }
 26.2491 +      glp_delete_graph(G);
 26.2492 +      return 0;
 26.2493 +}
 26.2494 +\end{verbatim}
 26.2495 +\end{footnotesize}
 26.2496 +
 26.2497 +If `\verb|sample.max|' is the example data file from the subsection
 26.2498 +describing the routine \verb|glp_read_maxflow|, the output may look like
 26.2499 +follows:
 26.2500 +
 26.2501 +\begin{footnotesize}
 26.2502 +\begin{verbatim}
 26.2503 +Reading maximum flow problem data from `sample.max'...
 26.2504 +Flow network has 9 nodes and 14 arcs
 26.2505 +24 lines were read
 26.2506 +ret = 0; sol =    29
 26.2507 +x[1->4] =    19 (0)
 26.2508 +x[1->2] =    10 (0)
 26.2509 +x[2->4] =     0 (0)
 26.2510 +x[2->3] =    10 (1)
 26.2511 +x[3->8] =    10 (0)
 26.2512 +x[3->5] =     0 (1)
 26.2513 +x[4->5] =    19 (0)
 26.2514 +x[5->7] =     4 (1)
 26.2515 +x[5->6] =    15 (0)
 26.2516 +x[5->2] =     0 (0)
 26.2517 +x[6->8] =     8 (1)
 26.2518 +x[6->7] =     7 (1)
 26.2519 +x[7->9] =    11 (0)
 26.2520 +x[8->9] =    18 (0)
 26.2521 +\end{verbatim}
 26.2522 +\end{footnotesize}
 26.2523 +
 26.2524 +\newpage
 26.2525 +
 26.2526 +\subsection{glp\_rmfgen---Goldfarb's maximum flow problem generator}
 26.2527 +
 26.2528 +\subsubsection*{Synopsis}
 26.2529 +
 26.2530 +\begin{verbatim}
 26.2531 +int glp_rmfgen(glp_graph *G, int *s, int *t, int a_cap,
 26.2532 +      const int parm[1+5]);
 26.2533 +\end{verbatim}
 26.2534 +
 26.2535 +\subsubsection*{Description}
 26.2536 +
 26.2537 +The routine \verb|glp_rmfgen| is a GLPK version of the maximum flow
 26.2538 +problem generator developed by D.~Goldfarb and
 26.2539 +M.~Grigoriadis.\footnote{D.~Goldfarb and M.~D.~Grigoriadis,
 26.2540 +``A computational comparison of the Dinic and network simplex methods
 26.2541 +for maximum flow.'' Annals of Op. Res. 13 (1988),
 26.2542 +pp.~83-123.}$^{,}$\footnote{U.~Derigs and W.~Meier, ``Implementing
 26.2543 +Goldberg's max-flow algorithm: A computational investigation.''
 26.2544 +Zeitschrift f\"ur Operations Research 33 (1989),
 26.2545 +pp.~383-403.}$^{,}$\footnote{The original code of RMFGEN implemented by
 26.2546 +Tamas Badics is publically available from
 26.2547 +{\tt <ftp://dimacs.rutgers.edu/pub/netflow/generators/network/genrmf>}.}
 26.2548 +
 26.2549 +The parameter \verb|G| specifies the graph object, to which the
 26.2550 +generated problem data have to be stored. Note that on entry the graph
 26.2551 +object is erased with the routine \verb|glp_erase_graph|.
 26.2552 +
 26.2553 +The pointers \verb|s| and \verb|t| specify locations, to which the
 26.2554 +routine stores the source and sink node numbers, respectively. If
 26.2555 +\verb|s| or \verb|t| is \verb|NULL|, corresponding node number is not
 26.2556 +stored.
 26.2557 +
 26.2558 +The parameter \verb|a_cap| specifies an offset of the field of type
 26.2559 +\verb|double| in the arc data block, to which the routine stores the arc
 26.2560 +capacity. If \verb|a_cap| $<0$, the capacity is not stored.
 26.2561 +
 26.2562 +The array \verb|parm| contains description of the network to be
 26.2563 +generated:
 26.2564 +
 26.2565 +\begin{tabular}{@{}lll@{}}
 26.2566 +\verb|parm[0]|&           &not used\\
 26.2567 +\verb|parm[1]|&\verb|seed|&random number seed (a positive integer)\\
 26.2568 +\verb|parm[2]|&\verb|a   |&frame size\\
 26.2569 +\verb|parm[3]|&\verb|b   |&depth\\
 26.2570 +\verb|parm[4]|&\verb|c1  |&minimal arc capacity\\
 26.2571 +\verb|parm[5]|&\verb|c2  |&maximal arc capacity\\
 26.2572 +\end{tabular}
 26.2573 +
 26.2574 +\subsubsection*{Returns}
 26.2575 +
 26.2576 +If the instance was successfully generated, the routine
 26.2577 +\verb|glp_netgen| returns zero; otherwise, if specified parameters are
 26.2578 +inconsistent, the routine returns a non-zero error code.
 26.2579 +
 26.2580 +\newpage
 26.2581 +
 26.2582 +\subsubsection*{Comments\footnote{This material is based on comments
 26.2583 +to the original version of RMFGEN.}}
 26.2584 +
 26.2585 +The generated network is as follows. It has $b$ pieces of frames of
 26.2586 +size $a\times a$. (So alltogether the number of vertices is
 26.2587 +$a\times a\times b$.)
 26.2588 +
 26.2589 +In each frame all the vertices are connected with their neighbours
 26.2590 +(forth and back). In addition the vertices of a frame are connected
 26.2591 +one to one with the vertices of next frame using a random permutation
 26.2592 +of those vertices.
 26.2593 +
 26.2594 +The source is the lower left vertex of the first frame, the sink is
 26.2595 +the upper right vertex of the $b$-th frame.
 26.2596 +
 26.2597 +\begin{verbatim}
 26.2598 +                              t
 26.2599 +                     +-------+
 26.2600 +                     |      .|
 26.2601 +                     |     . |
 26.2602 +                  /  |    /  |
 26.2603 +                 +-------+/ -+ b
 26.2604 +                 |    |  |/.
 26.2605 +               a |   -v- |/
 26.2606 +                 |    |  |/
 26.2607 +                 +-------+ 1
 26.2608 +                s    a
 26.2609 +\end{verbatim}
 26.2610 +
 26.2611 +The capacities are randomly chosen integers from the range of
 26.2612 +$[c_1,c_2]$  in the case of interconnecting edges, and $c_2\cdot a^2$
 26.2613 +for the in-frame edges.
 26.2614 +
 26.2615 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 26.2616 +
 26.2617 +\newpage
 26.2618 +
 26.2619 +\section{Assignment problem}
 26.2620 +
 26.2621 +\subsection{Background}
 26.2622 +
 26.2623 +Let there be given an undirected bipartite graph $G=(R\cup S,E)$, where
 26.2624 +$R$ and $S$ are disjoint sets of vertices (nodes), and
 26.2625 +$E\subseteq R\times S$ is a set of edges. Let also for each edge
 26.2626 +$e=(i,j)\in E$ there be given its cost $c_{ij}$. A {\it matching}
 26.2627 +(which in case of bipartite graph is also called {\it assignment})
 26.2628 +$M\subseteq E$ in $G$ is a set of pairwise non-adjacent edges, that is,
 26.2629 +no two edges in $M$ share a common vertex. A matching, which matches
 26.2630 +all vertices of the graph, is called a {\it perfect matching}.
 26.2631 +Obviously, a perfect matching in bipartite graph $G=(R\cup S,E)$
 26.2632 +defines some bijection $R\leftrightarrow S$.
 26.2633 +
 26.2634 +The {\it assignment problem} has two different variants. In the first
 26.2635 +variant the problem is to find matching (assignment) $M$, which
 26.2636 +maximizes the sum:
 26.2637 +$$\sum_{(i,j)\in M}c_{ij}\eqno(10)$$
 26.2638 +(so this variant is also called the {\it maximum weighted bipartite
 26.2639 +matching problem} or, if all $c_{ij}=1$, the {\it maximum cardinality
 26.2640 +bipartite matching problem}). In the second, classic variant the
 26.2641 +problem is to find {\it perfect} matching (assignment) $M$, which
 26.2642 +minimizes or maximizes the sum (10).
 26.2643 +
 26.2644 +An example of the assignment problem, which is the maximum weighted
 26.2645 +bipartite matching problem, is shown on Fig. 3.
 26.2646 +
 26.2647 +The maximum weighted bipartite matching problem can be naturally
 26.2648 +formulated as the following LP problem:
 26.2649 +
 26.2650 +\medskip
 26.2651 +
 26.2652 +\noindent
 26.2653 +\hspace{.5in}maximize
 26.2654 +$$z=\sum_{(i,j)\in E}c_{ij}x_{ij}\eqno(11)$$
 26.2655 +\hspace{.5in}subject to
 26.2656 +$$\sum_{(i,j)\in E}x_{ij}\leq 1\ \ \ \hbox{for all}\ i\in R\eqno(12)$$
 26.2657 +$$\sum_{(i,j)\in E}x_{ij}\leq 1\ \ \ \hbox{for all}\ j\in S\eqno(13)$$
 26.2658 +$$\ \ \ \ \ \ \ \ 0\leq x_{ij}\leq 1\ \ \ \hbox{for all}\ (i,j)\in E
 26.2659 +\eqno(14)$$
 26.2660 +
 26.2661 +\medskip
 26.2662 +
 26.2663 +\noindent
 26.2664 +where $x_{ij}=1$ means that $(i,j)\in M$, and $x_{ij}=0$ means that
 26.2665 +$(i,j)\notin M$.\footnote{The constraint matrix of LP formulation
 26.2666 +(11)---(14) is totally unimodular, due to which $x_{ij}\in\{0,1\}$ for
 26.2667 +any basic solution.}
 26.2668 +
 26.2669 +\newpage
 26.2670 +
 26.2671 +\bigskip
 26.2672 +
 26.2673 +\noindent\hfil
 26.2674 +\xymatrix @C=48pt
 26.2675 +{v_1\ar@{-}[rr]|{_{13}}\ar@{-}[rrd]|{_{21}}\ar@{-}[rrddd]|(.2){_{20}}&&
 26.2676 +v_9\\
 26.2677 +v_2\ar@{-}[rr]|{_{12}}\ar@{-}[rrdd]|(.3){_{8}}
 26.2678 +\ar@{-}[rrddd]|(.4){_{26}}&&v_{10}\\
 26.2679 +v_3\ar@{-}[rr]|(.2){_{22}}\ar@{-}[rrdd]|(.3){_{11}}&&v_{11}\\
 26.2680 +v_4\ar@{-}[rruuu]|(.6){_{12}}\ar@{-}[rr]|(.2){_{36}}
 26.2681 +\ar@{-}[rrdd]|(.7){_{25}}&&v_{12}\\
 26.2682 +v_5\ar@{-}[rruu]|(.42){_{41}}\ar@{-}[rru]|(.4){_{40}}
 26.2683 +\ar@{-}[rr]|(.75){_{11}}\ar@{-}[rrd]|(.6){_{4}}\ar@{-}[rrdd]|{_{8}}
 26.2684 +\ar@{-}[rrddd]|{_{35}}\ar@{-}[rrdddd]|{_{32}}&&v_{13}\\
 26.2685 +v_6\ar@{-}[rruuuuu]|(.7){_{13}}&&v_{14}\\
 26.2686 +v_7\ar@{-}[rruuuuu]|(.15){_{19}}&&v_{15}\\
 26.2687 +v_8\ar@{-}[rruuuuuu]|(.25){_{39}}\ar@{-}[rruuuuu]|(.65){_{15}}&&
 26.2688 +v_{16}\\
 26.2689 +&&v_{17}\\
 26.2690 +}
 26.2691 +
 26.2692 +\bigskip
 26.2693 +
 26.2694 +\noindent\hfil
 26.2695 +Fig.~3. An example of the assignment problem.
 26.2696 +
 26.2697 +\bigskip
 26.2698 +
 26.2699 +Similarly, the perfect assignment problem can be naturally formulated
 26.2700 +as the following LP problem:
 26.2701 +
 26.2702 +\medskip
 26.2703 +
 26.2704 +\noindent
 26.2705 +\hspace{.5in}minimize (or maximize)
 26.2706 +$$z=\sum_{(i,j)\in E}c_{ij}x_{ij}\eqno(15)$$
 26.2707 +\hspace{.5in}subject to
 26.2708 +$$\sum_{(i,j)\in E}x_{ij}=1\ \ \ \hbox{for all}\ i\in R\eqno(16)$$
 26.2709 +$$\sum_{(i,j)\in E}x_{ij}=1\ \ \ \hbox{for all}\ j\in S\eqno(17)$$
 26.2710 +$$\ \ \ \ \ \ \ \ 0\leq x_{ij}\leq 1\ \ \ \hbox{for all}\ (i,j)\in E
 26.2711 +\eqno(18)$$
 26.2712 +
 26.2713 +\medskip
 26.2714 +
 26.2715 +\noindent
 26.2716 +where variables $x_{ij}$ have the same meaning as for (11)---(14)
 26.2717 +above.
 26.2718 +
 26.2719 +\newpage
 26.2720 +
 26.2721 +In GLPK an undirected bipartite graph $G=(R\cup S,E)$ is represented as
 26.2722 +directed graph $\overline{G}=(V,A)$, where $V=R\cup S$ and
 26.2723 +$A=\{(i,j):(i,j)\in E\}$, i.e. every edge $(i,j)\in E$ in $G$
 26.2724 +corresponds to arc $(i\rightarrow j)\in A$ in $\overline{G}$.
 26.2725 +
 26.2726 +\subsection{glp\_read\_asnprob---read assignment problem data in\\DIMACS
 26.2727 +format}
 26.2728 +
 26.2729 +\subsubsection*{Synopsis}
 26.2730 +
 26.2731 +\begin{verbatim}
 26.2732 +int glp_read_asnprob(glp_graph *G, int v_set, int a_cost,
 26.2733 +      const char *fname);
 26.2734 +\end{verbatim}
 26.2735 +
 26.2736 +\subsubsection*{Description}
 26.2737 +
 26.2738 +The routine \verb|glp_read_asnprob| reads the assignment problem data
 26.2739 +from a text file in DIMACS format.
 26.2740 +
 26.2741 +The parameter \verb|G| specifies the graph object, to which the problem
 26.2742 +data have to be stored. Note that before reading data the current
 26.2743 +content of the graph object is completely erased with the routine
 26.2744 +\verb|glp_erase_graph|.
 26.2745 +
 26.2746 +The parameter \verb|v_set| specifies an offset of the field of type
 26.2747 +\verb|int| in the vertex data block, to which the routine stores the
 26.2748 +node set indicator:
 26.2749 +
 26.2750 +0 --- the node is in set $R$;
 26.2751 +
 26.2752 +1 --- the node is in set $S$.
 26.2753 +
 26.2754 +\noindent
 26.2755 +If \verb|v_set| $<0$, the node set indicator is not stored.
 26.2756 +
 26.2757 +The parameter \verb|a_cost| specifies an offset of the field of type
 26.2758 +\verb|double| in the arc data block, to which the routine stores the
 26.2759 +edge cost $c_{ij}$. If \verb|a_cost| $<0$, the edge cost is not stored.
 26.2760 +
 26.2761 +The character string \verb|fname| specifies the name of a text file to
 26.2762 +be read in. (If the file name name ends with the suffix `\verb|.gz|',
 26.2763 +the file is assumed to be compressed, in which case the routine
 26.2764 +decompresses it ``on the fly''.)
 26.2765 +
 26.2766 +\subsubsection*{Returns}
 26.2767 +
 26.2768 +If the operation was successful, the routine returns zero. Otherwise,
 26.2769 +it prints an error message and returns non-zero.
 26.2770 +
 26.2771 +\newpage
 26.2772 +
 26.2773 +\subsubsection*{Example}
 26.2774 +
 26.2775 +\begin{footnotesize}
 26.2776 +\begin{verbatim}
 26.2777 +typedef struct
 26.2778 +{     /* vertex data block */
 26.2779 +      ...
 26.2780 +      int set;
 26.2781 +      ...
 26.2782 +} v_data;
 26.2783 +
 26.2784 +typedef struct
 26.2785 +{     /* arc data block */
 26.2786 +      ...
 26.2787 +      double cost;
 26.2788 +      ...
 26.2789 +} a_data;
 26.2790 +
 26.2791 +int main(void)
 26.2792 +{     glp_graph *G;
 26.2793 +      int ret;
 26.2794 +      G = glp_create_graph(sizeof(v_data), sizeof(a_data));
 26.2795 +      ret = glp_read_asnprob(G, offsetof(v_data, set),
 26.2796 +         offsetof(a_data, cost), "sample.asn");
 26.2797 +      if (ret != 0) goto ...
 26.2798 +      ...
 26.2799 +}
 26.2800 +\end{verbatim}
 26.2801 +\end{footnotesize}
 26.2802 +
 26.2803 +\subsubsection*{DIMACS assignment problem format\footnote{This
 26.2804 +material is based on the paper ``The First DIMACS International
 26.2805 +Algorithm Implementation Challenge: Problem Definitions and
 26.2806 +Specifications'', which is publically available at
 26.2807 +{\tt http://dimacs.rutgers.edu/Challenges/}.}}
 26.2808 +\label{subsecasnprob}
 26.2809 +
 26.2810 +The DIMACS input file is a plain ASCII text file. It contains
 26.2811 +{\it lines} of several types described below. A line is terminated with
 26.2812 +an end-of-line character. Fields in each line are separated by at least
 26.2813 +one blank space. Each line begins with a one-character designator to
 26.2814 +identify the line type.
 26.2815 +
 26.2816 +Note that DIMACS requires all numerical quantities to be integers in
 26.2817 +the range $[-2^{31},\ 2^{31}-1]$ while GLPK allows the quantities to be
 26.2818 +floating-point numbers.
 26.2819 +
 26.2820 +\paragraph{Comment lines.} Comment lines give human-readable information
 26.2821 +about the file and are ignored by programs. Comment lines can appear
 26.2822 +anywhere in the file. Each comment line begins with a lower-case
 26.2823 +character \verb|c|.
 26.2824 +
 26.2825 +\begin{verbatim}
 26.2826 +   c This is a comment line
 26.2827 +\end{verbatim}
 26.2828 +
 26.2829 +\newpage
 26.2830 +
 26.2831 +\paragraph{Problem line.} There is one problem line per data file. The
 26.2832 +problem line must appear before any node or arc descriptor lines. It has
 26.2833 +the following format:
 26.2834 +
 26.2835 +\begin{verbatim}
 26.2836 +   p asn NODES EDGES
 26.2837 +\end{verbatim}
 26.2838 +
 26.2839 +\noindent
 26.2840 +The lower-case character \verb|p| signifies that this is a problem line.
 26.2841 +The three-character problem designator \verb|asn| identifies the file as
 26.2842 +containing specification information for the assignment problem.
 26.2843 +The \verb|NODES| field contains an integer value specifying the total
 26.2844 +number of nodes in the graph (i.e. in both sets $R$ and $S$). The
 26.2845 +\verb|EDGES| field contains an integer value specifying the number of
 26.2846 +edges in the graph.
 26.2847 +
 26.2848 +\paragraph{Node descriptors.} All node descriptor lines must appear
 26.2849 +before all edge descriptor lines. The node descriptor lines lists the
 26.2850 +nodes in set $R$ only, and all other nodes are assumed to be in set
 26.2851 +$S$. There is one node descriptor line for each such node, with the
 26.2852 +following format:
 26.2853 +
 26.2854 +\begin{verbatim}
 26.2855 +   n ID
 26.2856 +\end{verbatim}
 26.2857 +
 26.2858 +\noindent
 26.2859 +The lower-case character \verb|n| signifies that this is a node
 26.2860 +descriptor line. The \verb|ID| field gives a node identification number,
 26.2861 +an integer between 1 and \verb|NODES|.
 26.2862 +
 26.2863 +\paragraph{Edge descriptors.} There is one edge descriptor line for
 26.2864 +each edge in the graph. Edge descriptor lines are of the following
 26.2865 +format:
 26.2866 +
 26.2867 +\begin{verbatim}
 26.2868 +   a SRC DST COST
 26.2869 +\end{verbatim}
 26.2870 +
 26.2871 +\noindent
 26.2872 +The lower-case character \verb|a| signifies that this is an edge
 26.2873 +descriptor line. For each edge $(i,j)$, where $i\in R$ and $j\in S$,
 26.2874 +the \verb|SRC| field gives the identification number of vertex $i$, and
 26.2875 +the \verb|DST| field gives the identification number of vertex $j$.
 26.2876 +Identification numbers are integers between 1 and \verb|NODES|. The
 26.2877 +\verb|COST| field contains the cost of edge $(i,j)$.
 26.2878 +
 26.2879 +\paragraph{Example.} Below here is an example of the data file in
 26.2880 +DIMACS format corresponding to the assignment problem shown on Fig~3.
 26.2881 +
 26.2882 +\newpage
 26.2883 +
 26.2884 +\begin{footnotesize}
 26.2885 +\begin{verbatim}
 26.2886 +c sample.asn
 26.2887 +c
 26.2888 +c This is an example of the assignment problem data
 26.2889 +c in DIMACS format.
 26.2890 +c
 26.2891 +p asn 17 22
 26.2892 +c
 26.2893 +n 1
 26.2894 +n 2
 26.2895 +n 3
 26.2896 +n 4
 26.2897 +n 5
 26.2898 +n 6
 26.2899 +n 7
 26.2900 +n 8
 26.2901 +c
 26.2902 +a 1  9 13
 26.2903 +a 1 10 21
 26.2904 +a 1 12 20
 26.2905 +a 2 10 12
 26.2906 +a 2 12  8
 26.2907 +a 2 13 26
 26.2908 +a 3 11 22
 26.2909 +a 3 13 11
 26.2910 +a 4  9 12
 26.2911 +a 4 12 36
 26.2912 +a 4 14 25
 26.2913 +a 5 11 41
 26.2914 +a 5 12 40
 26.2915 +a 5 13 11
 26.2916 +a 5 14  4
 26.2917 +a 5 15  8
 26.2918 +a 5 16 35
 26.2919 +a 5 17 32
 26.2920 +a 6  9 13
 26.2921 +a 7 10 19
 26.2922 +a 8 10 39
 26.2923 +a 8 11 15
 26.2924 +c
 26.2925 +c eof
 26.2926 +\end{verbatim}
 26.2927 +\end{footnotesize}
 26.2928 +
 26.2929 +\newpage
 26.2930 +
 26.2931 +\subsection{glp\_write\_asnprob---write assignment problem data in\\
 26.2932 +DIMACS format}
 26.2933 +
 26.2934 +\subsubsection*{Synopsis}
 26.2935 +
 26.2936 +\begin{verbatim}
 26.2937 +int glp_write_asnprob(glp_graph *G, int v_set, int a_cost,
 26.2938 +      const char *fname);
 26.2939 +\end{verbatim}
 26.2940 +
 26.2941 +\subsubsection*{Description}
 26.2942 +
 26.2943 +The routine \verb|glp_write_asnprob| writes the assignment problem data
 26.2944 +to a text file in DIMACS format.
 26.2945 +
 26.2946 +The parameter \verb|G| is the graph program object, which specifies the
 26.2947 +assignment problem instance.
 26.2948 +
 26.2949 +The parameter \verb|v_set| specifies an offset of the field of type
 26.2950 +\verb|int| in the vertex data block, which contains the node set
 26.2951 +indicator:
 26.2952 +
 26.2953 +0 --- the node is in set $R$;
 26.2954 +
 26.2955 +1 --- the node is in set $S$.
 26.2956 +
 26.2957 +\noindent
 26.2958 +If \verb|v_set| $<0$, it is assumed that a node having no incoming arcs
 26.2959 +is in set $R$, and a node having no outgoing arcs is in set $S$.
 26.2960 +
 26.2961 +The parameter \verb|a_cost| specifies an offset of the field of type
 26.2962 +\verb|double| in the arc data block, which contains $c_{ij}$, the edge
 26.2963 +cost. If \verb|a_cost| $<0$, it is assumed that $c_{ij}=1$ for all
 26.2964 +edges.
 26.2965 +
 26.2966 +The character string \verb|fname| specifies a name of the text file to
 26.2967 +be written out. (If the file name ends with suffix `\verb|.gz|', the
 26.2968 +file is assumed to be compressed, in which case the routine performs
 26.2969 +automatic compression on writing it.)
 26.2970 +
 26.2971 +\subsubsection*{Note}
 26.2972 +
 26.2973 +The routine \verb|glp_write_asnprob| does not check that the specified
 26.2974 +graph object correctly represents a bipartite graph. To make sure that
 26.2975 +the problem data are correct, use the routine \verb|glp_check_asnprob|.
 26.2976 +
 26.2977 +\subsubsection*{Returns}
 26.2978 +
 26.2979 +If the operation was successful, the routine returns zero. Otherwise,
 26.2980 +it prints an error message and returns non-zero.
 26.2981 +
 26.2982 +\newpage
 26.2983 +
 26.2984 +\subsection{glp\_check\_asnprob---check correctness of assignment
 26.2985 +problem data}
 26.2986 +
 26.2987 +\subsubsection*{Synopsis}
 26.2988 +
 26.2989 +\begin{verbatim}
 26.2990 +int glp_check_asnprob(glp_graph *G, int v_set);
 26.2991 +\end{verbatim}
 26.2992 +
 26.2993 +\subsubsection*{Description}
 26.2994 +
 26.2995 +The routine \verb|glp_check_asnprob| checks that the specified graph
 26.2996 +object \verb|G| correctly represents a bipartite graph.
 26.2997 +
 26.2998 +The parameter \verb|v_set| specifies an offset of the field of type
 26.2999 +\verb|int| in the vertex data block, which contains the node set
 26.3000 +indicator:
 26.3001 +
 26.3002 +0 --- the node is in set $R$;
 26.3003 +
 26.3004 +1 --- the node is in set $S$.
 26.3005 +
 26.3006 +\noindent
 26.3007 +If \verb|v_set| $<0$, it is assumed that a node having no incoming arcs
 26.3008 +is in set $R$, and a node having no outgoing arcs is in set $S$.
 26.3009 +
 26.3010 +\subsubsection*{Returns}
 26.3011 +
 26.3012 +The routine \verb|glp_check_asnprob| may return the following codes:
 26.3013 +
 26.3014 +0 --- the data are correct;
 26.3015 +
 26.3016 +1 --- the set indicator of some node is 0, however, that node has one
 26.3017 +or more incoming arcs;
 26.3018 +
 26.3019 +2 --- the set indicator of some node is 1, however, that node has one
 26.3020 +or more outgoing arcs;
 26.3021 +
 26.3022 +3 --- the set indicator of some node is invalid (neither 0 nor 1);
 26.3023 +
 26.3024 +4 --- some node has both incoming and outgoing arcs.
 26.3025 +
 26.3026 +\subsection{glp\_asnprob\_lp---convert assignment problem to LP}
 26.3027 +
 26.3028 +\subsubsection*{Synopsis}
 26.3029 +
 26.3030 +\begin{verbatim}
 26.3031 +int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G,
 26.3032 +      int names, int v_set, int a_cost);
 26.3033 +\end{verbatim}
 26.3034 +
 26.3035 +\subsubsection*{Description}
 26.3036 +
 26.3037 +The routine \verb|glp_asnprob_lp| builds LP problem, which corresponds
 26.3038 +to the specified assignment problem.
 26.3039 +
 26.3040 +The parameter \verb|lp| is the resultant LP problem object to be built.
 26.3041 +Note that on entry its current content is erased with the routine
 26.3042 +\verb|glp_erase_prob|.
 26.3043 +
 26.3044 +The parameter \verb|form| defines which LP formulation should be used:
 26.3045 +
 26.3046 +\verb|GLP_ASN_MIN| --- perfect matching (15)---(18), minimization;
 26.3047 +
 26.3048 +\verb|GLP_ASN_MAX| --- perfect matching (15)---(18), maximization;
 26.3049 +
 26.3050 +\verb|GLP_ASN_MMP| --- maximum weighted matching (11)---(14).
 26.3051 +
 26.3052 +The parameter \verb|G| is the graph program object, which specifies the
 26.3053 +assignment problem instance.
 26.3054 +
 26.3055 +The parameter \verb|names| is a flag. If it is \verb|GLP_ON|, the
 26.3056 +routine uses symbolic names of the graph object components to assign
 26.3057 +symbolic names to the LP problem object components. If the \verb|flag|
 26.3058 +is \verb|GLP_OFF|, no symbolic names are assigned.
 26.3059 +
 26.3060 +The parameter \verb|v_set| specifies an offset of the field of type
 26.3061 +\verb|int| in the vertex data block, which contains the node set
 26.3062 +indicator:
 26.3063 +
 26.3064 +0 --- the node is in set $R$;
 26.3065 +
 26.3066 +1 --- the node is in set $S$.
 26.3067 +
 26.3068 +\noindent
 26.3069 +If \verb|v_set| $<0$, it is assumed that a node having no incoming arcs
 26.3070 +is in set $R$, and a node having no outgoing arcs is in set $S$.
 26.3071 +
 26.3072 +The parameter \verb|a_cost| specifies an offset of the field of type
 26.3073 +\verb|double| in the arc data block, which contains $c_{ij}$, the edge
 26.3074 +cost. If \verb|a_cost| $<0$, it is assumed that $c_{ij}=1$ for all
 26.3075 +edges.
 26.3076 +
 26.3077 +\subsubsection*{Returns}
 26.3078 +
 26.3079 +If the LP problem has been successfully built, the routine
 26.3080 +\verb|glp_asnprob_lp| returns zero, otherwise, non-zero (see the
 26.3081 +routine \verb|glp_check_asnprob|).
 26.3082 +
 26.3083 +\subsubsection*{Example}
 26.3084 +
 26.3085 +The example program below reads the assignment problem instance in
 26.3086 +DIMACS format from file `\verb|sample.asn|', converts the instance to
 26.3087 +LP (11)---(14), and writes the resultant LP in CPLEX format to file
 26.3088 +`\verb|matching.lp|'.
 26.3089 +
 26.3090 +\begin{footnotesize}
 26.3091 +\begin{verbatim}
 26.3092 +#include <stddef.h>
 26.3093 +#include <glpk.h>
 26.3094 +
 26.3095 +typedef struct { int set; } v_data;
 26.3096 +typedef struct { double cost; } a_data;
 26.3097 +
 26.3098 +int main(void)
 26.3099 +{     glp_graph *G;
 26.3100 +      glp_prob *P;
 26.3101 +      G = glp_create_graph(sizeof(v_data), sizeof(a_data));
 26.3102 +      glp_read_asnprob(G, offsetof(v_data, set),
 26.3103 +         offsetof(a_data, cost), "sample.asn");
 26.3104 +      P = glp_create_prob();
 26.3105 +      glp_asnprob_lp(P, GLP_ASN_MMP, G, GLP_ON,
 26.3106 +         offsetof(v_data, set), offsetof(a_data, cost));
 26.3107 +      glp_delete_graph(G);
 26.3108 +      glp_write_lp(P, NULL, "matching.lp");
 26.3109 +      glp_delete_prob(P);
 26.3110 +      return 0;
 26.3111 +}
 26.3112 +\end{verbatim}
 26.3113 +\end{footnotesize}
 26.3114 +
 26.3115 +If `\verb|sample.asn|' is the example data file from the subsection
 26.3116 +describing the routine \verb|glp_read_asnprob|, file
 26.3117 +`\verb|matching.lp|' may look like follows:
 26.3118 +
 26.3119 +\begin{footnotesize}
 26.3120 +\begin{verbatim}
 26.3121 +Maximize
 26.3122 + obj: + 20 x(1,12) + 21 x(1,10) + 13 x(1,9) + 26 x(2,13) + 8 x(2,12)
 26.3123 + + 12 x(2,10) + 11 x(3,13) + 22 x(3,11) + 25 x(4,14) + 36 x(4,12)
 26.3124 + + 12 x(4,9) + 32 x(5,17) + 35 x(5,16) + 8 x(5,15) + 4 x(5,14)
 26.3125 + + 11 x(5,13) + 40 x(5,12) + 41 x(5,11) + 13 x(6,9) + 19 x(7,10)
 26.3126 + + 15 x(8,11) + 39 x(8,10)
 26.3127 +
 26.3128 +Subject To
 26.3129 + r_1: + x(1,9) + x(1,10) + x(1,12) <= 1
 26.3130 + r_2: + x(2,10) + x(2,12) + x(2,13) <= 1
 26.3131 + r_3: + x(3,11) + x(3,13) <= 1
 26.3132 + r_4: + x(4,9) + x(4,12) + x(4,14) <= 1
 26.3133 + r_5: + x(5,11) + x(5,12) + x(5,13) + x(5,14) + x(5,15) + x(5,16)
 26.3134 + + x(5,17) <= 1
 26.3135 + r_6: + x(6,9) <= 1
 26.3136 + r_7: + x(7,10) <= 1
 26.3137 + r_8: + x(8,10) + x(8,11) <= 1
 26.3138 + r_9: + x(6,9) + x(4,9) + x(1,9) <= 1
 26.3139 + r_10: + x(8,10) + x(7,10) + x(2,10) + x(1,10) <= 1
 26.3140 + r_11: + x(8,11) + x(5,11) + x(3,11) <= 1
 26.3141 + r_12: + x(5,12) + x(4,12) + x(2,12) + x(1,12) <= 1
 26.3142 + r_13: + x(5,13) + x(3,13) + x(2,13) <= 1
 26.3143 + r_14: + x(5,14) + x(4,14) <= 1
 26.3144 + r_15: + x(5,15) <= 1
 26.3145 + r_16: + x(5,16) <= 1
 26.3146 + r_17: + x(5,17) <= 1
 26.3147 +
 26.3148 +Bounds
 26.3149 + 0 <= x(1,12) <= 1
 26.3150 + 0 <= x(1,10) <= 1
 26.3151 + 0 <= x(1,9) <= 1
 26.3152 + 0 <= x(2,13) <= 1
 26.3153 + 0 <= x(2,12) <= 1
 26.3154 + 0 <= x(2,10) <= 1
 26.3155 + 0 <= x(3,13) <= 1
 26.3156 + 0 <= x(3,11) <= 1
 26.3157 + 0 <= x(4,14) <= 1
 26.3158 + 0 <= x(4,12) <= 1
 26.3159 + 0 <= x(4,9) <= 1
 26.3160 + 0 <= x(5,17) <= 1
 26.3161 + 0 <= x(5,16) <= 1
 26.3162 + 0 <= x(5,15) <= 1
 26.3163 + 0 <= x(5,14) <= 1
 26.3164 + 0 <= x(5,13) <= 1
 26.3165 + 0 <= x(5,12) <= 1
 26.3166 + 0 <= x(5,11) <= 1
 26.3167 + 0 <= x(6,9) <= 1
 26.3168 + 0 <= x(7,10) <= 1
 26.3169 + 0 <= x(8,11) <= 1
 26.3170 + 0 <= x(8,10) <= 1
 26.3171 +
 26.3172 +End
 26.3173 +\end{verbatim}
 26.3174 +\end{footnotesize}
 26.3175 +
 26.3176 +\subsection{glp\_asnprob\_okalg---solve assignment problem with
 26.3177 +out-of-kilter algorithm}
 26.3178 +
 26.3179 +\subsubsection*{Synopsis}
 26.3180 +
 26.3181 +\begin{verbatim}
 26.3182 +int glp_asnprob_okalg(int form, glp_graph *G, int v_set,
 26.3183 +      int a_cost, double *sol, int a_x);
 26.3184 +\end{verbatim}
 26.3185 +
 26.3186 +\subsubsection*{Description}
 26.3187 +
 26.3188 +The routine \verb|glp_mincost_okalg| finds optimal solution to the
 26.3189 +assignment problem with the out-of-kilter
 26.3190 +algorithm.\footnote{GLPK implementation of the out-of-kilter algorithm
 26.3191 +is based on the following book: L.~R.~Ford,~Jr., and D.~R.~Fulkerson,
 26.3192 +``Flows in Networks,'' The RAND Corp., Report R-375-PR (August 1962),
 26.3193 +Chap. III ``Minimal Cost Flow Problems,'' pp.~113-26.} Note that this
 26.3194 +routine requires all the problem data to be integer-valued.
 26.3195 +
 26.3196 +The parameter \verb|form| defines which LP formulation should be used:
 26.3197 +
 26.3198 +\verb|GLP_ASN_MIN| --- perfect matching (15)---(18), minimization;
 26.3199 +
 26.3200 +\verb|GLP_ASN_MAX| --- perfect matching (15)---(18), maximization;
 26.3201 +
 26.3202 +\verb|GLP_ASN_MMP| --- maximum weighted matching (11)---(14).
 26.3203 +
 26.3204 +The parameter \verb|G| is the graph program object, which specifies the
 26.3205 +assignment problem instance.
 26.3206 +
 26.3207 +The parameter \verb|v_set| specifies an offset of the field of type
 26.3208 +\verb|int| in the vertex data block, which contains the node set
 26.3209 +indicator:
 26.3210 +
 26.3211 +0 --- the node is in set $R$;
 26.3212 +
 26.3213 +1 --- the node is in set $S$.
 26.3214 +
 26.3215 +\newpage
 26.3216 +
 26.3217 +\noindent
 26.3218 +If \verb|v_set| $<0$, it is assumed that a node having no incoming arcs
 26.3219 +is in set $R$, and a node having no outgoing arcs is in set $S$.
 26.3220 +
 26.3221 +The parameter \verb|a_cost| specifies an offset of the field of type
 26.3222 +\verb|double| in the arc data block, which contains $c_{ij}$, the edge
 26.3223 +cost. This value must be integer in the range [\verb|-INT_MAX|,
 26.3224 +\verb|+INT_MAX|]. If \verb|a_cost| $<0$, it is assumed that $c_{ij}=1$
 26.3225 +for all edges.
 26.3226 +
 26.3227 +The parameter \verb|sol| specifies a location, to which the routine
 26.3228 +stores the objective value (that is, the total cost) found.
 26.3229 +If \verb|sol| is \verb|NULL|, the objective value is not stored.
 26.3230 +
 26.3231 +The parameter \verb|a_x| specifies an offset of the field of type
 26.3232 +\verb|int| in the arc data block, to which the routine stores $x_{ij}$.
 26.3233 +If \verb|a_x| $<0$, this value is not stored.
 26.3234 +
 26.3235 +\subsubsection*{Returns}
 26.3236 +
 26.3237 +\def\arraystretch{1}
 26.3238 +
 26.3239 +\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
 26.3240 +0 & Optimal solution found.\\
 26.3241 +\verb|GLP_ENOPFS| & No (primal) feasible solution exists.\\
 26.3242 +\verb|GLP_EDATA| & Unable to start the search, because the assignment
 26.3243 +problem data are either incorrect (this error is detected by the
 26.3244 +routine \verb|glp_check_asnprob|), not integer-valued or out of range.\\
 26.3245 +\verb|GLP_ERANGE| & The search was prematurely terminated because of
 26.3246 +integer overflow.\\
 26.3247 +\verb|GLP_EFAIL| & An error has been detected in the program logic.
 26.3248 +(If this code is returned for your problem instance, please report to
 26.3249 +\verb|<bug-glpk@gnu.org>|.)\\
 26.3250 +\end{tabular}
 26.3251 +
 26.3252 +\subsubsection*{Comments}
 26.3253 +
 26.3254 +Since the out-of-kilter algorithm is designed to find a minimal cost
 26.3255 +circulation, the routine \verb|glp_asnprob_okalg| converts the original
 26.3256 +graph to a network suitable for this algorithm in the following
 26.3257 +way:\footnote{The conversion is performed internally and does not change
 26.3258 +the original graph program object passed to the routine.}
 26.3259 +
 26.3260 +1) it replaces each edge $(i,j)$ by arc $(i\rightarrow j)$,
 26.3261 +flow $x_{ij}$ through which has zero lower bound ($l_{ij}=0$), unity
 26.3262 +upper bound ($u_{ij}=1$), and per-unit cost $+c_{ij}$ (in case of
 26.3263 +\verb|GLP_ASN_MIN|), or $-c_{ij}$ (in case of \verb|GLP_ASN_MAX| and
 26.3264 +\verb|GLP_ASN_MMP|);
 26.3265 +
 26.3266 +2) then it adds one auxiliary feedback node $k$;
 26.3267 +
 26.3268 +\newpage
 26.3269 +
 26.3270 +3) for each original node $i\in R$ the routine adds auxiliary supply
 26.3271 +arc $(k\rightarrow i)$, flow $x_{ki}$ through which is costless
 26.3272 +($c_{ki}=0$) and either fixed at 1 ($l_{ki}=u_{ki}=1$, in case of
 26.3273 +\verb|GLP_ASN_MIN| and \verb|GLP_ASN_MAX|) or has zero lower bound and
 26.3274 +unity upper bound ($l_{ij}=0$, $u_{ij}=1$, in case of
 26.3275 +\verb|GLP_ASN_MMP|);
 26.3276 +
 26.3277 +4) similarly, for each original node $j\in S$ the routine adds
 26.3278 +auxiliary demand arc $(j\rightarrow k)$, flow $x_{jk}$ through which is
 26.3279 +costless ($c_{jk}=0$) and either fixed at 1 ($l_{jk}=u_{jk}=1$, in case
 26.3280 +of \verb|GLP_ASN_MIN| and \verb|GLP_ASN_MAX|) or has zero lower bound
 26.3281 +and unity upper bound ($l_{jk}=0$, $u_{jk}=1$, in case of
 26.3282 +\verb|GLP_ASN_MMP|).
 26.3283 +
 26.3284 +\subsubsection*{Example}
 26.3285 +
 26.3286 +The example program shown below reads the assignment problem instance
 26.3287 +in DIMACS format from file `\verb|sample.asn|', solves it by using the
 26.3288 +routine \verb|glp_asnprob_okalg|, and writes the solution found to the
 26.3289 +standard output.
 26.3290 +
 26.3291 +\begin{footnotesize}
 26.3292 +\begin{verbatim}
 26.3293 +#include <stddef.h>
 26.3294 +#include <stdio.h>
 26.3295 +#include <stdlib.h>
 26.3296 +#include <glpk.h>
 26.3297 +
 26.3298 +typedef struct { int set; } v_data;
 26.3299 +typedef struct { double cost; int x; } e_data;
 26.3300 +
 26.3301 +#define node(v) ((v_data *)((v)->data))
 26.3302 +#define edge(e) ((e_data *)((e)->data))
 26.3303 +
 26.3304 +int main(void)
 26.3305 +{     glp_graph *G;
 26.3306 +      glp_vertex *v;
 26.3307 +      glp_arc *e;
 26.3308 +      int i, ret;
 26.3309 +      double sol;
 26.3310 +      G = glp_create_graph(sizeof(v_data), sizeof(e_data));
 26.3311 +      glp_read_asnprob(G, offsetof(v_data, set),
 26.3312 +         offsetof(e_data, cost), "sample.asn");
 26.3313 +      ret = glp_asnprob_okalg(GLP_ASN_MMP, G,
 26.3314 +         offsetof(v_data, set), offsetof(e_data, cost), &sol,
 26.3315 +         offsetof(e_data, x));
 26.3316 +      printf("ret = %d; sol = %5g\n", ret, sol);
 26.3317 +      for (i = 1; i <= G->nv; i++)
 26.3318 +      {  v = G->v[i];
 26.3319 +         for (e = v->out; e != NULL; e = e->t_next)
 26.3320 +            printf("edge %2d %2d: x = %d; c = %g\n",
 26.3321 +               e->tail->i, e->head->i, edge(e)->x, edge(e)->cost);
 26.3322 +      }
 26.3323 +      glp_delete_graph(G);
 26.3324 +      return 0;
 26.3325 +}
 26.3326 +\end{verbatim}
 26.3327 +\end{footnotesize}
 26.3328 +
 26.3329 +If `\verb|sample.asn|' is the example data file from the subsection
 26.3330 +describing the routine \verb|glp_read_asnprob|, the output may look
 26.3331 +like follows:
 26.3332 +
 26.3333 +\begin{footnotesize}
 26.3334 +\begin{verbatim}
 26.3335 +Reading assignment problem data from `sample.asn'...
 26.3336 +Assignment problem has 8 + 9 = 17 nodes and 22 arcs
 26.3337 +38 lines were read
 26.3338 +ret = 0; sol =   180
 26.3339 +edge  1 12: x = 1; c = 20
 26.3340 +edge  1 10: x = 0; c = 21
 26.3341 +edge  1  9: x = 0; c = 13
 26.3342 +edge  2 13: x = 1; c = 26
 26.3343 +edge  2 12: x = 0; c = 8
 26.3344 +edge  2 10: x = 0; c = 12
 26.3345 +edge  3 13: x = 0; c = 11
 26.3346 +edge  3 11: x = 1; c = 22
 26.3347 +edge  4 14: x = 1; c = 25
 26.3348 +edge  4 12: x = 0; c = 36
 26.3349 +edge  4  9: x = 0; c = 12
 26.3350 +edge  5 17: x = 0; c = 32
 26.3351 +edge  5 16: x = 1; c = 35
 26.3352 +edge  5 15: x = 0; c = 8
 26.3353 +edge  5 14: x = 0; c = 4
 26.3354 +edge  5 13: x = 0; c = 11
 26.3355 +edge  5 12: x = 0; c = 40
 26.3356 +edge  5 11: x = 0; c = 41
 26.3357 +edge  6  9: x = 1; c = 13
 26.3358 +edge  7 10: x = 0; c = 19
 26.3359 +edge  8 11: x = 0; c = 15
 26.3360 +edge  8 10: x = 1; c = 39
 26.3361 +\end{verbatim}
 26.3362 +\end{footnotesize}
 26.3363 +
 26.3364 +\newpage
 26.3365 +
 26.3366 +\subsection{glp\_asnprob\_hall---find bipartite matching of maximum
 26.3367 +cardinality}
 26.3368 +
 26.3369 +\subsubsection*{Synopsis}
 26.3370 +
 26.3371 +\begin{verbatim}
 26.3372 +int glp_asnprob_hall(glp_graph *G, int v_set, int a_x);
 26.3373 +\end{verbatim}
 26.3374 +
 26.3375 +\subsubsection*{Description}
 26.3376 +
 26.3377 +The routine \verb|glp_asnprob_hall| finds a matching of maximal
 26.3378 +cardinality in the specified bipartite graph. It uses a version of the
 26.3379 +Fortran routine \verb|MC21A| developed by
 26.3380 +I.~S.~Duff\footnote{I.~S.~Duff, Algorithm 575: Permutations for
 26.3381 +zero-free diagonal, ACM Trans. on Math. Softw. 7 (1981), pp.~387-390.},
 26.3382 +which implements Hall's algorithm.\footnote{M.~Hall, ``An Algorithm for
 26.3383 +Distinct Representatives,'' Am. Math. Monthly 63 (1956), pp.~716-717.}
 26.3384 +
 26.3385 +The parameter \verb|G| is a pointer to the graph program object.
 26.3386 +
 26.3387 +The parameter \verb|v_set| specifies an offset of the field of type
 26.3388 +\verb|int| in the vertex data block, which contains the node set
 26.3389 +indicator:
 26.3390 +
 26.3391 +0 --- the node is in set $R$;
 26.3392 +
 26.3393 +1 --- the node is in set $S$.
 26.3394 +
 26.3395 +\noindent
 26.3396 +If \verb|v_set| $<0$, it is assumed that a node having no incoming arcs
 26.3397 +is in set $R$, and a node having no outgoing arcs is in set $S$.
 26.3398 +
 26.3399 +The parameter \verb|a_x| specifies an offset of the field of type
 26.3400 +\verb|int| in the arc data block, to which the routine stores $x_{ij}$.
 26.3401 +If \verb|a_x| $<0$, this value is not stored.
 26.3402 +
 26.3403 +\subsubsection*{Returns}
 26.3404 +
 26.3405 +The routine \verb|glp_asnprob_hall| returns the cardinality of the
 26.3406 +matching found. However, if the specified graph is incorrect (as
 26.3407 +detected by the routine \verb|glp_check_asnprob|), this routine returns
 26.3408 +a negative value.
 26.3409 +
 26.3410 +\subsubsection*{Comments}
 26.3411 +
 26.3412 +The same solution may be obtained with the routine
 26.3413 +\verb|glp_asnprob_okalg| (for LP formulation \verb|GLP_ASN_MMP| and
 26.3414 +all edge costs equal to 1). However, the routine \verb|glp_asnprob_hall|
 26.3415 +is much faster.
 26.3416 +
 26.3417 +\newpage
 26.3418 +
 26.3419 +\subsubsection*{Example}
 26.3420 +
 26.3421 +The example program shown below reads the assignment problem instance
 26.3422 +in DIMACS format from file `\verb|sample.asn|', finds a bipartite
 26.3423 +matching of maximal cardinality by using the routine
 26.3424 +\verb|glp_asnprob_hall|, and writes the solution found to the standard
 26.3425 +output.
 26.3426 +
 26.3427 +\begin{footnotesize}
 26.3428 +\begin{verbatim}
 26.3429 +#include <stddef.h>
 26.3430 +#include <stdio.h>
 26.3431 +#include <stdlib.h>
 26.3432 +#include <glpk.h>
 26.3433 +
 26.3434 +typedef struct { int set; } v_data;
 26.3435 +typedef struct { int x;   } e_data;
 26.3436 +
 26.3437 +#define node(v) ((v_data *)((v)->data))
 26.3438 +#define edge(e) ((e_data *)((e)->data))
 26.3439 +
 26.3440 +int main(void)
 26.3441 +{     glp_graph *G;
 26.3442 +      glp_vertex *v;
 26.3443 +      glp_arc *e;
 26.3444 +      int i, card;
 26.3445 +      G = glp_create_graph(sizeof(v_data), sizeof(e_data));
 26.3446 +      glp_read_asnprob(G, offsetof(v_data, set), -1,
 26.3447 +         "sample.asn");
 26.3448 +      card = glp_asnprob_hall(G, offsetof(v_data, set),
 26.3449 +         offsetof(e_data, x));
 26.3450 +      printf("card = %d\n", card);
 26.3451 +      for (i = 1; i <= G->nv; i++)
 26.3452 +      {  v = G->v[i];
 26.3453 +         for (e = v->out; e != NULL; e = e->t_next)
 26.3454 +            printf("edge %2d %2d: x = %d\n",
 26.3455 +               e->tail->i, e->head->i, edge(e)->x);
 26.3456 +      }
 26.3457 +      glp_delete_graph(G);
 26.3458 +      return 0;
 26.3459 +}
 26.3460 +\end{verbatim}
 26.3461 +\end{footnotesize}
 26.3462 +
 26.3463 +If `\verb|sample.asn|' is the example data file from the subsection
 26.3464 +describing the routine \verb|glp_read_asnprob|, the output may look
 26.3465 +like follows:
 26.3466 +
 26.3467 +\begin{footnotesize}
 26.3468 +\begin{verbatim}
 26.3469 +Reading assignment problem data from `sample.asn'...
 26.3470 +Assignment problem has 8 + 9 = 17 nodes and 22 arcs
 26.3471 +38 lines were read
 26.3472 +card = 7
 26.3473 +edge  1 12: x = 1
 26.3474 +edge  1 10: x = 0
 26.3475 +edge  1  9: x = 0
 26.3476 +edge  2 13: x = 1
 26.3477 +edge  2 12: x = 0
 26.3478 +edge  2 10: x = 0
 26.3479 +edge  3 13: x = 0
 26.3480 +edge  3 11: x = 1
 26.3481 +edge  4 14: x = 1
 26.3482 +edge  4 12: x = 0
 26.3483 +edge  4  9: x = 0
 26.3484 +edge  5 17: x = 1
 26.3485 +edge  5 16: x = 0
 26.3486 +edge  5 15: x = 0
 26.3487 +edge  5 14: x = 0
 26.3488 +edge  5 13: x = 0
 26.3489 +edge  5 12: x = 0
 26.3490 +edge  5 11: x = 0
 26.3491 +edge  6  9: x = 1
 26.3492 +edge  7 10: x = 1
 26.3493 +edge  8 11: x = 0
 26.3494 +edge  8 10: x = 0
 26.3495 +\end{verbatim}
 26.3496 +\end{footnotesize}
 26.3497 +
 26.3498 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 26.3499 +
 26.3500 +\newpage
 26.3501 +
 26.3502 +\section{Critical path problem}
 26.3503 +
 26.3504 +\subsection{Background}
 26.3505 +
 26.3506 +The {\it critical path problem} (CPP) is stated as follows. Let there
 26.3507 +be given a project $J$, which a set of jobs (tasks, activities, etc.).
 26.3508 +Performing each job $i\in J$ requires time $t_i\geq 0$. Besides, over
 26.3509 +the set $J$ there is given a precedence relation $R\subseteq J\times J$,
 26.3510 +where $(i,j)\in R$ means that job $i$ immediately precedes job $j$, i.e.
 26.3511 +performing job $j$ cannot start until job $i$ has been completely
 26.3512 +performed. The problem is to find starting times $x_i$ for each job
 26.3513 +$i\in J$, which satisfy to the precedence relation and minimize the
 26.3514 +total duration (makespan) of the project.
 26.3515 +
 26.3516 +The following is an example of the critical path problem:
 26.3517 +
 26.3518 +\begin{center}
 26.3519 +\begin{tabular}{|c|l|c|c|}
 26.3520 +\hline
 26.3521 +Job&Desription&Time&Predecessors\\
 26.3522 +\hline
 26.3523 +A&Excavate&3&---\\
 26.3524 +B&Lay foundation&4&A\\
 26.3525 +C&Rough plumbing&3&B\\
 26.3526 +D&Frame&10&B\\
 26.3527 +E&Finish exterior&8&D\\
 26.3528 +F&Install HVAC&4&D\\
 26.3529 +G&Rough electric&6&D\\
 26.3530 +H&Sheet rock&8&C, E, F, G\\
 26.3531 +I&Install cabinets&5&H\\
 26.3532 +J&Paint&5&H\\
 26.3533 +K&Final plumbing&4&I\\
 26.3534 +L&Final electric&2&J\\
 26.3535 +M&Install flooring&4&K, L\\
 26.3536 +\hline
 26.3537 +\end{tabular}
 26.3538 +\end{center}
 26.3539 +
 26.3540 +Obviously, the project along with the precedence relation can be
 26.3541 +represented as a directed graph $G=(J,R)$ called {\it project network},
 26.3542 +where each node $i\in J$ corresponds to a job, and arc
 26.3543 +$(i\rightarrow j)\in R$ means that job $i$ immediately precedes job
 26.3544 +$j$.\footnote{There exists another network representation of the
 26.3545 +critical path problem, where jobs correspond to arcs while nodes
 26.3546 +correspond to events introduced to express the precedence relation.
 26.3547 +That representation, however, is much less convenient than the one,
 26.3548 +where jobs are represented as nodes of the network.} The project network
 26.3549 +for the example above is shown on Fig.~4.
 26.3550 +
 26.3551 +May note that the project network must be acyclic; otherwise, it would
 26.3552 +be impossible to satisfy to the precedence relation for any job that
 26.3553 +belongs to a cycle.
 26.3554 +
 26.3555 +\newpage
 26.3556 +
 26.3557 +\xymatrix
 26.3558 +{&&&C|3\ar[rd]&&I|5\ar[r]&K|4\ar[rd]&\\
 26.3559 +A|3\ar[r]&B|4\ar[rru]\ar[rd]&&E|8\ar[r]&H|8\ar[ru]\ar[rd]&&&M|4\\
 26.3560 +&&D|10\ar[ru]\ar[r]\ar[rd]&F|4\ar[ru]&&J|5\ar[r]&L|2\ar[ru]&\\
 26.3561 +&&&G|6\ar[ruu]&&&&\\
 26.3562 +}
 26.3563 +
 26.3564 +\bigskip
 26.3565 +
 26.3566 +\noindent\hfil
 26.3567 +Fig.~4. An example of the project network.
 26.3568 +
 26.3569 +\bigskip
 26.3570 +
 26.3571 +The critical path problem can be naturally formulated as the following
 26.3572 +LP problem:
 26.3573 +
 26.3574 +\medskip
 26.3575 +
 26.3576 +\noindent
 26.3577 +\hspace{.5in}minimize
 26.3578 +$$z\eqno(19)$$
 26.3579 +\hspace{.5in}subject to
 26.3580 +$$x_i+t_i\leq z\ \ \ \hbox{for all}\ i\in J\ \ \ \ \eqno(20)$$
 26.3581 +$$x_i+t_i\leq x_j\ \ \ \hbox{for all}\ (i,j)\in R\eqno(21)$$
 26.3582 +$$x_i\geq 0\ \ \ \ \ \ \ \hbox{for all}\ i\in J\ \ \eqno(22)$$
 26.3583 +
 26.3584 +The inequality constraints (21), which are active in the optimal
 26.3585 +solution, define so called {\it critical path} having the following
 26.3586 +property: the minimal project duration $z$ can be decreased only by
 26.3587 +decreasing the times $t_j$ for jobs on the critical path, and delaying
 26.3588 +any critical job delays the entire project.
 26.3589 +
 26.3590 +\subsection{glp\_cpp---solve critical path problem}
 26.3591 +
 26.3592 +\subsubsection{Synopsis}
 26.3593 +
 26.3594 +\begin{verbatim}
 26.3595 +double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls);
 26.3596 +\end{verbatim}
 26.3597 +
 26.3598 +\subsubsection{Description}
 26.3599 +
 26.3600 +The routine \verb|glp_cpp| solves the critical path problem represented
 26.3601 +in the form of the project network.
 26.3602 +
 26.3603 +The parameter \verb|G| is a pointer to the graph object, which
 26.3604 +specifies the project network. This graph must be acyclic. Multiple
 26.3605 +arcs are allowed being considered as single arcs.
 26.3606 +
 26.3607 +The parameter \verb|v_t| specifies an offset of the field of type
 26.3608 +\verb|double| in the vertex data block, which contains time $t_i\geq 0$
 26.3609 +needed to perform corresponding job $j\in J$. If \verb|v_t| $<0$, it is
 26.3610 +assumed that $t_i=1$ for all jobs.
 26.3611 +
 26.3612 +The parameter \verb|v_es| specifies an offset of the field of type
 26.3613 +\verb|double| in the vertex data block, to which the routine stores
 26.3614 +the {\it earliest start time} for corresponding job. If \verb|v_es|
 26.3615 +$<0$, this time is not stored.
 26.3616 +
 26.3617 +The parameter \verb|v_ls| specifies an offset of the field of type
 26.3618 +\verb|double| in the vertex data block, to which the routine stores
 26.3619 +the {\it latest start time} for corresponding job. If \verb|v_ls|
 26.3620 +$<0$, this time is not stored.
 26.3621 +
 26.3622 +The difference between the latest and earliest start times of some job
 26.3623 +is called its {\it time reserve}. Delaying a job within its time reserve
 26.3624 +does not affect the project duration, so if the time reserve is zero,
 26.3625 +the corresponding job is critical.
 26.3626 +
 26.3627 +\subsubsection{Returns}
 26.3628 +
 26.3629 +The routine \verb|glp_cpp| returns the minimal project duration, i.e.
 26.3630 +minimal time needed to perform all jobs in the project.
 26.3631 +
 26.3632 +\subsubsection{Example}
 26.3633 +
 26.3634 +The example program below solves the critical path problem shown on
 26.3635 +Fig.~4 by using the routine \verb|glp_cpp| and writes the solution found
 26.3636 +to the standard output.
 26.3637 +
 26.3638 +\begin{footnotesize}
 26.3639 +\begin{verbatim}
 26.3640 +#include <stddef.h>
 26.3641 +#include <stdio.h>
 26.3642 +#include <stdlib.h>
 26.3643 +#include <glpk.h>
 26.3644 +
 26.3645 +typedef struct { double t, es, ls; } v_data;
 26.3646 +
 26.3647 +#define node(v) ((v_data *)((v)->data))
 26.3648 +
 26.3649 +int main(void)
 26.3650 +{     glp_graph *G;
 26.3651 +      int i;
 26.3652 +      double t, es, ef, ls, lf, total;
 26.3653 +      G = glp_create_graph(sizeof(v_data), 0);
 26.3654 +      glp_add_vertices(G, 13);
 26.3655 +      node(G->v[1])->t = 3;   /* A: Excavate */
 26.3656 +      node(G->v[2])->t = 4;   /* B: Lay foundation */
 26.3657 +      node(G->v[3])->t = 3;   /* C: Rough plumbing */
 26.3658 +      node(G->v[4])->t = 10;  /* D: Frame */
 26.3659 +      node(G->v[5])->t = 8;   /* E: Finish exterior */
 26.3660 +      node(G->v[6])->t = 4;   /* F: Install HVAC */
 26.3661 +      node(G->v[7])->t = 6;   /* G: Rough elecrtic */
 26.3662 +      node(G->v[8])->t = 8;   /* H: Sheet rock */
 26.3663 +      node(G->v[9])->t = 5;   /* I: Install cabinets */
 26.3664 +      node(G->v[10])->t = 5;  /* J: Paint */
 26.3665 +      node(G->v[11])->t = 4;  /* K: Final plumbing */
 26.3666 +      node(G->v[12])->t = 2;  /* L: Final electric */
 26.3667 +      node(G->v[13])->t = 4;  /* M: Install flooring */
 26.3668 +      glp_add_arc(G, 1, 2);   /* A precedes B */
 26.3669 +      glp_add_arc(G, 2, 3);   /* B precedes C */
 26.3670 +      glp_add_arc(G, 2, 4);   /* B precedes D */
 26.3671 +      glp_add_arc(G, 4, 5);   /* D precedes E */
 26.3672 +      glp_add_arc(G, 4, 6);   /* D precedes F */
 26.3673 +      glp_add_arc(G, 4, 7);   /* D precedes G */
 26.3674 +      glp_add_arc(G, 3, 8);   /* C precedes H */
 26.3675 +      glp_add_arc(G, 5, 8);   /* E precedes H */
 26.3676 +      glp_add_arc(G, 6, 8);   /* F precedes H */
 26.3677 +      glp_add_arc(G, 7, 8);   /* G precedes H */
 26.3678 +      glp_add_arc(G, 8, 9);   /* H precedes I */
 26.3679 +      glp_add_arc(G, 8, 10);  /* H precedes J */
 26.3680 +      glp_add_arc(G, 9, 11);  /* I precedes K */
 26.3681 +      glp_add_arc(G, 10, 12); /* J precedes L */
 26.3682 +      glp_add_arc(G, 11, 13); /* K precedes M */
 26.3683 +      glp_add_arc(G, 12, 13); /* L precedes M */
 26.3684 +      total = glp_cpp(G, offsetof(v_data, t), offsetof(v_data, es),
 26.3685 +         offsetof(v_data, ls));
 26.3686 +      printf("Minimal project duration is %.2f\n\n", total);
 26.3687 +      printf("Job  Time      ES     EF     LS     LF\n");
 26.3688 +      printf("--- ------   ------ ------ ------ ------\n");
 26.3689 +      for (i = 1; i <= G->nv; i++)
 26.3690 +      {  t = node(G->v[i])->t;
 26.3691 +         es = node(G->v[i])->es;
 26.3692 +         ef = es + node(G->v[i])->t;
 26.3693 +         ls = node(G->v[i])->ls;
 26.3694 +         lf = ls + node(G->v[i])->t;
 26.3695 +         printf("%3d %6.2f %s %6.2f %6.2f %6.2f %6.2f\n",
 26.3696 +            i, t, ls - es < 0.001 ? "*" : " ", es, ef, ls, lf);
 26.3697 +      }
 26.3698 +      glp_delete_graph(G);
 26.3699 +      return 0;
 26.3700 +}
 26.3701 +\end{verbatim}
 26.3702 +\end{footnotesize}
 26.3703 +
 26.3704 +The output from the example program shown below includes job number,
 26.3705 +the time needed to perform a job, earliest start time (\verb|ES|),
 26.3706 +earliest finish time (\verb|EF|), latest start time (\verb|LS|), and
 26.3707 +latest finish time (\verb|LF|) for each job in the project. Critical
 26.3708 +jobs are marked by asterisks.
 26.3709 +
 26.3710 +\newpage
 26.3711 +
 26.3712 +\begin{footnotesize}
 26.3713 +\begin{verbatim}
 26.3714 +Minimal project duration is 46.00
 26.3715 +
 26.3716 +Job  Time      ES     EF     LS     LF
 26.3717 +--- ------   ------ ------ ------ ------
 26.3718 +  1   3.00 *   0.00   3.00   0.00   3.00
 26.3719 +  2   4.00 *   3.00   7.00   3.00   7.00
 26.3720 +  3   3.00     7.00  10.00  22.00  25.00
 26.3721 +  4  10.00 *   7.00  17.00   7.00  17.00
 26.3722 +  5   8.00 *  17.00  25.00  17.00  25.00
 26.3723 +  6   4.00    17.00  21.00  21.00  25.00
 26.3724 +  7   6.00    17.00  23.00  19.00  25.00
 26.3725 +  8   8.00 *  25.00  33.00  25.00  33.00
 26.3726 +  9   5.00 *  33.00  38.00  33.00  38.00
 26.3727 + 10   5.00    33.00  38.00  35.00  40.00
 26.3728 + 11   4.00 *  38.00  42.00  38.00  42.00
 26.3729 + 12   2.00    38.00  40.00  40.00  42.00
 26.3730 + 13   4.00 *  42.00  46.00  42.00  46.00
 26.3731 +\end{verbatim}
 26.3732 +\end{footnotesize}
 26.3733 +
 26.3734 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 26.3735 +
 26.3736 +\chapter{Graph Optimization API Routines}
 26.3737 +
 26.3738 +\section{Maximum clique problem}
 26.3739 +
 26.3740 +\subsection{Background}
 26.3741 +
 26.3742 +The {\it maximum clique problem (MCP)} is a classic combinatorial
 26.3743 +optimization problem. Given an undirected graph $G=(V,E)$, where $V$ is
 26.3744 +a set of vertices, and $E$ is a set of edges, this problem is to find
 26.3745 +the largest {\it clique} $C\subseteq G$, i.e. the largest induced
 26.3746 +complete subgraph. A generalization of this problem is the {\it maximum
 26.3747 +weight clique problem (MWCP)}, which is to find a clique $C\subseteq G$
 26.3748 +of the largest weight $\displaystyle\sum_{v\in C}w(v)\rightarrow\max$,
 26.3749 +where $w(v)$ is a weight of vertex $v\in V$.
 26.3750 +
 26.3751 +An example of the maximum weight clique problem is shown on Fig.~5.
 26.3752 +
 26.3753 +\begin{figure}
 26.3754 +\noindent\hfil
 26.3755 +\begin{tabular}{c}
 26.3756 +{\xymatrix %@C=16pt
 26.3757 +{&&&{v_1}\ar@{-}[lllddd]\ar@{-}[llddddd]\ar@{-}[dddddd]
 26.3758 +\ar@{-}[rrrddd]&&&\\
 26.3759 +&{v_2}\ar@{-}[rrrr]\ar@{-}[rrrrdddd]\ar@{-}[rrddddd]\ar@{-}[dddd]&&&&
 26.3760 +{v_3}\ar@{-}[llllldd]\ar@{-}[lllldddd]\ar@{-}[dddd]&\\
 26.3761 +&&&&&&\\
 26.3762 +{v_4}\ar@{-}[rrrrrr]\ar@{-}[rrrddd]&&&&&&{v_5}\ar@{-}[lllddd]
 26.3763 +\ar@{-}[ldd]\\
 26.3764 +&&&&&&\\
 26.3765 +&{v_6}\ar@{-}[rrrr]&&&&{v_7}&\\
 26.3766 +&&&{v_8}&&&\\
 26.3767 +}}
 26.3768 +\end{tabular}
 26.3769 +\begin{tabular}{r@{\ }c@{\ }l}
 26.3770 +$w(v_1)$&=&3\\$w(v_2)$&=&4\\$w(v_3)$&=&8\\$w(v_4)$&=&1\\
 26.3771 +$w(v_5)$&=&5\\$w(v_6)$&=&2\\$w(v_7)$&=&1\\$w(v_8)$&=&3\\
 26.3772 +\end{tabular}
 26.3773 +
 26.3774 +\begin{center}
 26.3775 +Fig.~5. An example of the maximum weight clique problem.
 26.3776 +\end{center}
 26.3777 +\end{figure}
 26.3778 +
 26.3779 +\subsection{glp\_wclique\_exact---find maximum weight clique with exact
 26.3780 +algorithm}
 26.3781 +
 26.3782 +\subsubsection*{Synopsis}
 26.3783 +
 26.3784 +\begin{verbatim}
 26.3785 +int glp_wclique_exact(glp_graph *G, int v_wgt, double *sol,
 26.3786 +      int v_set);
 26.3787 +\end{verbatim}
 26.3788 +
 26.3789 +\subsection*{Description}
 26.3790 +
 26.3791 +The routine {\it glp\_wclique\_exact} finds a maximum weight clique in
 26.3792 +the specified undirected graph with the exact algorithm developed by
 26.3793 +Patric \"Osterg{\aa}rd.\footnote{P.~R.~J.~\"Osterg{\aa}rd, A new
 26.3794 +algorithm for the maximum-weight clique problem, Nordic J. of Computing,
 26.3795 +Vol.~8, No.~4, 2001, pp.~424--36.}
 26.3796 +
 26.3797 +The parameter $G$ is the program object, which specifies an undirected
 26.3798 +graph. Each arc $(x\rightarrow y)$ in $G$ is considered as edge
 26.3799 +$(x,y)$, self-loops are ignored, and multiple edges, if present, are
 26.3800 +replaced (internally) by simple edges.
 26.3801 +
 26.3802 +The parameter {\it v\_wgt} specifies an offset of the field of type
 26.3803 +{\bf double} in the vertex data block, which contains a weight of
 26.3804 +corresponding vertex. Vertex weights must be integer-valued in the
 26.3805 +range $[0,$ {\it INT\_MAX}$]$. If {\it v\_wgt} $<0$, it is assumed that
 26.3806 +all vertices of the graph have the weight 1.
 26.3807 +
 26.3808 +The parameter {\it sol} specifies a location, to which the routine
 26.3809 +stores the weight of the clique found (the clique weight is the sum
 26.3810 +of weights of all vertices included in the clique.) If {\it sol} is
 26.3811 +{\it NULL}, the solution is not stored.
 26.3812 +
 26.3813 +The parameter {\it v\_set} specifies an offset of the field of type
 26.3814 +{\bf int} in the vertex data block, to which the routines stores a
 26.3815 +vertex flag: 1 means that the corresponding vertex is included in the
 26.3816 +clique found, and 0 otherwise. If {\it v\_set} $<0$, vertex flags are
 26.3817 +not stored.
 26.3818 +
 26.3819 +\subsubsection*{Returns}
 26.3820 +
 26.3821 +\def\arraystretch{1}
 26.3822 +
 26.3823 +\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
 26.3824 +0 & Optimal solution found.\\
 26.3825 +\verb|GLP_EDATA| & Unable to start the search, because some vertex
 26.3826 +weights are either not integer-valued or out of range. This code is
 26.3827 +also returned if the sum of weights of all vertices exceeds
 26.3828 +{\it INT\_MAX}. \\
 26.3829 +\end{tabular}
 26.3830 +
 26.3831 +\subsubsection*{Notes}
 26.3832 +
 26.3833 +\noindent\indent
 26.3834 +1. The routine {\it glp\_wclique\_exact} finds exact solution. Since
 26.3835 +both MCP and MWCP problems are NP-complete, the algorithm may require
 26.3836 +exponential time in worst cases.
 26.3837 +
 26.3838 +2. Internally the specified graph is converted to an adjacency matrix
 26.3839 +in {\it dense} format. This requires about $|V|^2/16$ bytes of memory,
 26.3840 +where $|V|$ is the number of vertices in the graph.
 26.3841 +
 26.3842 +\subsubsection*{Example}
 26.3843 +
 26.3844 +The example program shown below reads a MWCP instance in DIMACS
 26.3845 +clique/coloring format from file `\verb|sample.clq|', finds the clique
 26.3846 +of largest weight, and writes the solution found to the standard output.
 26.3847 +
 26.3848 +\begin{footnotesize}
 26.3849 +\begin{verbatim}
 26.3850 +#include <stddef.h>
 26.3851 +#include <stdio.h>
 26.3852 +#include <stdlib.h>
 26.3853 +#include <glpk.h>
 26.3854 +
 26.3855 +typedef struct { double wgt; int set; } v_data;
 26.3856 +
 26.3857 +#define vertex(v) ((v_data *)((v)->data))
 26.3858 +
 26.3859 +int main(void)
 26.3860 +{     glp_graph *G;
 26.3861 +      glp_vertex *v;
 26.3862 +      int i, ret;
 26.3863 +      double sol;
 26.3864 +      G = glp_create_graph(sizeof(v_data), 0);
 26.3865 +      glp_read_ccdata(G, offsetof(v_data, wgt), "sample.clq");
 26.3866 +      ret = glp_wclique_exact(G, offsetof(v_data, wgt), &sol,
 26.3867 +         offsetof(v_data, set));
 26.3868 +      printf("ret = %d; sol = %g\n", ret, sol);
 26.3869 +      for (i = 1; i <= G->nv; i++)
 26.3870 +      {  v = G->v[i];
 26.3871 +         printf("vertex %d: weight = %g, flag = %d\n",
 26.3872 +            i, vertex(v)->wgt, vertex(v)->set);
 26.3873 +      }
 26.3874 +      glp_delete_graph(G);
 26.3875 +      return 0;
 26.3876 +}
 26.3877 +\end{verbatim}
 26.3878 +\end{footnotesize}
 26.3879 +
 26.3880 +\noindent
 26.3881 +For the example shown on Fig.~5 the data file may look like follows:
 26.3882 +
 26.3883 +\begin{footnotesize}
 26.3884 +\begin{verbatim}
 26.3885 +c sample.clq
 26.3886 +c
 26.3887 +c This is an example of the maximum weight clique
 26.3888 +c problem in DIMACS clique/coloring format.
 26.3889 +c
 26.3890 +p edge 8 16
 26.3891 +n 1 3
 26.3892 +n 2 4
 26.3893 +n 3 8
 26.3894 +n 5 5
 26.3895 +n 6 2
 26.3896 +n 8 3
 26.3897 +e 1 4
 26.3898 +e 1 5
 26.3899 +e 1 6
 26.3900 +e 1 8
 26.3901 +e 2 3
 26.3902 +e 2 6
 26.3903 +e 2 7
 26.3904 +e 2 8
 26.3905 +e 3 4
 26.3906 +e 3 6
 26.3907 +e 3 7
 26.3908 +e 4 5
 26.3909 +e 4 8
 26.3910 +e 5 7
 26.3911 +e 5 8
 26.3912 +e 6 7
 26.3913 +c
 26.3914 +c eof
 26.3915 +\end{verbatim}
 26.3916 +\end{footnotesize}
 26.3917 +
 26.3918 +\noindent
 26.3919 +The corresponding output from the example program is the following:
 26.3920 +
 26.3921 +\begin{footnotesize}
 26.3922 +\begin{verbatim}
 26.3923 +Reading graph from `sample.clq'...
 26.3924 +Graph has 8 vertices and 16 edges
 26.3925 +28 lines were read
 26.3926 +ret = 0; sol = 15
 26.3927 +vertex 1: weight = 3, flag = 0
 26.3928 +vertex 2: weight = 4, flag = 1
 26.3929 +vertex 3: weight = 8, flag = 1
 26.3930 +vertex 4: weight = 1, flag = 0
 26.3931 +vertex 5: weight = 5, flag = 0
 26.3932 +vertex 6: weight = 2, flag = 1
 26.3933 +vertex 7: weight = 1, flag = 1
 26.3934 +vertex 8: weight = 3, flag = 0
 26.3935 +\end{verbatim}
 26.3936 +\end{footnotesize}
 26.3937 +
 26.3938 +\end{document}
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/doc/miplib2.txt	Mon Dec 06 13:09:21 2010 +0100
    27.3 @@ -0,0 +1,135 @@
    27.4 +Solver:   GLPSOL 4.40 (options used: --pcost)
    27.5 +Computer: Intel Pentium 4, 3.0 GHz
    27.6 +Platform: Cygwin 1.5.25
    27.7 +Compiler: GCC 3.4.4 (options used: -O3)
    27.8 +Test set: MIPLIB 2.0 <http://miplib.zib.de/miplib3/miplib/>
    27.9 +
   27.10 +Problem  Optimal Solution Cuts Used    Nodes  Iters Time,s Mem,MB
   27.11 +-------- ---------------- --------- -------- ------ ------ ------
   27.12 +air01    +6.796000000e+03                  3     41    < 1    1.2
   27.13 +air02    +7.810000000e+03                 43    201      6   13.8
   27.14 +air03    +3.401600000e+05                 33    414     12   21.0
   27.15 +air04    +5.613700000e+04               1901 109800    396   32.4
   27.16 +air05    +2.637400000e+04               6445 201649    452   45.0
   27.17 +air06    +4.964900000e+04                 11   6868     31   18.1
   27.18 +bell3a   +8.784303160e+05 --gomory      7965  42363     17    6.1
   27.19 +bell3b   +1.178616062e+07 --gomory      6031  30467     19    3.2
   27.20 +bell4    +1.854148420e+07 --gomory      7203  25019     16    2.9
   27.21 +bell5    +8.966406492e+06 --gomory      5605  18555      8    1.5
   27.22 +bm23     +3.400000000e+01                373    878    < 1    0.2
   27.23 +cracpb1  +2.219900000e+04                 47   5258      2    1.3
   27.24 +dcmulti  +1.881820000e+05                743   3366      2    1.1
   27.25 +diamond        infeasible                  3      4    < 1    0.1
   27.26 +dsbmip   -3.051981750e+02 --mir          217  46088     24    4.5
   27.27 +egout    +5.681007000e+02                 91    137    < 1    0.3
   27.28 +enigma   +0.000000000e+00              16419  55071      6    3.2
   27.29 +fixnet3  +5.197300000e+04                 81    380    < 1    1.4
   27.30 +fixnet4  +8.936000000e+03                211   1095      1    1.4
   27.31 +fixnet6  +3.983000000e+03               1031   3136      2    1.7
   27.32 +flugpl   +1.201500000e+06                397    231    < 1    0.1
   27.33 +gen      +1.123133627e+05                195   3991      1    1.7
   27.34 +khb05250 +1.069402260e+08               2163  14498      5    2.8
   27.35 +l152lav  +4.722000000e+03               7419  95299     68   12.0
   27.36 +lp4l     +2.967000000e+03                173   1331      2    1.7
   27.37 +lseu     +1.120000000e+03              10821  31954      5    2.5
   27.38 +misc01   +5.635000000e+02                769   4593      1    0.5
   27.39 +misc02   +1.690000000e+03                 29    282    < 1    0.2
   27.40 +misc03   +3.360000000e+03                957   6742      2    1.1
   27.41 +misc04   +2.666699247e+03                 17   2052      1    7.0
   27.42 +misc05   +2.984500000e+03                293   2520      1    1.1
   27.43 +misc06   +1.285086074e+04                 57    941    < 1    2.7
   27.44 +misc07   +2.810000000e+03 --mir        66075 579129    424   33.4
   27.45 +mod008   +3.070000000e+02               8185  24245      8    2.3
   27.46 +mod010   +6.548000000e+03                315   6283      7    5.3
   27.47 +mod011
   27.48 +mod013   +2.809500000e+02                545   1155    < 1    0.3
   27.49 +modglob  +2.074050809e+07 --mir         5197  31985     20    2.8
   27.50 +noswot
   27.51 +p0033    +3.089000000e+03                305    955    < 1    0.2
   27.52 +p0040    +6.202700000e+04                 17     66    < 1    0.1
   27.53 +p0201    +7.615000000e+03                521   3660      1    0.9
   27.54 +p0282    +2.584110000e+05                623   1204      1    0.8
   27.55 +p0291    +5.223749000e+03                 71    154    < 1    0.7
   27.56 +p0548    +8.691000000e+03               7617  23556      9    2.9
   27.57 +p2756    +3.124000000e+03 --mir         3911  15157     57   10.9
   27.58 +p6000    -2.451377000e+06              19209  40906    570   15.8
   27.59 +pipex    +7.882630000e+02               1569   2469    < 1    0.4
   27.60 +qiu      -1.328731369e+02              80473 1918742  1174   69.2
   27.61 +rentacar +3.035676098e+07                 43   1649      3   12.1
   27.62 +rgn      +8.219999924e+01               3325  18700      2    1.2
   27.63 +sample2  +3.750000000e+02                163    347    < 1    0.2
   27.64 +sentoy   -7.772000000e+03                335    723    < 1    0.4
   27.65 +set1al   +1.586975000e+04 --mir           17    532    < 1    1.5
   27.66 +set1ch
   27.67 +set1cl   +6.484250000e+03 --mir            1    502    < 1    1.1
   27.68 +stein15  +9.000000000e+00                 87    375    < 1    0.2
   27.69 +stein27  +1.800000000e+01               3255  15327      2    1.0
   27.70 +stein45  +3.000000000e+01              52301 389140    139   19.2
   27.71 +stein9   +5.000000000e+00                 17     45    < 1    0.1
   27.72 +vpm1     +2.000000000e+01 --mir            9    836    < 1    0.9
   27.73 +
   27.74 +PROBLEM CHARACTERISTICS
   27.75 +
   27.76 +Problem    Rows   Cols (   Int    0/1)   Nonz    Best Solution
   27.77 +-------- ------ ---------------------- ------ --------------------------
   27.78 +air01        24    771 (   all    all)   4986             6796 (opt)
   27.79 +air02        51   6774 (   all    all)  68329             7810 (opt)
   27.80 +air03       125  10757 (   all    all) 101785           340160 (opt)
   27.81 +air04       824   8904 (   all    all)  81869            56138 (opt)
   27.82 +air05       427   7195 (   all    all)  59316            26402 (not opt)
   27.83 +air06       826   8627 (   all    all)  79433            49649 (opt)
   27.84 +bell3a      124    133 (    71     39)    441        878430.32 (opt)
   27.85 +bell3b      124    133 (    71     39)    441      11786160.62 (opt)
   27.86 +bell4       106    117 (    64     34)    385      18541484.20 (opt)
   27.87 +bell5        92    104 (    58     30)    340       8966406.49 (opt)
   27.88 +bm23         21     27 (   all    all)    505               34 (opt)
   27.89 +cracpb1     144    572 (   all    all)   4730            22199 (opt)
   27.90 +dcmulti     291    548 (    75    all)   1833      188182.0000 (opt)
   27.91 +diamond       5      2 (   all    all)      9     integer infeasible
   27.92 +dsbmip     1855   1886 (   192    160)   9768         -305.198 (opt)
   27.93 +egout        99    141 (    55    all)    392          568.101 (opt)
   27.94 +enigma       22    100 (   all    all)    298              0.0 (opt)
   27.95 +fixnet3     479    878 (   378    all)   2631            51973 (opt)
   27.96 +fixnet4     479    878 (   378    all)   2621             8936 (opt)
   27.97 +fixnet6     479    878 (   378    all)   2550             3983 (opt)
   27.98 +flugpl       19     18 (    11   none)     64          1201500 (opt)
   27.99 +gen         781    870 (   150    144)   3174           112313 (opt)
  27.100 +khb05250    102   1350 (    24    all)   3973        106940226 (opt)
  27.101 +l152lav      98   1989 (   all    all)  11911             4750 (not opt)
  27.102 +lp4l         86   1086 (   all    all)   5763             2967 (opt)
  27.103 +lseu         29     89 (   all    all)    394             1120 (opt)
  27.104 +misc01       55     83 (    82    all)    746            563.5 (opt)
  27.105 +misc02       40     59 (    58    all)    414             1690 (opt)
  27.106 +misc03       97    160 (   159    all)   2054             3360 (opt)
  27.107 +misc04     1726   4897 (    30    all)  17253         2666.699 (opt)
  27.108 +misc05      301    136 (    74    all)   2946           2984.5 (opt)
  27.109 +misc06      821   1808 (   112    all)   5860       12850.8607 (opt)
  27.110 +misc07      213    260 (   259    all)   8620             2810 (not opt)
  27.111 +mod008        7    319 (   all    all)   1562              307 (opt)
  27.112 +mod010      147   2655 (   all    all)  13858             6548 (opt)
  27.113 +mod011     4482  10958 (    96    all)  37425        -54558535 (opt)
  27.114 +mod013       63     96 (    48    all)    288           280.95 (opt)
  27.115 +modglob     292    422 (    98    all)   1390         20740508 (opt)
  27.116 +noswot      183    128 (   100     75)    760              -43 (opt)
  27.117 +p0033        17     33 (   all    all)    131             3089 (opt)
  27.118 +p0040        24     40 (   all    all)    150            62027 (opt)
  27.119 +p0201       134    201 (   all    all)   2124             7615 (opt)
  27.120 +p0282       242    282 (   all    all)   2248           258411 (opt)
  27.121 +p0291       253    291 (   all    all)    349        5223.7490 (opt)
  27.122 +p0548       177    548 (   all    all)   2127             8691 (opt)
  27.123 +p2756       756   2756 (   all    all)  11103             3124 (opt)
  27.124 +p6000      2177   6000 (   all    all)  54238         -2451377 (opt)
  27.125 +pipex        26     48 (   all    all)    240          788.263 (opt)
  27.126 +qiu        1193    840 (    48    all)   3432      -132.873137 (opt)
  27.127 +rentacar   6804   9557 (    55    all)  42019         30356761 (opt)
  27.128 +rgn          25    180 (   100    all)    540          82.1999 (opt)
  27.129 +sample2      46     67 (    21    all)    179              375 (opt)
  27.130 +sentoy       31     60 (   all    all)   1860            -7772 (opt)
  27.131 +set1al      493    712 (   240    all)   1884          15869.7 (opt)
  27.132 +set1ch      493    712 (   240    all)   1884          54537.7 (opt)
  27.133 +set1cl      493    712 (   240    all)   1884          6484.25 (opt)
  27.134 +stein15      37     15 (   all    all)    135                9 (opt)
  27.135 +stein27     119     27 (   all    all)    405               18 (opt)
  27.136 +stein45     332     45 (   all    all)   1079               30 (opt)
  27.137 +stein9       14      9 (   all    all)     54                5 (opt)
  27.138 +vpm1        235    378 (   168    all)    917               20 (opt)
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/doc/miplib3.txt	Mon Dec 06 13:09:21 2010 +0100
    28.3 @@ -0,0 +1,143 @@
    28.4 +Solver:   GLPSOL 4.40 
    28.5 +Computer: Intel Pentium 4, 3.0 GHz
    28.6 +Platform: Cygwin 1.5.25
    28.7 +Compiler: GCC 3.4.4 (options used: -O3)
    28.8 +Test set: MIPLIB 3.0 <http://miplib.zib.de/miplib3/miplib.html>
    28.9 +
   28.10 +Problem  Optimal Solution Options Used        Nodes  Iters Time,s Mem,MB
   28.11 +-------- ---------------- ---------------- -------- ------ ------ ------
   28.12 +10teams  +9.240000000e+02 --pcost --gomory     6013 349276    207   12.7
   28.13 +air03    +3.401600000e+05 --pcost                33    414     12   21.0
   28.14 +air04    +5.613700000e+04 --pcost              1901 109800    396   32.4
   28.15 +air05    +2.637400000e+04 --pcost              6445 201649    452   45.0
   28.16 +arki001
   28.17 +bell3a   +8.784303160e+05 --pcost --gomory     7965  42363     17    6.1
   28.18 +bell5    +8.966406492e+06 --pcost --gomory     5605  18555      8    1.5
   28.19 +blend2   +7.598985000e+00 --pcost              7185  24256      7    2.1
   28.20 +cap6000  -2.451377000e+06 --pcost             19209  40906    569   15.8
   28.21 +dano3mip 
   28.22 +danoint
   28.23 +dcmulti  +1.881820000e+05 --pcost               743   3366      2    1.1
   28.24 +dsbmip   -3.051981750e+02 --pcost --mir         217  46088     24    4.5
   28.25 +egout    +5.681007000e+02 --pcost                91    137    < 1    0.3
   28.26 +enigma   +0.000000000e+00 --pcost             16419  55071      6    3.2
   28.27 +fast0507
   28.28 +fiber    +4.059351800e+05 --pcost --mir         407   3108      4    2.4
   28.29 +fixnet6  +3.983000000e+03 --pcost              1031   3136      2    1.7
   28.30 +flugpl   +1.201500000e+06 --pcost               397    231    < 1    0.1
   28.31 +gen      +1.123133627e+05 --pcost               195   3991      1    1.7
   28.32 +gesa2    +2.577985637e+07 --pcost --mir          59   2723      4    4.1
   28.33 +gesa2_o  +2.577985637e+07 --pcost --mir          69   2588      5    3.7
   28.34 +gesa3    +2.799104265e+07 --pcost --mir          93   2774      5    3.7
   28.35 +gesa3_o  +2.799104265e+07 --pcost --mir         117   3271      6    3.6
   28.36 +gt2      +2.116600000e+04 --pcost              5613  26115      2    1.2
   28.37 +harp2
   28.38 +khb05250 +1.069402260e+08 --pcost              2163  14498      5    2.8
   28.39 +l152lav  +4.722000000e+03 --pcost              7419  95299     68   12.0
   28.40 +lseu     +1.120000000e+03 --pcost             10821  31954      5    2.5
   28.41 +marksh1
   28.42 +marksh2
   28.43 +mas74
   28.44 +mas76
   28.45 +misc03   +3.360000000e+03 --pcost               957   6742      2    1.1
   28.46 +misc06   +1.285086074e+04 --pcost                57    941    < 1    2.7
   28.47 +misc07   +2.810000000e+03 --pcost --mir       66075 579129    424   33.4
   28.48 +mitre
   28.49 +mkc
   28.50 +mod008   +3.070000000e+02 --pcost              8185  24245      8    2.3
   28.51 +mod010   +6.548000000e+03 --pcost               315   6283      7    5.3
   28.52 +mod011
   28.53 +modglob  +2.074050809e+07 --pcost --mir        5197  31985     20    2.8
   28.54 +noswot
   28.55 +nw04     +1.686200000e+04 (none)                361   5544    345  138.3
   28.56 +p0033    +3.089000000e+03 --pcost               305    955    < 1    0.2
   28.57 +p0201    +7.615000000e+03 --pcost               521   3660      1    0.9
   28.58 +p0282    +2.584110000e+05 --pcost               623   1204      1    0.8
   28.59 +p0548    +8.691000000e+03 --pcost              7617  23556      9    2.9
   28.60 +p2756    +3.124000000e+03 --pcost --mir        3911  15157     57   10.9
   28.61 +pk1
   28.62 +pp08a    +7.350000000e+03 --pcost --mir         663   9196      4    1.3
   28.63 +pp08acut +7.350000000e+03 --pcost --mir       17233 260160    154   21.1
   28.64 +qiu      -1.328731369e+02 --pcost             80473 1918742  1174   69.2
   28.65 +qnet1    +1.602969268e+04 --pcost --mir         183  20352     16    3.6
   28.66 +qnet1_o  +1.602969268e+04 --pcost --mir          75   7645      9    3.3
   28.67 +rentacar +3.035676098e+07 --pcost                43   1649      3   12.1
   28.68 +rgn      +8.219999924e+01 --pcost              3325  18700      2    1.2
   28.69 +rout
   28.70 +set1ch
   28.71 +seymour
   28.72 +stein27  +1.800000000e+01 --pcost              3255  15327      2    1.0
   28.73 +stein45  +3.000000000e+01 --pcost             52301 389140    139   19.2
   28.74 +swath
   28.75 +vpm1     +2.000000000e+01 --pcost --mir           9    836    < 1    0.9
   28.76 +vpm2     +1.375000000e+01 --pcost --mir       11729 164856     91    9.2
   28.77 +
   28.78 +PROBLEM CHARACTERISTICS
   28.79 +
   28.80 +Problem    Rows   Cols (   Int    0/1)   Nonz    Best Solution
   28.81 +-------- ------ ---------------------- ------ --------------------------
   28.82 +10teams     230   2025 (  1800    all)  12150              924 (opt)
   28.83 +air03       125  10757 (   all    all) 101785           340160 (opt)
   28.84 +air04       824   8904 (   all    all)  81869            56138 (opt)
   28.85 +air05       427   7195 (   all    all)  59316            26402 (not opt)
   28.86 +arki001    1048   1388 (   538    415)  20439     7580813.0459 (not opt)
   28.87 +bell3a      124    133 (    71     39)    441        878430.32 (opt)
   28.88 +bell5        92    104 (    58     30)    340       8966406.49 (opt)
   28.89 +blend2      274    353 (   264    231)   1409         7.598985 (opt)
   28.90 +cap6000    2176   6000 (   all    all)  48249         -2451377 (opt)
   28.91 +dano3mip   3202  13873 (   552    all)  79655         728.1111 (not opt)
   28.92 +danoint     664    521 (    56    all)   3232            65.67 (opt)
   28.93 +dcmulti     291    548 (    75    all)   1833      188182.0000 (opt)
   28.94 +dsbmip     1855   1886 (   192    160)   9768         -305.198 (opt)
   28.95 +egout        99    141 (    55    all)    392          568.101 (opt)
   28.96 +enigma       22    100 (   all    all)    298              0.0 (opt)
   28.97 +fast0507    507  63009 (   all    all) 409439              174 (opt)
   28.98 +fiber       363   1298 (  1254    all)   2944     405935.18000 (opt)
   28.99 +fixnet6     479    878 (   378    all)   2550             3983 (opt)
  28.100 +flugpl       19     18 (    11   none)     64          1201500 (opt)
  28.101 +gen         781    870 (   150    144)   3174           112313 (opt)
  28.102 +gesa2      1392   1224 (   408    240)   5064     25779856.372 (opt)
  28.103 +gesa2_o    1248   1224 (   720    384)   3672     25779856.372 (opt)
  28.104 +gesa3      1368   1152 (   384    216)   4944     27991042.648 (opt)
  28.105 +gesa3_o    1224   1152 (   672    336)   3624     27991042.648 (opt)
  28.106 +gt2          29    188 (   all     24)    376        21166.000 (opt)
  28.107 +harp2       112   2993 (   all    all)   5840     -73899798.00 (opt)
  28.108 +khb05250    102   1350 (    24    all)   3973        106940226 (opt)
  28.109 +l152lav      98   1989 (   all    all)  11911             4750 (not opt)
  28.110 +lseu         29     89 (   all    all)    394             1120 (opt)
  28.111 +marksh1       7     62 (    50    all)    324
  28.112 +marksh2       8     74 (    60    all)    448
  28.113 +mas74        13    151 (   150    all)   1705       11801.1857 (opt)
  28.114 +mas76        12    151 (   150    all)   1639       40005.0541 (opt)
  28.115 +misc03       97    160 (   159    all)   2054             3360 (opt)
  28.116 +misc06      821   1808 (   112    all)   5860       12850.8607 (opt)
  28.117 +misc07      213    260 (   259    all)   8620             2810 (not opt)
  28.118 +mitre      2054  10724 (   all    all)  39704           115155 (opt)
  28.119 +mkc        3412   5325 (  5323    all)  20621
  28.120 +mod008        7    319 (   all    all)   1562              307 (opt)
  28.121 +mod010      147   2655 (   all    all)  13858             6548 (opt)
  28.122 +mod011     4482  10958 (    96    all)  37425        -54558535 (opt)
  28.123 +modglob     292    422 (    98    all)   1390         20740508 (opt)
  28.124 +noswot      183    128 (   100     75)    760              -43 (opt)
  28.125 +nw04         36  87482 (   all    all) 636666            16862 (opt)
  28.126 +p0033        17     33 (   all    all)    131             3089 (opt)
  28.127 +p0201       134    201 (   all    all)   2124             7615 (opt)
  28.128 +p0282       242    282 (   all    all)   2248           258411 (opt)
  28.129 +p0548       177    548 (   all    all)   2127             8691 (opt)
  28.130 +p2756       756   2756 (   all    all)  11103             3124 (opt)
  28.131 +pk1          45     86 (    55    all)    915               11 (opt)
  28.132 +pp08a       136    240 (    64    all)    480             7350 (opt)
  28.133 +pp08acut    246    240 (    64    all)    839             7350 (opt)
  28.134 +qiu        1193    840 (    48    all)   3432      -132.873137 (opt)
  28.135 +qnet1       503   1541 (  1417   1288)   4622     16029.692681 (opt)
  28.136 +qnet1_o     456   1541 (  1417   1288)   4214     16029.692681 (opt)
  28.137 +rentacar   6804   9557 (    55    all)  42019         30356761 (opt)
  28.138 +rgn          25    180 (   100    all)    540          82.1999 (opt)
  28.139 +rout        291    556 (   315    300)   2431          1077.56 (opt)
  28.140 +set1ch      493    712 (   240    all)   1884          54537.7 (opt)
  28.141 +seymour    4944   1372 (   all    all)  33549          423 (not opt)
  28.142 +stein27     119     27 (   all    all)    405               18 (opt)
  28.143 +stein45     332     45 (   all    all)   1079               30 (opt)
  28.144 +swath       885   6805 (  6724    all)  34966
  28.145 +vpm1        235    378 (   168    all)    917               20 (opt)
  28.146 +vpm2        234    378 (   168    all)    917            13.75 (opt)
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/doc/netlib.txt	Mon Dec 06 13:09:21 2010 +0100
    29.3 @@ -0,0 +1,103 @@
    29.4 +Solver:   GLPSOL 4.40 (default options used)
    29.5 +Computer: Intel Pentium 4, 3.0 GHz
    29.6 +Platform: Cygwin 1.5.25
    29.7 +Compiler: GCC 3.4.4 (options used: -O3)
    29.8 +Test set: Netlib LP collection <ftp://ftp.netlib.org/lp/data/>
    29.9 +
   29.10 +Problem    Rows   Cols   Nonz       Optimum        Iters  Time,s  Mem,MB
   29.11 +--------  -----  -----  ------  ----------------  ------  ------  ------
   29.12 +25fv47      822   1571   11127  +5.501845888e+03    1651     < 1     2.1
   29.13 +80bau3b    2263   9799   29063  +9.872241924e+05    5358       3     6.4
   29.14 +adlittle     57     97     465  +2.254949632e+05      71     < 1     0.1   
   29.15 +afiro        28     32      88  -4.647531429e+02      10     < 1     0.1
   29.16 +agg         489    163    2541  -3.599176729e+07     100     < 1     0.5
   29.17 +agg2        517    302    4515  -2.023925236e+07     178     < 1     0.8
   29.18 +agg3        517    302    4531  +1.031211594e+07     182     < 1     0.8
   29.19 +bandm       306    472    2659  -1.586280185e+02     252     < 1     0.6
   29.20 +beaconfd    174    262    3476  +3.359248581e+04      61     < 1     0.4
   29.21 +blend        75     83     521  -3.081214985e+01      41     < 1     0.1
   29.22 +bnl1        644   1175    6129  +1.977629562e+03     581     < 1     1.4
   29.23 +bnl2       2325   3489   16124  +1.811236540e+03    1730       1     3.7
   29.24 +boeing1     351    384    3865  -3.352135675e+02     419     < 1     0.7
   29.25 +boeing2     167    143    1339  -3.150187280e+02     161     < 1     0.3
   29.26 +bore3d      234    315    1525  +1.373080394e+03      38     < 1     0.3
   29.27 +brandy      221    249    2150  +1.518509896e+03     191     < 1     0.5
   29.28 +capri       272    353    1786  +2.690012914e+03     203     < 1     0.4
   29.29 +cycle      1904   2857   21322  -5.226393025e+00     953     < 1     3.5
   29.30 +czprob      930   3523   14173  +2.185196699e+06     754     < 1     2.6
   29.31 +d2q06c     2172   5167   35674  +1.227842108e+05    5368       7     6.2
   29.32 +d6cube      416   6184   43888  +3.154916667e+02    6596       6     6.0
   29.33 +degen2      445    534    4449  -1.435178000e+03     506     < 1     1.0
   29.34 +degen3     1504   1818   26230  -9.872940000e+02    2205       2     4.1
   29.35 +dfl001     6072  12230   41873  +1.126639605e+07   39863     117    11.0
   29.36 +e226        224    282    2767  -2.586492907e+01     206     < 1     0.5
   29.37 +etamacro    401    688    2489  -7.557152333e+02     444     < 1     0.7
   29.38 +fffff800    525    854    6235  +5.556795648e+05     167     < 1     1.0
   29.39 +finnis      498    614    2714  +1.727910656e+05     338     < 1     0.6
   29.40 +fit1d        25   1026   14430  -9.146378092e+03     488     < 1     1.7
   29.41 +fit1p       628   1677   10894  +9.146378092e+03    1379     < 1     1.9
   29.42 +fit2d        26  10500  138018  -6.846429329e+04    5751      16    15.8
   29.43 +fit2p      3001  13525   60784  +6.846429329e+04   11960      17    11.3
   29.44 +forplan     162    421    4916  -6.642189613e+02     170     < 1     0.7
   29.45 +ganges     1310   1681    7021  -1.095857361e+05     724     < 1     1.9
   29.46 +gfrd-pnc    617   1092    3467  +6.902236000e+06     416     < 1     1.0
   29.47 +greenbea   2393   5405   31499  -7.255524813e+07    3012       3     5.8
   29.48 +greenbeb   2393   5405   31499  -4.302260261e+06    2153       2     5.8
   29.49 +grow15      301    645    5665  -1.068709413e+08     358     < 1     1.1
   29.50 +grow22      441    946    8318  -1.608343365e+08     606     < 1     1.6
   29.51 +grow7       141    301    2633  -4.778781181e+07     159     < 1     0.5
   29.52 +israel      175    142    2358  -8.966448219e+05     123     < 1     0.4
   29.53 +kb2          44     41     291  -1.749900130e+03      38     < 1     0.1
   29.54 +lotfi       154    308    1086  -2.526470606e+01     104     < 1     0.3
   29.55 +maros       847   1443   10006  -5.806374370e+04     703     < 1     1.8
   29.56 +maros-r7   3137   9408  151120  +1.497185166e+06    2340       5    16.7
   29.57 +modszk1     688   1620    4158  +3.206197291e+02     705     < 1     1.4
   29.58 +nesm        663   2923   13988  +1.407603649e+07    2240       1     2.4
   29.59 +perold      626   1376    6026  -9.380755278e+03    1103     < 1     1.5
   29.60 +pilot      1442   3652   43220  -5.574831533e+02    5726      11     7.8
   29.61 +pilot-ja    941   1988   14706  -6.113136466e+03    1697       1     2.5
   29.62 +pilot-we    723   2789    9218  -2.720107533e+06    1382       1     2.3
   29.63 +pilot4      411   1000    5145  -2.581139259e+03     532     < 1     1.3
   29.64 +pilot87    2031   4883   73804  +3.017103744e+02    7573      28    12.2
   29.65 +pilotnov    976   2172   13129  -4.497276188e+03     988       1     2.5
   29.66 +recipe       92    180     752  -2.666160000e+02      17     < 1     0.2
   29.67 +sc105       106    103     281  -5.220206121e+01      51     < 1     0.2
   29.68 +sc205       206    203     552  -5.220206121e+01     124     < 1     0.3
   29.69 +sc50a        51     48     131  -6.457507706e+01      25     < 1     0.1
   29.70 +sc50b        51     48     119  -7.000000000e+01      30     < 1     0.1
   29.71 +scagr25     472    500    2029  -1.475343306e+07     352     < 1     0.7
   29.72 +scagr7      130    140     553  -2.331389824e+06      94     < 1     0.2
   29.73 +scfxm1      331    457    2612  +1.841675903e+04     281     < 1     0.6
   29.74 +scfxm2      661    914    5229  +3.666026156e+04     587     < 1     1.1
   29.75 +scfxm3      991   1371    7846  +5.490125455e+04     881     < 1     1.7
   29.76 +scorpion    389    358    1708  +1.878124823e+03     146     < 1     0.4
   29.77 +scrs8       491   1169    4029  +9.042969538e+02     545     < 1     1.1
   29.78 +scsd1        78    760    3148  +8.666666674e+00      91     < 1     0.6
   29.79 +scsd6       148   1350    5666  +5.050000008e+01     182     < 1     1.0
   29.80 +scsd8       398   2750   11334  +9.049999999e+02     397     < 1     2.1
   29.81 +sctap1      301    480    2052  +1.412250000e+03     196     < 1     0.5
   29.82 +sctap2     1091   1880    8124  +1.724807143e+03     425     < 1     1.7
   29.83 +sctap3     1481   2480   10734  +1.424000000e+03     729     < 1     2.4
   29.84 +seba        516   1028    4874  +1.571160000e+04     883     < 1     1.0
   29.85 +share1b     118    225    1182  -7.658931858e+04     167     < 1     0.3
   29.86 +share2b      97     79     730  -4.157322407e+02      87     < 1     0.2
   29.87 +shell       537   1775    4900  +1.208825346e+09     467     < 1     1.2
   29.88 +ship04l     403   2118    8450  +1.793324538e+06     373     < 1     1.5
   29.89 +ship04s     403   1458    5810  +1.798714700e+06     262     < 1     1.0
   29.90 +ship08l     779   4283   17085  +1.909055211e+06     516     < 1     2.9
   29.91 +ship08s     779   2387    9501  +1.920098211e+06     274     < 1     1.7
   29.92 +ship12l    1152   5427   21597  +1.470187919e+06     686     < 1     3.7
   29.93 +ship12s    1152   2763   10941  +1.489236134e+06     383     < 1     2.0
   29.94 +sierra     1228   2036    9252  +1.539436218e+07     857     < 1     2.1
   29.95 +stair       357    467    3857  -2.512669512e+02     399     < 1     1.0
   29.96 +standata    360   1075    3038  +1.257699500e+03     140     < 1     0.7
   29.97 +standgub    362   1184    3147  +1.257699500e+03     140     < 1     0.8
   29.98 +standmps    468   1075    3686  +1.406017500e+03     299     < 1     0.9
   29.99 +stocfor1    118    111     474  -4.113197622e+04      24     < 1     0.2
  29.100 +stocfor2   2158   2031    9492  -3.902440854e+04     499     < 1     2.6
  29.101 +stocfor3  16676  15695   74004  -3.997678394e+04    4456      11    19.7
  29.102 +truss      1001   8806   36642  +4.588158472e+05    4744       4     6.5
  29.103 +tuff        334    587    4523  +2.921477651e-01      61     < 1     0.8
  29.104 +vtp-base    199    203     914  +1.298314625e+05      69     < 1     0.2
  29.105 +wood1p      245   2594   70216  +1.442902412e+00     326     < 1     7.1
  29.106 +woodw      1099   8405   37478  +1.304476333e+00    1093     < 1     6.0
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/examples/INDEX	Mon Dec 06 13:09:21 2010 +0100
    30.3 @@ -0,0 +1,52 @@
    30.4 +assign.mod     Assignment problem
    30.5 +bpp.mod        Bin packing problem
    30.6 +cal.mod        Print an ASCII calendar of the given year
    30.7 +cf12a.mod      Curve fitting problem
    30.8 +cf12b.mod      Curve fitting problem
    30.9 +cflsq.mod      Curve fitting problem by least squares
   30.10 +color.mod      Graph coloring problem
   30.11 +cpp.mod        Critical path problem
   30.12 +crypto.mod     A crypto-arithmetic puzzle
   30.13 +dea.mod        Data envelopment analysis (DEA)
   30.14 +diet.mod       Stigler's nutrition model
   30.15 +dist.mod       A product distribution model
   30.16 +egypt.mod      A static model for fertilizer production
   30.17 +fctp.mod       Fixed-charge transportation problem
   30.18 +food.mod       Food manufacture model
   30.19 +food2.mod      Food manufacture model
   30.20 +gap.mod        Generalized assignment problem
   30.21 +graph.mod      Graph visualization
   30.22 +hashi.mod      A solver for the Japanese number-puzzle Hashiwokakero
   30.23 +huge.mod       Arithmetic mean of a large number of integers
   30.24 +jssp.mod       Job-shop scheduling problem
   30.25 +magic.mod      Magic square
   30.26 +maxcut.mod     Maximum cut problem
   30.27 +maxflow.mod    Maximum flow problem
   30.28 +mfasp.mod      Minimum feedback arc set problem
   30.29 +mfvsp.mod      Minimum feedback vertex set problem
   30.30 +min01ks.mod    Finding minimal equivalent 0-1 knapsack inequality
   30.31 +misp.mod       Maximum independent set problem
   30.32 +money.mod      A crypto-arithmetic puzzle
   30.33 +mvcp.mod       Minimum vertex cover problem
   30.34 +numbrix.mod    Number placement puzzle
   30.35 +pbn.mod        Paint-by-numbers puzzle
   30.36 +plan.mod       A simple LP problem
   30.37 +prod.mod       A multiperiod production model
   30.38 +qfit.mod       Quadratic curve fitting solution
   30.39 +queens.mod     A classic combinatorial optimization problem
   30.40 +sat.mod        Satisfiability problem
   30.41 +shiftcover.mod Workforce shift coverage assignment problem
   30.42 +shikaku.mod    A solver for the logic puzzle Shikaku
   30.43 +sorting.mod    How to sort arrays in MathProg
   30.44 +spp.mod        Shortest path problem
   30.45 +stigler.mod    Original Stigler's 1939 diet problem
   30.46 +sudoku.mod     Number placement puzzle
   30.47 +tas.mod        Tail assignment problem
   30.48 +todd.mod       A class of hard instances of 0-1 knapsack problems
   30.49 +train.mod      A model of railroad passenger car allocation
   30.50 +transp.mod     A transportation problem
   30.51 +trick.mod      A transportation design problem
   30.52 +tsp.mod        Traveling salesman problem
   30.53 +xyacfs.mod     Extended yet another curve fitting solution
   30.54 +yacfs.mod      Yet another curve fitting solution
   30.55 +zebra.mod      Who owns the zebra?
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/examples/Makefile.am	Mon Dec 06 13:09:21 2010 +0100
    31.3 @@ -0,0 +1,15 @@
    31.4 +## Process this file with automake to produce Makefile.in ##
    31.5 +
    31.6 +INCLUDES = -I$(srcdir)/../include
    31.7 +
    31.8 +LDADD = ../src/libglpk.la
    31.9 +
   31.10 +bin_PROGRAMS = glpsol
   31.11 +
   31.12 +glpsol_SOURCES = glpsol.c
   31.13 +
   31.14 +check: glpsol$(EXEEXT)
   31.15 +	./glpsol$(EXEEXT) --version
   31.16 +	./glpsol$(EXEEXT) --mps $(srcdir)/plan.mps
   31.17 +
   31.18 +## eof ##
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/examples/assign.mod	Mon Dec 06 13:09:21 2010 +0100
    32.3 @@ -0,0 +1,77 @@
    32.4 +/* ASSIGN, Assignment Problem */
    32.5 +
    32.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
    32.7 +
    32.8 +/* The assignment problem is one of the fundamental combinatorial
    32.9 +   optimization problems.
   32.10 +
   32.11 +   In its most general form, the problem is as follows:
   32.12 +
   32.13 +   There are a number of agents and a number of tasks. Any agent can be
   32.14 +   assigned to perform any task, incurring some cost that may vary
   32.15 +   depending on the agent-task assignment. It is required to perform all
   32.16 +   tasks by assigning exactly one agent to each task in such a way that
   32.17 +   the total cost of the assignment is minimized.
   32.18 +
   32.19 +   (From Wikipedia, the free encyclopedia.) */
   32.20 +
   32.21 +param m, integer, > 0;
   32.22 +/* number of agents */
   32.23 +
   32.24 +param n, integer, > 0;
   32.25 +/* number of tasks */
   32.26 +
   32.27 +set I := 1..m;
   32.28 +/* set of agents */
   32.29 +
   32.30 +set J := 1..n;
   32.31 +/* set of tasks */
   32.32 +
   32.33 +param c{i in I, j in J}, >= 0;
   32.34 +/* cost of allocating task j to agent i */
   32.35 +
   32.36 +var x{i in I, j in J}, >= 0;
   32.37 +/* x[i,j] = 1 means task j is assigned to agent i
   32.38 +   note that variables x[i,j] are binary, however, there is no need to
   32.39 +   declare them so due to the totally unimodular constraint matrix */
   32.40 +
   32.41 +s.t. phi{i in I}: sum{j in J} x[i,j] <= 1;
   32.42 +/* each agent can perform at most one task */
   32.43 +
   32.44 +s.t. psi{j in J}: sum{i in I} x[i,j] = 1;
   32.45 +/* each task must be assigned exactly to one agent */
   32.46 +
   32.47 +minimize obj: sum{i in I, j in J} c[i,j] * x[i,j];
   32.48 +/* the objective is to find a cheapest assignment */
   32.49 +
   32.50 +solve;
   32.51 +
   32.52 +printf "\n";
   32.53 +printf "Agent  Task       Cost\n";
   32.54 +printf{i in I} "%5d %5d %10g\n", i, sum{j in J} j * x[i,j],
   32.55 +   sum{j in J} c[i,j] * x[i,j];
   32.56 +printf "----------------------\n";
   32.57 +printf "     Total: %10g\n", sum{i in I, j in J} c[i,j] * x[i,j];
   32.58 +printf "\n";
   32.59 +
   32.60 +data;
   32.61 +
   32.62 +/* These data correspond to an example from [Christofides]. */
   32.63 +
   32.64 +/* Optimal solution is 76 */
   32.65 +
   32.66 +param m := 8;
   32.67 +
   32.68 +param n := 8;
   32.69 +
   32.70 +param c : 1  2  3  4  5  6  7  8 :=
   32.71 +      1  13 21 20 12  8 26 22 11
   32.72 +      2  12 36 25 41 40 11  4  8
   32.73 +      3  35 32 13 36 26 21 13 37
   32.74 +      4  34 54  7  8 12 22 11 40
   32.75 +      5  21  6 45 18 24 34 12 48
   32.76 +      6  42 19 39 15 14 16 28 46
   32.77 +      7  16 34 38  3 34 40 22 24
   32.78 +      8  26 20  5 17 45 31 37 43 ;
   32.79 +
   32.80 +end;
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/examples/bpp.mod	Mon Dec 06 13:09:21 2010 +0100
    33.3 @@ -0,0 +1,83 @@
    33.4 +/* BPP, Bin Packing Problem */
    33.5 +
    33.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
    33.7 +
    33.8 +/* Given a set of items I = {1,...,m} with weight w[i] > 0, the Bin
    33.9 +   Packing Problem (BPP) is to pack the items into bins of capacity c
   33.10 +   in such a way that the number of bins used is minimal. */
   33.11 +
   33.12 +param m, integer, > 0;
   33.13 +/* number of items */
   33.14 +
   33.15 +set I := 1..m;
   33.16 +/* set of items */
   33.17 +
   33.18 +param w{i in 1..m}, > 0;
   33.19 +/* w[i] is weight of item i */
   33.20 +
   33.21 +param c, > 0;
   33.22 +/* bin capacity */
   33.23 +
   33.24 +/* We need to estimate an upper bound of the number of bins sufficient
   33.25 +   to contain all items. The number of items m can be used, however, it
   33.26 +   is not a good idea. To obtain a more suitable estimation an easy
   33.27 +   heuristic is used: we put items into a bin while it is possible, and
   33.28 +   if the bin is full, we use another bin. The number of bins used in
   33.29 +   this way gives us a more appropriate estimation. */
   33.30 +
   33.31 +param z{i in I, j in 1..m} :=
   33.32 +/* z[i,j] = 1 if item i is in bin j, otherwise z[i,j] = 0 */
   33.33 +
   33.34 +   if i = 1 and j = 1 then 1
   33.35 +   /* put item 1 into bin 1 */
   33.36 +
   33.37 +   else if exists{jj in 1..j-1} z[i,jj] then 0
   33.38 +   /* if item i is already in some bin, do not put it into bin j */
   33.39 +
   33.40 +   else if sum{ii in 1..i-1} w[ii] * z[ii,j] + w[i] > c then 0
   33.41 +   /* if item i does not fit into bin j, do not put it into bin j */
   33.42 +
   33.43 +   else 1;
   33.44 +   /* otherwise put item i into bin j */
   33.45 +
   33.46 +check{i in I}: sum{j in 1..m} z[i,j] = 1;
   33.47 +/* each item must be exactly in one bin */
   33.48 +
   33.49 +check{j in 1..m}: sum{i in I} w[i] * z[i,j] <= c;
   33.50 +/* no bin must be overflowed */
   33.51 +
   33.52 +param n := sum{j in 1..m} if exists{i in I} z[i,j] then 1;
   33.53 +/* determine the number of bins used by the heuristic; obviously it is
   33.54 +   an upper bound of the optimal solution */
   33.55 +
   33.56 +display n;
   33.57 +
   33.58 +set J := 1..n;
   33.59 +/* set of bins */
   33.60 +
   33.61 +var x{i in I, j in J}, binary;
   33.62 +/* x[i,j] = 1 means item i is in bin j */
   33.63 +
   33.64 +var used{j in J}, binary;
   33.65 +/* used[j] = 1 means bin j contains at least one item */
   33.66 +
   33.67 +s.t. one{i in I}: sum{j in J} x[i,j] = 1;
   33.68 +/* each item must be exactly in one bin */
   33.69 +
   33.70 +s.t. lim{j in J}: sum{i in I} w[i] * x[i,j] <= c * used[j];
   33.71 +/* if bin j is used, it must not be overflowed */
   33.72 +
   33.73 +minimize obj: sum{j in J} used[j];
   33.74 +/* objective is to minimize the number of bins used */
   33.75 +
   33.76 +data;
   33.77 +
   33.78 +/* The optimal solution is 3 bins */
   33.79 +
   33.80 +param m := 6;
   33.81 +
   33.82 +param w := 1 50, 2 60, 3 30, 4 70, 5 50, 6 40;
   33.83 +
   33.84 +param c := 100;
   33.85 +
   33.86 +end;
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/examples/cal.mod	Mon Dec 06 13:09:21 2010 +0100
    34.3 @@ -0,0 +1,49 @@
    34.4 +/* cal.mod - print an ASCII calendar of the given year */
    34.5 +
    34.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
    34.7 +
    34.8 +param year, integer, >= 0001, <= 3999, default 2010;
    34.9 +
   34.10 +param first_day{m in 1..12}, integer, >= 0, <= 6, :=
   34.11 +      time2str(str2time(year & "-" & m & "-01", "%Y-%m-%d"), "%w");
   34.12 +
   34.13 +param days_in_month{m in 1..12}, integer, >= 28, <= 31, :=
   34.14 +      (str2time(year + (if m < 12 then 0 else 1) & "-" &
   34.15 +         (if m < 12 then m+1 else 1) & "-01", "%Y-%m-%d") -
   34.16 +      str2time(year & "-" & m & "-01", "%Y-%m-%d")) / 86400;
   34.17 +
   34.18 +param foo{m in 1..12, k in 0..5, d in 0..6}, integer, :=
   34.19 +      7 * k + d + 1 - first_day[m];
   34.20 +
   34.21 +param cal{m in 1..12, k in 0..5, d in 0..6}, integer, :=
   34.22 +      if 1 <= foo[m,k,d] and foo[m,k,d] <= days_in_month[m] then
   34.23 +         foo[m,k,d];
   34.24 +
   34.25 +printf "\n";
   34.26 +printf "%33s%04d\n", "", year;
   34.27 +printf "\n";
   34.28 +for {t in 1..12 by 3}
   34.29 +{     for {m in t..t+2}
   34.30 +      {  printf "%7s%-14s", "", time2str(str2time(m, "%m"), "%B");
   34.31 +         printf{0..0: m < t+2} "   ";
   34.32 +      }
   34.33 +      printf "\n";
   34.34 +      for {m in t..t+2}
   34.35 +      {  printf "  S  M Tu  W Th  F  S";
   34.36 +         printf{0..0: m < t+2} "   ";
   34.37 +      }
   34.38 +      printf "\n";
   34.39 +      for {k in 0..5}
   34.40 +      {  for {m in t..t+2}
   34.41 +         {  for {d in 0..6}
   34.42 +            {  printf{0..0: cal[m,k,d]  = 0} "   ";
   34.43 +               printf{0..0: cal[m,k,d] != 0} " %2d", cal[m,k,d];
   34.44 +            }
   34.45 +            printf{0..0: m < t+2} "   ";
   34.46 +         }
   34.47 +         printf "\n";
   34.48 +      }
   34.49 +}
   34.50 +printf "\n";
   34.51 +
   34.52 +end;
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/examples/cf12a.mod	Mon Dec 06 13:09:21 2010 +0100
    35.3 @@ -0,0 +1,81 @@
    35.4 +/*
    35.5 +
    35.6 +  Curve fitting problem 12.11(a) H P Williams "Model Building in Mathematical Programming"
    35.7 +
    35.8 +  Dr. H J Mackenzie
    35.9 +  HARD software
   35.10 +  hjm@hardsoftware.com
   35.11 +
   35.12 +  2006-01-05
   35.13 +
   35.14 + */
   35.15 +
   35.16 +# set of points
   35.17 +
   35.18 +set I;
   35.19 +
   35.20 +# independent variable
   35.21 +
   35.22 +param x {i in I};
   35.23 +
   35.24 +# dependent variable
   35.25 +
   35.26 +param y {i in I};
   35.27 +
   35.28 +# output input values
   35.29 +
   35.30 +printf {i in I} "x = %.1f; y = %.1f\n", x[i], y[i];
   35.31 +
   35.32 +# define equation variables
   35.33 +
   35.34 +var a;
   35.35 +
   35.36 +var b;
   35.37 +
   35.38 +var u {i in I}, >= 0;
   35.39 +
   35.40 +var v {i in I}, >= 0;
   35.41 +
   35.42 +# define objective function
   35.43 +
   35.44 +minimize error: sum {i in I} u[i] + sum {i in I} v[i];
   35.45 +
   35.46 +# define equation constraint
   35.47 +
   35.48 +s.t. equation {i in I} : b * x[i] + a + u[i] - v[i] = y[i];
   35.49 +
   35.50 +solve;
   35.51 +
   35.52 +printf "y = %.4fx + %.4f\n", b, a;
   35.53 +
   35.54 +/*
   35.55 + *
   35.56 + * DATA section
   35.57 + *
   35.58 + */
   35.59 +
   35.60 +data;
   35.61 +
   35.62 +param : I :   x    y :=
   35.63 +        1     0    1
   35.64 +        2   0.5  0.9
   35.65 +        3     1  0.7
   35.66 +        4   1.5  1.5
   35.67 +        5   1.9    2
   35.68 +        6   2.5  2.4
   35.69 +        7     3  3.2
   35.70 +        8   3.5    2
   35.71 +        9     4  2.7
   35.72 +       10   4.5  3.5
   35.73 +       11     5    1
   35.74 +       12   5.5    4
   35.75 +       13     6  3.6
   35.76 +       14   6.6  2.7
   35.77 +       15     7  5.7
   35.78 +       16   7.6  4.6
   35.79 +       17   8.5    6
   35.80 +       18     9  6.8
   35.81 +       19    10  7.3
   35.82 +;
   35.83 +
   35.84 +end;
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/examples/cf12b.mod	Mon Dec 06 13:09:21 2010 +0100
    36.3 @@ -0,0 +1,88 @@
    36.4 +/*
    36.5 +
    36.6 +  Curve fitting problem 12.11(b) H P Williams "Model Building in Mathematical Programming"
    36.7 +
    36.8 +  Dr. H J Mackenzie
    36.9 +  HARD software
   36.10 +  hjm@hardsoftware.com
   36.11 +
   36.12 +  2006-01-23
   36.13 +
   36.14 + */
   36.15 +
   36.16 +# set of points
   36.17 +
   36.18 +set I;
   36.19 +
   36.20 +# independent variable
   36.21 +
   36.22 +param x {i in I};
   36.23 +
   36.24 +# dependent variable
   36.25 +
   36.26 +param y {i in I};
   36.27 +
   36.28 +# output input values
   36.29 +
   36.30 +printf {i in I} "x = %.1f; y = %.1f\n", x[i], y[i];
   36.31 +
   36.32 +# define equation variables
   36.33 +
   36.34 +var a;
   36.35 +
   36.36 +var b;
   36.37 +
   36.38 +var u {i in I}, >= 0;
   36.39 +
   36.40 +var v {i in I}, >= 0;
   36.41 +
   36.42 +var z;
   36.43 +
   36.44 +# define objective function
   36.45 +
   36.46 +minimize deviation: z;
   36.47 +
   36.48 +# define equation constraint
   36.49 +
   36.50 +s.t. equation {i in I} : b * x[i] + a + u[i] - v[i] = y[i];
   36.51 +
   36.52 +# define deviation constrains
   36.53 +
   36.54 +s.t. u_deviation {i in I} : z - u[i] >= 0;
   36.55 +s.t. v_deviation {i in I} : z - v[i] >= 0;
   36.56 +
   36.57 +solve;
   36.58 +
   36.59 +printf "y = %.4fx + %.4f Max deviation = %.4f\n", b, a, z;
   36.60 +
   36.61 +/*
   36.62 + *
   36.63 + * DATA section
   36.64 + *
   36.65 + */
   36.66 +
   36.67 +data;
   36.68 +
   36.69 +param : I :   x    y :=
   36.70 +        1     0    1
   36.71 +        2   0.5  0.9
   36.72 +        3     1  0.7
   36.73 +        4   1.5  1.5
   36.74 +        5   1.9    2
   36.75 +        6   2.5  2.4
   36.76 +        7     3  3.2
   36.77 +        8   3.5    2
   36.78 +        9     4  2.7
   36.79 +       10   4.5  3.5
   36.80 +       11     5    1
   36.81 +       12   5.5    4
   36.82 +       13     6  3.6
   36.83 +       14   6.6  2.7
   36.84 +       15     7  5.7
   36.85 +       16   7.6  4.6
   36.86 +       17   8.5    6
   36.87 +       18     9  6.8
   36.88 +       19    10  7.3
   36.89 +;
   36.90 +
   36.91 +end;
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/examples/cflsq.mod	Mon Dec 06 13:09:21 2010 +0100
    37.3 @@ -0,0 +1,51 @@
    37.4 +/*Curve fitting problem by Least Squares
    37.5 +  Nigel_Galloway@operamail.com
    37.6 +  October 1st., 2007
    37.7 +*/
    37.8 +set Sample;
    37.9 +param Sx {z in Sample};
   37.10 +param Sy {z in Sample};
   37.11 +
   37.12 +var X;
   37.13 +var Y;
   37.14 +var Ex{z in Sample};
   37.15 +var Ey{z in Sample};
   37.16 +
   37.17 +/* sum of variances is zero for Sx*/
   37.18 +variencesX{z in Sample}: X + Ex[z] = Sx[z];
   37.19 +zumVariancesX: sum{z in Sample} Ex[z] = 0;
   37.20 +/* sum of variances is zero for Sy*/
   37.21 +variencesY{z in Sample}: Y + Ey[z] = Sy[z];
   37.22 +zumVariancesY: sum{z in Sample} Ey[z] = 0;
   37.23 +
   37.24 +solve;
   37.25 +
   37.26 +param b1 := (sum{z in Sample} Ex[z]*Ey[z])/(sum{z in Sample} Ex[z]*Ex[z]);
   37.27 +printf "\nbest linear fit is:\n\ty = %f %s %fx\n\n", Y-b1*X, if b1 < 0 then "-" else "+", abs(b1);
   37.28 +
   37.29 +data;
   37.30 +
   37.31 +param:
   37.32 +Sample:   Sx    Sy :=
   37.33 +  1         0    1
   37.34 +  2       0.5  0.9
   37.35 +  3         1  0.7
   37.36 +  4       1.5  1.5
   37.37 +  5       1.9    2
   37.38 +  6       2.5  2.4
   37.39 +  7         3  3.2
   37.40 +  8       3.5    2
   37.41 +  9         4  2.7
   37.42 + 10       4.5  3.5
   37.43 + 11         5    1
   37.44 + 12       5.5    4
   37.45 + 13         6  3.6
   37.46 + 14       6.6  2.7
   37.47 + 15         7  5.7
   37.48 + 16       7.6  4.6
   37.49 + 17       8.5    6
   37.50 + 18         9  6.8
   37.51 + 19        10  7.3
   37.52 +;
   37.53 +
   37.54 +end;
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/examples/color.mod	Mon Dec 06 13:09:21 2010 +0100
    38.3 @@ -0,0 +1,113 @@
    38.4 +/* COLOR, Graph Coloring Problem */
    38.5 +
    38.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
    38.7 +
    38.8 +/* Given an undirected loopless graph G = (V, E), where V is a set of
    38.9 +   nodes, E <= V x V is a set of arcs, the Graph Coloring Problem is to
   38.10 +   find a mapping (coloring) F: V -> C, where C = {1, 2, ... } is a set
   38.11 +   of colors whose cardinality is as small as possible, such that
   38.12 +   F(i) != F(j) for every arc (i,j) in E, that is adjacent nodes must
   38.13 +   be assigned different colors. */
   38.14 +
   38.15 +param n, integer, >= 2;
   38.16 +/* number of nodes */
   38.17 +
   38.18 +set V := {1..n};
   38.19 +/* set of nodes */
   38.20 +
   38.21 +set E, within V cross V;
   38.22 +/* set of arcs */
   38.23 +
   38.24 +check{(i,j) in E}: i != j;
   38.25 +/* there must be no loops */
   38.26 +
   38.27 +/* We need to estimate an upper bound of the number of colors |C|.
   38.28 +   The number of nodes |V| can be used, however, for sparse graphs such
   38.29 +   bound is not very good. To obtain a more suitable estimation we use
   38.30 +   an easy "greedy" heuristic. Let nodes 1, ..., i-1 are already
   38.31 +   assigned some colors. To assign a color to node i we see if there is
   38.32 +   an existing color not used for coloring nodes adjacent to node i. If
   38.33 +   so, we use this color, otherwise we introduce a new color. */
   38.34 +
   38.35 +set EE := setof{(i,j) in E} (i,j) union setof{(i,j) in E} (j,i);
   38.36 +/* symmetrisized set of arcs */
   38.37 +
   38.38 +param z{i in V, case in 0..1} :=
   38.39 +/* z[i,0] = color index assigned to node i
   38.40 +   z[i,1] = maximal color index used for nodes 1, 2, ..., i-1 which are
   38.41 +            adjacent to node i */
   38.42 +(  if case = 0 then
   38.43 +   (  /* compute z[i,0] */
   38.44 +      min{c in 1..z[i,1]}
   38.45 +      (  if not exists{j in V: j < i and (i,j) in EE} z[j,0] = c then
   38.46 +            c
   38.47 +         else
   38.48 +            z[i,1] + 1
   38.49 +      )
   38.50 +   )
   38.51 +   else
   38.52 +   (  /* compute z[i,1] */
   38.53 +      if not exists{j in V: j < i} (i,j) in EE then
   38.54 +         1
   38.55 +      else
   38.56 +         max{j in V: j < i and (i,j) in EE} z[j,0]
   38.57 +   )
   38.58 +);
   38.59 +
   38.60 +check{(i,j) in E}: z[i,0] != z[j,0];
   38.61 +/* check that all adjacent nodes are assigned distinct colors */
   38.62 +
   38.63 +param nc := max{i in V} z[i,0];
   38.64 +/* number of colors used by the heuristic; obviously, it is an upper
   38.65 +   bound of the optimal solution */
   38.66 +
   38.67 +display nc;
   38.68 +
   38.69 +var x{i in V, c in 1..nc}, binary;
   38.70 +/* x[i,c] = 1 means that node i is assigned color c */
   38.71 +
   38.72 +var u{c in 1..nc}, binary;
   38.73 +/* u[c] = 1 means that color c is used, i.e. assigned to some node */
   38.74 +
   38.75 +s.t. map{i in V}: sum{c in 1..nc} x[i,c] = 1;
   38.76 +/* each node must be assigned exactly one color */
   38.77 +
   38.78 +s.t. arc{(i,j) in E, c in 1..nc}: x[i,c] + x[j,c] <= u[c];
   38.79 +/* adjacent nodes cannot be assigned the same color */
   38.80 +
   38.81 +minimize obj: sum{c in 1..nc} u[c];
   38.82 +/* objective is to minimize the number of colors used */
   38.83 +
   38.84 +data;
   38.85 +
   38.86 +/* These data correspond to the instance myciel3.col from:
   38.87 +   http://mat.gsia.cmu.edu/COLOR/instances.html */
   38.88 +
   38.89 +/* The optimal solution is 4 */
   38.90 +
   38.91 +param n := 11;
   38.92 +
   38.93 +set E :=
   38.94 + 1 2
   38.95 + 1 4
   38.96 + 1 7
   38.97 + 1 9
   38.98 + 2 3
   38.99 + 2 6
  38.100 + 2 8
  38.101 + 3 5
  38.102 + 3 7
  38.103 + 3 10
  38.104 + 4 5
  38.105 + 4 6
  38.106 + 4 10
  38.107 + 5 8
  38.108 + 5 9
  38.109 + 6 11
  38.110 + 7 11
  38.111 + 8 11
  38.112 + 9 11
  38.113 + 10 11
  38.114 +;
  38.115 +
  38.116 +end;
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/examples/cplex/README	Mon Dec 06 13:09:21 2010 +0100
    39.3 @@ -0,0 +1,44 @@
    39.4 +The program module in this subdirectory is a crude implementation of
    39.5 +CPLEX-like interface to GLPK API. It consists of two files: cplex.c and
    39.6 +cplex.h.
    39.7 +
    39.8 +NOTE that this module is NOT a clean room implementation of the CPLEX
    39.9 +callable library. It only implements a CPLEX-like interface to the GLPK
   39.10 +API routines, and its main purpose is to provide possibility to build
   39.11 +and run applications which normally use the CPLEX callable library.
   39.12 +
   39.13 +This module approximately corresponds to CPLEX 9.0.
   39.14 +
   39.15 +Currently this module can be used as a linear programming solver for
   39.16 +Concorde, the state-of-the-art computer code for solving the symmetric
   39.17 +traveling salesman problem (TSP) developed by David Applegate, Robert
   39.18 +Bixby, Vasek Chvatal, and William Cook. For details about Concorde see
   39.19 +its web page at http://www.tsp.gatech.edu/concorde.html.
   39.20 +
   39.21 +To build Concorde along with GLPK you need to do the following:
   39.22 +
   39.23 +1. Configure, build, and install GLPK.
   39.24 +
   39.25 +2. Download the Concorde tarball co031219.tgz (version Dec 19, 2003),
   39.26 +   unpack and unarchive it.
   39.27 +
   39.28 +3. Copy files cplex.h and cplex.c to subdirectory concorde/LP/.
   39.29 +
   39.30 +4. Create file named lpglpk.c in subdirectory concorde/LP/. This file
   39.31 +   must contain the following two lines:
   39.32 +
   39.33 +      #include "cplex.c"
   39.34 +      #include "lpcplex8.c"
   39.35 +
   39.36 +5. Configure Concorde in usual way (./configure) and then build it with
   39.37 +   the following command:
   39.38 +
   39.39 +      make CPPFLAGS=-I. LPSOLVER_INTERFACE=lpglpk.c LPSOLVER_LIB=-lglpk
   39.40 +
   39.41 +   The Concorde executable can be found in subdirectory concorde/TSP/.
   39.42 +
   39.43 +Please note that currently this GLPK interface module does not support
   39.44 +some important features (namely, CPXgetijdiv, CPXmdleave, CPXpivotin,
   39.45 +CPXpivotout, and CPXstrongbranch), so large (more than 1000 nodes) TSP
   39.46 +instances cannot be solved in a reasonable time, and some instances may
   39.47 +cause abnormal termination of Concorde (if CPXgetijdiv is called).
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/examples/cplex/concorde.txt	Mon Dec 06 13:09:21 2010 +0100
    40.3 @@ -0,0 +1,121 @@
    40.4 +Solver:     Concorde-03.12.19 (options used: -s 99)
    40.5 +            http://www.tsp.gatech.edu/concorde.html
    40.6 +LP Solver:  GLPK 4.34 (CPLEX-like interface module examples/cplex)
    40.7 +Computer:   Intel Pentium 4 CPU 3GHz, 2GB of RAM
    40.8 +Platform:   Cygwin 1.5.24 (Windows XP 5.1 Build 2600 Service Pack 4)
    40.9 +Compiler:   GCC 3.4.4 (options used: -O2)
   40.10 +Test set:   http://www.iwr.uni-heidelberg.de/groups/comopt/software/
   40.11 +            TSPLIB95/
   40.12 +
   40.13 +Problem     Solution   B&B   Time, s
   40.14 +---------   --------   ---   -------
   40.15 +a280            2579     1      3.09
   40.16 +ali535        202339     1     21.88
   40.17 +att48          10628     1      0.20
   40.18 +att532         27686     7     74.31
   40.19 +bayg29          1610     1      0.08
   40.20 +bays29          2020     1      0.08
   40.21 +berlin52        7542     1      0.11
   40.22 +bier127       118282     1      0.62
   40.23 +brazil58       25395     1      0.23
   40.24 +brd14051
   40.25 +brg180          1950     1      0.34
   40.26 +burma14         3323     1      0.06
   40.27 +ch130           6110     1      0.92
   40.28 +ch150           6528     1      1.69
   40.29 +d1291
   40.30 +d15112
   40.31 +d1655
   40.32 +d18512
   40.33 +d198           15780     3      4.92
   40.34 +d2103
   40.35 +d493           35002     5    123.89
   40.36 +d657           48913    11    148.17
   40.37 +dantzig42        699     1      0.08
   40.38 +dsj1000     18660188    13    251.00
   40.39 +eil101                                 (failed due to CPXgetijdiv)
   40.40 +eil51            426     1      0.17
   40.41 +eil76            538     1      0.11
   40.42 +fl1400
   40.43 +fl1577
   40.44 +fl3795
   40.45 +fl417          11861     1     47.20
   40.46 +fnl4461
   40.47 +fri26            937     1      0.05
   40.48 +gil262          2378     3     10.39
   40.49 +gr120           6942     1      0.66
   40.50 +gr137          69853     1      2.09
   40.51 +gr17            2085     1      0.03
   40.52 +gr202          40160     1      3.97
   40.53 +gr21            2707     1      0.03
   40.54 +gr229         134602     7     19.45
   40.55 +gr24            1272     1      0.03
   40.56 +gr431         171414     9     40.67
   40.57 +gr48            5046     1      0.22
   40.58 +gr666         294358     3     40.23
   40.59 +gr96           55209     1      1.22
   40.60 +hk48           11461     1      0.08
   40.61 +kroA100        21282     1      0.41
   40.62 +kroA150        26524     1      2.09
   40.63 +kroA200        29368     1      2.44
   40.64 +kroB100        22141     1      1.20
   40.65 +kroB150        26130     1      1.66
   40.66 +kroB200        29437     1      1.41
   40.67 +kroC100        20749     1      0.42
   40.68 +kroD100        21294     1      0.50
   40.69 +kroE100        22068     1      0.94
   40.70 +lin105         14379     1      0.23
   40.71 +lin318         42029     1      4.28
   40.72 +nrw1379
   40.73 +p654           34643     1     17.08
   40.74 +pa561           2763    15    370.70
   40.75 +pcb1173        56892    11    370.30
   40.76 +pcb3038
   40.77 +pcb442         59778    13     35.86
   40.78 +pla33810
   40.79 +pla7397
   40.80 +pla85900
   40.81 +pr1002        259045     1     23.08
   40.82 +pr107          44303     1      0.38
   40.83 +pr124          59030     1      1.23
   40.84 +pr136          96772     1      2.19
   40.85 +pr144          58537     1      0.89
   40.86 +pr152          73682     1      2.73
   40.87 +pr226          80369     1      2.72
   40.88 +pr2392
   40.89 +pr264          49135     1      1.61
   40.90 +pr299          48191     3     14.52
   40.91 +pr439         107217    15    117.75
   40.92 +pr76          108159     1      0.95
   40.93 +rat195          2323     5     12.91
   40.94 +rat575          6773    19    202.52
   40.95 +rat783          8806     1     37.92
   40.96 +rat99           1211     1      0.50
   40.97 +rd100           7910     1      0.28
   40.98 +rd400          15281    11     74.41
   40.99 +rl11849
  40.100 +rl1304
  40.101 +rl1323
  40.102 +rl1889
  40.103 +rl5915
  40.104 +rl5934
  40.105 +si1032         92650     1     82.09
  40.106 +si175          21407     3      8.97
  40.107 +si535          48450     1     71.28
  40.108 +st70             675     1      0.20
  40.109 +swiss42         1273     1      0.06
  40.110 +ts225         126643     1     21.25
  40.111 +tsp225          3916     1     10.14
  40.112 +u1060         224094    13    507.44
  40.113 +u1432
  40.114 +u159           42080     1      0.41
  40.115 +u1817
  40.116 +u2152
  40.117 +u2319
  40.118 +u574           36905     1     32.84
  40.119 +u724           41910    19    238.42
  40.120 +ulysses16       6859     1      0.19
  40.121 +ulysses22       7013     1      0.47
  40.122 +usa13509
  40.123 +vm1084        239297     9    543.38
  40.124 +vm1748
    41.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    41.2 +++ b/examples/cplex/cplex.c	Mon Dec 06 13:09:21 2010 +0100
    41.3 @@ -0,0 +1,2130 @@
    41.4 +/* cplex.c (CPLEX-like interface to GLPK API) */
    41.5 +
    41.6 +/***********************************************************************
    41.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
    41.8 +*
    41.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
   41.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
   41.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
   41.12 +*  E-mail: <mao@gnu.org>.
   41.13 +*
   41.14 +*  GLPK is free software: you can redistribute it and/or modify it
   41.15 +*  under the terms of the GNU General Public License as published by
   41.16 +*  the Free Software Foundation, either version 3 of the License, or
   41.17 +*  (at your option) any later version.
   41.18 +*
   41.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
   41.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   41.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
   41.22 +*  License for more details.
   41.23 +*
   41.24 +*  You should have received a copy of the GNU General Public License
   41.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
   41.26 +***********************************************************************/
   41.27 +
   41.28 +#include <ctype.h>
   41.29 +#include <stdarg.h>
   41.30 +#include <stdio.h>
   41.31 +#include <stdlib.h>
   41.32 +#include <string.h>
   41.33 +#include <glpk.h>
   41.34 +#include "cplex.h"
   41.35 +
   41.36 +struct CPXENV
   41.37 +{     /* environment block */
   41.38 +      CPXLP *list;
   41.39 +      /* linked list of problem objects */
   41.40 +      int *intparam; /* int intparam[]; */
   41.41 +      /* integer control parameters */
   41.42 +      double *dblparam; /* double dblparam[]; */
   41.43 +      /* floating-point control parameters */
   41.44 +};
   41.45 +
   41.46 +struct CPXLP
   41.47 +{     /* problem object */
   41.48 +      CPXENV *env;
   41.49 +      /* pointer to environment block */
   41.50 +      glp_prob *prob;
   41.51 +      /* pointer to underlying GLPK problem object */
   41.52 +      int rflen;
   41.53 +      /* length of the array rflag */
   41.54 +      char *rflag; /* char rflag[rflen]; */
   41.55 +      /* rflag[i], i = 0,...,nrows-1, is a flag of i-th row: */
   41.56 +#define RF_NOT_RANGED   0  /* not ranged */
   41.57 +#define RF_RANGED_POS   1  /* ranged, RHS = lower bound */
   41.58 +#define RF_RANGED_NEG   2  /* ranged, RHS = upper bound */
   41.59 +      int stat;
   41.60 +      /* solution status reported by CPXgetstat; zero means no solution
   41.61 +         exists */
   41.62 +      int meth;
   41.63 +      /* method indicator reported by CPXgetmethod */
   41.64 +      int iwlen;
   41.65 +      /* length of the working array */
   41.66 +      int *iwork; /* int iwork[iwlen] */
   41.67 +      /* working array initialized by binary zeros */
   41.68 +      CPXLP *link;
   41.69 +      /* pointer to another problem object */
   41.70 +};
   41.71 +
   41.72 +struct intparam
   41.73 +{     int which;
   41.74 +      int defv;
   41.75 +      int minv;
   41.76 +      int maxv;
   41.77 +};
   41.78 +
   41.79 +struct dblparam
   41.80 +{     int which;
   41.81 +      double defv;
   41.82 +      double minv;
   41.83 +      double maxv;
   41.84 +};
   41.85 +
   41.86 +struct errstring
   41.87 +{     int code;
   41.88 +      const char *string;
   41.89 +};
   41.90 +
   41.91 +#define BIGINT 2100000000
   41.92 +#define BIGDBL 1e75
   41.93 +
   41.94 +static const struct intparam intparam[] =
   41.95 +{     {CPX_PARAM_ADVIND, 0, 0, 2},
   41.96 +      {CPX_PARAM_AGGIND, -1, -1, BIGINT},
   41.97 +      {CPX_PARAM_DATACHECK, CPX_OFF, CPX_OFF, CPX_ON},
   41.98 +      {CPX_PARAM_DPRIIND, CPX_DPRIIND_AUTO, CPX_DPRIIND_AUTO,
   41.99 +         CPX_DPRIIND_DEVEX},
  41.100 +      {CPX_PARAM_FASTMIP, CPX_OFF, CPX_OFF, CPX_ON}, /* ??? */
  41.101 +      {CPX_PARAM_ITLIM, BIGINT, 0, BIGINT},
  41.102 +      {CPX_PARAM_PERIND, CPX_OFF, CPX_OFF, CPX_ON},
  41.103 +      {CPX_PARAM_PPRIIND, CPX_PPRIIND_AUTO, CPX_PPRIIND_PARTIAL,
  41.104 +         CPX_PPRIIND_FULL},
  41.105 +      {CPX_PARAM_PREIND, CPX_ON, CPX_OFF, CPX_ON},
  41.106 +      {CPX_PARAM_REINV, 0, 0, 10000},
  41.107 +      {CPX_PARAM_SCRIND, CPX_OFF, CPX_OFF, CPX_ON},
  41.108 +      {CPX_PARAM_SIMDISPLAY, 1, 0, 2},
  41.109 +};
  41.110 +
  41.111 +static const struct dblparam dblparam[] =
  41.112 +{     {CPX_PARAM_EPOPT, 1e-6, 1e-9, 1e-1},
  41.113 +      {CPX_PARAM_EPPER, 1e-6, 1e-8, BIGDBL},
  41.114 +      {CPX_PARAM_EPRHS, 1e-6, 1e-9, 1e-1},
  41.115 +      {CPX_PARAM_OBJLLIM, -BIGDBL, -BIGDBL, +BIGDBL},
  41.116 +      {CPX_PARAM_OBJULIM, +BIGDBL, -BIGDBL, +BIGDBL},
  41.117 +};
  41.118 +
  41.119 +static const struct errstring errstring[] =
  41.120 +{     {CPXERR_ARRAY_NOT_ASCENDING, "Array entry %d not ascending"},
  41.121 +      {CPXERR_BAD_ARGUMENT, "Invalid argument"},
  41.122 +      {CPXERR_BAD_CTYPE, "Invalid ctype entry %d"},
  41.123 +      {CPXERR_BAD_FILETYPE, "Invalid filetype"},
  41.124 +      {CPXERR_BAD_LUB, "Invalid bound change indicator entry %d"},
  41.125 +      {CPXERR_BAD_PARAM_NUM, "Invalid parameter number"},
  41.126 +      {CPXERR_BAD_SENSE, "Invalid sense entry %d"},
  41.127 +      {CPXERR_BAD_STATUS, "Invalid status entry %d for basis specificat"
  41.128 +         "ion"},
  41.129 +      {CPXERR_COL_INDEX_RANGE, "Column index %d out of range"},
  41.130 +      {CPXERR_COUNT_RANGE, "Count entry %d negative or larger than allo"
  41.131 +         "wed"},
  41.132 +      {CPXERR_DUP_ENTRY, "Duplicate entry"},
  41.133 +      {CPXERR_FAIL_OPEN_WRITE, "Could not open file '%s' for writing"},
  41.134 +      {CPXERR_INDEX_RANGE, "Index is outside range of valid values"},
  41.135 +      {CPXERR_NEGATIVE_SURPLUS, "Insufficient array length"},
  41.136 +      {CPXERR_NO_BASIC_SOLN, "No basic solution exists"},
  41.137 +      {CPXERR_NO_ENVIRONMENT, "No environment exists"},
  41.138 +      {CPXERR_NO_FILENAME, "File name not specified"},
  41.139 +      {CPXERR_NO_MEMORY, "Out of memory"},
  41.140 +      {CPXERR_NO_PROBLEM, "No problem exists"},
  41.141 +      {CPXERR_NO_SOLN, "No solution exists"},
  41.142 +      {CPXERR_NOT_FIXED, "Only fixed variables are pivoted out"},
  41.143 +      {CPXERR_NULL_NAME, "Null pointer %d in name array"},
  41.144 +      {CPXERR_NULL_POINTER, "Null pointer for required data"},
  41.145 +      {CPXERR_PARAM_TOO_BIG, "Parameter value too big"},
  41.146 +      {CPXERR_PARAM_TOO_SMALL, "Parameter value too small"},
  41.147 +      {CPXERR_ROW_INDEX_RANGE, "Row index %d out of range"},
  41.148 +};
  41.149 +
  41.150 +/**********************************************************************/
  41.151 +
  41.152 +#define xassert glp_assert
  41.153 +#define xprintf glp_printf
  41.154 +#define xmalloc glp_malloc
  41.155 +#define xcalloc glp_calloc
  41.156 +#define xfree   glp_free
  41.157 +
  41.158 +/**********************************************************************/
  41.159 +
  41.160 +static int findintparam(int whichparam)
  41.161 +{     int k, card;
  41.162 +      card = sizeof(intparam) / sizeof(struct intparam);
  41.163 +      for (k = 0; k < card; k++)
  41.164 +         if (intparam[k].which == whichparam) return k;
  41.165 +      return -1;
  41.166 +}
  41.167 +
  41.168 +static int getintparam(CPXENV *env, int whichparam)
  41.169 +{     int k;
  41.170 +      xassert(env != NULL);
  41.171 +      k = findintparam(whichparam);
  41.172 +      xassert(k >= 0);
  41.173 +      return env->intparam[k];
  41.174 +}
  41.175 +
  41.176 +static int finddblparam(int whichparam)
  41.177 +{     int k, card;
  41.178 +      card = sizeof(dblparam) / sizeof(struct dblparam);
  41.179 +      for (k = 0; k < card; k++)
  41.180 +         if (dblparam[k].which == whichparam) return k;
  41.181 +      return -1;
  41.182 +}
  41.183 +
  41.184 +static double getdblparam(CPXENV *env, int whichparam)
  41.185 +{     int k;
  41.186 +      xassert(env != NULL);
  41.187 +      k = finddblparam(whichparam);
  41.188 +      xassert(k >= 0);
  41.189 +      return env->dblparam[k];
  41.190 +}
  41.191 +
  41.192 +static const char *finderrstring(int errcode)
  41.193 +{     int k, card;
  41.194 +      card = sizeof(errstring) / sizeof(struct errstring);
  41.195 +      for (k = 0; k < card; k++)
  41.196 +      {  if (errstring[k].code == errcode)
  41.197 +            return errstring[k].string;
  41.198 +      }
  41.199 +      return NULL;
  41.200 +}
  41.201 +
  41.202 +static int error(CPXENV *env, int errcode, ...)
  41.203 +{     va_list arg;
  41.204 +      char buffer[510];
  41.205 +      xassert(env != NULL);
  41.206 +      if (getintparam(env, CPX_PARAM_SCRIND) == CPX_ON)
  41.207 +      {  xassert(CPXgeterrorstring(env, errcode, buffer) == buffer);
  41.208 +         va_start(arg, errcode);
  41.209 +         vprintf(buffer, arg);
  41.210 +         va_end(arg);
  41.211 +      }
  41.212 +      return errcode;
  41.213 +}
  41.214 +
  41.215 +static int checkenv(CPXENV *env)
  41.216 +{     int errcode;
  41.217 +      if (env == NULL)
  41.218 +         errcode = CPXERR_NO_ENVIRONMENT;
  41.219 +      else
  41.220 +         errcode = 0;
  41.221 +      return errcode;
  41.222 +}
  41.223 +
  41.224 +static checklp(CPXENV *env, CPXLP *lp)
  41.225 +{     int errcode;
  41.226 +      errcode = checkenv(env);
  41.227 +      if (errcode) goto done;
  41.228 +      if (lp == NULL)
  41.229 +         errcode = error(env, CPXERR_NO_PROBLEM);
  41.230 +done: return errcode;
  41.231 +}
  41.232 +
  41.233 +static void invalidate(CPXLP *lp)
  41.234 +{     lp->stat = 0;
  41.235 +      lp->meth = CPX_ALG_NONE;
  41.236 +      return;
  41.237 +}
  41.238 +
  41.239 +static void enlargerflag(CPXLP *lp)
  41.240 +{     int m;
  41.241 +      xassert(lp != NULL);
  41.242 +      m = glp_get_num_rows(lp->prob);
  41.243 +      if (lp->rflen < m)
  41.244 +      {  int rflen = lp->rflen;
  41.245 +         char *rflag = lp->rflag;
  41.246 +         while (lp->rflen < m)
  41.247 +         {  lp->rflen += lp->rflen;
  41.248 +            xassert(lp->rflen > 0);
  41.249 +         }
  41.250 +         lp->rflag = xcalloc(lp->rflen, sizeof(char));
  41.251 +         memcpy(lp->rflag, rflag, rflen);
  41.252 +         xfree(rflag);
  41.253 +      }
  41.254 +      return;
  41.255 +}
  41.256 +
  41.257 +static void enlargeiwork(CPXLP *lp, int len)
  41.258 +{     xassert(len >= 0);
  41.259 +      if (lp->iwlen < len)
  41.260 +      {  xfree(lp->iwork);
  41.261 +         while (lp->iwlen < len)
  41.262 +         {  lp->iwlen += lp->iwlen;
  41.263 +            xassert(lp->iwlen > 0);
  41.264 +         }
  41.265 +         lp->iwork = xcalloc(lp->iwlen, sizeof(int));
  41.266 +         memset(lp->iwork, 0, lp->iwlen * sizeof(int));
  41.267 +      }
  41.268 +      return;
  41.269 +}
  41.270 +
  41.271 +/**********************************************************************/
  41.272 +
  41.273 +int CPXaddcols(CPXENV *env, CPXLP *lp, int ccnt, int nzcnt,
  41.274 +      const double obj[], const int cmatbeg[], const int cmatind[],
  41.275 +      const double cmatval[], const double lb[], const double ub[],
  41.276 +      char *colname[])
  41.277 +{     int j, k, m, n, beg, end, type, errcode;
  41.278 +      double lbnd, ubnd;
  41.279 +      errcode = checklp(env, lp);
  41.280 +      if (errcode) goto done;
  41.281 +      if (ccnt < 0 || nzcnt < 0)
  41.282 +      {  errcode = error(env, CPXERR_BAD_ARGUMENT);
  41.283 +         goto done;
  41.284 +      }
  41.285 +      if (ccnt > 0)
  41.286 +      {  if (cmatbeg == NULL || cmatind == NULL || cmatval == NULL)
  41.287 +         {  errcode = error(env, CPXERR_NULL_POINTER);
  41.288 +            goto done;
  41.289 +         }
  41.290 +      }
  41.291 +      m = glp_get_num_rows(lp->prob);
  41.292 +      n = glp_get_num_cols(lp->prob);
  41.293 +      enlargeiwork(lp, m);
  41.294 +      for (j = 0; j < ccnt; j++)
  41.295 +      {  beg = cmatbeg[j];
  41.296 +         if (j > 0 && !(cmatbeg[j-1] <= beg))
  41.297 +         {  errcode = error(env, CPXERR_ARRAY_NOT_ASCENDING, j);
  41.298 +            goto done;
  41.299 +         }
  41.300 +         if (!(0 <= beg && beg <= nzcnt))
  41.301 +         {  errcode = error(env, CPXERR_INDEX_RANGE);
  41.302 +            goto done;
  41.303 +         }
  41.304 +         end = (j < ccnt-1 ? cmatbeg[j+1] : nzcnt);
  41.305 +         for (k = beg; k < end; k++)
  41.306 +         {  if (!(0 <= cmatind[k] && cmatind[k] < m))
  41.307 +            {  errcode = error(env, CPXERR_ROW_INDEX_RANGE, k);
  41.308 +               goto done;
  41.309 +            }
  41.310 +         }
  41.311 +         errcode = 0;
  41.312 +         for (k = beg; k < end; k++)
  41.313 +         {  if (lp->iwork[cmatind[k]])
  41.314 +            {  errcode = error(env, CPXERR_DUP_ENTRY);
  41.315 +               break;
  41.316 +            }
  41.317 +            lp->iwork[cmatind[k]] = 1;
  41.318 +         }
  41.319 +         for (k = beg; k < end; k++)
  41.320 +            lp->iwork[cmatind[k]] = 0;
  41.321 +         if (errcode) goto done;
  41.322 +         if (colname != NULL)
  41.323 +         {  if (colname[j] == NULL)
  41.324 +            {  errcode = error(env, CPXERR_NULL_NAME, j);
  41.325 +               goto done;
  41.326 +            }
  41.327 +         }
  41.328 +      }
  41.329 +      errcode = 0;
  41.330 +      invalidate(lp);
  41.331 +      if (ccnt > 0)
  41.332 +         glp_add_cols(lp->prob, ccnt);
  41.333 +      for (j = 0; j < ccnt; j++)
  41.334 +      {  if (colname != NULL)
  41.335 +            glp_set_col_name(lp->prob, n+j+1, colname[j]);
  41.336 +         lbnd = (lb == NULL ? 0.0 : lb[j]);
  41.337 +         ubnd = (ub == NULL ? +CPX_INFBOUND : ub[j]);
  41.338 +         if (lbnd <= -CPX_INFBOUND && ubnd >= +CPX_INFBOUND)
  41.339 +            type = GLP_FR;
  41.340 +         else if (ubnd >= +CPX_INFBOUND)
  41.341 +            type = GLP_LO;
  41.342 +         else if (lbnd <= -CPX_INFBOUND)
  41.343 +            type = GLP_UP;
  41.344 +         else if (lbnd != ubnd)
  41.345 +            type = GLP_DB;
  41.346 +         else
  41.347 +            type = GLP_FX;
  41.348 +         glp_set_col_bnds(lp->prob, n+j+1, type, lbnd, ubnd);
  41.349 +         if (obj != NULL)
  41.350 +            glp_set_obj_coef(lp->prob, n+j+1, obj[j]);
  41.351 +         beg = cmatbeg[j];
  41.352 +         end = (j < ccnt-1 ? cmatbeg[j+1] : nzcnt);
  41.353 +         for (k = beg; k < end; k++)
  41.354 +            lp->iwork[k-beg] = cmatind[k]+1;
  41.355 +         glp_set_mat_col(lp->prob, n+j+1, end-beg, lp->iwork-1,
  41.356 +            cmatval+beg-1);
  41.357 +         for (k = beg; k < end; k++)
  41.358 +            lp->iwork[k-beg] = 0;
  41.359 +      }
  41.360 +done: return errcode;
  41.361 +}
  41.362 +
  41.363 +int CPXaddrows(CPXENV *env, CPXLP *lp, int ccnt, int rcnt, int nzcnt,
  41.364 +      const double rhs[], const char sense[], const int rmatbeg[],
  41.365 +      const int rmatind[], const double rmatval[], char *colname[],
  41.366 +      char *rowname[])
  41.367 +{     int i, j, k, m, n, beg, end, type, errcode;
  41.368 +      double temp;
  41.369 +      errcode = checklp(env, lp);
  41.370 +      if (errcode) goto done;
  41.371 +      if (ccnt < 0 || rcnt < 0 || nzcnt < 0)
  41.372 +      {  errcode = error(env, CPXERR_BAD_ARGUMENT);
  41.373 +         goto done;
  41.374 +      }
  41.375 +      if (rcnt > 0)
  41.376 +      {  if (rmatbeg == NULL || rmatind == NULL || rmatval == NULL)
  41.377 +         {  errcode = error(env, CPXERR_NULL_POINTER);
  41.378 +            goto done;
  41.379 +         }
  41.380 +      }
  41.381 +      m = glp_get_num_rows(lp->prob);
  41.382 +      n = glp_get_num_cols(lp->prob);
  41.383 +      enlargeiwork(lp, n+ccnt);
  41.384 +      for (i = 0; i < rcnt; i++)
  41.385 +      {  if (sense != NULL)
  41.386 +         {  if (!(sense[i] == 'L' || sense[i] == 'E' ||
  41.387 +                  sense[i] == 'G' || sense[i] == 'R'))
  41.388 +            {  errcode = error(env, CPXERR_BAD_SENSE, i);
  41.389 +               goto done;
  41.390 +            }
  41.391 +         }
  41.392 +         beg = rmatbeg[i];
  41.393 +         if (i > 0 && !(rmatbeg[i-1] <= beg))
  41.394 +         {  errcode = error(env, CPXERR_ARRAY_NOT_ASCENDING, i);
  41.395 +            goto done;
  41.396 +         }
  41.397 +         if (!(0 <= beg && beg <= nzcnt))
  41.398 +         {  errcode = error(env, CPXERR_INDEX_RANGE);
  41.399 +            goto done;
  41.400 +         }
  41.401 +         end = (i < rcnt-1 ? rmatbeg[i+1] : nzcnt);
  41.402 +         for (k = beg; k < end; k++)
  41.403 +         {  if (!(0 <= rmatind[k] && rmatind[k] < n+ccnt))
  41.404 +            {  errcode = error(env, CPXERR_COL_INDEX_RANGE, k);
  41.405 +               goto done;
  41.406 +            }
  41.407 +         }
  41.408 +         errcode = 0;
  41.409 +         for (k = beg; k < end; k++)
  41.410 +         {  if (lp->iwork[rmatind[k]])
  41.411 +            {  errcode = error(env, CPXERR_DUP_ENTRY);
  41.412 +               break;
  41.413 +            }
  41.414 +            lp->iwork[rmatind[k]] = 1;
  41.415 +         }
  41.416 +         for (k = beg; k < end; k++)
  41.417 +            lp->iwork[rmatind[k]] = 0;
  41.418 +         if (errcode) goto done;
  41.419 +         if (rowname != NULL)
  41.420 +         {  if (rowname[i] == NULL)
  41.421 +            {  errcode = error(env, CPXERR_NULL_NAME, i);
  41.422 +               goto done;
  41.423 +            }
  41.424 +         }
  41.425 +      }
  41.426 +      for (j = 0; j < ccnt; j++)
  41.427 +      {  if (colname != NULL)
  41.428 +         {  if (colname[j] == NULL)
  41.429 +            {  errcode = error(env, CPXERR_NULL_NAME, j);
  41.430 +               goto done;
  41.431 +            }
  41.432 +         }
  41.433 +      }
  41.434 +      errcode = 0;
  41.435 +      invalidate(lp);
  41.436 +      if (rcnt > 0)
  41.437 +         glp_add_rows(lp->prob, rcnt);
  41.438 +      if (ccnt > 0)
  41.439 +         glp_add_cols(lp->prob, ccnt);
  41.440 +      enlargerflag(lp);
  41.441 +      for (i = 0; i < rcnt; i++)
  41.442 +      {  if (rowname != NULL)
  41.443 +            glp_set_row_name(lp->prob, m+i+1, rowname[i]);
  41.444 +         temp = (rhs == NULL ? 0.0 : rhs[i]);
  41.445 +         if (sense == NULL || sense[i] == 'E')
  41.446 +         {  lp->rflag[m+i] = RF_NOT_RANGED;
  41.447 +            type = GLP_FX;
  41.448 +         }
  41.449 +         else if (sense[i] == 'L')
  41.450 +         {  lp->rflag[m+i] = RF_NOT_RANGED;
  41.451 +            type = GLP_UP;
  41.452 +         }
  41.453 +         else if (sense[i] == 'G')
  41.454 +         {  lp->rflag[m+i] = RF_NOT_RANGED;
  41.455 +            type = GLP_LO;
  41.456 +         }
  41.457 +         else if (sense[i] == 'R')
  41.458 +         {  lp->rflag[m+i] = RF_RANGED_POS;
  41.459 +            type = GLP_FX;
  41.460 +         }
  41.461 +         else
  41.462 +            xassert(sense != sense);
  41.463 +         glp_set_row_bnds(lp->prob, m+i+1, type, temp, temp);
  41.464 +         beg = rmatbeg[i];
  41.465 +         end = (i < rcnt-1 ? rmatbeg[i+1] : nzcnt);
  41.466 +         for (k = beg; k < end; k++)
  41.467 +            lp->iwork[k-beg] = rmatind[k]+1;
  41.468 +         glp_set_mat_row(lp->prob, m+i+1, end-beg, lp->iwork-1,
  41.469 +            rmatval+beg-1);
  41.470 +         for (k = beg; k < end; k++)
  41.471 +            lp->iwork[k-beg] = 0;
  41.472 +      }
  41.473 +      for (j = 0; j < ccnt; j++)
  41.474 +      {  if (colname != NULL)
  41.475 +            glp_set_col_name(lp->prob, n+j+1, colname[j]);
  41.476 +         glp_set_col_bnds(lp->prob, n+j+1, GLP_LO, 0.0, 0.0);
  41.477 +      }
  41.478 +done: return errcode;
  41.479 +}
  41.480 +
  41.481 +int CPXbaropt(CPXENV *env, CPXLP *lp)
  41.482 +{     xassert(env == env);
  41.483 +      xassert(lp == lp);
  41.484 +      xprintf("CPXbaropt: not implemented yet\n");
  41.485 +      exit(EXIT_FAILURE);
  41.486 +      return -1;
  41.487 +}
  41.488 +
  41.489 +int CPXbinvrow(CPXENV *env, CPXLP *lp, int i, double y[])
  41.490 +{     xassert(env == env);
  41.491 +      xassert(lp == lp);
  41.492 +      xassert(i == i);
  41.493 +      xassert(y == y);
  41.494 +      xprintf("CPXbinvrow: not implemented yet\n");
  41.495 +      exit(EXIT_FAILURE);
  41.496 +      return -1;
  41.497 +}
  41.498 +
  41.499 +int CPXchgbds(CPXENV *env, CPXLP *lp, int cnt, const int indices[],
  41.500 +      const char lu[], const double bd[])
  41.501 +{     int j, n, type, errcode;
  41.502 +      double lbnd, ubnd;
  41.503 +      errcode = checklp(env, lp);
  41.504 +      if (errcode) goto done;
  41.505 +      if (cnt < 0)
  41.506 +      {  errcode = error(env, CPXERR_BAD_ARGUMENT);
  41.507 +         goto done;
  41.508 +      }
  41.509 +      if (cnt > 0)
  41.510 +      {  if (indices == NULL || lu == NULL || bd == NULL)
  41.511 +         {  errcode = error(env, CPXERR_NULL_POINTER);
  41.512 +            goto done;
  41.513 +         }
  41.514 +      }
  41.515 +      n = glp_get_num_cols(lp->prob);
  41.516 +      for (j = 0; j < cnt; j++)
  41.517 +      {  if (!(0 <= indices[j] && indices[j] < n))
  41.518 +         {  errcode = error(env, CPXERR_COL_INDEX_RANGE, j);
  41.519 +            goto done;
  41.520 +         }
  41.521 +         if (!(lu[j] == 'L' || lu[j] == 'U' || lu[j] == 'B'))
  41.522 +         {  errcode = error(env, CPXERR_BAD_LUB, j);
  41.523 +            goto done;
  41.524 +         }
  41.525 +      }
  41.526 +      errcode = 0;
  41.527 +      invalidate(lp);
  41.528 +      for (j = 0; j < cnt; j++)
  41.529 +      {  type = glp_get_col_type(lp->prob, indices[j]+1);
  41.530 +         lbnd = glp_get_col_lb(lp->prob, indices[j]+1);
  41.531 +         ubnd = glp_get_col_ub(lp->prob, indices[j]+1);
  41.532 +         if (type == GLP_FR || type == GLP_UP)
  41.533 +            lbnd = -CPX_INFBOUND;
  41.534 +         if (type == GLP_FR || type == GLP_LO)
  41.535 +            ubnd = +CPX_INFBOUND;
  41.536 +         if (lu[j] == 'L')
  41.537 +            lbnd = bd[j];
  41.538 +         else if (lu[j] == 'U')
  41.539 +            ubnd = bd[j];
  41.540 +         else if (lu[j] == 'B')
  41.541 +            lbnd = ubnd = bd[j];
  41.542 +         else
  41.543 +            xassert(lu != lu);
  41.544 +         if (lbnd <= -CPX_INFBOUND && ubnd >= +CPX_INFBOUND)
  41.545 +            type = GLP_FR;
  41.546 +         else if (ubnd >= +CPX_INFBOUND)
  41.547 +            type = GLP_LO;
  41.548 +         else if (lbnd <= -CPX_INFBOUND)
  41.549 +            type = GLP_UP;
  41.550 +         else if (lbnd != ubnd)
  41.551 +            type = GLP_DB;
  41.552 +         else
  41.553 +            type = GLP_FX;
  41.554 +         glp_set_col_bnds(lp->prob, indices[j]+1, type, lbnd, ubnd);
  41.555 +      }
  41.556 +done: return errcode;
  41.557 +}
  41.558 +
  41.559 +int CPXchgcoeflist(CPXENV *env, CPXLP *lp, int numcoefs,
  41.560 +      const int rowlist[], const int collist[], const double vallist[])
  41.561 +{     int i, j, k, m, n, rcnt, ccnt, len, ptr, errcode;
  41.562 +      int *head, *next, *ind;
  41.563 +      double *val;
  41.564 +      errcode = checklp(env, lp);
  41.565 +      if (errcode) goto done;
  41.566 +      if (numcoefs < 0)
  41.567 +      {  errcode = error(env, CPXERR_BAD_ARGUMENT);
  41.568 +         goto done;
  41.569 +      }
  41.570 +      if (numcoefs == 0)
  41.571 +      {  errcode = 0;
  41.572 +         goto done;
  41.573 +      }
  41.574 +      if (rowlist == NULL || collist == NULL || vallist == NULL)
  41.575 +      {  errcode = error(env, CPXERR_NULL_POINTER);
  41.576 +         goto done;
  41.577 +      }
  41.578 +      /* check triplets and determine the number of rows and columns
  41.579 +         to be changed */
  41.580 +      m = glp_get_num_rows(lp->prob);
  41.581 +      n = glp_get_num_cols(lp->prob);
  41.582 +      enlargeiwork(lp, m);
  41.583 +      enlargeiwork(lp, n);
  41.584 +      rcnt = ccnt = 0;
  41.585 +      for (k = 0; k < numcoefs; k++)
  41.586 +      {  i = rowlist[k];
  41.587 +         if (!(0 <= i && i < m))
  41.588 +         {  errcode = error(env, CPXERR_ROW_INDEX_RANGE, i);
  41.589 +            goto done;
  41.590 +         }
  41.591 +         if (!(lp->iwork[i] & 0x01))
  41.592 +            rcnt++, lp->iwork[i] |= 0x01;
  41.593 +         j = collist[k];
  41.594 +         if (!(0 <= j && j < n))
  41.595 +         {  errcode = error(env, CPXERR_COL_INDEX_RANGE, j);
  41.596 +            goto done;
  41.597 +         }
  41.598 +         if (!(lp->iwork[j] & 0x02))
  41.599 +            ccnt++, lp->iwork[j] |= 0x02;
  41.600 +      }
  41.601 +      memset(lp->iwork, 0, m * sizeof(int));
  41.602 +      memset(lp->iwork, 0, n * sizeof(int));
  41.603 +      errcode = 0;
  41.604 +      invalidate(lp);
  41.605 +      if (rcnt <= ccnt)
  41.606 +      {  /* change the matrix by rows */
  41.607 +         /* build the linked list of triplets:
  41.608 +            head[i] is a pointer to first triplet for row i
  41.609 +            next[k] is a pointer to next triplet for the same row */
  41.610 +         head = xcalloc(m, sizeof(int));
  41.611 +         for (i = 0; i < m; i++)
  41.612 +            head[i] = -1;
  41.613 +         next = xcalloc(numcoefs, sizeof(int));
  41.614 +         for (k = 0; k < numcoefs; k++)
  41.615 +         {  i = rowlist[k];
  41.616 +            next[k] = head[i];
  41.617 +            head[i] = k;
  41.618 +         }
  41.619 +         /* check duplicate columns */
  41.620 +         for (i = 0; i < m; i++)
  41.621 +         {  for (k = head[i]; k >= 0; k = next[k])
  41.622 +            {  j = collist[k];
  41.623 +               if (lp->iwork[j])
  41.624 +               {  xfree(head);
  41.625 +                  xfree(next);
  41.626 +                  errcode = error(env, CPXERR_DUP_ENTRY);
  41.627 +                  goto done;
  41.628 +               }
  41.629 +               lp->iwork[j] = 1;
  41.630 +            }
  41.631 +            for (k = head[i]; k >= 0; k = next[k])
  41.632 +               lp->iwork[collist[k]] = 0;
  41.633 +         }
  41.634 +         /* perform operation */
  41.635 +         ind = xcalloc(1+n, sizeof(int));
  41.636 +         val = xcalloc(1+n, sizeof(double));
  41.637 +         for (i = 0; i < m; i++)
  41.638 +         {  if (head[i] < 0) continue;
  41.639 +            len = glp_get_mat_row(lp->prob, i+1, ind, val);
  41.640 +            for (ptr = 1; ptr <= len; ptr++)
  41.641 +            {  j = ind[ptr]-1;
  41.642 +               xassert(lp->iwork[j] == 0);
  41.643 +               lp->iwork[j] = ptr;
  41.644 +            }
  41.645 +            for (k = head[i]; k >= 0; k = next[k])
  41.646 +            {  j = collist[k];
  41.647 +               if (lp->iwork[j] == 0)
  41.648 +                  lp->iwork[j] = ++len;
  41.649 +               ptr = lp->iwork[j];
  41.650 +               ind[ptr] = j+1, val[ptr] = vallist[k];
  41.651 +            }
  41.652 +            glp_set_mat_row(lp->prob, i+1, len, ind, val);
  41.653 +            for (ptr = 1; ptr <= len; ptr++)
  41.654 +               lp->iwork[ind[ptr]-1] = 0;
  41.655 +         }
  41.656 +      }
  41.657 +      else
  41.658 +      {  /* change the matrix by columns */
  41.659 +         /* build the linked lists of triplets:
  41.660 +            head[j] is a pointer to first triplet for column j
  41.661 +            next[k] is a pointer to next triplet for the same column */
  41.662 +         head = xcalloc(n, sizeof(int));
  41.663 +         for (j = 0; j < n; j++)
  41.664 +            head[j] = -1;
  41.665 +         next = xcalloc(numcoefs, sizeof(int));
  41.666 +         for (k = 0; k < numcoefs; k++)
  41.667 +         {  j = collist[k];
  41.668 +            next[k] = head[j];
  41.669 +            head[j] = k;
  41.670 +         }
  41.671 +         /* check duplicate rows */
  41.672 +         for (j = 0; j < n; j++)
  41.673 +         {  for (k = head[j]; k >= 0; k = next[k])
  41.674 +            {  i = rowlist[k];
  41.675 +               if (lp->iwork[i])
  41.676 +               {  xfree(head);
  41.677 +                  xfree(next);
  41.678 +                  errcode = error(env, CPXERR_DUP_ENTRY);
  41.679 +                  goto done;
  41.680 +               }
  41.681 +               lp->iwork[i] = 1;
  41.682 +            }
  41.683 +            for (k = head[j]; k >= 0; k = next[k])
  41.684 +               lp->iwork[rowlist[k]] = 0;
  41.685 +         }
  41.686 +         /* perform operation */
  41.687 +         ind = xcalloc(1+m, sizeof(int));
  41.688 +         val = xcalloc(1+m, sizeof(double));
  41.689 +         for (j = 0; j < n; j++)
  41.690 +         {  if (head[j] < 0) continue;
  41.691 +            len = glp_get_mat_col(lp->prob, j+1, ind, val);
  41.692 +            for (ptr = 1; ptr <= len; ptr++)
  41.693 +            {  i = ind[ptr]-1;
  41.694 +               xassert(lp->iwork[i] == 0);
  41.695 +               lp->iwork[i] = ptr;
  41.696 +            }
  41.697 +            for (k = head[j]; k >= 0; k = next[k])
  41.698 +            {  i = rowlist[k];
  41.699 +               if (lp->iwork[i] == 0)
  41.700 +                  lp->iwork[i] = ++len;
  41.701 +               ptr = lp->iwork[i];
  41.702 +               ind[ptr] = i+1, val[ptr] = vallist[k];
  41.703 +            }
  41.704 +            glp_set_mat_col(lp->prob, j+1, len, ind, val);
  41.705 +            for (ptr = 1; ptr <= len; ptr++)
  41.706 +               lp->iwork[ind[ptr]-1] = 0;
  41.707 +         }
  41.708 +      }
  41.709 +      xfree(head);
  41.710 +      xfree(next);
  41.711 +      xfree(ind);
  41.712 +      xfree(val);
  41.713 +done: return errcode;
  41.714 +}
  41.715 +
  41.716 +void CPXchgobjsen(CPXENV *env, CPXLP *lp, int maxormin)
  41.717 +{     int errcode;
  41.718 +      errcode = checklp(env, lp);
  41.719 +      if (errcode) goto done;
  41.720 +      if (!(maxormin == CPX_MIN || maxormin == CPX_MAX))
  41.721 +      {  errcode = error(env, CPXERR_BAD_ARGUMENT);
  41.722 +         goto done;
  41.723 +      }
  41.724 +      errcode = 0;
  41.725 +      invalidate(lp);
  41.726 +      if (maxormin == CPX_MIN)
  41.727 +         glp_set_obj_dir(lp->prob, GLP_MIN);
  41.728 +      else
  41.729 +         glp_set_obj_dir(lp->prob, GLP_MAX);
  41.730 +done: xassert(errcode == errcode);
  41.731 +      return;
  41.732 +}
  41.733 +
  41.734 +int CPXchgsense(CPXENV *env, CPXLP *lp, int cnt, const int indices[],
  41.735 +      const char sense[])
  41.736 +{     int i, m, type, errcode;
  41.737 +      double rhs;
  41.738 +      errcode = checklp(env, lp);
  41.739 +      if (errcode) goto done;
  41.740 +      if (cnt < 0)
  41.741 +      {  errcode = error(env, CPXERR_BAD_ARGUMENT);
  41.742 +         goto done;
  41.743 +      }
  41.744 +      if (cnt > 0 && (indices == NULL || sense == NULL))
  41.745 +      {  errcode = error(env, CPXERR_NULL_POINTER);
  41.746 +         goto done;
  41.747 +      }
  41.748 +      m = glp_get_num_rows(lp->prob);
  41.749 +      for (i = 0; i < cnt; i++)
  41.750 +      {  if (!(0 <= indices[i] && indices[i] < m))
  41.751 +         {  errcode = error(env, CPXERR_ROW_INDEX_RANGE, i);
  41.752 +            goto done;
  41.753 +         }
  41.754 +         if (!(sense[i] == 'L' || sense[i] == 'E' || sense[i] == 'G' ||
  41.755 +               sense[i] == 'R'))
  41.756 +         {  errcode = error(env, CPXERR_BAD_SENSE, i);
  41.757 +            goto done;
  41.758 +         }
  41.759 +      }
  41.760 +      errcode = 0;
  41.761 +      invalidate(lp);
  41.762 +      for (i = 0; i < cnt; i++)
  41.763 +      {  type = glp_get_row_type(lp->prob, indices[i]+1);
  41.764 +         if (lp->rflag[indices[i]] == RF_NOT_RANGED)
  41.765 +         {  if (type == GLP_LO || type == GLP_FX)
  41.766 +               rhs = glp_get_row_lb(lp->prob, indices[i]+1);
  41.767 +            else if (type == GLP_UP)
  41.768 +               rhs = glp_get_row_ub(lp->prob, indices[i]+1);
  41.769 +            else
  41.770 +               xassert(type != type);
  41.771 +         }
  41.772 +         else if (lp->rflag[indices[i]] == RF_RANGED_POS)
  41.773 +         {  xassert(type == GLP_DB || type == GLP_FX);
  41.774 +            rhs = glp_get_row_lb(lp->prob, indices[i]+1);
  41.775 +         }
  41.776 +         else if (lp->rflag[indices[i]] == RF_RANGED_NEG)
  41.777 +         {  xassert(type == GLP_DB);
  41.778 +            rhs = glp_get_row_ub(lp->prob, indices[i]+1);
  41.779 +         }
  41.780 +         else
  41.781 +            xassert(lp != lp);
  41.782 +         if (sense[i] == 'L')
  41.783 +         {  lp->rflag[indices[i]] = RF_NOT_RANGED;
  41.784 +            type = GLP_UP;
  41.785 +         }
  41.786 +         else if (sense[i] == 'E')
  41.787 +         {  lp->rflag[indices[i]] = RF_NOT_RANGED;
  41.788 +            type = GLP_FX;
  41.789 +         }
  41.790 +         else if (sense[i] == 'G')
  41.791 +         {  lp->rflag[indices[i]] = RF_NOT_RANGED;
  41.792 +            type = GLP_LO;
  41.793 +         }
  41.794 +         else if (sense[i] == 'R')
  41.795 +         {  lp->rflag[indices[i]] = RF_RANGED_POS;
  41.796 +            type = GLP_FX;
  41.797 +         }
  41.798 +         else
  41.799 +            xassert(sense != sense);
  41.800 +         glp_set_row_bnds(lp->prob, indices[i]+1, type, rhs, rhs);
  41.801 +      }
  41.802 +done: return errcode;
  41.803 +}
  41.804 +
  41.805 +int CPXcloseCPLEX(CPXENV **_env)
  41.806 +{     CPXENV *env;
  41.807 +      CPXLP *lp;
  41.808 +      int errcode;
  41.809 +      if (_env == NULL)
  41.810 +      {  errcode = CPXERR_NULL_POINTER;
  41.811 +         goto done;
  41.812 +      }
  41.813 +      env = *_env;
  41.814 +      errcode = checkenv(env);
  41.815 +      if (errcode) goto done;
  41.816 +      while (env->list != NULL)
  41.817 +      {  lp = env->list;
  41.818 +         errcode = CPXfreeprob(env, &lp);
  41.819 +         xassert(!errcode);
  41.820 +      }
  41.821 +      xfree(env->intparam);
  41.822 +      xfree(env->dblparam);
  41.823 +      xfree(env);
  41.824 +      *_env = NULL;
  41.825 +      errcode = 0;
  41.826 +done: return errcode;
  41.827 +}
  41.828 +
  41.829 +int CPXcopybase(CPXENV *env, CPXLP *lp, const int cstat[],
  41.830 +      const int rstat[])
  41.831 +{     int i, j, m, n, stat, errcode;
  41.832 +      errcode = checklp(env, lp);
  41.833 +      if (errcode) goto done;
  41.834 +      m = glp_get_num_rows(lp->prob);
  41.835 +      n = glp_get_num_cols(lp->prob);
  41.836 +      if (m > 0 && rstat == NULL || n > 0 && cstat == NULL)
  41.837 +      {  errcode = error(env, CPXERR_NULL_POINTER);
  41.838 +         goto done;
  41.839 +      }
  41.840 +      for (i = 0; i < m; i++)
  41.841 +      {  if (!(rstat[i] == CPX_AT_LOWER || rstat[i] == CPX_BASIC ||
  41.842 +               rstat[i] == CPX_AT_UPPER))
  41.843 +         {  errcode = error(env, CPXERR_BAD_STATUS, i);
  41.844 +            goto done;
  41.845 +         }
  41.846 +      }
  41.847 +      for (j = 0; j < n; j++)
  41.848 +      {  if (!(cstat[j] == CPX_AT_LOWER || cstat[j] == CPX_BASIC ||
  41.849 +               cstat[j] == CPX_AT_UPPER || cstat[j] == CPX_FREE_SUPER))
  41.850 +         {  errcode = error(env, CPXERR_BAD_STATUS, j);
  41.851 +            goto done;
  41.852 +         }
  41.853 +      }
  41.854 +      errcode = 0;
  41.855 +      invalidate(lp);
  41.856 +      for (i = 0; i < m; i++)
  41.857 +      {  if (rstat[i] == CPX_AT_LOWER)
  41.858 +            stat = GLP_NL;
  41.859 +         else if (rstat[i] == CPX_BASIC)
  41.860 +            stat = GLP_BS;
  41.861 +         else if (rstat[i] == CPX_AT_UPPER)
  41.862 +            stat = GLP_NU;
  41.863 +         else
  41.864 +            xassert(rstat != rstat);
  41.865 +         glp_set_row_stat(lp->prob, i+1, stat);
  41.866 +      }
  41.867 +      for (j = 0; j < n; j++)
  41.868 +      {  if (cstat[j] == CPX_AT_LOWER)
  41.869 +            stat = GLP_NL;
  41.870 +         else if (cstat[j] == CPX_BASIC)
  41.871 +            stat = GLP_BS;
  41.872 +         else if (cstat[j] == CPX_AT_UPPER)
  41.873 +            stat = GLP_NU;
  41.874 +         else if (cstat[j] == CPX_FREE_SUPER)
  41.875 +            stat = GLP_NF;
  41.876 +         else
  41.877 +            xassert(cstat != cstat);
  41.878 +         glp_set_col_stat(lp->prob, j+1, stat);
  41.879 +      }
  41.880 +done: return errcode;
  41.881 +}
  41.882 +
  41.883 +int CPXcopybasednorms(CPXENV *env, CPXLP *lp, const int cstat[],
  41.884 +      const int rstat[], const double dnorm[])
  41.885 +{     int errcode;
  41.886 +      errcode = CPXcopybase(env, lp, cstat, rstat);
  41.887 +      xassert(dnorm == dnorm);
  41.888 +      return errcode;
  41.889 +}
  41.890 +
  41.891 +int CPXcopylp(CPXENV *env, CPXLP *lp, int numcols, int numrows,
  41.892 +      int objsen, const double obj[], const double rhs[],
  41.893 +      const char sense[], const int matbeg[], const int matcnt[],
  41.894 +      const int matind[], const double matval[], const double lb[],
  41.895 +      const double ub[], const double rngval[])
  41.896 +{     int errcode;
  41.897 +      errcode = CPXcopylpwnames(env, lp, numcols, numrows, objsen, obj,
  41.898 +         rhs, sense, matbeg, matcnt, matind, matval, lb, ub, rngval,
  41.899 +         NULL, NULL);
  41.900 +      return errcode;
  41.901 +}
  41.902 +
  41.903 +int CPXcopylpwnames(CPXENV *env, CPXLP *lp, int numcols, int numrows,
  41.904 +      int objsen, const double obj[], const double rhs[],
  41.905 +      const char sense[], const int matbeg[], const int matcnt[],
  41.906 +      const int matind[], const double matval[], const double lb[],
  41.907 +      const double ub[], const double rngval[], char *colname[],
  41.908 +      char *rowname[])
  41.909 +{     int i, j, k, beg, end, type, errcode;
  41.910 +      double lbnd, ubnd;
  41.911 +      char name[255+1];
  41.912 +      errcode = checklp(env, lp);
  41.913 +      if (errcode) goto done;
  41.914 +      if (numcols < 0 || numrows < 0)
  41.915 +      {  errcode = error(env, CPXERR_BAD_ARGUMENT);
  41.916 +         goto done;
  41.917 +      }
  41.918 +      if (!(objsen == CPX_MIN || objsen == CPX_MAX))
  41.919 +      {  errcode = error(env, CPXERR_BAD_ARGUMENT);
  41.920 +         goto done;
  41.921 +      }
  41.922 +      if (numcols > 0)
  41.923 +      {  if (matbeg == NULL || matcnt == NULL || matind == NULL ||
  41.924 +               matval == NULL)
  41.925 +         {  errcode = error(env, CPXERR_NULL_POINTER);
  41.926 +            goto done;
  41.927 +         }
  41.928 +      }
  41.929 +      for (i = 0; i < numrows; i++)
  41.930 +      {  if (sense != NULL)
  41.931 +         {  if (!(sense[i] == 'L' || sense[i] == 'E' ||
  41.932 +                  sense[i] == 'G' || sense[i] == 'R'))
  41.933 +            {  errcode = error(env, CPXERR_BAD_SENSE, i);
  41.934 +               goto done;
  41.935 +            }
  41.936 +         }
  41.937 +         if (rowname != NULL)
  41.938 +         {  if (rowname[i] == NULL)
  41.939 +            {  errcode = error(env, CPXERR_NULL_NAME, i);
  41.940 +               goto done;
  41.941 +            }
  41.942 +         }
  41.943 +      }
  41.944 +      enlargeiwork(lp, numrows);
  41.945 +      for (j = 0; j < numcols; j++)
  41.946 +      {  beg = matbeg[j];
  41.947 +         if (j > 0 && !(matbeg[j-1] <= beg))
  41.948 +         {  errcode = error(env, CPXERR_ARRAY_NOT_ASCENDING, j);
  41.949 +            goto done;
  41.950 +         }
  41.951 +         if (beg < 0)
  41.952 +         {  errcode = error(env, CPXERR_INDEX_RANGE);
  41.953 +            goto done;
  41.954 +         }
  41.955 +         end = beg + matcnt[j];
  41.956 +         if (!(beg <= end) || j < numcols-1 && !(end <= matbeg[j+1]))
  41.957 +         {  errcode = error(env, CPXERR_COUNT_RANGE, j);
  41.958 +            goto done;
  41.959 +         }
  41.960 +         for (k = beg; k < end; k++)
  41.961 +         {  if (!(0 <= matind[k] && matind[k] < numrows))
  41.962 +            {  errcode = error(env, CPXERR_ROW_INDEX_RANGE, k);
  41.963 +               goto done;
  41.964 +            }
  41.965 +         }
  41.966 +         errcode = 0;
  41.967 +         for (k = beg; k < end; k++)
  41.968 +         {  if (lp->iwork[matind[k]])
  41.969 +            {  errcode = error(env, CPXERR_DUP_ENTRY);
  41.970 +               break;
  41.971 +            }
  41.972 +            lp->iwork[matind[k]] = 1;
  41.973 +         }
  41.974 +         for (k = beg; k < end; k++)
  41.975 +            lp->iwork[matind[k]] = 0;
  41.976 +         if (errcode) goto done;
  41.977 +         if (colname != NULL)
  41.978 +         {  if (colname[j] != NULL)
  41.979 +            {  errcode = error(env, CPXERR_NULL_NAME, j);
  41.980 +               goto done;
  41.981 +            }
  41.982 +         }
  41.983 +      }
  41.984 +      errcode = 0;
  41.985 +      invalidate(lp);
  41.986 +      if (glp_get_prob_name(lp->prob) == NULL)
  41.987 +         name[0] = '\0';
  41.988 +      else
  41.989 +         strcpy(name, glp_get_prob_name(lp->prob));
  41.990 +      glp_erase_prob(lp->prob);
  41.991 +      glp_set_prob_name(lp->prob, name);
  41.992 +      if (objsen == CPX_MIN)
  41.993 +         glp_set_obj_dir(lp->prob, GLP_MIN);
  41.994 +      else if (objsen == CPX_MAX)
  41.995 +         glp_set_obj_dir(lp->prob, GLP_MAX);
  41.996 +      else
  41.997 +         xassert(objsen != objsen);
  41.998 +      if (numrows > 0)
  41.999 +         glp_add_rows(lp->prob, numrows);
 41.1000 +      enlargerflag(lp);
 41.1001 +      for (i = 0; i < numrows; i++)
 41.1002 +      {  if (rowname != NULL)
 41.1003 +            glp_set_row_name(lp->prob, i+1, rowname[i]);
 41.1004 +         lbnd = ubnd = (rhs == NULL ? 0.0 : rhs[i]);
 41.1005 +         if (sense == NULL || sense[i] == 'E')
 41.1006 +         {  lp->rflag[i] = RF_NOT_RANGED;
 41.1007 +            type = GLP_FX;
 41.1008 +         }
 41.1009 +         else if (sense[i] == 'L')
 41.1010 +         {  lp->rflag[i] = RF_NOT_RANGED;
 41.1011 +            type = GLP_UP;
 41.1012 +         }
 41.1013 +         else if (sense[i] == 'G')
 41.1014 +         {  lp->rflag[i] = RF_NOT_RANGED;
 41.1015 +            type = GLP_LO;
 41.1016 +         }
 41.1017 +         else if (sense[i] == 'R')
 41.1018 +         {  if (rngval == NULL || rngval[i] == 0.0)
 41.1019 +            {  lp->rflag[i] = RF_RANGED_POS;
 41.1020 +               type = GLP_FX;
 41.1021 +            }
 41.1022 +            else if (rngval[i] > 0.0)
 41.1023 +            {  lp->rflag[i] = RF_RANGED_POS;
 41.1024 +               type = GLP_DB;
 41.1025 +               ubnd += rngval[i];
 41.1026 +            }
 41.1027 +            else /* rngval[i] < 0.0 */
 41.1028 +            {  lp->rflag[i] = RF_RANGED_NEG;
 41.1029 +               type = GLP_DB;
 41.1030 +               lbnd += rngval[i];
 41.1031 +            }
 41.1032 +         }
 41.1033 +         else
 41.1034 +            xassert(sense != sense);
 41.1035 +         glp_set_row_bnds(lp->prob, i+1, type, lbnd, ubnd);
 41.1036 +      }
 41.1037 +      if (numcols > 0)
 41.1038 +         glp_add_cols(lp->prob, numcols);
 41.1039 +      for (j = 0; j < numcols; j++)
 41.1040 +      {  if (colname != NULL)
 41.1041 +            glp_set_col_name(lp->prob, j+1, colname[j]);
 41.1042 +         lbnd = (lb == NULL ? 0.0 : lb[j]);
 41.1043 +         ubnd = (ub == NULL ? +CPX_INFBOUND : ub[j]);
 41.1044 +         if (lbnd <= -CPX_INFBOUND && ubnd >= +CPX_INFBOUND)
 41.1045 +            type = GLP_FR;
 41.1046 +         else if (ubnd >= +CPX_INFBOUND)
 41.1047 +            type = GLP_LO;
 41.1048 +         else if (lbnd <= -CPX_INFBOUND)
 41.1049 +            type = GLP_UP;
 41.1050 +         else if (lbnd != ubnd)
 41.1051 +            type = GLP_DB;
 41.1052 +         else
 41.1053 +            type = GLP_FX;
 41.1054 +         glp_set_col_bnds(lp->prob, j+1, type, lbnd, ubnd);
 41.1055 +         if (obj != NULL)
 41.1056 +            glp_set_obj_coef(lp->prob, j+1, obj[j]);
 41.1057 +         beg = matbeg[j];
 41.1058 +         end = beg + matcnt[j];
 41.1059 +         for (k = beg; k < end; k++)
 41.1060 +            lp->iwork[k-beg] = matind[k]+1;
 41.1061 +         glp_set_mat_col(lp->prob, j+1, end-beg, lp->iwork-1,
 41.1062 +            matval+beg-1);
 41.1063 +         for (k = beg; k < end; k++)
 41.1064 +            lp->iwork[k-beg] = 0;
 41.1065 +      }
 41.1066 +done: return errcode;
 41.1067 +}
 41.1068 +
 41.1069 +CPXLP *CPXcreateprob(CPXENV *env, int *status, const char *probname)
 41.1070 +{     CPXLP *lp = NULL;
 41.1071 +      int errcode;
 41.1072 +      errcode = checkenv(env);
 41.1073 +      if (errcode) goto done;
 41.1074 +      lp = xmalloc(sizeof(struct CPXLP));
 41.1075 +      lp->env = env;
 41.1076 +      lp->prob = glp_create_prob();
 41.1077 +      glp_set_prob_name(lp->prob, probname);
 41.1078 +      lp->rflen = 100;
 41.1079 +      lp->rflag = xcalloc(lp->rflen, sizeof(char));
 41.1080 +      lp->iwlen = 100;
 41.1081 +      lp->iwork = xcalloc(lp->iwlen, sizeof(int));
 41.1082 +      memset(lp->iwork, 0, lp->iwlen * sizeof(int));
 41.1083 +      lp->link = env->list;
 41.1084 +      env->list = lp;
 41.1085 +      invalidate(lp);
 41.1086 +done: if (status != NULL) *status = errcode;
 41.1087 +      return lp;
 41.1088 +}
 41.1089 +
 41.1090 +int CPXdelcols(CPXENV *env, CPXLP *lp, int begin, int end)
 41.1091 +{     int j, n, errcode;
 41.1092 +      errcode = checklp(env, lp);
 41.1093 +      if (errcode) goto done;
 41.1094 +      n = glp_get_num_cols(lp->prob);
 41.1095 +      if (!(0 <= begin && begin <= end && end < n))
 41.1096 +      {  errcode = error(env, CPXERR_INDEX_RANGE);
 41.1097 +         goto done;
 41.1098 +      }
 41.1099 +      errcode = 0;
 41.1100 +      invalidate(lp);
 41.1101 +      enlargeiwork(lp, end-begin+1);
 41.1102 +      for (j = begin; j <= end; j++)
 41.1103 +         lp->iwork[j-begin] = j+1;
 41.1104 +      glp_del_cols(lp->prob, end-begin+1, lp->iwork-1);
 41.1105 +      for (j = begin; j <= end; j++)
 41.1106 +         lp->iwork[j-begin] = 0;
 41.1107 +done: return errcode;
 41.1108 +}
 41.1109 +
 41.1110 +int CPXdelrows(CPXENV *env, CPXLP *lp, int begin, int end)
 41.1111 +{     int i, m, errcode;
 41.1112 +      errcode = checklp(env, lp);
 41.1113 +      if (errcode) goto done;
 41.1114 +      m = glp_get_num_rows(lp->prob);
 41.1115 +      if (!(0 <= begin && begin <= end && end < m))
 41.1116 +      {  errcode = error(env, CPXERR_INDEX_RANGE);
 41.1117 +         goto done;
 41.1118 +      }
 41.1119 +      errcode = 0;
 41.1120 +      invalidate(lp);
 41.1121 +      enlargeiwork(lp, end-begin+1);
 41.1122 +      for (i = begin; i <= end; i++)
 41.1123 +         lp->iwork[i-begin] = i+1;
 41.1124 +      glp_del_rows(lp->prob, end-begin+1, lp->iwork-1);
 41.1125 +      for (i = begin; i <= end; i++)
 41.1126 +         lp->iwork[i-begin] = 0;
 41.1127 +      for (i = end+1; i < m; i++)
 41.1128 +         lp->rflag[i-(end-begin+1)] = lp->rflag[i];
 41.1129 +done: return errcode;
 41.1130 +}
 41.1131 +
 41.1132 +int CPXdelsetcols(CPXENV *env, CPXLP *lp, int delstat[])
 41.1133 +{     xassert(env == env);
 41.1134 +      xassert(lp == lp);
 41.1135 +      xassert(delstat == delstat);
 41.1136 +      xprintf("CPXdelsetcols: not implemented yet\n");
 41.1137 +      exit(EXIT_FAILURE);
 41.1138 +      return -1;
 41.1139 +}
 41.1140 +
 41.1141 +int CPXdelsetrows(CPXENV *env, CPXLP *lp, int delstat[])
 41.1142 +{     int i, m, cnt, ind, errcode;
 41.1143 +      errcode = checklp(env, lp);
 41.1144 +      if (errcode) goto done;
 41.1145 +      m = glp_get_num_rows(lp->prob);
 41.1146 +      if (m > 0 && delstat == NULL)
 41.1147 +      {  errcode = error(env, CPXERR_NULL_POINTER);
 41.1148 +         goto done;
 41.1149 +      }
 41.1150 +      errcode = 0;
 41.1151 +      invalidate(lp);
 41.1152 +      enlargeiwork(lp, m);
 41.1153 +      cnt = ind = 0;
 41.1154 +      for (i = 0; i < m; i++)
 41.1155 +      {  if (delstat[i] == 1)
 41.1156 +         {  delstat[i] = -1;
 41.1157 +            lp->iwork[cnt++] = i+1;
 41.1158 +         }
 41.1159 +         else
 41.1160 +         {  delstat[i] = ind;
 41.1161 +            lp->rflag[ind++] = lp->rflag[i];
 41.1162 +         }
 41.1163 +      }
 41.1164 +      if (cnt > 0)
 41.1165 +         glp_del_rows(lp->prob, cnt, lp->iwork-1);
 41.1166 +      for (i = 0; i < cnt; i++)
 41.1167 +         lp->iwork[i] = 0;
 41.1168 +done: return errcode;
 41.1169 +}
 41.1170 +
 41.1171 +int CPXdualopt(CPXENV *env, CPXLP *lp);
 41.1172 +
 41.1173 +int CPXfreeprob(CPXENV *env, CPXLP **_lp)
 41.1174 +{     CPXLP *lp;
 41.1175 +      int errcode;
 41.1176 +      errcode = checkenv(env);
 41.1177 +      if (errcode) goto done;
 41.1178 +      if (_lp == NULL)
 41.1179 +      {  errcode = error(env, CPXERR_NULL_POINTER);
 41.1180 +         goto done;
 41.1181 +      }
 41.1182 +      lp = *_lp;
 41.1183 +      errcode = checklp(env, lp);
 41.1184 +      if (errcode) goto done;
 41.1185 +      errcode = 0;
 41.1186 +      env = lp->env;
 41.1187 +      if (env->list == lp)
 41.1188 +         env->list = lp->link;
 41.1189 +      else
 41.1190 +      {  CPXLP *pp;
 41.1191 +         for (pp = env->list; pp != NULL; pp = pp->link)
 41.1192 +            if (pp->link == lp) break;
 41.1193 +         xassert(pp != NULL);
 41.1194 +         pp->link = lp->link;
 41.1195 +      }
 41.1196 +      glp_delete_prob(lp->prob);
 41.1197 +      xfree(lp->rflag);
 41.1198 +      xfree(lp->iwork);
 41.1199 +      xfree(lp);
 41.1200 +      *_lp = NULL;
 41.1201 +done: return errcode;
 41.1202 +}
 41.1203 +
 41.1204 +int CPXgetbase(CPXENV *env, CPXLP *lp, int cstat[], int rstat[])
 41.1205 +{     int i, j, m, n, stat, errcode;
 41.1206 +      errcode = checklp(env, lp);
 41.1207 +      if (errcode) goto done;
 41.1208 +      if (!lp->stat)
 41.1209 +      {  errcode = error(env, CPXERR_NO_SOLN);
 41.1210 +         goto done;
 41.1211 +      }
 41.1212 +      if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
 41.1213 +         ;
 41.1214 +      else
 41.1215 +      {  errcode = error(env, CPXERR_NO_BASIC_SOLN);
 41.1216 +         goto done;
 41.1217 +      }
 41.1218 +      errcode = 0;
 41.1219 +      if (rstat != NULL)
 41.1220 +      {  m = glp_get_num_rows(lp->prob);
 41.1221 +         for (i = 0; i < m; i++)
 41.1222 +         {  stat = glp_get_row_stat(lp->prob, i+1);
 41.1223 +            if (stat == GLP_BS)
 41.1224 +               rstat[i] = CPX_BASIC;
 41.1225 +            else if (lp->rflag[i] == RF_NOT_RANGED || stat != GLP_NU)
 41.1226 +               rstat[i] = CPX_AT_LOWER;
 41.1227 +            else
 41.1228 +               rstat[i] = CPX_AT_UPPER;
 41.1229 +         }
 41.1230 +      }
 41.1231 +      if (cstat != NULL)
 41.1232 +      {  n = glp_get_num_cols(lp->prob);
 41.1233 +         for (j = 0; j < n; j++)
 41.1234 +         {  stat = glp_get_col_stat(lp->prob, j+1);
 41.1235 +            if (stat == GLP_BS)
 41.1236 +               cstat[j] = CPX_BASIC;
 41.1237 +            else if (stat == GLP_NU)
 41.1238 +               cstat[j] = CPX_AT_UPPER;
 41.1239 +            else if (stat == GLP_NF)
 41.1240 +               cstat[j] = CPX_FREE_SUPER;
 41.1241 +            else
 41.1242 +               cstat[j] = CPX_AT_LOWER;
 41.1243 +         }
 41.1244 +      }
 41.1245 +done: return errcode;
 41.1246 +}
 41.1247 +
 41.1248 +int CPXgetbasednorms(CPXENV *env, CPXLP *lp, int cstat[], int rstat[],
 41.1249 +      double dnorm[])
 41.1250 +{     int i, m, errcode;
 41.1251 +      errcode = CPXgetbase(env, lp, cstat, rstat);
 41.1252 +      if (errcode) goto done;
 41.1253 +      if (dnorm != NULL)
 41.1254 +      {  m = glp_get_num_rows(lp->prob);
 41.1255 +         for (i = 0; i < m; i++) dnorm[i] = 1.0;
 41.1256 +      }
 41.1257 +done: return errcode;
 41.1258 +}
 41.1259 +
 41.1260 +int CPXgetbhead(CPXENV *env, CPXLP *lp, int head[], double x[])
 41.1261 +{     xassert(env == env);
 41.1262 +      xassert(lp == lp);
 41.1263 +      xassert(head == head);
 41.1264 +      xassert(x == x);
 41.1265 +      xprintf("CPXgetbhead: not implemented yet\n");
 41.1266 +      exit(EXIT_FAILURE);
 41.1267 +      return -1;
 41.1268 +}
 41.1269 +
 41.1270 +int CPXgetdblparam(CPXENV *env, int whichparam, double *value)
 41.1271 +{     int k, errcode;
 41.1272 +      errcode = checkenv(env);
 41.1273 +      if (errcode) goto done;
 41.1274 +      k = finddblparam(whichparam);
 41.1275 +      if (k < 0)
 41.1276 +      {  errcode = error(env, CPXERR_BAD_PARAM_NUM);
 41.1277 +         goto done;
 41.1278 +      }
 41.1279 +      errcode = 0;
 41.1280 +      if (value != NULL)
 41.1281 +         *value = env->dblparam[k];
 41.1282 +done: return errcode;
 41.1283 +}
 41.1284 +
 41.1285 +int CPXgetdj(CPXENV *env, CPXLP *lp, double dj[], int begin, int end)
 41.1286 +{     int j, n, errcode;
 41.1287 +      errcode = checklp(env, lp);
 41.1288 +      if (errcode) goto done;
 41.1289 +      n = glp_get_num_cols(lp->prob);
 41.1290 +      if (!(0 <= begin && begin <= end && end < n))
 41.1291 +      {  errcode = error(env, CPXERR_INDEX_RANGE);
 41.1292 +         goto done;
 41.1293 +      }
 41.1294 +      if (!lp->stat)
 41.1295 +      {  errcode = error(env, CPXERR_NO_SOLN);
 41.1296 +         goto done;
 41.1297 +      }
 41.1298 +      errcode = 0;
 41.1299 +      if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
 41.1300 +      {  if (dj != NULL)
 41.1301 +         {  for (j = begin; j <= end; j++)
 41.1302 +               dj[j-begin] = glp_get_col_dual(lp->prob, j+1);
 41.1303 +         }
 41.1304 +      }
 41.1305 +      else
 41.1306 +         xassert(lp != lp);
 41.1307 +done: return errcode;
 41.1308 +}
 41.1309 +
 41.1310 +char *CPXgeterrorstring(CPXENV *env, int errcode, char *buffer)
 41.1311 +{     const char *string;
 41.1312 +      xassert(env == env);
 41.1313 +      string = finderrstring(errcode);
 41.1314 +      if (string == NULL)
 41.1315 +         buffer = NULL;
 41.1316 +      else
 41.1317 +         sprintf(buffer, "CPLEX Error %5d:  %s.\n", errcode, string);
 41.1318 +      return buffer;
 41.1319 +}
 41.1320 +
 41.1321 +int CPXgetijdiv(CPXENV *env, CPXLP *lp, int *idiv, int *jdiv)
 41.1322 +{     xassert(env == env);
 41.1323 +      xassert(lp == lp);
 41.1324 +      xassert(idiv == idiv);
 41.1325 +      xassert(jdiv == jdiv);
 41.1326 +      xprintf("CPXgetijdiv: not implemented yet\n");
 41.1327 +      exit(EXIT_FAILURE);
 41.1328 +      return -1;
 41.1329 +}
 41.1330 +
 41.1331 +int CPXgetintparam(CPXENV *env, int whichparam, int *value)
 41.1332 +{     int k, errcode;
 41.1333 +      errcode = checkenv(env);
 41.1334 +      if (errcode) goto done;
 41.1335 +      k = findintparam(whichparam);
 41.1336 +      if (k < 0)
 41.1337 +      {  errcode = error(env, CPXERR_BAD_PARAM_NUM);
 41.1338 +         goto done;
 41.1339 +      }
 41.1340 +      errcode = 0;
 41.1341 +      if (value != NULL)
 41.1342 +         *value = env->intparam[k];
 41.1343 +done: return errcode;
 41.1344 +}
 41.1345 +
 41.1346 +int CPXgetlb(CPXENV *env, CPXLP *lp, double lb[], int begin, int end)
 41.1347 +{     xassert(env == env);
 41.1348 +      xassert(lp == lp);
 41.1349 +      xassert(lb == lb);
 41.1350 +      xassert(begin == begin);
 41.1351 +      xassert(end == end);
 41.1352 +      xprintf("CPXgetlb: not implemented yet\n");
 41.1353 +      exit(EXIT_FAILURE);
 41.1354 +      return -1;
 41.1355 +}
 41.1356 +
 41.1357 +int CPXgetmethod(CPXENV *env, CPXLP *lp)
 41.1358 +{     int method;
 41.1359 +      if (checklp(env, lp))
 41.1360 +         method = CPX_ALG_NONE;
 41.1361 +      else
 41.1362 +         method = lp->meth;
 41.1363 +      return method;
 41.1364 +}
 41.1365 +
 41.1366 +int CPXgetnumcols(CPXENV *env, CPXLP *lp)
 41.1367 +{     int numcols;
 41.1368 +      if (checklp(env, lp))
 41.1369 +         numcols = 0;
 41.1370 +      else
 41.1371 +         numcols = glp_get_num_cols(lp->prob);
 41.1372 +      return numcols;
 41.1373 +}
 41.1374 +
 41.1375 +int CPXgetnumnz(CPXENV *env, CPXLP *lp)
 41.1376 +{     int numnz;
 41.1377 +      if (checklp(env, lp))
 41.1378 +         numnz = 0;
 41.1379 +      else
 41.1380 +         numnz = glp_get_num_nz(lp->prob);
 41.1381 +      return numnz;
 41.1382 +}
 41.1383 +
 41.1384 +int CPXgetnumrows(CPXENV *env, CPXLP *lp)
 41.1385 +{     int numrows;
 41.1386 +      if (checklp(env, lp))
 41.1387 +         numrows = 0;
 41.1388 +      else
 41.1389 +         numrows = glp_get_num_rows(lp->prob);
 41.1390 +      return numrows;
 41.1391 +}
 41.1392 +
 41.1393 +int CPXgetobjval(CPXENV *env, CPXLP *lp, double *objval)
 41.1394 +{     int errcode;
 41.1395 +      errcode = checklp(env, lp);
 41.1396 +      if (errcode) goto done;
 41.1397 +      if (!lp->stat)
 41.1398 +      {  errcode = error(env, CPXERR_NO_SOLN);
 41.1399 +         goto done;
 41.1400 +      }
 41.1401 +      errcode = 0;
 41.1402 +      if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
 41.1403 +      {  if (objval != NULL)
 41.1404 +            *objval = glp_get_obj_val(lp->prob);
 41.1405 +      }
 41.1406 +      else
 41.1407 +         xassert(lp != lp);
 41.1408 +done: return errcode;
 41.1409 +}
 41.1410 +
 41.1411 +int CPXgetpi(CPXENV *env, CPXLP *lp, double pi[], int begin, int end)
 41.1412 +{     int i, m, errcode;
 41.1413 +      errcode = checklp(env, lp);
 41.1414 +      if (errcode) goto done;
 41.1415 +      m = glp_get_num_rows(lp->prob);
 41.1416 +      if (!(0 <= begin && begin <= end && end < m))
 41.1417 +      {  errcode = error(env, CPXERR_INDEX_RANGE);
 41.1418 +         goto done;
 41.1419 +      }
 41.1420 +      if (!lp->stat)
 41.1421 +      {  errcode = error(env, CPXERR_NO_SOLN);
 41.1422 +         goto done;
 41.1423 +      }
 41.1424 +      errcode = 0;
 41.1425 +      if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
 41.1426 +      {  if (pi != NULL)
 41.1427 +         {  for (i = begin; i <= end; i++)
 41.1428 +               pi[i-begin] = glp_get_row_dual(lp->prob, i+1);
 41.1429 +         }
 41.1430 +      }
 41.1431 +      else
 41.1432 +         xassert(lp != lp);
 41.1433 +done: return errcode;
 41.1434 +}
 41.1435 +
 41.1436 +int CPXgetsense(CPXENV *env, CPXLP *lp, char sense[], int begin,
 41.1437 +      int end)
 41.1438 +{     xassert(env == env);
 41.1439 +      xassert(lp == lp);
 41.1440 +      xassert(sense == sense);
 41.1441 +      xassert(begin == begin);
 41.1442 +      xassert(end == end);
 41.1443 +      xprintf("CPXgetsense: not implemented yet\n");
 41.1444 +      exit(EXIT_FAILURE);
 41.1445 +      return -1;
 41.1446 +}
 41.1447 +
 41.1448 +int CPXgetslack(CPXENV *env, CPXLP *lp, double slack[], int begin,
 41.1449 +      int end)
 41.1450 +{     int i, m, type, errcode;
 41.1451 +      double temp;
 41.1452 +      errcode = checklp(env, lp);
 41.1453 +      if (errcode) goto done;
 41.1454 +      m = glp_get_num_rows(lp->prob);
 41.1455 +      if (!(0 <= begin && begin <= end && end < m))
 41.1456 +      {  errcode = error(env, CPXERR_INDEX_RANGE);
 41.1457 +         goto done;
 41.1458 +      }
 41.1459 +      if (!lp->stat)
 41.1460 +      {  errcode = error(env, CPXERR_NO_SOLN);
 41.1461 +         goto done;
 41.1462 +      }
 41.1463 +      errcode = 0;
 41.1464 +      if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
 41.1465 +      {  if (slack != NULL)
 41.1466 +         {  for (i = begin; i <= end; i++)
 41.1467 +            {  type = glp_get_row_type(lp->prob, i+1);
 41.1468 +               temp = glp_get_row_prim(lp->prob, i+1);
 41.1469 +               if (lp->rflag[i] == RF_NOT_RANGED)
 41.1470 +               {  if (type == GLP_LO || type == GLP_FX)
 41.1471 +                     slack[i-begin] =
 41.1472 +                        glp_get_row_lb(lp->prob, i+1) - temp;
 41.1473 +                  else if (type == GLP_UP)
 41.1474 +                     slack[i-begin] =
 41.1475 +                        glp_get_row_ub(lp->prob, i+1) - temp;
 41.1476 +                  else
 41.1477 +                     xassert(type != type);
 41.1478 +               }
 41.1479 +               else if (lp->rflag[i] == RF_RANGED_POS)
 41.1480 +               {  xassert(type == GLP_DB || type == GLP_FX);
 41.1481 +                  slack[i-begin] =
 41.1482 +                     temp - glp_get_row_lb(lp->prob, i+1);
 41.1483 +               }
 41.1484 +               else if (lp->rflag[i] == RF_RANGED_NEG)
 41.1485 +               {  xassert(type == GLP_DB);
 41.1486 +                  slack[i-begin] =
 41.1487 +                     temp - glp_get_row_ub(lp->prob, i+1);
 41.1488 +               }
 41.1489 +               else
 41.1490 +                  xassert(lp != lp);
 41.1491 +            }
 41.1492 +         }
 41.1493 +      }
 41.1494 +      else
 41.1495 +         xassert(lp != lp);
 41.1496 +done: return errcode;
 41.1497 +}
 41.1498 +
 41.1499 +int CPXgetstat(CPXENV *env, CPXLP *lp)
 41.1500 +{     int stat;
 41.1501 +      if (checklp(env, lp))
 41.1502 +         stat = 0;
 41.1503 +      else
 41.1504 +         stat = lp->stat;
 41.1505 +      return stat;
 41.1506 +}
 41.1507 +
 41.1508 +int CPXgetub(CPXENV *env, CPXLP *lp, double ub[], int begin, int end)
 41.1509 +{     xassert(env == env);
 41.1510 +      xassert(lp == lp);
 41.1511 +      xassert(ub == ub);
 41.1512 +      xassert(begin == begin);
 41.1513 +      xassert(end == end);
 41.1514 +      xprintf("CPXgetub: not implemented yet\n");
 41.1515 +      exit(EXIT_FAILURE);
 41.1516 +      return -1;
 41.1517 +}
 41.1518 +
 41.1519 +int CPXgetweight(CPXENV *env, CPXLP *lp, int rcnt, const int rmatbeg[],
 41.1520 +      const int rmatind[], const double rmatval[], double weight[],
 41.1521 +      int dpriind)
 41.1522 +{     xassert(env == env);
 41.1523 +      xassert(lp == lp);
 41.1524 +      xassert(rcnt == rcnt);
 41.1525 +      xassert(rmatbeg == rmatbeg);
 41.1526 +      xassert(rmatind == rmatind);
 41.1527 +      xassert(rmatval == rmatval);
 41.1528 +      xassert(weight == weight);
 41.1529 +      xassert(dpriind == dpriind);
 41.1530 +      xprintf("CPXgetweight: not implemented yet\n");
 41.1531 +      exit(EXIT_FAILURE);
 41.1532 +      return -1;
 41.1533 +}
 41.1534 +
 41.1535 +int CPXgetx(CPXENV *env, CPXLP *lp, double x[], int begin, int end)
 41.1536 +{     int j, n, errcode;
 41.1537 +      errcode = checklp(env, lp);
 41.1538 +      if (errcode) goto done;
 41.1539 +      n = glp_get_num_cols(lp->prob);
 41.1540 +      if (!(0 <= begin && begin <= end && end < n))
 41.1541 +      {  errcode = error(env, CPXERR_INDEX_RANGE);
 41.1542 +         goto done;
 41.1543 +      }
 41.1544 +      if (!lp->stat)
 41.1545 +      {  errcode = error(env, CPXERR_NO_SOLN);
 41.1546 +         goto done;
 41.1547 +      }
 41.1548 +      errcode = 0;
 41.1549 +      if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
 41.1550 +      {  if (x != NULL)
 41.1551 +         {  for (j = begin; j <= end; j++)
 41.1552 +               x[j-begin] = glp_get_col_prim(lp->prob, j+1);
 41.1553 +         }
 41.1554 +      }
 41.1555 +      else
 41.1556 +         xassert(lp != lp);
 41.1557 +done: return errcode;
 41.1558 +}
 41.1559 +
 41.1560 +int CPXinfodblparam(CPXENV *env, int whichparam, double *defvalue,
 41.1561 +      double *minvalue, double *maxvalue)
 41.1562 +{     int k, errcode;
 41.1563 +      errcode = checkenv(env);
 41.1564 +      if (errcode) goto done;
 41.1565 +      k = finddblparam(whichparam);
 41.1566 +      if (k < 0)
 41.1567 +      {  errcode = error(env, CPXERR_BAD_PARAM_NUM);
 41.1568 +         goto done;
 41.1569 +      }
 41.1570 +      errcode = 0;
 41.1571 +      if (defvalue != NULL)
 41.1572 +         *defvalue = dblparam[k].defv;
 41.1573 +      if (minvalue != NULL)
 41.1574 +         *minvalue = dblparam[k].minv;
 41.1575 +      if (maxvalue != NULL)
 41.1576 +         *maxvalue = dblparam[k].maxv;
 41.1577 +done: return errcode;
 41.1578 +}
 41.1579 +
 41.1580 +int CPXinfointparam(CPXENV *env, int whichparam, int *defvalue,
 41.1581 +      int *minvalue, int *maxvalue)
 41.1582 +{     int k, errcode;
 41.1583 +      errcode = checkenv(env);
 41.1584 +      if (errcode) goto done;
 41.1585 +      k = findintparam(whichparam);
 41.1586 +      if (k < 0)
 41.1587 +      {  errcode = error(env, CPXERR_BAD_PARAM_NUM);
 41.1588 +         goto done;
 41.1589 +      }
 41.1590 +      errcode = 0;
 41.1591 +      if (defvalue != NULL)
 41.1592 +         *defvalue = intparam[k].defv;
 41.1593 +      if (minvalue != NULL)
 41.1594 +         *minvalue = intparam[k].minv;
 41.1595 +      if (maxvalue != NULL)
 41.1596 +         *maxvalue = intparam[k].maxv;
 41.1597 +done: return errcode;
 41.1598 +}
 41.1599 +
 41.1600 +int CPXmdleave(const CPXENV *env, CPXLP *lp, const int goodlist[],
 41.1601 +      int goodlen, double downratio[], double upratio[])
 41.1602 +{     int k;
 41.1603 +      xassert(env == env);
 41.1604 +      xassert(lp == lp);
 41.1605 +      xassert(goodlist == goodlist);
 41.1606 +      xassert(goodlen >= 0);
 41.1607 +      xassert(downratio != NULL);
 41.1608 +      xassert(upratio != NULL);
 41.1609 +      /* not implemented yet */
 41.1610 +      for (k = 0; k < goodlen; k++)
 41.1611 +         downratio[k] = upratio[k] = 0.0;
 41.1612 +      return 0;
 41.1613 +}
 41.1614 +
 41.1615 +int CPXnewcols(CPXENV *env, CPXLP *lp, int ccnt, const double obj[],
 41.1616 +      const double lb[], const double ub[], const char ctype[],
 41.1617 +      char *colname[])
 41.1618 +{     int j, n, kind, type, errcode;
 41.1619 +      double lbnd, ubnd;
 41.1620 +      errcode = checklp(env, lp);
 41.1621 +      if (errcode) goto done;
 41.1622 +      if (ccnt < 0)
 41.1623 +      {  errcode = error(env, CPXERR_BAD_ARGUMENT);
 41.1624 +         goto done;
 41.1625 +      }
 41.1626 +      for (j = 0; j < ccnt; j++)
 41.1627 +      {  if (ctype != NULL)
 41.1628 +         {  if (!(ctype[j] == 'C' || ctype[j] == 'B' ||
 41.1629 +                  ctype[j] == 'I'))
 41.1630 +            {  errcode = error(env, CPXERR_BAD_CTYPE, j);
 41.1631 +               goto done;
 41.1632 +            }
 41.1633 +         }
 41.1634 +         if (colname != NULL)
 41.1635 +         {  if (colname[j] == NULL)
 41.1636 +            {  errcode = error(env, CPXERR_NULL_NAME, j);
 41.1637 +               goto done;
 41.1638 +            }
 41.1639 +         }
 41.1640 +      }
 41.1641 +      errcode = 0;
 41.1642 +      invalidate(lp);
 41.1643 +      n = glp_get_num_cols(lp->prob);
 41.1644 +      if (ccnt > 0)
 41.1645 +         glp_add_cols(lp->prob, ccnt);
 41.1646 +      for (j = 0; j < ccnt; j++)
 41.1647 +      {  if (colname != NULL)
 41.1648 +            glp_set_col_name(lp->prob, n+j+1, colname[j]);
 41.1649 +         if (obj != NULL)
 41.1650 +            glp_set_obj_coef(lp->prob, n+j+1, obj[j]);
 41.1651 +         lbnd = (lb == NULL ? 0.0 : lb[j]);
 41.1652 +         ubnd = (ub == NULL ? 0.0 : ub[j]);
 41.1653 +         if (lbnd <= -CPX_INFBOUND && ubnd >= +CPX_INFBOUND)
 41.1654 +            type = GLP_FR;
 41.1655 +         else if (ubnd >= +CPX_INFBOUND)
 41.1656 +            type = GLP_LO;
 41.1657 +         else if (lbnd <= -CPX_INFBOUND)
 41.1658 +            type = GLP_UP;
 41.1659 +         else if (lbnd != ubnd)
 41.1660 +            type = GLP_DB;
 41.1661 +         else
 41.1662 +            type = GLP_FX;
 41.1663 +         glp_set_col_bnds(lp->prob, n+j+1, type, lbnd, ubnd);
 41.1664 +         if (ctype != NULL)
 41.1665 +         {  if (ctype[j] == 'C')
 41.1666 +               kind = GLP_CV;
 41.1667 +            else if (ctype[j] == 'B')
 41.1668 +               kind = GLP_BV;
 41.1669 +            else if (ctype[j] == 'I')
 41.1670 +               kind = GLP_IV;
 41.1671 +            else
 41.1672 +               xassert(ctype != ctype);
 41.1673 +            glp_set_col_kind(lp->prob, n+j+1, kind);
 41.1674 +         }
 41.1675 +      }
 41.1676 +done: return errcode;
 41.1677 +}
 41.1678 +
 41.1679 +int CPXnewrows(CPXENV *env, CPXLP *lp, int rcnt, const double rhs[],
 41.1680 +      const char sense[], const double rngval[], char *rowname[])
 41.1681 +{     int i, m, type, errcode;
 41.1682 +      double lbnd, ubnd;
 41.1683 +      errcode = checklp(env, lp);
 41.1684 +      if (errcode) goto done;
 41.1685 +      if (rcnt < 0)
 41.1686 +      {  errcode = error(env, CPXERR_BAD_ARGUMENT);
 41.1687 +         goto done;
 41.1688 +      }
 41.1689 +      for (i = 0; i < rcnt; i++)
 41.1690 +      {  if (sense != NULL)
 41.1691 +         {  if (!(sense[i] == 'L' || sense[i] == 'E' ||
 41.1692 +                  sense[i] == 'G' || sense[i] == 'R'))
 41.1693 +            {  errcode = error(env, CPXERR_BAD_SENSE, i);
 41.1694 +               goto done;
 41.1695 +            }
 41.1696 +         }
 41.1697 +         if (rowname != NULL)
 41.1698 +         {  if (rowname[i] == NULL)
 41.1699 +            {  errcode = error(env, CPXERR_NULL_NAME, i);
 41.1700 +               goto done;
 41.1701 +            }
 41.1702 +         }
 41.1703 +      }
 41.1704 +      errcode = 0;
 41.1705 +      invalidate(lp);
 41.1706 +      m = glp_get_num_rows(lp->prob);
 41.1707 +      if (rcnt > 0)
 41.1708 +         glp_add_rows(lp->prob, rcnt);
 41.1709 +      enlargerflag(lp);
 41.1710 +      for (i = 0; i < rcnt; i++)
 41.1711 +      {  if (rowname != NULL)
 41.1712 +            glp_set_row_name(lp->prob, m+i+1, rowname[i]);
 41.1713 +         lbnd = ubnd = (rhs == NULL ? 0.0 : rhs[i]);
 41.1714 +         if (sense == NULL || sense[i] == 'E')
 41.1715 +         {  lp->rflag[m+i] = RF_NOT_RANGED;
 41.1716 +            type = GLP_FX;
 41.1717 +         }
 41.1718 +         else if (sense[i] == 'L')
 41.1719 +         {  lp->rflag[m+i] = RF_NOT_RANGED;
 41.1720 +            type = GLP_UP;
 41.1721 +         }
 41.1722 +         else if (sense[i] == 'G')
 41.1723 +         {  lp->rflag[m+i] = RF_NOT_RANGED;
 41.1724 +            type = GLP_LO;
 41.1725 +         }
 41.1726 +         else if (sense[i] == 'R')
 41.1727 +         {  if (rngval == NULL || rngval[i] == 0.0)
 41.1728 +            {  lp->rflag[m+i] = RF_RANGED_POS;
 41.1729 +               type = GLP_FX;
 41.1730 +            }
 41.1731 +            else if (rngval[i] > 0.0)
 41.1732 +            {  lp->rflag[m+i] = RF_RANGED_POS;
 41.1733 +               type = GLP_DB;
 41.1734 +               ubnd += rngval[i];
 41.1735 +            }
 41.1736 +            else /* rngval[i] < 0.0 */
 41.1737 +            {  lp->rflag[m+i] = RF_RANGED_NEG;
 41.1738 +               type = GLP_DB;
 41.1739 +               lbnd += rngval[i];
 41.1740 +            }
 41.1741 +         }
 41.1742 +         else
 41.1743 +            xassert(sense != sense);
 41.1744 +         glp_set_row_bnds(lp->prob, m+i+1, type, lbnd, ubnd);
 41.1745 +      }
 41.1746 +done: return errcode;
 41.1747 +}
 41.1748 +
 41.1749 +CPXENV *CPXopenCPLEX(int *status)
 41.1750 +{     CPXENV *env;
 41.1751 +      int k, card;
 41.1752 +      env = xmalloc(sizeof(CPXENV));
 41.1753 +      env->list = NULL;
 41.1754 +      card = sizeof(intparam) / sizeof(struct intparam);
 41.1755 +      env->intparam = xcalloc(card, sizeof(int));
 41.1756 +      for (k = 0; k < card; k++)
 41.1757 +         env->intparam[k] = intparam[k].defv;
 41.1758 +      card = sizeof(dblparam) / sizeof(struct dblparam);
 41.1759 +      env->dblparam = xcalloc(card, sizeof(double));
 41.1760 +      for (k = 0; k < card; k++)
 41.1761 +         env->dblparam[k] = dblparam[k].defv;
 41.1762 +      if (status != NULL) *status = 0;
 41.1763 +      return env;
 41.1764 +}
 41.1765 +
 41.1766 +int CPXpivotin(CPXENV *env, CPXLP *lp, const int rlist[], int rlen)
 41.1767 +{     int i, m, errcode;
 41.1768 +      errcode = checklp(env, lp);
 41.1769 +      if (errcode) goto done;
 41.1770 +      if (rlen < 0)
 41.1771 +      {  errcode = error(env, CPXERR_BAD_ARGUMENT);
 41.1772 +         goto done;
 41.1773 +      }
 41.1774 +      if (rlen > 0 && rlist == NULL)
 41.1775 +      {  errcode = error(env, CPXERR_NULL_POINTER);
 41.1776 +         goto done;
 41.1777 +      }
 41.1778 +      m = glp_get_num_rows(lp->prob);
 41.1779 +      for (i = 0; i < rlen; i++)
 41.1780 +      {  if (!(0 <= rlist[i] && rlist[i] < m))
 41.1781 +         {  errcode = error(env, CPXERR_ROW_INDEX_RANGE, i);
 41.1782 +            goto done;
 41.1783 +         }
 41.1784 +      }
 41.1785 +      errcode = 0;
 41.1786 +      for (i = 0; i < rlen; i++)
 41.1787 +      {  if (glp_get_row_type(lp->prob, rlist[i]+1) != GLP_FX)
 41.1788 +         {  if (glp_get_row_stat(lp->prob, rlist[i]+1) != GLP_BS)
 41.1789 +            {  /* not implemented yet */
 41.1790 +               break;
 41.1791 +            }
 41.1792 +         }
 41.1793 +      }
 41.1794 +done: return errcode;
 41.1795 +}
 41.1796 +
 41.1797 +int CPXpivotout(CPXENV *env, CPXLP *lp, const int clist[], int clen)
 41.1798 +{     int j, n, errcode;
 41.1799 +      errcode = checklp(env, lp);
 41.1800 +      if (errcode) goto done;
 41.1801 +      if (clen < 0)
 41.1802 +      {  errcode = error(env, CPXERR_BAD_ARGUMENT);
 41.1803 +         goto done;
 41.1804 +      }
 41.1805 +      if (clen > 0 && clist == NULL)
 41.1806 +      {  errcode = error(env, CPXERR_NULL_POINTER);
 41.1807 +         goto done;
 41.1808 +      }
 41.1809 +      n = glp_get_num_cols(lp->prob);
 41.1810 +      for (j = 0; j < clen; j++)
 41.1811 +      {  if (!(0 <= clist[j] && clist[j] < n))
 41.1812 +         {  errcode = error(env, CPXERR_COL_INDEX_RANGE, j);
 41.1813 +            goto done;
 41.1814 +         }
 41.1815 +         if (glp_get_col_type(lp->prob, clist[j]+1) != GLP_FX)
 41.1816 +         {  errcode = error(env, CPXERR_NOT_FIXED);
 41.1817 +            goto done;
 41.1818 +         }
 41.1819 +      }
 41.1820 +      errcode = 0;
 41.1821 +      for (j = 0; j < clen; j++)
 41.1822 +      {  if (glp_get_col_stat(lp->prob, clist[j]+1) == GLP_BS)
 41.1823 +         {  /* not implemented yet */
 41.1824 +            break;
 41.1825 +         }
 41.1826 +      }
 41.1827 +done: return errcode;
 41.1828 +}
 41.1829 +
 41.1830 +int CPXprimopt(CPXENV *env, CPXLP *lp);
 41.1831 +
 41.1832 +int CPXsavwrite(CPXENV *env, CPXLP *lp, const char *filename)
 41.1833 +{     xassert(env == env);
 41.1834 +      xassert(lp == lp);
 41.1835 +      xassert(filename == filename);
 41.1836 +      xprintf("CPXsavwrite: not implemented yet\n");
 41.1837 +      exit(EXIT_FAILURE);
 41.1838 +      return -1;
 41.1839 +}
 41.1840 +
 41.1841 +int CPXsetdblparam(CPXENV *env, int whichparam, double newvalue)
 41.1842 +{     int k, errcode;
 41.1843 +      errcode = checkenv(env);
 41.1844 +      if (errcode) goto done;
 41.1845 +      k = finddblparam(whichparam);
 41.1846 +      if (k < 0)
 41.1847 +      {  errcode = error(env, CPXERR_BAD_PARAM_NUM);
 41.1848 +         goto done;
 41.1849 +      }
 41.1850 +      if (newvalue < dblparam[k].minv)
 41.1851 +      {  errcode = error(env, CPXERR_PARAM_TOO_SMALL);
 41.1852 +         goto done;
 41.1853 +      }
 41.1854 +      if (newvalue > dblparam[k].maxv)
 41.1855 +      {  errcode = error(env, CPXERR_PARAM_TOO_BIG);
 41.1856 +         goto done;
 41.1857 +      }
 41.1858 +      errcode = 0;
 41.1859 +      env->dblparam[k] = newvalue;
 41.1860 +done: return errcode;
 41.1861 +}
 41.1862 +
 41.1863 +int CPXsetintparam(CPXENV *env, int whichparam, int newvalue)
 41.1864 +{     int k, errcode;
 41.1865 +      errcode = checkenv(env);
 41.1866 +      if (errcode) goto done;
 41.1867 +      k = findintparam(whichparam);
 41.1868 +      if (k < 0)
 41.1869 +      {  errcode = error(env, CPXERR_BAD_PARAM_NUM);
 41.1870 +         goto done;
 41.1871 +      }
 41.1872 +      if (newvalue < intparam[k].minv)
 41.1873 +      {  errcode = error(env, CPXERR_PARAM_TOO_SMALL);
 41.1874 +         goto done;
 41.1875 +      }
 41.1876 +      if (newvalue > intparam[k].maxv)
 41.1877 +      {  errcode = error(env, CPXERR_PARAM_TOO_BIG);
 41.1878 +         goto done;
 41.1879 +      }
 41.1880 +      errcode = 0;
 41.1881 +      env->intparam[k] = newvalue;
 41.1882 +done: return errcode;
 41.1883 +}
 41.1884 +
 41.1885 +int CPXsolninfo(CPXENV *env, CPXLP *lp, int *solnmethod, int *solntype,
 41.1886 +      int *pfeasind, int *dfeasind)
 41.1887 +{     int type, pfeas, dfeas, errcode;
 41.1888 +      errcode = checklp(env, lp);
 41.1889 +      if (errcode) goto done;
 41.1890 +      errcode = 0;
 41.1891 +      if (!lp->stat)
 41.1892 +         type = CPX_NO_SOLN, pfeas = dfeas = 0;
 41.1893 +      else if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
 41.1894 +      {  type = CPX_BASIC_SOLN;
 41.1895 +         pfeas = (glp_get_prim_stat(lp->prob) == GLP_FEAS);
 41.1896 +         dfeas = (glp_get_dual_stat(lp->prob) == GLP_FEAS);
 41.1897 +      }
 41.1898 +      else
 41.1899 +         xassert(lp != lp);
 41.1900 +      if (solnmethod != NULL)
 41.1901 +         *solnmethod = lp->meth;
 41.1902 +      if (solntype != NULL)
 41.1903 +         *solntype = type;
 41.1904 +      if (pfeasind != NULL)
 41.1905 +         *pfeasind = pfeas;
 41.1906 +      if (dfeasind != NULL)
 41.1907 +         *dfeasind = dfeas;
 41.1908 +done: return errcode;
 41.1909 +}
 41.1910 +
 41.1911 +int CPXsolution(CPXENV *env, CPXLP *lp, int *lpstat, double *objval,
 41.1912 +      double x[], double pi[], double slack[], double dj[])
 41.1913 +{     int m, n, errcode;
 41.1914 +      errcode = checklp(env, lp);
 41.1915 +      if (errcode) goto done;
 41.1916 +      if (!lp->stat)
 41.1917 +      {  errcode = error(env, CPXERR_NO_SOLN);
 41.1918 +         goto done;
 41.1919 +      }
 41.1920 +      errcode = 0;
 41.1921 +      m = glp_get_num_rows(lp->prob);
 41.1922 +      n = glp_get_num_cols(lp->prob);
 41.1923 +      if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
 41.1924 +      {  if (lpstat != NULL)
 41.1925 +            *lpstat = CPXgetstat(env, lp);
 41.1926 +         if (objval != NULL)
 41.1927 +            xassert(CPXgetobjval(env, lp, objval) == 0);
 41.1928 +         if (x != NULL)
 41.1929 +            xassert(CPXgetx(env, lp, x, 0, n-1) == 0);
 41.1930 +         if (pi != NULL)
 41.1931 +            xassert(CPXgetpi(env, lp, pi, 0, m-1) == 0);
 41.1932 +         if (slack != NULL)
 41.1933 +            xassert(CPXgetslack(env, lp, slack, 0, m-1) == 0);
 41.1934 +         if (dj != NULL)
 41.1935 +            xassert(CPXgetdj(env, lp, dj, 0, n-1) == 0);
 41.1936 +      }
 41.1937 +      else
 41.1938 +         xassert(lp != lp);
 41.1939 +done: return errcode;
 41.1940 +}
 41.1941 +
 41.1942 +int CPXstrongbranch(CPXENV *env, CPXLP *lp, const int goodlist[],
 41.1943 +      int goodlen, double downpen[], double uppen[], int itlim)
 41.1944 +{     int k;
 41.1945 +      xassert(env == env);
 41.1946 +      xassert(lp == lp);
 41.1947 +      xassert(goodlist == goodlist);
 41.1948 +      xassert(goodlen >= 0);
 41.1949 +      xassert(downpen != NULL);
 41.1950 +      xassert(uppen != NULL);
 41.1951 +      xassert(itlim == itlim);
 41.1952 +      /* not implemented yet */
 41.1953 +      for (k = 0; k < goodlen; k++)
 41.1954 +         downpen[k] = uppen[k] = 0.0;
 41.1955 +      return 0;
 41.1956 +}
 41.1957 +
 41.1958 +static int xstrcasecmp(const char *s1, const char *s2)
 41.1959 +{     int c1, c2;
 41.1960 +      for (;;)
 41.1961 +      {  c1 = toupper((unsigned char)*s1++);
 41.1962 +         c2 = toupper((unsigned char)*s2++);
 41.1963 +         if (c1 == '\0' || c1 != c2) break;
 41.1964 +      }
 41.1965 +      return c1 - c2;
 41.1966 +}
 41.1967 +
 41.1968 +static void getfiletype(const char *filename, char type[3+1])
 41.1969 +{     /* determine filetype from filename */
 41.1970 +      int beg, end;
 41.1971 +      beg = end = strlen(filename);
 41.1972 +      while (beg > 0 && filename[beg-1] != '.' && end - beg < 3)
 41.1973 +         beg--;
 41.1974 +      if (beg > 0 && filename[beg-1] == '.' &&
 41.1975 +          xstrcasecmp(&filename[beg], "gz") == 0)
 41.1976 +      {  end = --beg;
 41.1977 +         while (beg > 0 && filename[beg-1] != '.' && end - beg < 3)
 41.1978 +            beg--;
 41.1979 +      }
 41.1980 +      if (beg > 0 && filename[beg-1] == '.')
 41.1981 +      {  memcpy(type, &filename[beg], end - beg);
 41.1982 +         type[end - beg] = '\0';
 41.1983 +      }
 41.1984 +      else
 41.1985 +         type[0] = '\0';
 41.1986 +      return;
 41.1987 +}
 41.1988 +
 41.1989 +int CPXwriteprob(CPXENV *env, CPXLP *lp, const char *filename,
 41.1990 +      const char *filetype)
 41.1991 +{     glp_prob *copy;
 41.1992 +      int errcode;
 41.1993 +      char type[3+1];
 41.1994 +      errcode = checklp(env, lp);
 41.1995 +      if (errcode) goto done;
 41.1996 +      if (filename == NULL)
 41.1997 +      {  errcode = error(env, CPXERR_NO_FILENAME);
 41.1998 +         goto done;
 41.1999 +      }
 41.2000 +      if (filetype == NULL)
 41.2001 +         getfiletype(filename, type), filetype = type;
 41.2002 +      if (xstrcasecmp(filetype, "MPS") == 0)
 41.2003 +      {  glp_term_out(GLP_OFF);
 41.2004 +         errcode = glp_write_mps(lp->prob, GLP_MPS_FILE, NULL, filename)
 41.2005 +            ;
 41.2006 +         glp_term_out(GLP_ON);
 41.2007 +      }
 41.2008 +      else if (xstrcasecmp(filetype, "LP") == 0)
 41.2009 +      {  glp_term_out(GLP_OFF);
 41.2010 +         errcode = glp_write_lp(lp->prob, NULL, filename);
 41.2011 +         glp_term_out(GLP_ON);
 41.2012 +      }
 41.2013 +      else if (xstrcasecmp(filetype, "RMP") == 0 ||
 41.2014 +               xstrcasecmp(filetype, "REW") == 0)
 41.2015 +      {  copy = glp_create_prob();
 41.2016 +         glp_copy_prob(copy, lp->prob, GLP_OFF);
 41.2017 +         glp_term_out(GLP_OFF);
 41.2018 +         errcode = glp_write_mps(copy, GLP_MPS_DECK, NULL, filename);
 41.2019 +         glp_term_out(GLP_ON);
 41.2020 +         glp_delete_prob(copy);
 41.2021 +      }
 41.2022 +      else if (xstrcasecmp(filetype, "RLP") == 0)
 41.2023 +      {  copy = glp_create_prob();
 41.2024 +         glp_copy_prob(copy, lp->prob, GLP_OFF);
 41.2025 +         glp_term_out(GLP_OFF);
 41.2026 +         errcode = glp_write_lp(copy, NULL, filename);
 41.2027 +         glp_term_out(GLP_ON);
 41.2028 +         glp_delete_prob(copy);
 41.2029 +      }
 41.2030 +      else
 41.2031 +      {  errcode = error(env, CPXERR_BAD_FILETYPE);
 41.2032 +         goto done;
 41.2033 +      }
 41.2034 +      if (errcode)
 41.2035 +         errcode = error(env, CPXERR_FAIL_OPEN_WRITE, filename);
 41.2036 +done: return errcode;
 41.2037 +}
 41.2038 +
 41.2039 +/**********************************************************************/
 41.2040 +
 41.2041 +static int solvelp(CPXENV *env, CPXLP *lp, int meth)
 41.2042 +{     glp_smcp parm;
 41.2043 +      int errcode;
 41.2044 +      errcode = checklp(env, lp);
 41.2045 +      if (errcode) goto done;
 41.2046 +      errcode = 0;
 41.2047 +      invalidate(lp);
 41.2048 +      glp_init_smcp(&parm);
 41.2049 +      switch (meth)
 41.2050 +      {  case CPX_ALG_PRIMAL:
 41.2051 +            parm.meth = GLP_PRIMAL;
 41.2052 +            break;
 41.2053 +         case CPX_ALG_DUAL:
 41.2054 +            parm.meth = GLP_DUAL;
 41.2055 +            break;
 41.2056 +         default:
 41.2057 +            xassert(meth != meth);
 41.2058 +      }
 41.2059 +      switch (getintparam(env, CPX_PARAM_SIMDISPLAY))
 41.2060 +      {  case 0:
 41.2061 +            parm.msg_lev = GLP_MSG_OFF;
 41.2062 +            break;
 41.2063 +         case 1:
 41.2064 +            parm.msg_lev = GLP_MSG_ALL;
 41.2065 +            break;
 41.2066 +         case 2:
 41.2067 +            parm.msg_lev = GLP_MSG_ALL;
 41.2068 +            parm.out_frq = 1;
 41.2069 +            break;
 41.2070 +         default:
 41.2071 +            xassert(env != env);
 41.2072 +      }
 41.2073 +      xassert(getdblparam == getdblparam);
 41.2074 +      switch (getintparam(env, CPX_PARAM_ADVIND))
 41.2075 +      {  case 0:
 41.2076 +            glp_term_out(GLP_OFF);
 41.2077 +            glp_adv_basis(lp->prob, 0);
 41.2078 +            glp_term_out(GLP_ON);
 41.2079 +            break;
 41.2080 +         case 1:
 41.2081 +         case 2:
 41.2082 +            break;
 41.2083 +         default:
 41.2084 +            xassert(env != env);
 41.2085 +      }
 41.2086 +      if (!glp_bf_exists(lp->prob))
 41.2087 +      {  if (glp_factorize(lp->prob) != 0)
 41.2088 +         {  glp_term_out(GLP_OFF);
 41.2089 +            glp_adv_basis(lp->prob, 0);
 41.2090 +            glp_term_out(GLP_ON);
 41.2091 +            if (glp_factorize(lp->prob) != 0)
 41.2092 +               glp_std_basis(lp->prob);
 41.2093 +         }
 41.2094 +      }
 41.2095 +      xassert(glp_simplex(lp->prob, &parm) == 0);
 41.2096 +      switch (glp_get_status(lp->prob))
 41.2097 +      {  case GLP_OPT:
 41.2098 +            lp->stat = CPX_STAT_OPTIMAL;
 41.2099 +            lp->meth = meth;
 41.2100 +            break;
 41.2101 +         case GLP_NOFEAS:
 41.2102 +            lp->stat = CPX_STAT_INFEASIBLE;
 41.2103 +            lp->meth = meth;
 41.2104 +            break;
 41.2105 +         case GLP_UNBND:
 41.2106 +            lp->stat = CPX_STAT_UNBOUNDED;
 41.2107 +            lp->meth = meth;
 41.2108 +            break;
 41.2109 +         default:
 41.2110 +            xassert(lp != lp);
 41.2111 +      }
 41.2112 +done: return errcode;
 41.2113 +}
 41.2114 +
 41.2115 +int CPXprimopt(CPXENV *env, CPXLP *lp)
 41.2116 +{     int errcode;
 41.2117 +      errcode = solvelp(env, lp, CPX_ALG_PRIMAL);
 41.2118 +      return errcode;
 41.2119 +}
 41.2120 +
 41.2121 +int CPXdualopt(CPXENV *env, CPXLP *lp)
 41.2122 +{     int errcode;
 41.2123 +      errcode = solvelp(env, lp, CPX_ALG_DUAL);
 41.2124 +      return errcode;
 41.2125 +}
 41.2126 +
 41.2127 +int CPXlpopt(CPXENV *env, CPXLP *lp)
 41.2128 +{     int errcode;
 41.2129 +      errcode = solvelp(env, lp, CPX_ALG_PRIMAL);
 41.2130 +      return errcode;
 41.2131 +}
 41.2132 +
 41.2133 +/* eof */
    42.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    42.2 +++ b/examples/cplex/cplex.h	Mon Dec 06 13:09:21 2010 +0100
    42.3 @@ -0,0 +1,301 @@
    42.4 +/* cplex.h (CPLEX-like interface to GLPK API) */
    42.5 +
    42.6 +/***********************************************************************
    42.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
    42.8 +*
    42.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
   42.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
   42.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
   42.12 +*  E-mail: <mao@gnu.org>.
   42.13 +*
   42.14 +*  GLPK is free software: you can redistribute it and/or modify it
   42.15 +*  under the terms of the GNU General Public License as published by
   42.16 +*  the Free Software Foundation, either version 3 of the License, or
   42.17 +*  (at your option) any later version.
   42.18 +*
   42.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
   42.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   42.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
   42.22 +*  License for more details.
   42.23 +*
   42.24 +*  You should have received a copy of the GNU General Public License
   42.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
   42.26 +***********************************************************************/
   42.27 +
   42.28 +#ifndef _CPLEX_H
   42.29 +#define _CPLEX_H
   42.30 +
   42.31 +#ifdef __cplusplus
   42.32 +extern "C" {
   42.33 +#endif
   42.34 +
   42.35 +typedef struct CPXENV CPXENV, *CPXENVptr;
   42.36 +typedef struct CPXLP CPXLP, *CPXLPptr;
   42.37 +
   42.38 +#define CPX_VERSION                 900
   42.39 +
   42.40 +#define CPX_OFF                     0
   42.41 +#define CPX_ON                      1
   42.42 +
   42.43 +#define CPX_INFBOUND                1e20
   42.44 +
   42.45 +/* error codes: */
   42.46 +#define CPXERR_NO_MEMORY            1001
   42.47 +#define CPXERR_NO_ENVIRONMENT       1002
   42.48 +#define CPXERR_BAD_ARGUMENT         1003
   42.49 +#define CPXERR_NULL_POINTER         1004
   42.50 +#define CPXERR_NO_PROBLEM           1009
   42.51 +#define CPXERR_BAD_PARAM_NUM        1013
   42.52 +#define CPXERR_PARAM_TOO_SMALL      1014
   42.53 +#define CPXERR_PARAM_TOO_BIG        1015
   42.54 +#define CPXERR_INDEX_RANGE          1200
   42.55 +#define CPXERR_COL_INDEX_RANGE      1201
   42.56 +#define CPXERR_ROW_INDEX_RANGE      1203
   42.57 +#define CPXERR_NEGATIVE_SURPLUS     1207
   42.58 +#define CPXERR_BAD_SENSE            1215
   42.59 +#define CPXERR_NO_SOLN              1217
   42.60 +#define CPXERR_NOT_FIXED            1221
   42.61 +#define CPXERR_DUP_ENTRY            1222
   42.62 +#define CPXERR_NULL_NAME            1224
   42.63 +#define CPXERR_ARRAY_NOT_ASCENDING  1226
   42.64 +#define CPXERR_COUNT_RANGE          1227
   42.65 +#define CPXERR_BAD_LUB              1229
   42.66 +#define CPXERR_BAD_STATUS           1253
   42.67 +#define CPXERR_NO_BASIC_SOLN        1261
   42.68 +#define CPXERR_NO_FILENAME          1421
   42.69 +#define CPXERR_FAIL_OPEN_WRITE      1422
   42.70 +#define CPXERR_BAD_FILETYPE         1424
   42.71 +#define CPXERR_BAD_CTYPE            3021
   42.72 +
   42.73 +/* control parameters: */
   42.74 +#define CPX_PARAM_ADVIND            1001
   42.75 +#define CPX_PARAM_AGGIND            1003
   42.76 +#define CPX_PARAM_DPRIIND           1009
   42.77 +#define CPX_PARAM_EPOPT             1014
   42.78 +#define CPX_PARAM_EPPER             1015
   42.79 +#define CPX_PARAM_EPRHS             1016
   42.80 +#define CPX_PARAM_FASTMIP           1017 /* ??? */
   42.81 +#define CPX_PARAM_SIMDISPLAY        1019
   42.82 +#define CPX_PARAM_ITLIM             1020
   42.83 +#define CPX_PARAM_OBJLLIM           1025
   42.84 +#define CPX_PARAM_OBJULIM           1026
   42.85 +#define CPX_PARAM_PERIND            1027
   42.86 +#define CPX_PARAM_PPRIIND           1029
   42.87 +#define CPX_PARAM_PREIND            1030
   42.88 +#define CPX_PARAM_REINV             1031
   42.89 +#define CPX_PARAM_SCRIND            1035
   42.90 +#define CPX_PARAM_DATACHECK         1056
   42.91 +
   42.92 +/* CPX_PARAM_DPRIIND: */
   42.93 +#define CPX_DPRIIND_AUTO            0
   42.94 +#define CPX_DPRIIND_FULL            1
   42.95 +#define CPX_DPRIIND_STEEP           2
   42.96 +#define CPX_DPRIIND_FULL_STEEP      3
   42.97 +#define CPX_DPRIIND_STEEPQSTART     4
   42.98 +#define CPX_DPRIIND_DEVEX           5
   42.99 +
  42.100 +/* CPX_PARAM_PPRIIND: */
  42.101 +#define CPX_PPRIIND_PARTIAL         (-1)
  42.102 +#define CPX_PPRIIND_AUTO            0
  42.103 +#define CPX_PPRIIND_DEVEX           1
  42.104 +#define CPX_PPRIIND_STEEP           2
  42.105 +#define CPX_PPRIIND_STEEPQSTART     3
  42.106 +#define CPX_PPRIIND_FULL            4
  42.107 +
  42.108 +/* CPXgetprobtype: */
  42.109 +#define CPXPROB_LP                  0
  42.110 +#define CPXPROB_MIP                 1
  42.111 +#define CPXPROB_RELAXED             2
  42.112 +#define CPXPROB_FIXED               3
  42.113 +#define CPXPROB_QP                  5
  42.114 +#define CPXPROB_ZEROEDQP            6
  42.115 +
  42.116 +/* CPXgetobjsen: */
  42.117 +#define CPX_MIN                     1
  42.118 +#define CPX_MAX                     (-1)
  42.119 +
  42.120 +/* CPXgetbase: */
  42.121 +#define CPX_AT_LOWER                0
  42.122 +#define CPX_BASIC                   1
  42.123 +#define CPX_AT_UPPER                2
  42.124 +#define CPX_FREE_SUPER              3
  42.125 +
  42.126 +/* CPXgetstat: */
  42.127 +#define CPX_STAT_OPTIMAL            1
  42.128 +#define CPX_STAT_UNBOUNDED          2
  42.129 +#define CPX_STAT_INFEASIBLE         3
  42.130 +#define CPX_STAT_INForUNBD          4
  42.131 +#define CPX_STAT_OPTIMAL_INFEAS     5
  42.132 +#define CPX_STAT_ABORT_IT_LIM       10
  42.133 +#define CPX_STAT_ABORT_OBJ_LIM      12
  42.134 +
  42.135 +/* CPXgetmethod: */
  42.136 +#define CPX_ALG_NONE                0
  42.137 +#define CPX_ALG_PRIMAL              1
  42.138 +#define CPX_ALG_DUAL                2
  42.139 +#define CPX_ALG_BARRIER             4
  42.140 +
  42.141 +/* CPXsolninfo: */
  42.142 +#define CPX_NO_SOLN                 0
  42.143 +#define CPX_BASIC_SOLN              1
  42.144 +#define CPX_NONBASIC_SOLN           2
  42.145 +#define CPX_PRIMAL_SOLN             3
  42.146 +
  42.147 +int CPXaddcols(CPXENV *env, CPXLP *lp, int ccnt, int nzcnt,
  42.148 +      const double obj[], const int cmatbeg[], const int cmatind[],
  42.149 +      const double cmatval[], const double lb[], const double ub[],
  42.150 +      char *colname[]);
  42.151 +
  42.152 +int CPXaddrows(CPXENV *env, CPXLP *lp, int ccnt, int rcnt, int nzcnt,
  42.153 +      const double rhs[], const char sense[], const int rmatbeg[],
  42.154 +      const int rmatind[], const double rmatval[], char *colname[],
  42.155 +      char *rowname[]);
  42.156 +
  42.157 +int CPXbaropt(CPXENV *env, CPXLP *lp);
  42.158 +
  42.159 +int CPXbinvrow(CPXENV *env, CPXLP *lp, int i, double y[]);
  42.160 +
  42.161 +int CPXchgbds(CPXENV *env, CPXLP *lp, int cnt, const int indices[],
  42.162 +      const char lu[], const double bd[]);
  42.163 +
  42.164 +int CPXchgcoeflist(CPXENV *env, CPXLP *lp, int numcoefs,
  42.165 +      const int rowlist[], const int collist[], const double vallist[]);
  42.166 +
  42.167 +void CPXchgobjsen(CPXENV *env, CPXLP *lp, int maxormin);
  42.168 +
  42.169 +int CPXchgsense(CPXENV *env, CPXLP *lp, int cnt, const int indices[],
  42.170 +      const char sense[]);
  42.171 +
  42.172 +int CPXcloseCPLEX(CPXENV **env);
  42.173 +
  42.174 +int CPXcopybase(CPXENV *env, CPXLP *lp, const int cstat[],
  42.175 +      const int rstat[]);
  42.176 +
  42.177 +int CPXcopybasednorms(CPXENV *env, CPXLP *lp, const int cstat[],
  42.178 +      const int rstat[], const double dnorm[]);
  42.179 +
  42.180 +int CPXcopylp(CPXENV *env, CPXLP *lp, int numcols, int numrows,
  42.181 +      int objsen, const double obj[], const double rhs[],
  42.182 +      const char sense[], const int matbeg[], const int matcnt[],
  42.183 +      const int matind[], const double matval[], const double lb[],
  42.184 +      const double ub[], const double rngval[]);
  42.185 +
  42.186 +int CPXcopylpwnames(CPXENV *env, CPXLP *lp, int numcols, int numrows,
  42.187 +      int objsen, const double obj[], const double rhs[],
  42.188 +      const char sense[], const int matbeg[], const int matcnt[],
  42.189 +      const int matind[], const double matval[], const double lb[],
  42.190 +      const double ub[], const double rngval[], char *colname[],
  42.191 +      char *rowname[]);
  42.192 +
  42.193 +CPXLP *CPXcreateprob(CPXENV *env, int *status, const char *probname);
  42.194 +
  42.195 +int CPXdelcols(CPXENV *env, CPXLP *lp, int begin, int end);
  42.196 +
  42.197 +int CPXdelrows(CPXENV *env, CPXLP *lp, int begin, int end);
  42.198 +
  42.199 +int CPXdelsetcols(CPXENV *env, CPXLP *lp, int delstat[]);
  42.200 +
  42.201 +int CPXdelsetrows(CPXENV *env, CPXLP *lp, int delstat[]);
  42.202 +
  42.203 +int CPXdualopt(CPXENV *env, CPXLP *lp);
  42.204 +
  42.205 +int CPXfreeprob(CPXENV *env, CPXLP **lp);
  42.206 +
  42.207 +int CPXgetbase(CPXENV *env, CPXLP *lp, int cstat[], int rstat[]);
  42.208 +
  42.209 +int CPXgetbasednorms(CPXENV *env, CPXLP *lp, int cstat[], int rstat[],
  42.210 +      double dnorm[]);
  42.211 +
  42.212 +int CPXgetbhead(CPXENV *env, CPXLP *lp, int head[], double x[]);
  42.213 +
  42.214 +int CPXgetdblparam(CPXENV *env, int whichparam, double *value);
  42.215 +
  42.216 +int CPXgetdj(CPXENV *env, CPXLP *lp, double dj[], int begin, int end);
  42.217 +
  42.218 +char *CPXgeterrorstring(CPXENV *env, int errcode, char *buffer);
  42.219 +
  42.220 +int CPXgetijdiv(CPXENV *env, CPXLP *lp, int *idiv, int *jdiv);
  42.221 +
  42.222 +int CPXgetintparam(CPXENV *env, int whichparam, int *value);
  42.223 +
  42.224 +int CPXgetlb(CPXENV *env, CPXLP *lp, double lb[], int begin, int end);
  42.225 +
  42.226 +int CPXgetmethod(CPXENV *env, CPXLP *lp);
  42.227 +
  42.228 +int CPXgetnumcols(CPXENV *env, CPXLP *lp);
  42.229 +
  42.230 +int CPXgetnumnz(CPXENV *env, CPXLP *lp);
  42.231 +
  42.232 +int CPXgetnumrows(CPXENV *env, CPXLP *lp);
  42.233 +
  42.234 +int CPXgetobjval(CPXENV *env, CPXLP *lp, double *objval);
  42.235 +
  42.236 +int CPXgetpi(CPXENV *env, CPXLP *lp, double pi[], int begin, int end);
  42.237 +
  42.238 +int CPXgetsense(CPXENV *env, CPXLP *lp, char sense[], int begin,
  42.239 +      int end);
  42.240 +
  42.241 +int CPXgetslack(CPXENV *env, CPXLP *lp, double slack[], int begin,
  42.242 +      int end);
  42.243 +
  42.244 +int CPXgetstat(CPXENV *env, CPXLP *lp);
  42.245 +
  42.246 +int CPXgetub(CPXENV *env, CPXLP *lp, double ub[], int begin, int end);
  42.247 +
  42.248 +int CPXgetweight(CPXENV *env, CPXLP *lp, int rcnt, const int rmatbeg[],
  42.249 +      const int rmatind[], const double rmatval[], double weight[],
  42.250 +      int dpriind);
  42.251 +
  42.252 +int CPXgetx(CPXENV *env, CPXLP *lp, double x[], int begin, int end);
  42.253 +
  42.254 +int CPXinfodblparam(CPXENV *env, int whichparam, double *defvalue,
  42.255 +      double *minvalue, double *maxvalue);
  42.256 +
  42.257 +int CPXinfointparam(CPXENV *env, int whichparam, int *defvalue,
  42.258 +      int *minvalue, int *maxvalue);
  42.259 +
  42.260 +int CPXlpopt(CPXENV *env, CPXLP *lp);
  42.261 +
  42.262 +int CPXmdleave(const CPXENV *env, CPXLP *lp, const int goodlist[],
  42.263 +      int goodlen, double downratio[], double upratio[]);
  42.264 +
  42.265 +int CPXnewcols(CPXENV *env, CPXLP *lp, int ccnt, const double obj[],
  42.266 +      const double lb[], const double ub[], const char ctype[],
  42.267 +      char *colname[]);
  42.268 +
  42.269 +int CPXnewrows(CPXENV *env, CPXLP *lp, int rcnt, const double rhs[],
  42.270 +      const char sense[], const double rngval[], char *rowname[]);
  42.271 +
  42.272 +CPXENV *CPXopenCPLEX(int *status);
  42.273 +
  42.274 +int CPXpivotin(CPXENV *env, CPXLP *lp, const int rlist[], int rlen);
  42.275 +
  42.276 +int CPXpivotout(CPXENV *env, CPXLP *lp, const int clist[], int clen);
  42.277 +
  42.278 +int CPXprimopt(CPXENV *env, CPXLP *lp);
  42.279 +
  42.280 +int CPXsavwrite(CPXENV *env, CPXLP *lp, const char *filename);
  42.281 +
  42.282 +int CPXsetdblparam(CPXENV *env, int whichparam, double newvalue);
  42.283 +
  42.284 +int CPXsetintparam(CPXENV *env, int whichparam, int newvalue);
  42.285 +
  42.286 +int CPXsolninfo(CPXENV *env, CPXLP *lp, int *solnmethod, int *solntype,
  42.287 +      int *pfeasind, int *dfeasind);
  42.288 +
  42.289 +int CPXsolution(CPXENV *env, CPXLP *lp, int *lpstat, double *objval,
  42.290 +      double x[], double pi[], double slack[], double dj[]);
  42.291 +
  42.292 +int CPXstrongbranch(CPXENV *env, CPXLP *lp, const int goodlist[],
  42.293 +      int goodlen, double downpen[], double uppen[], int itlim);
  42.294 +
  42.295 +int CPXwriteprob(CPXENV *env, CPXLP *lp, const char *filename,
  42.296 +      const char *filetype);
  42.297 +
  42.298 +#ifdef __cplusplus
  42.299 +}
  42.300 +#endif
  42.301 +
  42.302 +#endif
  42.303 +
  42.304 +/* eof */
    43.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    43.2 +++ b/examples/cpp.mod	Mon Dec 06 13:09:21 2010 +0100
    43.3 @@ -0,0 +1,67 @@
    43.4 +/* CPP, Critical Path Problem */
    43.5 +
    43.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
    43.7 +
    43.8 +/* Note: Reduced costs of auxiliary variables phi[j,k] (see below)
    43.9 +         can be only zero or one. The critical path is defined by the
   43.10 +         constraints, whose reduced cost is one. */
   43.11 +
   43.12 +set J;
   43.13 +/* set of jobs (activities) */
   43.14 +
   43.15 +set P{j in J}, in J, default {};
   43.16 +/* P[j] is a subset of jobs that immediately precede job j */
   43.17 +
   43.18 +param t{j in J}, >= 0;
   43.19 +/* duration required to perform job j */
   43.20 +
   43.21 +var x{j in J}, >= 0;
   43.22 +/* starting time of job j */
   43.23 +
   43.24 +s.t. phi{j in J, k in P[j]}: x[j] >= x[k] + t[k];
   43.25 +/* job j can start only after all immediately preceding jobs have been
   43.26 +   completely performed */
   43.27 +
   43.28 +var z;
   43.29 +/* project makespan */
   43.30 +
   43.31 +s.t. fin{j in J}: z >= x[j] + t[j];
   43.32 +/* which is the maximum of the completion times of all the jobs */
   43.33 +
   43.34 +minimize obj: z;
   43.35 +/* the objective is make z as small as possible */
   43.36 +
   43.37 +data;
   43.38 +
   43.39 +/* The optimal solution is 46 */
   43.40 +
   43.41 +param : J :  t :=
   43.42 +        A    3    /* Excavate */
   43.43 +        B    4    /* Lay foundation */
   43.44 +        C    3    /* Rough plumbing */
   43.45 +        D   10    /* Frame */
   43.46 +        E    8    /* Finish exterior */
   43.47 +        F    4    /* Install HVAC */
   43.48 +        G    6    /* Rough electric */
   43.49 +        H    8    /* Sheet rock */
   43.50 +        I    5    /* Install cabinets */
   43.51 +        J    5    /* Paint */
   43.52 +        K    4    /* Final plumbing */
   43.53 +        L    2    /* Final electric */
   43.54 +        M    4    /* Install flooring */
   43.55 +;
   43.56 +
   43.57 +set P[B] := A;
   43.58 +set P[C] := B;
   43.59 +set P[D] := B;
   43.60 +set P[E] := D;
   43.61 +set P[F] := D;
   43.62 +set P[G] := D;
   43.63 +set P[H] := C E F G;
   43.64 +set P[I] := H;
   43.65 +set P[J] := H;
   43.66 +set P[K] := I;
   43.67 +set P[L] := J;
   43.68 +set P[M] := K L;
   43.69 +
   43.70 +end;
    44.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    44.2 +++ b/examples/crypto.mod	Mon Dec 06 13:09:21 2010 +0100
    44.3 @@ -0,0 +1,84 @@
    44.4 +/* CRYPTO, a crypto-arithmetic puzzle */
    44.5 +
    44.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
    44.7 +
    44.8 +/* This problem comes from the newsgroup rec.puzzle.
    44.9 +   The numbers from 1 to 26 are assigned to the letters of the alphabet.
   44.10 +   The numbers beside each word are the total of the values assigned to
   44.11 +   the letters in the word (e.g. for LYRE: L, Y, R, E might be to equal
   44.12 +   5, 9, 20 and 13, or any other combination that add up to 47).
   44.13 +   Find the value of each letter under the equations:
   44.14 +
   44.15 +   BALLET  45     GLEE  66     POLKA      59     SONG     61
   44.16 +   CELLO   43     JAZZ  58     QUARTET    50     SOPRANO  82
   44.17 +   CONCERT 74     LYRE  47     SAXOPHONE 134     THEME    72
   44.18 +   FLUTE   30     OBOE  53     SCALE      51     VIOLIN  100
   44.19 +   FUGUE   50     OPERA 65     SOLO       37     WALTZ    34
   44.20 +
   44.21 +   Solution:
   44.22 +   A, B,C, D, E,F, G, H, I, J, K,L,M, N, O, P,Q, R, S,T,U, V,W, X, Y, Z
   44.23 +   5,13,9,16,20,4,24,21,25,17,23,2,8,12,10,19,7,11,15,3,1,26,6,22,14,18
   44.24 +
   44.25 +   Reference:
   44.26 +   Koalog Constraint Solver <http://www.koalog.com/php/jcs.php>,
   44.27 +   Simple problems, the crypto-arithmetic puzzle ALPHACIPHER. */
   44.28 +
   44.29 +set LETTERS :=
   44.30 +{     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
   44.31 +      'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
   44.32 +};
   44.33 +/* set of letters */
   44.34 +
   44.35 +set VALUES := 1..card(LETTERS);
   44.36 +/* set of values assigned to the letters */
   44.37 +
   44.38 +set WORDS;
   44.39 +/* set of words */
   44.40 +
   44.41 +param total{word in WORDS};
   44.42 +/* total[word] is the total of the values assigned to the letters in
   44.43 +   the word */
   44.44 +
   44.45 +var x{i in LETTERS, j in VALUES}, binary;
   44.46 +/* x[i,j] = 1 means that letter i is assigned value j */
   44.47 +
   44.48 +s.t. phi{i in LETTERS}: sum{j in VALUES} x[i,j] = 1;
   44.49 +
   44.50 +s.t. psi{j in VALUES}: sum{i in LETTERS} x[i,j] = 1;
   44.51 +
   44.52 +s.t. eqn{word in WORDS}: sum{k in 1..length(word), j in VALUES}
   44.53 +      j * x[substr(word,k,1), j] = total[word];
   44.54 +
   44.55 +solve;
   44.56 +
   44.57 +printf{i in LETTERS} "  %s", i;
   44.58 +printf "\n";
   44.59 +
   44.60 +printf{i in LETTERS} " %2d", sum{j in VALUES} j * x[i,j];
   44.61 +printf "\n";
   44.62 +
   44.63 +data;
   44.64 +
   44.65 +param :  WORDS :   total :=
   44.66 +         BALLET       45
   44.67 +         CELLO        43
   44.68 +         CONCERT      74
   44.69 +         FLUTE        30
   44.70 +         FUGUE        50
   44.71 +         GLEE         66
   44.72 +         JAZZ         58
   44.73 +         LYRE         47
   44.74 +         OBOE         53
   44.75 +         OPERA        65
   44.76 +         POLKA        59
   44.77 +         QUARTET      50
   44.78 +         SAXOPHONE   134
   44.79 +         SCALE        51
   44.80 +         SOLO         37
   44.81 +         SONG         61
   44.82 +         SOPRANO      82
   44.83 +         THEME        72
   44.84 +         VIOLIN      100
   44.85 +         WALTZ        34 ;
   44.86 +
   44.87 +end;
    45.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    45.2 +++ b/examples/csv/distances.csv	Mon Dec 06 13:09:21 2010 +0100
    45.3 @@ -0,0 +1,7 @@
    45.4 +plant,market,distance
    45.5 +"Seattle","New York",2.5
    45.6 +"Seattle","Chicago",1.7
    45.7 +"Seattle","Topeka",1.8
    45.8 +"San Diego","New York",2.5
    45.9 +"San Diego","Chicago",1.8
   45.10 +"San Diego","Topeka",1.4
    46.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    46.2 +++ b/examples/csv/markets.csv	Mon Dec 06 13:09:21 2010 +0100
    46.3 @@ -0,0 +1,4 @@
    46.4 +market,demand
    46.5 +"New York",325.
    46.6 +"Chicago",300.
    46.7 +"Topeka",275.
    47.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    47.2 +++ b/examples/csv/parameters.csv	Mon Dec 06 13:09:21 2010 +0100
    47.3 @@ -0,0 +1,2 @@
    47.4 +parameter,value
    47.5 +"transport cost",90.
    48.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    48.2 +++ b/examples/csv/plants.csv	Mon Dec 06 13:09:21 2010 +0100
    48.3 @@ -0,0 +1,3 @@
    48.4 +plant,capacity
    48.5 +"Seattle",350.
    48.6 +"San Diego",600.
    49.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    49.2 +++ b/examples/csv/transp_csv.mod	Mon Dec 06 13:09:21 2010 +0100
    49.3 @@ -0,0 +1,70 @@
    49.4 +# A TRANSPORTATION PROBLEM
    49.5 +#
    49.6 +# This problem finds a least cost shipping schedule that meets
    49.7 +# requirements at markets and supplies at factories.
    49.8 +#
    49.9 +#  References:
   49.10 +#              Dantzig G B, "Linear Programming and Extensions."
   49.11 +#              Princeton University Press, Princeton, New Jersey, 1963,
   49.12 +#              Chapter 3-3.
   49.13 +
   49.14 +set I;
   49.15 +/* canning plants */
   49.16 +
   49.17 +set J;
   49.18 +/* markets */
   49.19 +
   49.20 +set K dimen 2;
   49.21 +/* transportation lane */
   49.22 +
   49.23 +set L;
   49.24 +/* parameters */
   49.25 +
   49.26 +param a{i in I};
   49.27 +/* capacity of plant i in cases */
   49.28 +
   49.29 +param b{j in J};
   49.30 +/* demand at market j in cases */
   49.31 +
   49.32 +param d{i in I, j in J};
   49.33 +/* distance in thousands of miles */
   49.34 +
   49.35 +param e{l in L};
   49.36 +/* parameters */
   49.37 +
   49.38 +param f;
   49.39 +/* freight in dollars per case per thousand miles */
   49.40 +
   49.41 +table tab_plant IN "CSV" "plants.csv" :
   49.42 +  I <- [plant], a ~ capacity;
   49.43 +
   49.44 +table tab_market IN "CSV" "markets.csv" :
   49.45 +  J <- [market], b ~ demand;
   49.46 +
   49.47 +table tab_distance IN "CSV" "distances.csv" :
   49.48 +  K <- [plant, market], d ~ distance;
   49.49 +
   49.50 +table tab_parameter IN "CSV" "parameters.csv" :
   49.51 +  L <- [parameter], e ~ value ;
   49.52 +
   49.53 +param c{i in I, j in J} := e['transport cost'] * d[i,j] / 1000;
   49.54 +/* transport cost in thousands of dollars per case */
   49.55 +
   49.56 +var x{(i,j) in K} >= 0;
   49.57 +/* shipment quantities in cases */
   49.58 +
   49.59 +minimize cost: sum{(i,j) in K} c[i,j] * x[i,j];
   49.60 +/* total transportation costs in thousands of dollars */
   49.61 +
   49.62 +s.t. supply{i in I}: sum{(i,j) in K} x[i,j] <= a[i];
   49.63 +/* observe supply limit at plant i */
   49.64 +
   49.65 +s.t. demand{j in J}: sum{(i,j) in K} x[i,j] >= b[j];
   49.66 +/* satisfy demand at market j */
   49.67 +
   49.68 +solve;
   49.69 +
   49.70 +table tab_result{(i,j) in K} OUT "CSV" "result.csv" :
   49.71 +  i ~ plant, j ~ market, x[i,j] ~ shipment;
   49.72 +
   49.73 +end;
    50.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    50.2 +++ b/examples/dbf/ForestMgt_Model_I_GIS_dbf.mod	Mon Dec 06 13:09:21 2010 +0100
    50.3 @@ -0,0 +1,226 @@
    50.4 +#  Model I Forest Estate Modelling using GLPK/MathProg
    50.5 +#  Reading and writing dbf files
    50.6 +
    50.7 +#  by Noli Sicad --- nsicad@gmail.com
    50.8 +# 18 December 2009
    50.9 +
   50.10 +#  Forest Management 4th Edition 
   50.11 +#  by Lawrence Davis, K. Norman Johnson, Pete Bettinger, Theodore Howard
   50.12 +#  Chapter 11 - Daniel Pickett 
   50.13 +#  http://warnell.forestry.uga.edu/Warnell/Bettinger/mgtbook/index.htm
   50.14 +
   50.15 +#  Model I Formulation
   50.16 +
   50.17 +/*  Note: This is not the full LP model mentioned in the book.
   50.18 +Some of the constraints are deliberately omitted in this model for the purpose of clarity.
   50.19 +
   50.20 +The features of MathProg in this example are:
   50.21 +* reading and writing dbf from regular dbf files,
   50.22 +* reading dbf file (database of shapefile (stands.shp)) (e.g. area parameter),
   50.23 +* using the area data in the constraints and
   50.24 +* writing dbf file from result of LP model.
   50.25 +
   50.26 +Model I - Harvest Scheduling formulation for Sustainable Forest Management (SFM)
   50.27 +
   50.28 +Features are:
   50.29 +* Net Present Value for the objective function (Revenue - Cost)
   50.30 +* Harvest Constraints by period - Sustainable Yield per Period
   50.31 +* Even-Flow Constraint / Volume - Harvest Flow Constraint -  Alpha (1-Apha)
   50.32 +* Even-Flow Constraint / Volume - Harvest Flow Constraint - Beta  (1 +Beta)
   50.33 +* Forest / Land Constraint -- Total Area of the forest
   50.34 +* Forest Stand Constraint  -- Individual stands
   50.35 +
   50.36 +What is next? -- Forest Mgt Carbon Accounting for Climate Change
   50.37 +
   50.38 +Note: The model file that the data containing in
   50.39 +the dbf files is public domain material (so it is compatible with the
   50.40 +GNU GPL) and data can be found in 
   50.41 +http://warnell.forestry.uga.edu/Warnell/Bettinger/mgtbook/index.htm
   50.42 +
   50.43 +# Noli Sicad --- nsicad@gmail.com
   50.44 +
   50.45 +*/
   50.46 +
   50.47 +set G_STAND_TYPE; # A, B, C
   50.48 +
   50.49 +set I_CULTURAL_PRES; 
   50.50 +set J_MGT_YEAR; 
   50.51 +
   50.52 +param K_PERIOD;
   50.53 +param Forest_Cost{G_STAND_TYPE,I_CULTURAL_PRES, J_MGT_YEAR}; # cost
   50.54 +
   50.55 +param Yield_Table_Vol{G_STAND_TYPE, I_CULTURAL_PRES, J_MGT_YEAR, 1..K_PERIOD} >= 0;
   50.56 +
   50.57 +
   50.58 +param Alpha >= 0;
   50.59 +param Beta >= 0;
   50.60 +
   50.61 +param TCost_Table{G_STAND_TYPE, I_CULTURAL_PRES, J_MGT_YEAR, 1..K_PERIOD} >= 0;
   50.62 +
   50.63 +param NetRev_Table{G_STAND_TYPE, I_CULTURAL_PRES, J_MGT_YEAR, 1..K_PERIOD};
   50.64 +
   50.65 +
   50.66 +var XForestLand{g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} >= 0;
   50.67 +
   50.68 +
   50.69 +#reading dbf tables
   50.70 +table tab IN "xBASE" "standtype.dbf": G_STAND_TYPE <- [STAND];
   50.71 +display G_STAND_TYPE;
   50.72 +
   50.73 +
   50.74 +table tab2 IN "xBASE" "cultural_pres.dbf": I_CULTURAL_PRES <- [CUL_PRES];
   50.75 +display I_CULTURAL_PRES;
   50.76 +
   50.77 +table tab3 IN "xBASE" "mgt_year.dbf": J_MGT_YEAR <- [MGT_YEAR];
   50.78 +display J_MGT_YEAR;
   50.79 +
   50.80 +/*
   50.81 +param Forest_Cost{G_STAND_TYPE,I_CULTURAL_PRES, J_MGT_YEAR} default 0; # cost
   50.82 +*/
   50.83 +
   50.84 +set S1, dimen 3;
   50.85 +table tab4 IN "xBASE" "Forest_Cost.dbf": S1 <- [STAND, CUL_PRES, MGT_YEAR],Forest_Cost ~FCOST;
   50.86 +display Forest_Cost;
   50.87 +
   50.88 +set S2, dimen 4;
   50.89 +table tab5 IN "xBASE" "Yield_Table_Vol.dbf": S2 <- [STAND, CUL_PRES, MGT_YEAR, PERIOD],Yield_Table_Vol ~YIELD;
   50.90 +display Yield_Table_Vol;
   50.91 +
   50.92 +set S3, dimen 4;
   50.93 +table tab5 IN "xBASE" "TCost_Table.dbf": S3 <- [STAND, CUL_PRES, MGT_YEAR, PERIOD],TCost_Table ~TCOST;
   50.94 +display TCost_Table;
   50.95 +
   50.96 +
   50.97 +set S4, dimen 4;
   50.98 +table tab5 IN "xBASE" "NetRev_Table.dbf": S4 <- [STAND, CUL_PRES, MGT_YEAR, PERIOD],NetRev_Table ~NETREV;
   50.99 +display NetRev_Table;
  50.100 +
  50.101 +
  50.102 +param MGT;
  50.103 +
  50.104 +param Area_Stand_Indi{g in G_STAND_TYPE, m in 1..MGT} default 0; 
  50.105 +
  50.106 +set ST, dimen 2;
  50.107 +table tab5 IN "xBASE" "stands.dbf": ST <- [VEG_TYPE, MGT], Area_Stand_Indi ~ACRES;
  50.108 +display Area_Stand_Indi;
  50.109 +
  50.110 +param Area_Stand_Type{g in G_STAND_TYPE}:= sum {m in 1..MGT } Area_Stand_Indi[g,m];
  50.111 +display Area_Stand_Type;
  50.112 +
  50.113 +
  50.114 +param Total_Area := sum {g in G_STAND_TYPE, m in 1..MGT } Area_Stand_Indi[g,m];
  50.115 +display Total_Area;
  50.116 +
  50.117 +param Harvest_Min_Vol_Period;
  50.118 +
  50.119 +
  50.120 +var NetPresentValue;
  50.121 +
  50.122 +# Objective function
  50.123 +maximize Net_Present_Value: NetPresentValue;
  50.124 +
  50.125 +subject to NPV:
  50.126 +   NetPresentValue = sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} Forest_Cost[g,i,j] * XForestLand[g,i,j];
  50.127 +
  50.128 +# Harvest Constraint by Period
  50.129 +subject to Harvest_Period_H {k in 1..K_PERIOD}:
  50.130 +   sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k] * XForestLand[g,i,j] >= Harvest_Min_Vol_Period;
  50.131 +   
  50.132 +
  50.133 +#Even-Flow Constraint / Volume - Harvest Flow Constraint - Alpha
  50.134 +subject to Even_Flow_Constaints_Alpha {k in 6..K_PERIOD-1}:
  50.135 +    (1 - Alpha) * sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k] * XForestLand[g,i,j] -
  50.136 +    sum {g in G_STAND_TYPE,i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k+1] * XForestLand[g,i,j] <= 0;
  50.137 +
  50.138 +# Even-Flow Constraint / Volume - Harvest Flow Constraint - Beta
  50.139 +subject to Even_Flow_Constaints_Beta {k in 6..K_PERIOD-1}:
  50.140 +    (1 + Beta) * sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k] * XForestLand[g,i,j] -
  50.141 +    sum {g in G_STAND_TYPE,i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k+1] * XForestLand[g,i,j] >= 0;
  50.142 +   
  50.143 +# Forest / Land Constraints
  50.144 +subject to Total_Area_Constraint: 
  50.145 +  sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} XForestLand[g,i,j] <= Total_Area;
  50.146 +display Total_Area;   
  50.147 +
  50.148 +# Forest / Land Constraints for A B C
  50.149 +subject to Area {g in G_STAND_TYPE}:
  50.150 +   sum {i in I_CULTURAL_PRES,j in J_MGT_YEAR} XForestLand[g,i,j] = Area_Stand_Type[g];
  50.151 +
  50.152 +
  50.153 +
  50.154 +solve;
  50.155 +#RESULT SECTION
  50.156 +printf '#################################\n';
  50.157 +printf 'Forest Management Model I - Noli Sicad\n';
  50.158 +printf '\n';
  50.159 +printf 'Net Present Value = %.2f\n', NetPresentValue;
  50.160 +printf '\n';
  50.161 +
  50.162 +printf '\n';
  50.163 +printf 'Variables\n';
  50.164 +printf 'Stand_Type  Age_Class  Mgt_Presc  Sign Value \n';
  50.165 +printf{g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR}:'%5s %10s %11s = %10.2f\n', g,i,j, XForestLand[g,i,j]; 
  50.166 +printf '\n';
  50.167 +
  50.168 +printf 'Constraints\n';
  50.169 +printf 'Period Harvest Sign \n';
  50.170 +for {k in 1..K_PERIOD} {
  50.171 + printf '%5s %10.2f >= %.3f\n', k, sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k] * XForestLand[g,i,j], Harvest_Min_Vol_Period;
  50.172 +   }
  50.173 +
  50.174 +# xbase (dbf) output
  50.175 +table Harvest{k in 1..K_PERIOD} OUT "xBASE" "HarvestArea1.dbf" "N(5)N(15,2)" :  k ~ Period, (sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k] * XForestLand[g,i,j]) ~ H_Area;
  50.176 +
  50.177 +# xbase (dbf) read
  50.178 +set S, dimen 2;
  50.179 +table tab2 IN "xBASE" "HarvestArea1.dbf": S <- [Period, H_Area];
  50.180 +display S;
  50.181 +
  50.182 +
  50.183 +
  50.184 +
  50.185 +printf '\n';
  50.186 +printf 'Constraint\n';
  50.187 +printf 'Harvest Period\n';
  50.188 +printf 'Type AgeClass  PrescMgt Period    Value\n';
  50.189 +printf{g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR, k in 1..K_PERIOD}:'%5s %11s %11s %5s %10.2f\n', g,i,j, k, (Yield_Table_Vol[g,i,j,k] * XForestLand[g,i,j]); 
  50.190 +
  50.191 +
  50.192 +printf 'Even_Flow_Constaint_Alpha (1-Alpha)\n';
  50.193 +printf 'Period Sign \n';
  50.194 +for {k in 6..K_PERIOD-1} {
  50.195 +   printf "%s %10.2f <= %s\n", k, ((1 - Alpha) * sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k] * XForestLand[g,i,j] - sum {g in G_STAND_TYPE,i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k+1] * XForestLand[g,i,j]),0;
  50.196 +  }
  50.197 +printf '\n';
  50.198 +
  50.199 +
  50.200 +# Forest / Land Constraints
  50.201 +printf '\n';  
  50.202 +printf 'Total Area Constraint\n';
  50.203 +printf 'Type AgeClass  PrescMgt  Value Sign Total_Area \n';
  50.204 +printf '%5s <= %.3f\n',sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} XForestLand[g,i,j], Total_Area;
  50.205 +
  50.206 +printf 'Area\n';
  50.207 +printf 'Area Value Sign Areas_Stand\n';
  50.208 +for {g in G_STAND_TYPE} {
  50.209 +  printf '%5s %10.2f <= %.3f\n', g, sum {i in I_CULTURAL_PRES,j in J_MGT_YEAR} XForestLand[g,i,j],  Area_Stand_Type[g];
  50.210 +   }
  50.211 +
  50.212 +
  50.213 +#DATA SECTION 
  50.214 +      
  50.215 +data;
  50.216 +
  50.217 +# Most of the data has been moved to dbf format
  50.218 +
  50.219 +param MGT:=31;
  50.220 +
  50.221 +param K_PERIOD:= 7;
  50.222 +
  50.223 +param Alpha:= 0.20;
  50.224 +param Beta:= 0.20;
  50.225 +
  50.226 +param Harvest_Min_Vol_Period:= 12000;
  50.227 +
  50.228 +end;
  50.229 +
    51.1 Binary file examples/dbf/Forest_Cost.dbf has changed
    52.1 Binary file examples/dbf/NetRev_Table.dbf has changed
    53.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    53.2 +++ b/examples/dbf/README	Mon Dec 06 13:09:21 2010 +0100
    53.3 @@ -0,0 +1,2 @@
    53.4 +This subdirectory contains an example MathProg model that demonstrates
    53.5 +using data tables in DBF format.
    54.1 Binary file examples/dbf/TCost_Table.dbf has changed
    55.1 Binary file examples/dbf/Yield_Table_Vol.dbf has changed
    56.1 Binary file examples/dbf/cultural_pres.dbf has changed
    57.1 Binary file examples/dbf/mgt_year.dbf has changed
    58.1 Binary file examples/dbf/stands.dbf has changed
    59.1 Binary file examples/dbf/standtype.dbf has changed
    60.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    60.2 +++ b/examples/dea.mod	Mon Dec 06 13:09:21 2010 +0100
    60.3 @@ -0,0 +1,222 @@
    60.4 +/* Data Envelopment Analysis (DEA)
    60.5 + *
    60.6 + * DEA quantifies the relative efficiency of decision making units (DMUs) by
    60.7 + * finding the efficient frontier in multiple input multiple output data.  The
    60.8 + * inputs are resources (eg. number of employees, available machines, ...),
    60.9 + * the outputs are productive outputs (eg. contracts made, total sales, ...).
   60.10 + * The method is non-parametric.  More details are available in the paper
   60.11 + * below.
   60.12 + *
   60.13 + * Models according to: Seiford, Threall, "Recent developments in DEA", 1990.
   60.14 + *
   60.15 + * Implementation: Sebastian Nowozin <nowozin@gmail.com>
   60.16 + */
   60.17 +
   60.18 +### SETS ###
   60.19 +
   60.20 +set dmus;       # Decision Making Units (DMU)
   60.21 +set inputs;     # Input parameters
   60.22 +set outputs;    # Output parameters
   60.23 +
   60.24 +
   60.25 +### PARAMETERS ###
   60.26 +
   60.27 +param input_data{dmus,inputs} >= 0;
   60.28 +param output_data{dmus,outputs} >= 0;
   60.29 +
   60.30 +
   60.31 +### PROGRAM ###
   60.32 +
   60.33 +var theta{dmus} >= 0;
   60.34 +var lambda{dmus,dmus} >= 0;
   60.35 +
   60.36 +minimize inefficiency: sum{td in dmus} theta[td];
   60.37 +
   60.38 +s.t. output_lower_limit{o in outputs, td in dmus}:
   60.39 +    sum{d in dmus} lambda[d,td]*output_data[d,o] >= output_data[td,o];
   60.40 +s.t. input_upper_limit{i in inputs, td in dmus}:
   60.41 +    sum{d in dmus} lambda[d,td]*input_data[d,i] <= theta[td]*input_data[td,i];
   60.42 +
   60.43 +    s.t. PI1{td in dmus}:
   60.44 +        sum{d in dmus} lambda[d,td] = 1;
   60.45 +/*
   60.46 +possibilities:
   60.47 +      i) (no constraint)
   60.48 +     ii) s.t. PI1{td in dmus}:
   60.49 +        sum{d in dmus} lambda[d,td] <= 1;
   60.50 +    iii) s.t. PI1{td in dmus}:
   60.51 +        sum{d in dmus} lambda[d,td] >= 1;
   60.52 +*/
   60.53 +
   60.54 +
   60.55 +### SOLVE AND PRINT SOLUTION ###
   60.56 +
   60.57 +solve;
   60.58 +
   60.59 +printf "DMU\tEfficiency\n";
   60.60 +for {td in dmus} {
   60.61 +    printf "%s\t%1.4f\n", td, theta[td];
   60.62 +}
   60.63 +
   60.64 +### DATA ###
   60.65 +
   60.66 +data;
   60.67 +
   60.68 +set dmus := 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
   60.69 +    21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
   60.70 +    41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
   60.71 +    61 62 63 64 65 66 67 68 69 ;
   60.72 +set inputs := AvgInventory LaborCost OperatingCost Population ;
   60.73 +set outputs := PrescrVol kDollarValue ;
   60.74 +
   60.75 +param input_data default 0.0 :
   60.76 +
   60.77 +        AvgInventory LaborCost OperatingCost Population :=
   60.78 +
   60.79 +1 8000 17030 1280 1410
   60.80 +2 9000 25890 2779 1523
   60.81 +3 13694 29076 2372 1354
   60.82 +4 4250 17506 1385 822
   60.83 +5 6500 23208 639 746
   60.84 +6 7000 12946 802 1281
   60.85 +7 4500 18001 1130 1016
   60.86 +8 5000 14473 1097 1070
   60.87 +9 27000 31760 5559 1694
   60.88 +10 21560 50972 15010 1910
   60.89 +11 15000 39523 4799 1745
   60.90 +12 8500 13076 3489 1353
   60.91 +13 35000 35427 1704 500
   60.92 +14 18000 27554 2882 1016
   60.93 +15 59750 53848 14208 2500
   60.94 +16 19200 38253 1480 2293
   60.95 +17 40000 109404 83016 2718
   60.96 +18 8466 18198 1278 2877
   60.97 +19 16000 40891 7599 4150
   60.98 +20 10000 45444 5556 4421
   60.99 +21 25000 35623 2121 3883
  60.100 +22 14000 20192 5515 3519
  60.101 +23 12500 34973 10475 32366
  60.102 +24 17260 32284 14498 3393
  60.103 +25 7000 17920 7585 4489
  60.104 +26 14000 42094 3742 2217
  60.105 +27 16400 35422 14236 4641
  60.106 +28 13000 19100 3529 5968
  60.107 +29 30000 72167 8656 8715
  60.108 +30 12530 19970 1714 5968
  60.109 +31 31500 39183 4919 5607
  60.110 +32 10000 32048 3483 7324
  60.111 +33 22000 68877 12279 8685
  60.112 +34 10000 29812 3332 8685
  60.113 +35 16000 47686 2507 5420
  60.114 +36 10000 33415 4738 7703
  60.115 +37 9000 12359 4603 4665
  60.116 +38 16439 23614 2989 6317
  60.117 +39 14500 36069 1793 31839
  60.118 +40 39000 76307 9539 15619
  60.119 +41 24927 40706 12661 30213
  60.120 +42 13858 39267 4609 34719
  60.121 +43 33375 29509 11323 31839
  60.122 +44 29044 44482 5542 34719
  60.123 +45 32257 61365 20550 32366
  60.124 +46 8800 49671 3306 43561
  60.125 +47 47000 40425 10396 31263
  60.126 +48 12000 33034 4915 31263
  60.127 +49 28000 69163 4688 15173
  60.128 +50 13300 28931 16735 73064
  60.129 +51 13500 29758 4260 62309
  60.130 +52 24000 40927 8285 23166
  60.131 +53 16000 40403 2131 99836
  60.132 +54 17000 38730 2539 60348
  60.133 +55 25000 35978 2502 99836
  60.134 +56 16000 37509 6278 99836
  60.135 +57 20000 46950 10715 85925
  60.136 +58 14000 35966 3144 85925
  60.137 +59 22000 68318 8015 108987
  60.138 +60 21879 69537 7778 108987
  60.139 +61 15000 25425 2812 201404
  60.140 +62 10000 19508 2454 201404
  60.141 +63 20000 28191 3367 201404
  60.142 +64 18000 37073 8624 108987
  60.143 +65 19051 23763 3496 201404
  60.144 +66 15000 28642 3366 201404
  60.145 +67 10000 35919 3868 201404
  60.146 +68 24000 54653 26494 108987
  60.147 +69 1800 6276 3413 60348
  60.148 +        ;
  60.149 +
  60.150 +param output_data default 0.0 :
  60.151 +
  60.152 +        PrescrVol kDollarValue :=
  60.153 +
  60.154 +1 12293 61.00
  60.155 +2 18400 92.00
  60.156 +3 16789 92.65
  60.157 +4 10700 45.00
  60.158 +5 9800 50.00
  60.159 +6 6500 29.00
  60.160 +7 8200 56.00
  60.161 +8 8680 45.00
  60.162 +9 33800 183.00
  60.163 +10 23710 156.00
  60.164 +11 24000 120.00
  60.165 +12 17500 75.00
  60.166 +13 25000 130.00
  60.167 +14 26000 122.00
  60.168 +15 26830 178.513
  60.169 +16 16600 106.00
  60.170 +17 90000 450.00
  60.171 +18 11140 73.624
  60.172 +19 25868 136.00
  60.173 +20 32700 191.295
  60.174 +21 29117 152.864
  60.175 +22 18000 100.00
  60.176 +23 11100 60.00
  60.177 +24 23030 137.778
  60.178 +25 10656 58.00
  60.179 +26 24682 152.095
  60.180 +27 26908 120.00
  60.181 +28 16464 80.00
  60.182 +29 57000 321.00
  60.183 +30 17532 94.747
  60.184 +31 30035 168.00
  60.185 +32 16000 100.00
  60.186 +33 63700 277.00
  60.187 +34 18000 90.00
  60.188 +35 27339 139.134
  60.189 +36 19500 116.00
  60.190 +37 13000 80.00
  60.191 +38 15370 102.00
  60.192 +39 18446 90.00
  60.193 +40 56000 260.00
  60.194 +41 73845 364.951
  60.195 +42 28600 145.00
  60.196 +43 27000 243.00
  60.197 +44 52423 279.816
  60.198 +45 73759 363.388
  60.199 +46 20500 80.00
  60.200 +47 27100 115.00
  60.201 +48 15000 110.00
  60.202 +49 50895 277.852
  60.203 +50 19707 128.00
  60.204 +51 17994 78.80
  60.205 +52 36135 167.222
  60.206 +53 30000 153.00
  60.207 +54 26195 125.00
  60.208 +55 28000 216.00
  60.209 +56 24658 152.551
  60.210 +57 36850 190.00
  60.211 +58 29250 183.69
  60.212 +59 50000 250.00
  60.213 +60 40078 265.443
  60.214 +61 20200 110.00
  60.215 +62 12500 75.00
  60.216 +63 30890 195.00
  60.217 +64 31000 175.00
  60.218 +65 31277 192.992
  60.219 +66 11500 75.00
  60.220 +67 30000 175.668
  60.221 +68 38383 190.00
  60.222 +69 2075 8.650
  60.223 +        ;
  60.224 +
  60.225 +end;
    61.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    61.2 +++ b/examples/diet.mod	Mon Dec 06 13:09:21 2010 +0100
    61.3 @@ -0,0 +1,99 @@
    61.4 +# STIGLER'S NUTRITION MODEL
    61.5 +#
    61.6 +# This model determines a least cost diet which meets the daily
    61.7 +# allowances of nutrients for a moderately active man weighing 154 lbs.
    61.8 +#
    61.9 +#  References:
   61.10 +#              Dantzig G B, "Linear Programming and Extensions."
   61.11 +#              Princeton University Press, Princeton, New Jersey, 1963,
   61.12 +#              Chapter 27-1.
   61.13 +
   61.14 +set N;
   61.15 +/* nutrients */
   61.16 +
   61.17 +set F;
   61.18 +/* foods */
   61.19 +
   61.20 +param b{N};
   61.21 +/* required daily allowances of nutrients */
   61.22 +
   61.23 +param a{F,N};
   61.24 +/* nutritive value of foods (per dollar spent) */
   61.25 +
   61.26 +var x{f in F} >= 0;
   61.27 +/* dollars of food f to be purchased daily */
   61.28 +
   61.29 +s.t. nb{n in N}: sum{f in F} a[f,n] * x[f] = b[n];
   61.30 +/* nutrient balance (units) */
   61.31 +
   61.32 +minimize cost: sum{f in F} x[f];
   61.33 +/* total food bill (dollars) */
   61.34 +
   61.35 +data;
   61.36 +
   61.37 +param : N : b :=
   61.38 +         Calorie       3 /* thousands */
   61.39 +         Protein      70 /* grams */
   61.40 +         Calcium     0.8 /* grams */
   61.41 +         Iron         12 /* milligrams */
   61.42 +         Vitamin-A     5 /* thousands IUs */
   61.43 +         Vitamin-B1  1.8 /* milligrams */
   61.44 +         Vitamin-B2  2.7 /* milligrams */
   61.45 +         Niacin       18 /* milligrams */
   61.46 +         Vitamin-C    75 /* milligrams */  ;
   61.47 +
   61.48 +set F := Wheat Cornmeal Cannedmilk Margarine Cheese Peanut-B Lard
   61.49 +         Liver Porkroast Salmon Greenbeans Cabbage Onions Potatoes
   61.50 +         Spinach Sweet-Pot Peaches Prunes Limabeans Navybeans;
   61.51 +
   61.52 +param a default 0
   61.53 +
   61.54 +:           Calorie  Protein  Calcium  Iron  Vitamin-A  Vitamin-B1 :=
   61.55 +#            (1000)    (g)      (g)    (mg)   (1000IU)     (mg)
   61.56 +
   61.57 +Wheat         44.7     1411      2.0    365        .       55.4
   61.58 +Cornmeal      36        897      1.7     99      30.9      17.4
   61.59 +Cannedmilk     8.4      422     15.1      9      26         3
   61.60 +Margarine     20.6       17       .6      6      55.8        .2
   61.61 +Cheese         7.4      448     16.4     19      28.1        .8
   61.62 +Peanut-B      15.7      661      1       48        .        9.6
   61.63 +Lard          41.7        .       .       .        .2        .
   61.64 +Liver          2.2      333       .2    139     169.2       6.4
   61.65 +Porkroast      4.4      249       .3     37        .       18.2
   61.66 +Salmon         5.8      705      6.8     45       3.5       1
   61.67 +Greenbeans     2.4      138      3.7     80      69         4.3
   61.68 +Cabbage        2.6      125      4       36       7.2       9
   61.69 +Onions         5.8      166      3.8     59      16.6       4.7
   61.70 +Potatoes      14.3      336      1.8    118       6.7      29.4
   61.71 +Spinach        1.1      106       .     138     918.4       5.7
   61.72 +Sweet-Pot      9.6      138      2.7     54     290.7       8.4
   61.73 +Peaches        8.5       87      1.7    173      86.8       1.2
   61.74 +Prunes        12.8       99      2.5    154      85.7       3.9
   61.75 +Limabeans     17.4     1055      3.7    459       5.1      26.9
   61.76 +Navybeans     26.9     1691     11.4    792        .       38.4
   61.77 +
   61.78 +:          Vitamin-B2  Niacin  Vitamin-C :=
   61.79 +#             (mg)      (mg)     (mg)
   61.80 +
   61.81 +Wheat         33.3       441         .
   61.82 +Cornmeal       7.9       106         .
   61.83 +Cannedmilk    23.5        11        60
   61.84 +Margarine       .          .         .
   61.85 +Cheese        10.3         4         .
   61.86 +Peanut-B       8.1       471         .
   61.87 +Lard            .5         5         .
   61.88 +Liver         50.8       316       525
   61.89 +Porkroast      3.6        79         .
   61.90 +Salmon         4.9       209         .
   61.91 +Greenbeans     5.8        37       862
   61.92 +Cabbage        4.5        26      5369
   61.93 +Onions         5.9        21      1184
   61.94 +Potatoes       7.1       198      2522
   61.95 +Spinach       13.8        33      2755
   61.96 +Sweet-Pot      5.4        83      1912
   61.97 +Peaches        4.3        55        57
   61.98 +Prunes         4.3        65       257
   61.99 +Limabeans     38.2        93         .
  61.100 +Navybeans     24.6       217         .   ;
  61.101 +
  61.102 +end;
    62.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    62.2 +++ b/examples/dist.mod	Mon Dec 06 13:09:21 2010 +0100
    62.3 @@ -0,0 +1,565 @@
    62.4 +# DIST, a product distribution model
    62.5 +#
    62.6 +# References:
    62.7 +# Robert Fourer, David M. Gay and Brian W. Kernighan, "A Modeling Language
    62.8 +# for Mathematical Programming." Management Science 36 (1990) 519-554.
    62.9 +
   62.10 +###  SHIPPING SETS AND PARAMETERS  ###
   62.11 +
   62.12 +set whse 'warehouses';  # Locations from which demand is satisfied
   62.13 +
   62.14 +set dctr 'distribution centers' within whse;
   62.15 +
   62.16 +                        # Locations from which product may be shipped
   62.17 +
   62.18 +param sc 'shipping cost' {dctr,whse} >= 0;
   62.19 +
   62.20 +                        # Shipping costs, to whse from dctr, in $ / 100 lb
   62.21 +
   62.22 +param huge 'largest shipping cost' > 0;
   62.23 +
   62.24 +                        # Largest cost allowed for a usable shipping route
   62.25 +
   62.26 +param msr 'minimum size restriction' {dctr,whse} logical;
   62.27 +
   62.28 +                        # True indicates a minimum-size restriction on
   62.29 +                        # direct shipments using this dctr --> whse route
   62.30 +
   62.31 +param dsr 'direct shipment requirement' {dctr} >= 0;
   62.32 +
   62.33 +                        # Minimum total demand, in pallets, needed to
   62.34 +                        # allow shipment on routes subject to the
   62.35 +                        # minimum size restriction
   62.36 +
   62.37 +###  PLANT SETS AND PARAMETERS  ###
   62.38 +
   62.39 +set fact 'factories' within dctr;
   62.40 +
   62.41 +                        # Locations where product is manufactured
   62.42 +
   62.43 +param rtmin 'regular-time total minimum' >= 0;
   62.44 +
   62.45 +                        # Lower limit on (average) total regular-time
   62.46 +                        # crews employed at all factories
   62.47 +
   62.48 +param rtmax 'regular-time total maximum' >= rtmin;
   62.49 +
   62.50 +                        # Upper limit on (average) total regular-time
   62.51 +                        # crews employed at all factories
   62.52 +
   62.53 +param otmin 'overtime total minimum' >= 0;
   62.54 +
   62.55 +                        # Lower limit on total overtime hours at all factories
   62.56 +
   62.57 +param otmax 'overtime total maximum' >= otmin;
   62.58 +
   62.59 +                        # Upper limit on total overtime hours at all factories
   62.60 +
   62.61 +param rmin 'regular-time minimums' {fact} >= 0;
   62.62 +
   62.63 +                        # Lower limits on (average) regular-time crews
   62.64 +
   62.65 +param rmax 'regular-time maximums' {f in fact} >= rmin[f];
   62.66 +
   62.67 +                        # Upper limits on (average) regular-time crews
   62.68 +
   62.69 +param omin 'overtime minimums' {fact} >= 0;
   62.70 +
   62.71 +                        # Lower limits on overtime hours
   62.72 +
   62.73 +param omax 'overtime maximums' {f in fact} >= omin[f];
   62.74 +
   62.75 +                        # Upper limits on overtime hours
   62.76 +
   62.77 +param hd 'hours per day' {fact} >= 0;
   62.78 +
   62.79 +                        # Regular-time hours per working day
   62.80 +
   62.81 +param dp 'days in period' {fact} > 0;
   62.82 +
   62.83 +                        # Working days in the current planning period
   62.84 +
   62.85 +###  PRODUCT SETS AND PARAMETERS  ###
   62.86 +
   62.87 +set prd 'products';     # Elements of the product group
   62.88 +
   62.89 +param wt 'weight' {prd} > 0;
   62.90 +
   62.91 +                        # Weight in 100 lb / 1000 cases
   62.92 +
   62.93 +param cpp 'cases per pallet' {prd} > 0;
   62.94 +
   62.95 +                        # Cases of product per shipping pallet
   62.96 +
   62.97 +param tc 'transshipment cost' {prd} >= 0;
   62.98 +
   62.99 +                        # Transshipment cost in $ / 1000 cases
  62.100 +
  62.101 +param pt 'production time' {prd,fact} >= 0;
  62.102 +
  62.103 +                        # Crew-hours to produce 1000 cases
  62.104 +
  62.105 +param rpc 'regular-time production cost' {prd,fact} >= 0;
  62.106 +
  62.107 +                        # Cost of production on regular time,
  62.108 +                        # in $ / 1000 cases
  62.109 +
  62.110 +param opc 'overtime production cost' {prd,fact} >= 0;
  62.111 +
  62.112 +                        # Cost of production on overtime, in $ / 1000 cases
  62.113 +
  62.114 +###  DEMAND SETS AND PARAMETERS  ###
  62.115 +
  62.116 +param dt 'total demand' {prd} >= 0;
  62.117 +
  62.118 +                        # Total demands for products, in 1000s
  62.119 +
  62.120 +param ds 'demand shares' {prd,whse} >= 0.0, <= 1.0;
  62.121 +
  62.122 +                        # Historical demand data, from which each
  62.123 +                        # warehouse's share of total demand is deduced
  62.124 +
  62.125 +param dstot {p in prd} := sum {w in whse} ds[p,w];
  62.126 +
  62.127 +                        # Total of demand shares; should be 1, but often isn't
  62.128 +
  62.129 +param dem 'demand' {p in prd, w in whse} := dt[p] * ds[p,w] / dstot[p];
  62.130 +
  62.131 +                        # Projected demands to be satisfied, in 1000s
  62.132 +
  62.133 +set rt 'shipping routes available' :=
  62.134 +
  62.135 + {d in dctr, w in whse:
  62.136 +         d <> w  and  sc[d,w] < huge  and
  62.137 +         (w in dctr or sum {p in prd} dem[p,w] > 0)  and
  62.138 +         not (msr[d,w] and sum {p in prd} 1000*dem[p,w]/cpp[p] < dsr[d]) };
  62.139 +
  62.140 +                        # List of ordered pairs that represent routes
  62.141 +                        # on which shipments are allowed
  62.142 +
  62.143 +###  VARIABLES  ###
  62.144 +
  62.145 +var Rprd 'regular-time production' {prd,fact} >= 0;
  62.146 +
  62.147 +                        # Regular-time production of each product
  62.148 +                        # at each factory, in 1000s of cases
  62.149 +
  62.150 +var Oprd 'overtime production' {prd,fact} >= 0;
  62.151 +
  62.152 +                        # Overtime production of each product
  62.153 +                        # at each factory, in 1000s of cases
  62.154 +
  62.155 +var Ship 'shipments' {prd,rt} >= 0;
  62.156 +
  62.157 +                        # Shipments of each product on each allowed route,
  62.158 +                        # in 1000s of cases
  62.159 +
  62.160 +var Trans 'transshipments' {prd,dctr} >= 0;
  62.161 +
  62.162 +                        # Transshipments of each product at each
  62.163 +                        # distribution center, in 1000s of cases
  62.164 +
  62.165 +###  OBJECTIVE  ###
  62.166 +
  62.167 +minimize cost:  sum {p in prd, f in fact} rpc[p,f] * Rprd[p,f] +
  62.168 +                sum {p in prd, f in fact} opc[p,f] * Oprd[p,f] +
  62.169 +                sum {p in prd, (d,w) in rt} sc[d,w] * wt[p] * Ship[p,d,w] +
  62.170 +                sum {p in prd, d in dctr} tc[p] * Trans[p,d];
  62.171 +
  62.172 +                        # Total cost:  regular production, overtime
  62.173 +                        # production, shipping, and transshipment
  62.174 +
  62.175 +###  CONSTRAINTS  ###
  62.176 +
  62.177 +rtlim 'regular-time total limits':
  62.178 +
  62.179 +    rtmin <= sum {p in prd, f in fact}
  62.180 +                        (pt[p,f] * Rprd[p,f]) / (dp[f] * hd[f]) <= rtmax;
  62.181 +
  62.182 +                        # Total crews must lie between limits
  62.183 +
  62.184 +otlim 'overtime total limits':
  62.185 +
  62.186 +    otmin <= sum {p in prd, f in fact} pt[p,f] * Oprd[p,f] <= otmax;
  62.187 +
  62.188 +                        # Total overtime must lie between limits
  62.189 +
  62.190 +rlim 'regular-time limits' {f in fact}:
  62.191 +
  62.192 +    rmin[f] <= sum {p in prd}
  62.193 +                        (pt[p,f] * Rprd[p,f]) / (dp[f] * hd[f]) <= rmax[f];
  62.194 +
  62.195 +                        # Crews at each factory must lie between limits
  62.196 +
  62.197 +olim 'overtime limits' {f in fact}:
  62.198 +
  62.199 +    omin[f] <= sum {p in prd} pt[p,f] * Oprd[p,f] <= omax[f];
  62.200 +
  62.201 +                        # Overtime at each factory must lie between limits
  62.202 +
  62.203 +noRprd 'no regular production' {p in prd, f in fact: rpc[p,f] = 0}:
  62.204 +
  62.205 +    Rprd[p,f] = 0;
  62.206 +
  62.207 +noOprd 'no overtime production' {p in prd, f in fact: opc[p,f] = 0}:
  62.208 +
  62.209 +    Oprd[p,f] = 0;      # Do not produce where specified cost is zero
  62.210 +
  62.211 +bal 'material balance' {p in prd, w in whse}:
  62.212 +
  62.213 +    sum {(v,w) in rt}
  62.214 +       Ship [p,v,w] + (if w in fact then Rprd[p,w] + Oprd[p,w]) =
  62.215 +
  62.216 +    dem[p,w] + (if w in dctr then sum {(w,v) in rt} Ship[p,w,v]);
  62.217 +
  62.218 +                        # Demand is satisfied by shipment into warehouse
  62.219 +                        # plus production (if it is a factory)
  62.220 +                        # minus shipment out (if it is a distn. center)
  62.221 +
  62.222 +trdef 'transshipment definition' {p in prd, d in dctr}:
  62.223 +
  62.224 +    Trans[p,d] >= sum {(d,w) in rt} Ship [p,d,w] -
  62.225 +                  (if d in fact then Rprd[p,d] + Oprd[p,d]);
  62.226 +
  62.227 +                        # Transshipment at a distribution center is
  62.228 +                        # shipments out less production (if any)
  62.229 +
  62.230 +###  DATA -- 3 PRODUCTS  ###
  62.231 +
  62.232 +data;
  62.233 +
  62.234 +set prd := 18REG 24REG 24PRO ;
  62.235 +
  62.236 +set whse := w01 w02 w03 w04 w05 w06 w08 w09 w12 w14 w15 w17
  62.237 +            w18 w19 w20 w21 w24 w25 w26 w27 w28 w29 w30 w31
  62.238 +            w32 w33 w34 w35 w36 w37 w38 w39 w40 w41 w42 w43
  62.239 +            w44 w45 w46 w47 w48 w49 w50 w51 w53 w54 w55 w56
  62.240 +            w57 w59 w60 w61 w62 w63 w64 w65 w66 w68 w69 w71
  62.241 +            w72 w73 w74 w75 w76 w77 w78 w79 w80 w81 w82 w83
  62.242 +            w84 w85 w86 w87 w89 w90 w91 w92 w93 w94 w95 w96
  62.243 +            w98 x22 x23 ;
  62.244 +
  62.245 +set dctr := w01 w02 w03 w04 w05 w62 w76 w96 ;
  62.246 +
  62.247 +set fact := w01 w05 w96 ;
  62.248 +
  62.249 +param huge := 99. ;
  62.250 +
  62.251 +param rtmin := 0.0 ;
  62.252 +param rtmax := 8.0 ;
  62.253 +
  62.254 +param otmin :=  0.0 ;
  62.255 +param otmax := 96.0 ;
  62.256 +
  62.257 +param rmin  :=  w01 0.00   w05 0.00   w96 0.00 ;
  62.258 +param rmax  :=  w01 3.00   w05 2.00   w96 3.00 ;
  62.259 +
  62.260 +param omin  :=  w01  0.0   w05  0.0   w96  0.0 ;
  62.261 +param omax  :=  w01 48.0   w05  0.0   w96 48.0 ;
  62.262 +
  62.263 +param hd    :=  w01  8.0   w05  8.0   w96  8.0 ;
  62.264 +
  62.265 +param dp    :=  w01 19.0   w05 19.0   w96 19.0 ;
  62.266 +
  62.267 +param wt  :=  18REG  47.3    24REG  63.0    24PRO  63.0 ;
  62.268 +
  62.269 +param tc  :=  18REG  40.00   24REG  45.00   24PRO  45.00 ;
  62.270 +
  62.271 +param dt  :=  18REG 376.0    24REG 172.4    24PRO 316.3 ;
  62.272 +
  62.273 +param cpp :=  18REG 102.     24REG  91.     24PRO  91. ;
  62.274 +
  62.275 +param dsr := w01 96.  w02 96.  w03 96.  w04 96.  w05 96.
  62.276 +             w62 96.  w76 96.  w96 96. ;
  62.277 +
  62.278 +param pt (tr) :
  62.279 +
  62.280 +       18REG     24REG     24PRO    :=
  62.281 +
  62.282 +w01    1.194     1.429     1.429
  62.283 +w05    1.194     1.509     1.509
  62.284 +w96    0.000     1.600     1.600    ;
  62.285 +
  62.286 +param rpc (tr) :
  62.287 +
  62.288 +       18REG     24REG     24PRO    :=
  62.289 +
  62.290 +w01    2119.       2653.    2617.
  62.291 +w05    2489.       3182.    3176.
  62.292 +w96       0.       2925.    2918.   ;
  62.293 +
  62.294 +param opc (tr) :
  62.295 +
  62.296 +       18REG     24REG     24PRO    :=
  62.297 +
  62.298 +w01    2903.     3585.     3579.
  62.299 +w05       0.        0.        0.
  62.300 +w96       0.     3629.     3622.    ;
  62.301 +
  62.302 +param sc  default 99.99 (tr) :
  62.303 +
  62.304 +         w01     w02     w03     w04     w05     w62     w76     w96  :=
  62.305 +
  62.306 +w01      .      2.97    1.14    2.08    2.37    1.26    2.42    1.43
  62.307 +w02     4.74     .      4.17    6.12    7.41    3.78    7.04    5.21
  62.308 +w03     2.45    4.74     .      3.67    2.84    0.90    2.41    2.55
  62.309 +w04     1.74    5.03    2.43     .      3.19    2.45    2.69    0.58
  62.310 +w05     2.70    5.16    2.84    2.85     .      3.26    3.34    2.71
  62.311 +w06     1.99    4.17    2.13    2.19    2.52    2.06    2.00    1.51
  62.312 +w08     0.21    2.92    1.24    2.07    2.29    1.25    2.32    1.55
  62.313 +w09     0.66    3.76    1.41    2.47    1.82    1.66     .      1.87
  62.314 +w12     1.38    3.83    1.68    2.53    2.39     .      1.96    1.94
  62.315 +w14     2.47    1.58    2.40    3.59    3.85    2.25     .      3.05
  62.316 +w15     1.06    4.95    2.48    1.39    3.41    1.96     .      1.02
  62.317 +w17     0.88    3.39    1.46    2.00    2.67    1.45     .      1.46
  62.318 +w18     7.90    6.57    7.79    9.59    10.81    .       .      6.70
  62.319 +w19     1.42    4.12    1.96    1.99    3.52    1.88     .      1.26
  62.320 +w20     3.03    1.59    2.34    4.76    3.98    1.88     .      3.73
  62.321 +w24     1.58    2.80    2.27    2.87    3.19    1.31     .      2.05
  62.322 +w25     1.51    5.05    2.74    0.57    2.98     .      2.95    0.27
  62.323 +w26     1.75    3.61    2.70    1.54    4.07    3.52     .      1.03
  62.324 +w27     2.48    6.87    3.17    1.59    2.08    3.45     .      0.99
  62.325 +w28     2.05    6.83    2.97    1.13    2.91     .       .      1.26
  62.326 +w29     4.03    3.68    4.46    3.20    5.50     .       .      3.20
  62.327 +w30     2.48    5.78    2.99    2.24    1.79    3.10     .      1.39
  62.328 +w31     2.34    5.41    2.87    1.67    1.66     .       .      1.39
  62.329 +w32     14.36    .       .       .       .       .       .       .
  62.330 +w33     3.87    4.27    5.11    3.48    5.66    4.03     .      3.05
  62.331 +w34     3.26    4.80    3.21    2.70    4.14     .       .      1.77
  62.332 +w35     2.34    2.84    2.89    3.35    3.78    2.68     .      2.52
  62.333 +w36     2.43    5.69    2.96    2.95    1.02    2.61    1.07    2.54
  62.334 +w37     2.23    4.64    2.41    1.99    4.30    2.61     .      1.44
  62.335 +w38     4.66    4.36    5.23    3.04    4.46     .       .      3.82
  62.336 +w39     1.11    3.51    1.10    2.53    3.07    1.12     .      2.23
  62.337 +w40     2.99    4.78    4.23    1.57    3.92     .       .      1.80
  62.338 +w41     4.93    4.00    5.43    4.45    6.31     .       .      3.81
  62.339 +w42     3.86    6.55    5.03    2.11    4.41     .       .      2.63
  62.340 +w43     4.61    4.45    3.77    1.22    4.31     .       .      2.35
  62.341 +w44     2.05    4.48    1.06    3.70    3.46    1.10     .      3.21
  62.342 +w45     0.92    3.42    1.58    3.04    1.82    1.94     .      2.52
  62.343 +w46     1.36    2.44    0.95    3.08    2.78    0.39    2.16    2.37
  62.344 +w47     1.30    3.39    1.60    2.49    4.29    2.04     .      1.68
  62.345 +w48     1.65    3.78    1.03    2.97    2.21    1.31     .      2.74
  62.346 +w49     1.96    3.00    1.50    3.24    3.68    1.00     .      2.99
  62.347 +w50     0.90    4.14    1.60    1.95    3.61    1.61     .      1.52
  62.348 +w51     1.59    3.95    0.25    2.96    2.58    1.00    2.41    2.71
  62.349 +w53     1.59    3.79    1.28    3.12    3.10    0.89     .      2.98
  62.350 +w54     1.72    4.36    1.61    2.92    2.34    1.91    1.97    3.05
  62.351 +w55     2.45    2.73    2.21    4.47    4.30    2.57     .      4.48
  62.352 +w56     1.10    3.73    1.59    2.74    2.33    1.45     .      2.44
  62.353 +w57     0.95    3.39    1.37    2.30    2.47    1.15     .      1.95
  62.354 +w59     3.29    5.35    3.32    3.81    1.52    3.38    1.34    4.08
  62.355 +w60     2.41    6.12    2.46    3.65    2.35     .      1.37    4.06
  62.356 +w61     3.32    5.50    3.41    3.38    1.23     .      0.99    4.28
  62.357 +w62     1.12    3.00    0.82    3.22    2.95     .      3.33    2.53
  62.358 +w63     3.59    6.36    3.25    4.12    1.84    3.59    1.46    4.03
  62.359 +w64     1.85    4.45    2.17    3.43    2.13    2.03     .      4.02
  62.360 +w65     2.78    4.79    2.81    2.94    1.54    2.90    1.07    2.94
  62.361 +w66     3.90    5.79    3.05    3.65    1.36    3.39    1.22    3.57
  62.362 +w68     2.61    5.20    2.90    2.34    1.68    3.19    1.48    2.31
  62.363 +w69     2.94    5.21    2.78    3.43    0.21    3.26    0.68    2.54
  62.364 +w71     2.06    4.98    2.38    2.44    1.59    2.97    1.05    2.55
  62.365 +w72     2.61    5.50    2.83    3.12    1.35    3.23    0.88    2.99
  62.366 +w73     8.52    6.16    8.03    8.83    10.44   7.38    10.26    .
  62.367 +w74     6.11    5.46    9.07    9.38    10.80    .       .      8.25
  62.368 +w75     2.66    4.94    2.87    3.69    1.52    3.15    1.24    4.00
  62.369 +w76     1.99    5.26    2.23    3.36    0.58    3.17     .      2.50
  62.370 +w77     4.32    3.07    5.05    3.88    6.04     .       .      4.15
  62.371 +w78     5.60    2.59    5.78    5.56    7.10     .       .      5.60
  62.372 +w79     4.25    2.32    4.93    4.57    6.04     .       .      4.58
  62.373 +w80     5.94    4.00    5.60    7.02    9.46     .       .      7.51
  62.374 +w81     5.39    2.21    5.10    6.22    6.46     .       .      6.58
  62.375 +w82     8.80    5.69    9.29    9.88    11.69   8.63    11.52    .
  62.376 +w83     4.40     .      5.24    5.21    5.81    3.91    7.04    5.33
  62.377 +w84     5.87    5.43    6.17    5.70    7.63     .       .      5.70
  62.378 +w85     3.90    3.65    3.38    4.57    5.64    3.05     .      5.04
  62.379 +w86     5.48    2.10    5.70    6.37    7.33     .       .      6.19
  62.380 +w87     8.88    5.54    9.50    9.71    11.64   8.85    11.68    .
  62.381 +w89     4.62    4.01    4.03    6.30    6.30    3.81     .      7.77
  62.382 +w90     4.35    2.72    4.61    4.01    5.60     .       .      3.20
  62.383 +w91     7.61    4.42    7.83    6.85    8.79     .       .      7.66
  62.384 +w92     7.15    2.69    6.91    7.20     .       .       .      7.06
  62.385 +w93     3.17    3.95    4.37    3.74    5.05     .       .      2.40
  62.386 +w94     1.21    3.07    0.90    2.74    3.17     .      2.63    2.39
  62.387 +w95     5.82    3.29    6.55    7.06    11.47    .       .      7.83
  62.388 +w96     1.77    5.20    2.72    0.59    3.47    2.48     .       .
  62.389 +w98     3.04    1.92    3.64    3.70    4.90    3.05     .      3.88
  62.390 +x22     4.08    6.25    4.15    4.30    1.77     .      1.77     .
  62.391 +x23     3.39    5.74    3.55    4.08    1.69     .      1.47     .      ;
  62.392 +
  62.393 +param msr (tr) :
  62.394 +
  62.395 +         w01     w02     w03     w04     w05     w62     w76     w96    :=
  62.396 +
  62.397 +w01        0       0       0       0       0       0       1       0
  62.398 +w02        0       0       0       0       0       0       1       0
  62.399 +w03        0       0       0       0       0       0       1       0
  62.400 +w04        0       0       0       0       0       0       1       0
  62.401 +w05        0       0       0       0       0       0       0       0
  62.402 +w06        0       1       1       1       1       1       1       1
  62.403 +w08        0       1       1       1       1       1       1       1
  62.404 +w09        0       1       1       1       1       1       0       1
  62.405 +w12        0       1       1       1       1       0       1       1
  62.406 +w14        1       1       1       1       1       0       0       1
  62.407 +w15        0       1       1       1       1       1       0       1
  62.408 +w17        0       1       1       1       1       1       0       1
  62.409 +w18        0       1       1       1       1       0       0       1
  62.410 +w19        0       1       1       1       1       0       0       1
  62.411 +w20        1       1       1       1       1       0       0       1
  62.412 +w24        0       1       1       1       1       0       0       1
  62.413 +w25        0       1       1       1       1       0       1       0
  62.414 +w26        1       1       1       0       1       1       0       1
  62.415 +w27        1       1       1       0       1       1       0       1
  62.416 +w28        1       1       1       0       1       0       0       1
  62.417 +w29        0       1       1       1       1       0       0       1
  62.418 +w30        1       1       1       0       1       1       0       1
  62.419 +w31        1       1       1       0       1       0       0       1
  62.420 +w32        0       0       0       0       0       0       0       0
  62.421 +w33        1       0       1       1       1       1       0       1
  62.422 +w34        1       1       1       0       1       0       0       1
  62.423 +w35        1       1       1       1       1       0       0       1
  62.424 +w36        0       1       1       1       0       1       1       1
  62.425 +w37        1       1       1       0       1       1       0       1
  62.426 +w38        1       1       1       0       1       0       0       1
  62.427 +w39        0       1       1       1       1       1       0       1
  62.428 +w40        1       1       1       0       1       0       0       1
  62.429 +w41        1       0       1       1       1       0       0       1
  62.430 +w42        1       1       1       0       1       0       0       1
  62.431 +w43        1       1       1       0       1       0       0       1
  62.432 +w44        1       1       1       1       1       0       0       1
  62.433 +w45        0       1       1       1       1       1       0       1
  62.434 +w46        0       1       1       1       1       0       1       1
  62.435 +w47        0       1       1       1       1       1       0       1
  62.436 +w48        0       1       1       1       1       0       0       1
  62.437 +w49        1       1       1       1       1       0       0       1
  62.438 +w50        0       1       1       1       1       1       0       1
  62.439 +w51        0       1       1       1       1       0       1       1
  62.440 +w53        1       1       1       1       1       0       0       1
  62.441 +w54        0       1       1       1       1       1       1       1
  62.442 +w55        0       1       1       1       1       0       0       1
  62.443 +w56        0       1       1       1       1       1       0       1
  62.444 +w57        0       1       1       1       1       1       0       1
  62.445 +w59        0       1       1       1       0       1       1       1
  62.446 +w60        0       1       1       1       1       0       1       1
  62.447 +w61        0       1       1       1       0       0       1       1
  62.448 +w62        0       0       0       0       0       0       1       0
  62.449 +w63        0       1       1       1       0       1       1       1
  62.450 +w64        0       1       1       1       1       1       0       1
  62.451 +w65        0       1       1       1       0       1       1       1
  62.452 +w66        0       1       1       1       0       1       1       1
  62.453 +w68        0       1       1       1       0       1       1       1
  62.454 +w69        0       1       1       1       0       1       1       1
  62.455 +w71        0       1       1       1       0       1       1       1
  62.456 +w72        0       1       1       1       0       1       1       1
  62.457 +w73        0       1       1       1       0       1       1       0
  62.458 +w74        0       1       1       1       0       0       0       1
  62.459 +w75        0       1       1       1       0       1       1       1
  62.460 +w76        0       0       0       0       0       0       0       0
  62.461 +w77        1       0       1       1       1       0       0       1
  62.462 +w78        1       0       1       1       1       0       0       1
  62.463 +w79        1       0       1       1       1       0       0       1
  62.464 +w80        1       0       1       1       1       0       0       1
  62.465 +w81        1       0       1       1       1       0       0       1
  62.466 +w82        1       0       1       1       1       1       1       0
  62.467 +w83        1       0       1       1       1       0       1       1
  62.468 +w84        1       0       1       1       1       0       0       1
  62.469 +w85        1       1       1       1       1       0       0       1
  62.470 +w86        1       0       1       1       1       0       0       1
  62.471 +w87        1       0       1       1       1       1       1       0
  62.472 +w89        1       0       1       1       1       1       0       1
  62.473 +w90        0       1       1       1       1       0       0       1
  62.474 +w91        1       0       1       1       1       0       0       1
  62.475 +w92        1       0       1       1       1       0       0       1
  62.476 +w93        1       1       1       0       1       0       0       1
  62.477 +w94        0       0       1       1       1       0       1       1
  62.478 +w95        1       0       1       1       1       0       0       1
  62.479 +w96        0       0       0       0       0       0       0       0
  62.480 +w98        1       0       1       1       1       1       0       1
  62.481 +x22        1       1       1       1       0       0       1       0
  62.482 +x23        1       1       1       1       0       0       1       0    ;
  62.483 +
  62.484 +param ds default 0.000 (tr) :
  62.485 +
  62.486 +         18REG     24REG     24PRO    :=
  62.487 +
  62.488 +w01      0.000     0.000     0.008
  62.489 +w02      0.004     0.000     0.000
  62.490 +w03      0.000     0.000     0.000
  62.491 +w04      0.010     0.002     0.000
  62.492 +w05      0.000     0.000     0.000
  62.493 +w06      0.010     0.008     0.008
  62.494 +w08      0.030     0.024     0.024
  62.495 +w09      0.014     0.018     0.020
  62.496 +w12      0.014     0.012     0.010
  62.497 +w14      0.007     0.007     0.012
  62.498 +w15      0.010     0.019     0.018
  62.499 +w17      0.013     0.010     0.011
  62.500 +w19      0.015     0.012     0.009
  62.501 +w20      0.012     0.021     0.022
  62.502 +w21      0.000     0.000     0.000
  62.503 +w24      0.012     0.022     0.018
  62.504 +w25      0.019     0.025     0.020
  62.505 +w26      0.006     0.015     0.021
  62.506 +w27      0.008     0.010     0.015
  62.507 +w28      0.011     0.016     0.019
  62.508 +w29      0.008     0.020     0.013
  62.509 +w30      0.011     0.013     0.015
  62.510 +w31      0.011     0.013     0.017
  62.511 +w32      0.006     0.000     0.000
  62.512 +w33      0.000     0.015     0.014
  62.513 +w34      0.008     0.007     0.005
  62.514 +w35      0.002     0.006     0.014
  62.515 +w36      0.015     0.013     0.005
  62.516 +w37      0.017     0.016     0.015
  62.517 +w38      0.015     0.009     0.012
  62.518 +w39      0.007     0.017     0.022
  62.519 +w40      0.009     0.014     0.020
  62.520 +w41      0.003     0.014     0.011
  62.521 +w42      0.017     0.011     0.012
  62.522 +w43      0.009     0.013     0.011
  62.523 +w44      0.002     0.012     0.012
  62.524 +w45      0.016     0.025     0.028
  62.525 +w46      0.038     0.062     0.040
  62.526 +w47      0.007     0.010     0.010
  62.527 +w48      0.003     0.015     0.016
  62.528 +w49      0.005     0.016     0.017
  62.529 +w50      0.011     0.008     0.007
  62.530 +w51      0.010     0.022     0.021
  62.531 +w53      0.004     0.026     0.020
  62.532 +w54      0.020     0.017     0.025
  62.533 +w55      0.004     0.019     0.028
  62.534 +w56      0.004     0.010     0.008
  62.535 +w57      0.014     0.020     0.018
  62.536 +w59      0.012     0.006     0.007
  62.537 +w60      0.019     0.010     0.009
  62.538 +w61      0.028     0.010     0.012
  62.539 +w62      0.000     0.000     0.000
  62.540 +w63      0.070     0.027     0.037
  62.541 +w64      0.009     0.004     0.005
  62.542 +w65      0.022     0.015     0.016
  62.543 +w66      0.046     0.017     0.020
  62.544 +w68      0.005     0.012     0.016
  62.545 +w69      0.085     0.036     0.039
  62.546 +w71      0.011     0.013     0.010
  62.547 +w72      0.089     0.031     0.034
  62.548 +w75      0.026     0.012     0.010
  62.549 +w77      0.001     0.004     0.002
  62.550 +w78      0.002     0.004     0.002
  62.551 +w79      0.001     0.004     0.002
  62.552 +w80      0.001     0.001     0.002
  62.553 +w81      0.001     0.003     0.002
  62.554 +w83      0.009     0.010     0.008
  62.555 +w84      0.001     0.002     0.002
  62.556 +w85      0.001     0.004     0.005
  62.557 +w86      0.001     0.002     0.002
  62.558 +w87      0.002     0.003     0.000
  62.559 +w89      0.001     0.001     0.002
  62.560 +w90      0.006     0.017     0.013
  62.561 +w91      0.002     0.010     0.013
  62.562 +w92      0.000     0.003     0.002
  62.563 +w93      0.002     0.006     0.007
  62.564 +w95      0.001     0.007     0.007
  62.565 +w96      0.000     0.000     0.000
  62.566 +w98      0.006     0.005     0.002    ;
  62.567 +
  62.568 +end;
    63.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    63.2 +++ b/examples/dragon.dat	Mon Dec 06 13:09:21 2010 +0100
    63.3 @@ -0,0 +1,55 @@
    63.4 +/* dragon.dat, a hard Paint-By-Numbers puzzle */
    63.5 +
    63.6 +/* To reduce the solution time the clique cuts may be used. */
    63.7 +
    63.8 +data;
    63.9 +
   63.10 +param m := 20;
   63.11 +
   63.12 +param n := 20;
   63.13 +
   63.14 +param row :    1  2  3  4  5 :=
   63.15 +          1    7  1  .  .  .
   63.16 +          2    1  1  2  .  .
   63.17 +          3    2  1  2  .  .
   63.18 +          4    1  2  2  .  .
   63.19 +          5    4  2  3  .  .
   63.20 +          6    3  1  4  .  .
   63.21 +          7    3  1  3  .  .
   63.22 +          8    2  1  4  .  .
   63.23 +          9    2  9  .  .  .
   63.24 +          10   2  1  5  .  .
   63.25 +          11   2  7  .  .  .
   63.26 +          12   14 .  .  .  .
   63.27 +          13   8  2  .  .  .
   63.28 +          14   6  2  2  .  .
   63.29 +          15   2  8  1  3  .
   63.30 +          16   1  5  5  2  .
   63.31 +          17   1  3  2  4  1
   63.32 +          18   3  1  2  4  1
   63.33 +          19   1  1  3  1  3
   63.34 +          20   2  1  1  2  . ;
   63.35 +
   63.36 +param col :    1  2  3  4  5 :=
   63.37 +          1    1  1  1  2  .
   63.38 +          2    3  1  2  1  1
   63.39 +          3    1  4  2  1  1
   63.40 +          4    1  3  2  4  .
   63.41 +          5    1  4  6  1  .
   63.42 +          6    1  11 1  .  .
   63.43 +          7    5  1  6  2  .
   63.44 +          8    14 .  .  .  .
   63.45 +          9    7  2  .  .  .
   63.46 +          10   7  2  .  .  .
   63.47 +          11   6  1  1  .  .
   63.48 +          12   9  2  .  .  .
   63.49 +          13   3  1  1  1  .
   63.50 +          14   3  1  3  .  .
   63.51 +          15   2  1  3  .  .
   63.52 +          16   2  1  5  .  .
   63.53 +          17   3  2  2  .  .
   63.54 +          18   3  3  2  .  .
   63.55 +          19   2  3  2  .  .
   63.56 +          20   2  6  .  .  . ;
   63.57 +
   63.58 +end;
    64.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    64.2 +++ b/examples/egypt.mod	Mon Dec 06 13:09:21 2010 +0100
    64.3 @@ -0,0 +1,519 @@
    64.4 +# EGYPT, a static model of fertilizer production
    64.5 +#
    64.6 +# References:
    64.7 +# Robert Fourer, David M. Gay and Brian W. Kernighan, "A Modeling Language
    64.8 +# for Mathematical Programming." Management Science 36 (1990) 519-554.
    64.9 +
   64.10 +###  SETS  ###
   64.11 +
   64.12 +set center;                # Locations from which final product may be shipped
   64.13 +set port within center;    # Locations at which imports can be received
   64.14 +set plant within center;   # Locations of plants
   64.15 +
   64.16 +set region;                # Demand regions
   64.17 +
   64.18 +set unit;                  # Productive units
   64.19 +set proc;                  # Processes
   64.20 +
   64.21 +set nutr;                  # Nutrients
   64.22 +
   64.23 +set c_final;               # Final products (fertilizers)
   64.24 +set c_inter;               # Intermediate products
   64.25 +set c_ship within c_inter; # Intermediates for shipment
   64.26 +set c_raw;                 # Domestic raw materials and miscellaneous inputs
   64.27 +
   64.28 +set commod := c_final union c_inter union c_raw;
   64.29 +
   64.30 +                           # All commodities
   64.31 +
   64.32 +###  PARAMETERS  ###
   64.33 +
   64.34 +param cf75 {region,c_final} >= 0;
   64.35 +
   64.36 +                           # Consumption of fertilizer 1974-75 (1000 tpy)
   64.37 +
   64.38 +param fn {c_final,nutr} >= 0;
   64.39 +
   64.40 +                           # Nutrient content of fertilizers
   64.41 +
   64.42 +param cn75 {r in region, n in nutr} := sum {c in c_final} cf75[r,c] * fn[c,n];
   64.43 +
   64.44 +                           # Consumption of nutrients 1974-75 (1000 tpy)
   64.45 +
   64.46 +param road {region,center} >= 0;
   64.47 +
   64.48 +                           # Road distances
   64.49 +
   64.50 +param rail_half {plant,plant} >= 0;
   64.51 +param rail {p1 in plant, p2 in plant} :=
   64.52 +    if rail_half[p1,p2] > 0 then rail_half[p1,p2] else rail_half[p2,p1];
   64.53 +
   64.54 +                           # Interplant rail distances (kms)
   64.55 +
   64.56 +param impd_barg {plant} >= 0;
   64.57 +param impd_road {plant} >= 0;
   64.58 +
   64.59 +                           # Import distances (kms) by barge and road
   64.60 +
   64.61 +param tran_final {pl in plant, r in region} :=
   64.62 +              if road[r,pl] > 0 then .5 + .0144 * road[r,pl] else 0;
   64.63 +
   64.64 +param tran_import {r in region, po in port} :=
   64.65 +              if road[r,po] > 0 then .5 + .0144 * road[r,po] else 0;
   64.66 +
   64.67 +param tran_inter {p1 in plant, p2 in plant} :=
   64.68 +              if rail[p1,p2] > 0 then 3.5 + .03 * rail[p1,p2] else 0;
   64.69 +
   64.70 +param tran_raw {pl in plant} :=
   64.71 +            (if impd_barg[pl] > 0 then 1.0 + .0030 * impd_barg[pl] else 0)
   64.72 +          + (if impd_road[pl] > 0 then 0.5 + .0144 * impd_road[pl] else 0);
   64.73 +
   64.74 +                           # Transport cost (le per ton) for:
   64.75 +                           #   final products, imported final products,
   64.76 +                           #   interplant shipment, imported raw materials
   64.77 +
   64.78 +param io {commod,proc};    # Input-output coefficients
   64.79 +
   64.80 +param util {unit,proc} >= 0;
   64.81 +
   64.82 +                           # Capacity utilization coefficients
   64.83 +
   64.84 +param p_imp {commod} >= 0; # Import Price (cif US$ per ton 1975)
   64.85 +
   64.86 +param p_r {c_raw} >= 0;
   64.87 +param p_pr {plant,c_raw} >= 0;
   64.88 +
   64.89 +param p_dom {pl in plant, c in c_raw} :=
   64.90 +              if p_r[c] > 0 then p_r[c] else p_pr[pl,c];
   64.91 +
   64.92 +                           # Domestic raw material prices
   64.93 +
   64.94 +param dcap {plant,unit} >= 0;
   64.95 +
   64.96 +                           # Design capacity of plants (t/day)
   64.97 +
   64.98 +param icap {u in unit, pl in plant} := 0.33 * dcap[pl,u];
   64.99 +
  64.100 +                           # Initial capacity of plants (t/day)
  64.101 +
  64.102 +param exch := 0.4;         # Exchange rate
  64.103 +
  64.104 +param util_pct := 0.85;    # Utilization percent for initial capacity
  64.105 +
  64.106 +###  DERIVED SETS OF "POSSIBILITIES"  ###
  64.107 +
  64.108 +set m_pos {pl in plant} := {u in unit: icap[u,pl] > 0};
  64.109 +
  64.110 +                           # At each plant, set of units for which there is
  64.111 +                           # initial capacity
  64.112 +
  64.113 +set p_cap {pl in plant} :=
  64.114 +             {pr in proc: forall {u in unit: util[u,pr] > 0} u in m_pos[pl] };
  64.115 +
  64.116 +                           # At each plant, set of processes for which
  64.117 +                           # all necessary units have some initial capacity
  64.118 +
  64.119 +set p_except {plant} within proc;
  64.120 +
  64.121 +                           # At each plant, list of processes that are
  64.122 +                           # arbitrarily ruled out
  64.123 +
  64.124 +set p_pos {pl in plant} := p_cap[pl] diff p_except[pl];
  64.125 +
  64.126 +                           # At each plant, set of possible processes
  64.127 +
  64.128 +set cp_pos {c in commod} := {pl in plant: sum {pr in p_pos[pl]} io[c,pr] > 0};
  64.129 +
  64.130 +set cc_pos {c in commod} := {pl in plant: sum {pr in p_pos[pl]} io[c,pr] < 0};
  64.131 +
  64.132 +set c_pos {c in commod} := cp_pos[c] union cc_pos[c];
  64.133 +
  64.134 +                           # For each commodity, set of plants that can
  64.135 +                           # produce it (cp_pos) or consume it (cc_pos),
  64.136 +                           # and their union (c_pos)
  64.137 +
  64.138 +###  VARIABLES  ###
  64.139 +
  64.140 +var Z {pl in plant, p_pos[pl]} >= 0;
  64.141 +
  64.142 +                           # Z[pl,pr] is level of process pr at plant pl
  64.143 +
  64.144 +var Xf {c in c_final, cp_pos[c], region} >= 0;
  64.145 +
  64.146 +                           # Xf[c,pl,r] is amount of final product c
  64.147 +                           # shipped from plant pl to region r
  64.148 +
  64.149 +var Xi {c in c_ship, cp_pos[c], cc_pos[c]} >= 0;
  64.150 +
  64.151 +                           # Xi[c,p1,p2] is amount of intermediate c
  64.152 +                           # shipped from plant p1 to plant p2
  64.153 +
  64.154 +var Vf {c_final,region,port} >= 0;
  64.155 +
  64.156 +                           # Vf[c,r,po] is amount of final product c
  64.157 +                           # imported by region r from port po
  64.158 +
  64.159 +var Vr {c in c_raw, cc_pos[c]} >= 0;
  64.160 +
  64.161 +                           # Vr[c,pl] is amount of raw material c
  64.162 +                           # imported for use at plant pl
  64.163 +
  64.164 +var U {c in c_raw, cc_pos[c]} >= 0;
  64.165 +
  64.166 +                           # U[c,pl] is amount of raw material c
  64.167 +                           # purchased domestically for use at plant pl
  64.168 +
  64.169 +var Psip;                  # Domestic recurrent cost
  64.170 +var Psil;                  # Transport cost
  64.171 +var Psii;                  # Import cost
  64.172 +
  64.173 +###  OBJECTIVE  ###
  64.174 +
  64.175 +minimize Psi:  Psip + Psil + Psii;
  64.176 +
  64.177 +###  CONSTRAINTS  ###
  64.178 +
  64.179 +subject to mbd {n in nutr, r in region}:
  64.180 +
  64.181 +    sum {c in c_final} fn[c,n] *
  64.182 +                (sum {po in port} Vf[c,r,po] +
  64.183 +                 sum {pl in cp_pos[c]} Xf[c,pl,r])  >=  cn75[r,n];
  64.184 +
  64.185 +                           # Total nutrients supplied to a region by all
  64.186 +                           # final products (sum of imports plus internal
  64.187 +                           # shipments from plants) must meet requirements
  64.188 +
  64.189 +subject to mbdb {c in c_final, r in region: cf75[r,c] > 0}:
  64.190 +
  64.191 +    sum {po in port} Vf[c,r,po] +
  64.192 +    sum {pl in cp_pos[c]} Xf[c,pl,r]  >=  cf75[r,c];
  64.193 +
  64.194 +                           # Total of each final product supplied to each
  64.195 +                           # region (as in previous constraint) must meet
  64.196 +                           # requirements
  64.197 +
  64.198 +subject to mb {c in commod, pl in plant}:
  64.199 +
  64.200 +    sum {pr in p_pos[pl]} io[c,pr] * Z[pl,pr]
  64.201 +
  64.202 +   + ( if c in c_ship then
  64.203 +                ( if pl in cp_pos[c] then sum {p2 in cc_pos[c]} Xi[c,pl,p2] )
  64.204 +              - ( if pl in cc_pos[c] then sum {p2 in cp_pos[c]} Xi[c,p2,pl] ))
  64.205 +
  64.206 +   + ( if (c in c_raw and pl in cc_pos[c]) then
  64.207 +                 (( if p_imp[c] > 0 then Vr[c,pl] )
  64.208 +                + ( if p_dom[pl,c] > 0 then U[c,pl] )))
  64.209 +
  64.210 +  >= if (c in c_final and pl in cp_pos[c]) then sum {r in region} Xf[c,pl,r];
  64.211 +
  64.212 +                           # For each commodity at each plant:  sum of
  64.213 +                           #   (1) production or consumption at plant,
  64.214 +                           #   (2) inter-plant shipments in or out,
  64.215 +                           #   (3) import and domestic purchases (raw only)
  64.216 +                           # is >= 0 for raw materials and intermediates;
  64.217 +                           # is >= the total shipped for final products
  64.218 +
  64.219 +subject to cc {pl in plant, u in m_pos[pl]}:
  64.220 +
  64.221 +    sum {pr in p_pos[pl]} util[u,pr] * Z[pl,pr]  <=  util_pct * icap[u,pl];
  64.222 +
  64.223 +                           # For each productive unit at each plant,
  64.224 +                           # total utilization by all processes
  64.225 +                           # may not exceed the unit's capacity
  64.226 +
  64.227 +subject to ap:
  64.228 +
  64.229 +    Psip  =  sum {c in c_raw, pl in cc_pos[c]} p_dom[pl,c] * U[c,pl];
  64.230 +
  64.231 +                           # Psip is the cost of domestic raw materials,
  64.232 +                           # summed over all plants that consume them
  64.233 +
  64.234 +subject to al:
  64.235 +
  64.236 +    Psil  =  sum {c in c_final} (
  64.237 +
  64.238 +               sum {pl in cp_pos[c], r in region}
  64.239 +                                              tran_final[pl,r] * Xf[c,pl,r]
  64.240 +
  64.241 +             + sum {po in port, r in region} tran_import[r,po] * Vf[c,r,po] )
  64.242 +
  64.243 +           + sum {c in c_ship, p1 in cp_pos[c], p2 in cc_pos[c]}
  64.244 +                                               tran_inter[p1,p2] * Xi[c,p1,p2]
  64.245 +
  64.246 +           + sum {c in c_raw, pl in cc_pos[c]: p_imp[c] > 0}
  64.247 +                                                    tran_raw[pl] * Vr[c,pl];
  64.248 +
  64.249 +                           # Total transport cost is sum of shipping costs for
  64.250 +                           #   (1) all final products from all plants,
  64.251 +                           #   (2) all imports of final products,
  64.252 +                           #   (3) all intermediates shipped between plants,
  64.253 +                           #   (4) all imports of raw materials
  64.254 +
  64.255 +subject to ai:
  64.256 +
  64.257 +    Psii / exch  =  sum {c in c_final, r in region, po in port}
  64.258 +                                                      p_imp[c] * Vf[c,r,po]
  64.259 +
  64.260 +                  + sum {c in c_raw, pl in cc_pos[c]} p_imp[c] * Vr[c,pl];
  64.261 +
  64.262 +                           # Total import cost -- at exchange rate --
  64.263 +                           # is sum of import costs for final products
  64.264 +                           # in each region and raw materials at each plant
  64.265 +
  64.266 +###  DATA  ###
  64.267 +
  64.268 +data;
  64.269 +
  64.270 +set center := ASWAN HELWAN ASSIOUT KAFR_EL_ZT ABU_ZAABAL ABU_KIR TALKHA SUEZ ;
  64.271 +
  64.272 +set port := ABU_KIR ;
  64.273 +
  64.274 +set plant := ASWAN HELWAN ASSIOUT KAFR_EL_ZT ABU_ZAABAL ;
  64.275 +
  64.276 +set region := ALEXANDRIA BEHERA GHARBIA KAFR_EL_SH DAKAHLIA DAMIETTA
  64.277 +              SHARKIA ISMAILIA SUEZ MENOUFIA KALUBIA GIZA BENI_SUEF FAYOUM
  64.278 +              MINIA ASSIOUT NEW_VALLEY SOHAG QUENA ASWAN ;
  64.279 +
  64.280 +set unit := SULF_A_S SULF_A_P NITR_ACID AMM_ELEC AMM_C_GAS C_AMM_NITR
  64.281 +            AMM_SULF SSP ;
  64.282 +
  64.283 +set proc := SULF_A_S SULF_A_P NITR_ACID AMM_ELEC AMM_C_GAS CAN_310 CAN_335
  64.284 +            AMM_SULF SSP_155 ;
  64.285 +
  64.286 +set nutr := N P205 ;
  64.287 +
  64.288 +set c_final := UREA CAN_260 CAN_310 CAN_335 AMM_SULF DAP SSP_155 C_250_55
  64.289 +               C_300_100 ;
  64.290 +
  64.291 +set c_inter := AMMONIA NITR_ACID SULF_ACID ;
  64.292 +
  64.293 +set c_ship := AMMONIA SULF_ACID ;
  64.294 +
  64.295 +set c_raw := EL_ASWAN COKE_GAS PHOS_ROCK LIMESTONE EL_SULFUR PYRITES
  64.296 +             ELECTRIC BF_GAS WATER STEAM BAGS ;
  64.297 +
  64.298 +set p_except[ASWAN] := CAN_335 ;
  64.299 +set p_except[HELWAN] := CAN_310 ;
  64.300 +set p_except[ASSIOUT] := ;
  64.301 +set p_except[KAFR_EL_ZT] := ;
  64.302 +set p_except[ABU_ZAABAL] := ;
  64.303 +
  64.304 +param cf75  default 0.0  :
  64.305 +
  64.306 +               CAN_260    CAN_310    CAN_335    AMM_SULF     UREA   :=
  64.307 +
  64.308 +ALEXANDRIA        .           .         5.0        3.0        1.0
  64.309 +ASSIOUT          1.0        20.0       26.0        1.0       27.0
  64.310 +ASWAN             .         40.0         .          .          .
  64.311 +BEHERA           1.0          .        25.0       90.0       35.0
  64.312 +BENI_SUEF        1.0          .        15.0        1.0       20.0
  64.313 +DAKAHLIA         1.0          .        26.0       60.0       20.0
  64.314 +DAMIETTA          .           .         2.0       15.0        8.0
  64.315 +FAYOUM           1.0          .        20.0        6.0       20.0
  64.316 +GHARBIA           .           .        17.0       60.0       28.0
  64.317 +GIZA              .           .        40.0        6.0        2.0
  64.318 +ISMAILIA          .           .         4.0        6.0        2.0
  64.319 +KAFR_EL_SH       1.0          .        10.0       45.0       22.0
  64.320 +KALUBIA           .           .        25.0       16.0        7.0
  64.321 +MENOUFIA         1.0          .        24.0       21.0       30.0
  64.322 +MINIA            2.0        15.0       35.0        1.0       41.0
  64.323 +NEW_VALLEY        .           .          .          .         1.0
  64.324 +QUENA             .         95.0        2.0         .         3.0
  64.325 +SHARKIA          1.0          .        31.0       50.0       28.0
  64.326 +SOHAG             .         65.0        3.0         .         7.0
  64.327 +SUEZ              .           .         1.0         .          .
  64.328 +
  64.329 +   :          SSP_155    C_250_55   C_300_100    DAP   :=
  64.330 +
  64.331 +ALEXANDRIA       8.0         .          .         .
  64.332 +ASSIOUT         35.0        5.0         .1        .
  64.333 +ASWAN            8.0         .          .         .
  64.334 +BEHERA          64.0        1.0         .1        .1
  64.335 +BENI_SUEF       13.0        3.0         .         .
  64.336 +DAKAHLIA        52.0        1.0         .         .
  64.337 +DAMIETTA         5.0         .          .         .
  64.338 +FAYOUM          17.0        1.0         .         .
  64.339 +GHARBIA         57.0        1.0         .2        .1
  64.340 +GIZA            14.0        1.0         .1        .
  64.341 +ISMAILIA         4.0         .          .         .
  64.342 +KAFR_EL_SH      25.0        2.0         .1        .
  64.343 +KALUBIA         22.0        1.0         .         .1
  64.344 +MENOUFIA        33.0        2.0         .1        .1
  64.345 +MINIA           50.0        3.0         .2        .1
  64.346 +NEW_VALLEY       1.0         .          .         .
  64.347 +QUENA            8.0         .          .         .
  64.348 +SHARKIA         43.0        1.0         .1        .
  64.349 +SOHAG           20.0        1.0         .         .
  64.350 +SUEZ             1.0         .          .         .        ;
  64.351 +
  64.352 +param fn  default 0.0 :      N     P205    :=
  64.353 +
  64.354 +            AMM_SULF       .206     .
  64.355 +            CAN_260        .26      .
  64.356 +            CAN_310        .31      .
  64.357 +            CAN_335        .335     .
  64.358 +            C_250_55       .25      .055
  64.359 +            C_300_100      .30      .10
  64.360 +            DAP            .18      .46
  64.361 +            SSP_155        .        .15
  64.362 +            UREA           .46      .      ;
  64.363 +
  64.364 +param road  default 0.0  :
  64.365 +
  64.366 +            ABU_KIR ABU_ZAABAL ASSIOUT ASWAN HELWAN KAFR_EL_ZT SUEZ TALKHA :=
  64.367 +
  64.368 +ALEXANDRIA      16     210       607    1135   244      119     362   187
  64.369 +ASSIOUT        616     420         .     518   362      504     527   518
  64.370 +ASWAN         1134     938       518       .   880     1022    1045  1036
  64.371 +BEHERA          76      50       547    1065   184       42     288   120
  64.372 +BENI_SUEF      359     163       257     775   105      248     270   261
  64.373 +DAKAHLIA       208     138       515    1033   152       58     219     3
  64.374 +DAMIETTA       267     216       596    1114   233      131     286    66
  64.375 +FAYOUM         341     145       308     826    88      230     252   243
  64.376 +GHARBIA        150      65       485    1003   122       20     226    55
  64.377 +GIZA           287      48       372     890    .9      133     169   146
  64.378 +ISMAILIA       365     142       536    1054   173      241      89   146
  64.379 +KAFR_EL_SH     145     105       525    1043   162       20     266    35
  64.380 +KALUBIA        190      97       439     957    76       66     180    81
  64.381 +MENOUFIA       157     154       472     990   109       33     213    90
  64.382 +MINIA          384     288       132     650   230      372     394   386
  64.383 +NEW_VALLEY     815     619       199     519   561      703     726   717
  64.384 +QUENA          858     662       242     276   604      746     769   760
  64.385 +SHARKIA        240      60       473     991   110       78     214    58
  64.386 +SOHAG          715     519        99     419   461      603     626   617
  64.387 +SUEZ           370     224       541    1059   178      246       .   298  ;
  64.388 +
  64.389 +param rail_half  default 0  :
  64.390 +
  64.391 +              KAFR_EL_ZT   ABU_ZAABAL    HELWAN     ASSIOUT   :=
  64.392 +
  64.393 +ABU_ZAABAL         85            .           .          .
  64.394 +HELWAN            142           57           .          .
  64.395 +ASSIOUT           504          420         362          .
  64.396 +ASWAN            1022          938         880        518     ;
  64.397 +
  64.398 +param :            impd_barg   impd_road :=
  64.399 +
  64.400 +ABU_ZAABAL            210          .1
  64.401 +ASSIOUT               583         0
  64.402 +ASWAN                1087        10
  64.403 +HELWAN                183         0
  64.404 +KAFR_EL_ZT            104         6 ;
  64.405 +
  64.406 +param io  default 0.0  :=
  64.407 +
  64.408 +   [*,AMM_C_GAS]  AMMONIA        1.0
  64.409 +                  BF_GAS      -609.
  64.410 +                  COKE_GAS      -2.0
  64.411 +                  ELECTRIC   -1960.
  64.412 +                  STEAM         -4.
  64.413 +                  WATER       -700.
  64.414 +
  64.415 +   [*,AMM_ELEC]   AMMONIA        1.0
  64.416 +                  EL_ASWAN     -12.0
  64.417 +
  64.418 +   [*,AMM_SULF]   AMMONIA        -.26
  64.419 +                  AMM_SULF       1.0
  64.420 +                  BAGS         -22.
  64.421 +                  ELECTRIC     -19.
  64.422 +                  SULF_ACID      -.76
  64.423 +                  WATER        -17.
  64.424 +
  64.425 +   [*,CAN_310]    AMMONIA        -.20
  64.426 +                  BAGS         -23.
  64.427 +                  CAN_310        1.0
  64.428 +                  LIMESTONE      -.12
  64.429 +                  NITR_ACID      -.71
  64.430 +                  STEAM          -.4
  64.431 +                  WATER        -49.
  64.432 +
  64.433 +   [*,CAN_335]    AMMONIA        -.21
  64.434 +                  BAGS         -23.
  64.435 +                  CAN_335        1.0
  64.436 +                  LIMESTONE      -.04
  64.437 +                  NITR_ACID      -.76
  64.438 +                  STEAM          -.4
  64.439 +                  WATER        -49.
  64.440 +
  64.441 +   [*,NITR_ACID]  AMMONIA        -.292
  64.442 +                  ELECTRIC    -231.
  64.443 +                  NITR_ACID      1.0
  64.444 +                  WATER          -.6
  64.445 +
  64.446 +   [*,SSP_155]    BAGS         -22.
  64.447 +                  ELECTRIC     -14.
  64.448 +                  PHOS_ROCK      -.62
  64.449 +                  SSP_155        1.0
  64.450 +                  SULF_ACID      -.41
  64.451 +                  WATER         -6.
  64.452 +
  64.453 +   [*,SULF_A_P]   ELECTRIC     -75.
  64.454 +                  PYRITES        -.826
  64.455 +                  SULF_ACID      1.0
  64.456 +                  WATER        -60.
  64.457 +
  64.458 +   [*,SULF_A_S]   ELECTRIC     -50.
  64.459 +                  EL_SULFUR      -.334
  64.460 +                  SULF_ACID      1.0
  64.461 +                  WATER        -20. ;
  64.462 +
  64.463 +param util  default 0  :=
  64.464 +
  64.465 +   [*,*]   SULF_A_S SULF_A_S    1      SULF_A_P SULF_A_P   1
  64.466 +           NITR_ACID NITR_ACID  1      AMM_ELEC AMM_ELEC   1
  64.467 +           AMM_C_GAS AMM_C_GAS  1      SSP SSP_155         1
  64.468 +           C_AMM_NITR CAN_310   1      C_AMM_NITR CAN_335  1
  64.469 +           AMM_SULF AMM_SULF    1 ;
  64.470 +
  64.471 +param p_imp  default 0.0  :=
  64.472 +
  64.473 +     PYRITES       17.5           AMM_SULF      75.
  64.474 +     EL_SULFUR     55.            DAP          175.
  64.475 +     UREA         150.            SSP_155       80.
  64.476 +     CAN_260       75.            C_250_55     100.
  64.477 +     CAN_310       90.            C_300_100    130.
  64.478 +     CAN_335      100.   ;
  64.479 +
  64.480 +param p_r  default 0.0  :=
  64.481 +
  64.482 +     ELECTRIC     .007
  64.483 +     BF_GAS       .007
  64.484 +     WATER        .031
  64.485 +     STEAM       1.25
  64.486 +     BAGS         .28   ;
  64.487 +
  64.488 +param p_pr  default 0.0  :=
  64.489 +
  64.490 + [HELWAN,COKE_GAS]              16.0
  64.491 + [ASWAN,EL_ASWAN]                1.0
  64.492 +
  64.493 + [*,LIMESTONE]      ASWAN        1.2
  64.494 +                    HELWAN       1.2
  64.495 +
  64.496 + [*,PHOS_ROCK]      ABU_ZAABAL   4.0
  64.497 +                    ASSIOUT      3.5
  64.498 +                    KAFR_EL_ZT   5.0   ;
  64.499 +
  64.500 +param dcap  default 0.0  :=
  64.501 +
  64.502 +   [ABU_ZAABAL,*]   SSP          600
  64.503 +                    SULF_A_P     227
  64.504 +                    SULF_A_S     242
  64.505 +
  64.506 +   [ASSIOUT,*]      SSP          600
  64.507 +                    SULF_A_S     250
  64.508 +
  64.509 +   [ASWAN,*]        AMM_ELEC     450
  64.510 +                    C_AMM_NITR  1100
  64.511 +                    NITR_ACID    800
  64.512 +
  64.513 +   [HELWAN,*]       AMM_C_GAS    172
  64.514 +                    AMM_SULF      24
  64.515 +                    C_AMM_NITR   364
  64.516 +                    NITR_ACID    282
  64.517 +
  64.518 +   [KAFR_EL_ZT,*]   SSP          600
  64.519 +                    SULF_A_P      50
  64.520 +                    SULF_A_S     200  ;
  64.521 +
  64.522 +end;
    65.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    65.2 +++ b/examples/fctp.mod	Mon Dec 06 13:09:21 2010 +0100
    65.3 @@ -0,0 +1,93 @@
    65.4 +/* FCTP, Fixed-Charge Transportation Problem */
    65.5 +
    65.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
    65.7 +
    65.8 +/* The Fixed-Charge Transportation Problem (FCTP) is obtained from
    65.9 +   classical transportation problem by imposing a fixed cost on each
   65.10 +   transportation link if there is a positive flow on that link. */
   65.11 +
   65.12 +param m, integer, > 0;
   65.13 +/* number of sources */
   65.14 +
   65.15 +param n, integer, > 0;
   65.16 +/* number of customers */
   65.17 +
   65.18 +set I := 1..m;
   65.19 +/* set of sources */
   65.20 +
   65.21 +set J := 1..n;
   65.22 +/* set of customers */
   65.23 +
   65.24 +param supply{i in I}, >= 0;
   65.25 +/* supply at source i */
   65.26 +
   65.27 +param demand{j in J}, >= 0;
   65.28 +/* demand at customer j */
   65.29 +
   65.30 +param varcost{i in I, j in J}, >= 0;
   65.31 +/* variable cost (a cost per one unit shipped from i to j) */
   65.32 +
   65.33 +param fixcost{i in I, j in J}, >= 0;
   65.34 +/* fixed cost (a cost for shipping any amount from i to j) */
   65.35 +
   65.36 +var x{i in I, j in J}, >= 0;
   65.37 +/* amount shipped from source i to customer j */
   65.38 +
   65.39 +s.t. f{i in I}: sum{j in J} x[i,j] = supply[i];
   65.40 +/* observe supply at source i */
   65.41 +
   65.42 +s.t. g{j in J}: sum{i in I} x[i,j] = demand[j];
   65.43 +/* satisfy demand at customer j */
   65.44 +
   65.45 +var y{i in I, j in J}, binary;
   65.46 +/* y[i,j] = 1 means some amount is shipped from i to j */
   65.47 +
   65.48 +s.t. h{i in I, j in J}: x[i,j] <= min(supply[i], demand[j]) * y[i,j];
   65.49 +/* if y[i,j] is 0, force x[i,j] to be 0 (may note that supply[i] and
   65.50 +   demand[j] are implicit upper bounds for x[i,j] as follows from the
   65.51 +   constraints f[i] and g[j]) */
   65.52 +
   65.53 +minimize cost: sum{i in I, j in J} varcost[i,j] * x[i,j] +
   65.54 +               sum{i in I, j in J} fixcost[i,j] * y[i,j];
   65.55 +/* total transportation costs */
   65.56 +
   65.57 +data;
   65.58 +
   65.59 +/* These data correspond to the instance bal8x12 from [Balinski]. */
   65.60 +
   65.61 +/* The optimal solution is 471.55 */
   65.62 +
   65.63 +param m := 8;
   65.64 +
   65.65 +param n := 12;
   65.66 +
   65.67 +param supply := 1 15.00,  2 20.00,  3 45.00,  4 35.00,
   65.68 +                5 25.00,  6 35.00,  7 10.00,  8 25.00;
   65.69 +
   65.70 +param demand := 1 20.00,  2 15.00,  3 20.00,  4 15.00,
   65.71 +                5  5.00,  6 20.00,  7 30.00,  8 10.00,
   65.72 +                9 35.00, 10 25.00, 11 10.00, 12  5.00;
   65.73 +
   65.74 +param varcost
   65.75 +      :   1    2    3    4    5    6    7    8    9    10   11   12  :=
   65.76 +      1  0.69 0.64 0.71 0.79 1.70 2.83 2.02 5.64 5.94 5.94 5.94 7.68
   65.77 +      2  1.01 0.75 0.88 0.59 1.50 2.63 2.26 5.64 5.85 5.62 5.85 4.94
   65.78 +      3  1.05 1.06 1.08 0.64 1.22 2.37 1.66 5.64 5.91 5.62 5.91 4.94
   65.79 +      4  1.94 1.50 1.56 1.22 1.98 1.98 1.36 6.99 6.99 6.99 6.99 3.68
   65.80 +      5  1.61 1.40 1.61 1.33 1.68 2.83 1.54 4.26 4.26 4.26 4.26 2.99
   65.81 +      6  5.29 5.94 6.08 5.29 5.96 6.77 5.08 0.31 0.21 0.17 0.31 1.53
   65.82 +      7  5.29 5.94 6.08 5.29 5.96 6.77 5.08 0.55 0.35 0.40 0.19 1.53
   65.83 +      8  5.29 6.08 6.08 5.29 5.96 6.45 5.08 2.43 2.30 2.33 1.81 2.50 ;
   65.84 +
   65.85 +param fixcost
   65.86 +      :   1    2    3    4    5    6    7    8    9    10   11   12  :=
   65.87 +      1  11.0 16.0 18.0 17.0 10.0 20.0 17.0 13.0 15.0 12.0 14.0 14.0
   65.88 +      2  14.0 17.0 17.0 13.0 15.0 13.0 16.0 11.0 20.0 11.0 15.0 10.0
   65.89 +      3  12.0 13.0 20.0 17.0 13.0 15.0 16.0 13.0 12.0 13.0 10.0 18.0
   65.90 +      4  16.0 19.0 16.0 11.0 15.0 12.0 18.0 12.0 18.0 13.0 13.0 14.0
   65.91 +      5  19.0 18.0 15.0 16.0 12.0 14.0 20.0 19.0 11.0 17.0 16.0 18.0
   65.92 +      6  13.0 20.0 20.0 17.0 15.0 12.0 14.0 11.0 12.0 19.0 15.0 16.0
   65.93 +      7  11.0 12.0 15.0 10.0 17.0 11.0 11.0 16.0 10.0 18.0 17.0 12.0
   65.94 +      8  17.0 10.0 20.0 12.0 17.0 20.0 16.0 15.0 10.0 12.0 16.0 18.0 ;
   65.95 +
   65.96 +end;
    66.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    66.2 +++ b/examples/food.mod	Mon Dec 06 13:09:21 2010 +0100
    66.3 @@ -0,0 +1,127 @@
    66.4 +/* Food Manufacture 1, section 12.1 in
    66.5 + * Williams, "Model Building in Mathematical Programming"
    66.6 + *
    66.7 + * Sebastian Nowozin <nowozin@gmail.com>
    66.8 + */
    66.9 +
   66.10 +set oils;
   66.11 +set month;
   66.12 +
   66.13 +/* Buying prices of the raw oils in the next six month. */
   66.14 +param buyingprices{month,oils};
   66.15 +
   66.16 +/* Actual amount bought in each month. */
   66.17 +var buys{month,oils} >= 0;
   66.18 +
   66.19 +/* Stock for each oil. */
   66.20 +var stock{month,oils} >= 0;
   66.21 +
   66.22 +/* Price of the produced product */
   66.23 +param productprice >= 0;
   66.24 +param storagecost;
   66.25 +
   66.26 +param oilhardness{oils} >= 0;
   66.27 +
   66.28 +/* Actual amount of output oil produced in each month */
   66.29 +var production{m in month} >= 0;
   66.30 +var useoil{m in month, o in oils} >= 0;
   66.31 +
   66.32 +maximize totalprofit:
   66.33 +    sum{m in month} productprice*production[m]
   66.34 +    - sum{m in month, o in oils} buyingprices[m,o]*buys[m,o]
   66.35 +    - sum{m in month, o in oils} storagecost*stock[m,o];
   66.36 +
   66.37 +/* Constraints */
   66.38 +
   66.39 +/* 1. Starting stock */
   66.40 +s.t. startstock{o in oils}:
   66.41 +    stock[1,o] = 500;
   66.42 +s.t. endstock{o in oils}:
   66.43 +    stock[6,o] + buys[6,o] - useoil[6,o] >= 500;
   66.44 +
   66.45 +/* 2. Stock constraints */
   66.46 +s.t. stocklimit{m in month, o in oils}:
   66.47 +    stock[m,o] <= 1000;
   66.48 +
   66.49 +s.t. production1{m in month, o in oils}:
   66.50 +    useoil[m,o] <= stock[m,o] + buys[m,o];
   66.51 +s.t. production2{m1 in month, m2 in month, o in oils : m2 = m1+1}:
   66.52 +    stock[m2,o] = stock[m1,o] + buys[m1,o] - useoil[m1,o];
   66.53 +
   66.54 +s.t. production3a{m in month}:
   66.55 +    sum{o in oils} oilhardness[o]*useoil[m,o] >= 3*production[m];
   66.56 +s.t. production3b{m in month}:
   66.57 +    sum{o in oils} oilhardness[o]*useoil[m,o] <= 6*production[m];
   66.58 +
   66.59 +s.t. production4{m in month}:
   66.60 +    production[m] = sum{o in oils} useoil[m,o];
   66.61 +
   66.62 +/* 3. Refining constraints */
   66.63 +s.t. refine1{m in month}:
   66.64 +    useoil[m,"VEG1"]+useoil[m,"VEG2"] <= 200;
   66.65 +s.t. refine2{m in month}:
   66.66 +    useoil[m,"OIL1"]+useoil[m,"OIL2"]+useoil[m,"OIL3"] <= 250;
   66.67 +
   66.68 +solve;
   66.69 +
   66.70 +for {m in month} {
   66.71 +    printf "Month %d\n", m;
   66.72 +    printf "PRODUCE %4.2f tons, hardness %4.2f\n", production[m],
   66.73 +        (sum{o in oils} oilhardness[o]*useoil[m,o]) / (sum{o in oils} useoil[m,o]);
   66.74 +
   66.75 +    printf "\tVEG1\tVEG2\tOIL1\tOIL2\tOIL3\n";
   66.76 +    printf "STOCK";
   66.77 +    printf "%d", m;
   66.78 +    for {o in oils} {
   66.79 +        printf "\t%4.2f", stock[m,o];
   66.80 +    }
   66.81 +    printf "\nBUY";
   66.82 +    for {o in oils} {
   66.83 +        printf "\t%4.2f", buys[m,o];
   66.84 +    }
   66.85 +    printf "\nUSE";
   66.86 +    printf "%d", m;
   66.87 +    for {o in oils} {
   66.88 +        printf "\t%4.2f", useoil[m,o];
   66.89 +    }
   66.90 +    printf "\n";
   66.91 +    printf "\n";
   66.92 +}
   66.93 +printf "Total profit: %4.2f\n",
   66.94 +    (sum{m in month} productprice*production[m]
   66.95 +    - sum{m in month, o in oils} buyingprices[m,o]*buys[m,o]
   66.96 +    - sum{m in month, o in oils} storagecost*stock[m,o]);
   66.97 +printf "      turnover: %4.2f\n",
   66.98 +    sum{m in month} productprice*production[m];
   66.99 +printf "      buying costs: %4.2f\n",
  66.100 +    sum{m in month, o in oils} buyingprices[m,o]*buys[m,o];
  66.101 +printf "      storage costs: %4.2f\n",
  66.102 +    sum{m in month, o in oils} storagecost*stock[m,o];
  66.103 +
  66.104 +
  66.105 +data;
  66.106 +
  66.107 +param : oils : oilhardness :=
  66.108 +    VEG1    8.8
  66.109 +    VEG2    6.1
  66.110 +    OIL1    2.0
  66.111 +    OIL2    4.2
  66.112 +    OIL3    5.0 ;
  66.113 +
  66.114 +set month := 1 2 3 4 5 6;
  66.115 +
  66.116 +param buyingprices
  66.117 +
  66.118 +:           VEG1    VEG2    OIL1    OIL2    OIL3    :=
  66.119 +
  66.120 +1           110     120     130     110     115
  66.121 +2           130     130     110     90      115
  66.122 +3           110     140     130     100     95
  66.123 +4           120     110     120     120     125
  66.124 +5           100     120     150     110     105
  66.125 +6           90      100     140     80      135 ;
  66.126 +
  66.127 +param productprice := 150;
  66.128 +param storagecost := 5;
  66.129 +
  66.130 +end;
    67.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    67.2 +++ b/examples/food2.mod	Mon Dec 06 13:09:21 2010 +0100
    67.3 @@ -0,0 +1,150 @@
    67.4 +/* Food Manufacture 2, section 12.2 in
    67.5 + * Williams, "Model Building in Mathematical Programming"
    67.6 + *
    67.7 + * Sebastian Nowozin <nowozin@gmail.com>
    67.8 + */
    67.9 +
   67.10 +set oils;
   67.11 +set month;
   67.12 +
   67.13 +/* Buying prices of the raw oils in the next six month. */
   67.14 +param buyingprices{month,oils};
   67.15 +
   67.16 +/* Actual amount bought in each month. */
   67.17 +var buys{month,oils} >= 0;
   67.18 +
   67.19 +/* Stock for each oil. */
   67.20 +var stock{month,oils} >= 0;
   67.21 +
   67.22 +/* Price of the produced product */
   67.23 +param productprice >= 0;
   67.24 +param storagecost;
   67.25 +
   67.26 +param oilhardness{oils} >= 0;
   67.27 +param M >= 0;
   67.28 +
   67.29 +/* Actual amount of output oil produced in each month */
   67.30 +var production{m in month} >= 0;
   67.31 +var useoil{m in month, o in oils} >= 0, <= M;
   67.32 +var useoilb{m in month, o in oils}, binary;
   67.33 +
   67.34 +maximize totalprofit:
   67.35 +    sum{m in month} productprice*production[m]
   67.36 +    - sum{m in month, o in oils} buyingprices[m,o]*buys[m,o]
   67.37 +    - sum{m in month, o in oils} storagecost*stock[m,o];
   67.38 +
   67.39 +/* Constraints */
   67.40 +
   67.41 +/* 1. Starting stock */
   67.42 +s.t. startstock{o in oils}:
   67.43 +    stock[1,o] = 500;
   67.44 +s.t. endstock{o in oils}:
   67.45 +    stock[6,o] + buys[6,o] - useoil[6,o] >= 500;
   67.46 +
   67.47 +/* 2. Stock constraints */
   67.48 +s.t. stocklimit{m in month, o in oils}:
   67.49 +    stock[m,o] <= 1000;
   67.50 +
   67.51 +s.t. production1{m in month, o in oils}:
   67.52 +    useoil[m,o] <= stock[m,o] + buys[m,o];
   67.53 +s.t. production2{m1 in month, m2 in month, o in oils : m2 = m1+1}:
   67.54 +    stock[m2,o] = stock[m1,o] + buys[m1,o] - useoil[m1,o];
   67.55 +
   67.56 +s.t. production3a{m in month}:
   67.57 +    sum{o in oils} oilhardness[o]*useoil[m,o] >= 3*production[m];
   67.58 +s.t. production3b{m in month}:
   67.59 +    sum{o in oils} oilhardness[o]*useoil[m,o] <= 6*production[m];
   67.60 +
   67.61 +s.t. production4{m in month}:
   67.62 +    production[m] = sum{o in oils} useoil[m,o];
   67.63 +
   67.64 +/* 3. Refining constraints */
   67.65 +s.t. refine1{m in month}:
   67.66 +    useoil[m,"VEG1"]+useoil[m,"VEG2"] <= 200;
   67.67 +s.t. refine2{m in month}:
   67.68 +    useoil[m,"OIL1"]+useoil[m,"OIL2"]+useoil[m,"OIL3"] <= 250;
   67.69 +
   67.70 +/* 4. Additional conditions:
   67.71 + *    i) The food may never be made up of more than three oils every month
   67.72 + */
   67.73 +s.t. useoilb_calc{m in month, o in oils}:
   67.74 +    M*useoilb[m,o] >= useoil[m,o];
   67.75 +s.t. useoilb_limit{m in month}:
   67.76 +    sum{o in oils} useoilb[m,o] <= 3;
   67.77 +
   67.78 +/* ii) If an oil is used in a month, at least 20 tons must be used.
   67.79 + */
   67.80 +s.t. useminimum{m in month, o in oils}:
   67.81 +    20*useoilb[m,o] <= useoil[m,o];
   67.82 +
   67.83 +/* iii) If either of VEG1 or VEG2 is used in a month, OIL2 must also be used
   67.84 + */
   67.85 +s.t. use_oil2a{m in month}:
   67.86 +    useoilb[m,"VEG1"] <= useoilb[m,"OIL3"];
   67.87 +s.t. use_oil2b{m in month}:
   67.88 +    useoilb[m,"VEG2"] <= useoilb[m,"OIL3"];
   67.89 +
   67.90 +solve;
   67.91 +
   67.92 +for {m in month} {
   67.93 +    printf "Month %d\n", m;
   67.94 +    printf "PRODUCE %4.2f tons, hardness %4.2f\n", production[m],
   67.95 +        (sum{o in oils} oilhardness[o]*useoil[m,o]) / (sum{o in oils} useoil[m,o]);
   67.96 +
   67.97 +    printf "\tVEG1\tVEG2\tOIL1\tOIL2\tOIL3\n";
   67.98 +    printf "STOCK";
   67.99 +    printf "%d", m;
  67.100 +    for {o in oils} {
  67.101 +        printf "\t%4.2f", stock[m,o];
  67.102 +    }
  67.103 +    printf "\nBUY";
  67.104 +    for {o in oils} {
  67.105 +        printf "\t%4.2f", buys[m,o];
  67.106 +    }
  67.107 +    printf "\nUSE";
  67.108 +    printf "%d", m;
  67.109 +    for {o in oils} {
  67.110 +        printf "\t%4.2f", useoil[m,o];
  67.111 +    }
  67.112 +    printf "\n";
  67.113 +    printf "\n";
  67.114 +}
  67.115 +printf "Total profit: %4.2f\n",
  67.116 +    (sum{m in month} productprice*production[m]
  67.117 +    - sum{m in month, o in oils} buyingprices[m,o]*buys[m,o]
  67.118 +    - sum{m in month, o in oils} storagecost*stock[m,o]);
  67.119 +printf "      turnover: %4.2f\n",
  67.120 +    sum{m in month} productprice*production[m];
  67.121 +printf "      buying costs: %4.2f\n",
  67.122 +    sum{m in month, o in oils} buyingprices[m,o]*buys[m,o];
  67.123 +printf "      storage costs: %4.2f\n",
  67.124 +    sum{m in month, o in oils} storagecost*stock[m,o];
  67.125 +
  67.126 +
  67.127 +data;
  67.128 +
  67.129 +param : oils : oilhardness :=
  67.130 +    VEG1    8.8
  67.131 +    VEG2    6.1
  67.132 +    OIL1    2.0
  67.133 +    OIL2    4.2
  67.134 +    OIL3    5.0 ;
  67.135 +
  67.136 +set month := 1 2 3 4 5 6;
  67.137 +
  67.138 +param buyingprices
  67.139 +
  67.140 +:           VEG1    VEG2    OIL1    OIL2    OIL3    :=
  67.141 +
  67.142 +1           110     120     130     110     115
  67.143 +2           130     130     110     90      115
  67.144 +3           110     140     130     100     95
  67.145 +4           120     110     120     120     125
  67.146 +5           100     120     150     110     105
  67.147 +6           90      100     140     80      135 ;
  67.148 +
  67.149 +param productprice := 150;
  67.150 +param storagecost := 5;
  67.151 +param M := 1000;
  67.152 +
  67.153 +end;
    68.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    68.2 +++ b/examples/gap.mod	Mon Dec 06 13:09:21 2010 +0100
    68.3 @@ -0,0 +1,79 @@
    68.4 +/* GAP, Generalized Assignment Problem */
    68.5 +
    68.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
    68.7 +
    68.8 +/* The Generalized Assignment Problem (GAP) is to assign a set of jobs
    68.9 +   to a set of agents subject to the constraints that each job must be
   68.10 +   assigned exactly to one agent and the total resources consumed by all
   68.11 +   jobs assigned to an agent must not exceed the agent's capacity. */
   68.12 +
   68.13 +param m, integer, > 0;
   68.14 +/* number of agents */
   68.15 +
   68.16 +param n, integer, > 0;
   68.17 +/* number of jobs */
   68.18 +
   68.19 +set I := 1..m;
   68.20 +/* set of agents */
   68.21 +
   68.22 +set J := 1..n;
   68.23 +/* set of jobs */
   68.24 +
   68.25 +param a{i in I, j in J}, >= 0;
   68.26 +/* resource consumed in allocating job j to agent i */
   68.27 +
   68.28 +param b{i in I}, >= 0;
   68.29 +/* resource capacity of agent i */
   68.30 +
   68.31 +param c{i in I, j in J}, >= 0;
   68.32 +/* cost of allocating job j to agent i */
   68.33 +
   68.34 +var x{i in I, j in J}, binary;
   68.35 +/* x[i,j] = 1 means job j is assigned to agent i */
   68.36 +
   68.37 +s.t. one{j in J}: sum{i in I} x[i,j] = 1;
   68.38 +/* job j must be assigned exactly to one agent */
   68.39 +
   68.40 +s.t. lim{i in I}: sum{j in J} a[i,j] * x[i,j] <= b[i];
   68.41 +/* total amount of resources consumed by all jobs assigned to agent i
   68.42 +   must not exceed the agent's capacity */
   68.43 +
   68.44 +minimize obj: sum{i in I, j in J} c[i,j] * x[i,j];
   68.45 +/* the objective is to find cheapest assignment (note that gap can also
   68.46 +   be formulated as maximization problem) */
   68.47 +
   68.48 +data;
   68.49 +
   68.50 +/* These data correspond to the instance c515-1 (gap1) from:
   68.51 +
   68.52 +   I.H. Osman, "Heuristics for the Generalised Assignment Problem:
   68.53 +   Simulated Annealing and Tabu Search Approaches", OR Spektrum, Volume
   68.54 +   17, 211-225, 1995
   68.55 +
   68.56 +   D. Cattrysse, M. Salomon and L.N. Van Wassenhove, "A set partitioning
   68.57 +   heuristic for the generalized assignment problem", European Journal
   68.58 +   of Operational Research, Volume 72, 167-174, 1994 */
   68.59 +
   68.60 +/* The optimal solution is 261 (minimization) or 336 (maximization) */
   68.61 +
   68.62 +param m := 5;
   68.63 +
   68.64 +param n := 15;
   68.65 +
   68.66 +param a :  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 :=
   68.67 +      1    8 15 14 23  8 16  8 25  9 17 25 15 10  8 24
   68.68 +      2   15  7 23 22 11 11 12 10 17 16  7 16 10 18 22
   68.69 +      3   21 20  6 22 24 10 24  9 21 14 11 14 11 19 16
   68.70 +      4   20 11  8 14  9  5  6 19 19  7  6  6 13  9 18
   68.71 +      5    8 13 13 13 10 20 25 16 16 17 10 10  5 12 23 ;
   68.72 +
   68.73 +param b := 1 36, 2 34, 3 38, 4 27, 5 33;
   68.74 +
   68.75 +param c :  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 :=
   68.76 +      1   17 21 22 18 24 15 20 18 19 18 16 22 24 24 16
   68.77 +      2   23 16 21 16 17 16 19 25 18 21 17 15 25 17 24
   68.78 +      3   16 20 16 25 24 16 17 19 19 18 20 16 17 21 24
   68.79 +      4   19 19 22 22 20 16 19 17 21 19 25 23 25 25 25
   68.80 +      5   18 19 15 15 21 25 16 16 23 15 22 17 19 22 24 ;
   68.81 +
   68.82 +end;
    69.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    69.2 +++ b/examples/glpsol.c	Mon Dec 06 13:09:21 2010 +0100
    69.3 @@ -0,0 +1,10 @@
    69.4 +/* glpsol.c */
    69.5 +
    69.6 +#include <glpk.h>
    69.7 +
    69.8 +int main(int argc, const char *argv[])
    69.9 +{     /* stand-alone LP/MIP solver */
   69.10 +      return glp_main(argc, argv);
   69.11 +}
   69.12 +
   69.13 +/* eof */
    70.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    70.2 +++ b/examples/graph.mod	Mon Dec 06 13:09:21 2010 +0100
    70.3 @@ -0,0 +1,98 @@
    70.4 +/* graph.mod - graph visualization */
    70.5 +
    70.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
    70.7 +
    70.8 +/* This model creates a picture in EPS format to visualize a graph. */
    70.9 +
   70.10 +param file, symbolic, default "graph.eps";
   70.11 +/* output file to write the picture */
   70.12 +
   70.13 +param R, default 2;
   70.14 +/* radius to draw vertices, in mm */
   70.15 +
   70.16 +param n, integer, > 0;
   70.17 +/* number of vertices */
   70.18 +
   70.19 +set V, default 1..n;
   70.20 +/* set of vertices */
   70.21 +
   70.22 +set E, within V cross V;
   70.23 +/* set of edges */
   70.24 +
   70.25 +param x{i in V}, default 50 * cos((i - 1) / card(V) * 8 * atan(1));
   70.26 +param y{i in V}, default 50 * sin((i - 1) / card(V) * 8 * atan(1));
   70.27 +/* x[i] and y[i] are coordinates of node i, in mm */
   70.28 +
   70.29 +param x0 := (min{i in V} x[i]) - R - 3.0;
   70.30 +param y0 := (min{i in V} y[i]) - R - 3.0;
   70.31 +param x1 := (max{i in V} x[i]) + R + 3.0;
   70.32 +param y1 := (max{i in V} y[i]) + R + 3.0;
   70.33 +
   70.34 +printf "%%!PS-Adobe-3.0 EPSF-3.0\n" > file;
   70.35 +printf "%%%%BoundingBox: 0 0 %d %d\n",
   70.36 +      (72 / 25.4) * (x1 - x0), (72 / 25.4) * (y1 - y0) >> file;
   70.37 +printf "/Helvetica findfont 6 scalefont setfont\n" >> file;
   70.38 +printf "/mm { 72 mul 25.4 div } def\n" >> file;
   70.39 +
   70.40 +for {(i,j) in E}
   70.41 +{     printf "newpath\n" >> file;
   70.42 +      printf "%g mm %g mm moveto\n", x[i] - x0, y[i] - y0 >> file;
   70.43 +      printf "%g mm %g mm lineto\n", x[j] - x0, y[j] - y0 >> file;
   70.44 +      printf "closepath\n" >> file;
   70.45 +      printf "stroke\n" >> file;
   70.46 +}
   70.47 +
   70.48 +for {i in V}
   70.49 +{     printf "newpath\n" >> file;
   70.50 +      printf "%g mm %g mm %g mm 0 360 arc\n",
   70.51 +         x[i] - x0, y[i] - y0, R >> file;
   70.52 +      printf "closepath\n" >> file;
   70.53 +      printf "gsave 1 1 1 setrgbcolor fill grestore\n" >> file;
   70.54 +      printf "stroke\n" >> file;
   70.55 +      printf "%g mm %g mm moveto\n",
   70.56 +         x[i] - (if i <= 9 then 1.2 else 1.8) - x0,
   70.57 +         y[i] - 0.8 - y0 >> file;
   70.58 +      printf "( %d ) show\n", i >> file;
   70.59 +}
   70.60 +
   70.61 +printf "showpage\n" >> file;
   70.62 +printf "%%%%EOF\n" >> file;
   70.63 +
   70.64 +data;
   70.65 +
   70.66 +param
   70.67 +:  V  :  x     y :=
   70.68 +   1     0    40
   70.69 +   2    38    12
   70.70 +   3    24   -32
   70.71 +   4   -24   -32
   70.72 +   5   -38    12
   70.73 +   6   -19    26
   70.74 +   7    19    26
   70.75 +   8    31   -10
   70.76 +   9     0   -32
   70.77 +  10   -31   -10
   70.78 +  11    -9    12
   70.79 +  12     9    12
   70.80 +  13    14    -5
   70.81 +  14     0   -15
   70.82 +  15   -14    -5
   70.83 +  16     0     0 ;
   70.84 +
   70.85 +set E :=
   70.86 +   (1,*)  6 10 16 12  7
   70.87 +   (2,*)  7  6 16 13  8
   70.88 +   (3,*)  8  7 16 14  9
   70.89 +   (4,*)  9  8 16 15 10
   70.90 +   (5,*) 10  9 16 11  6
   70.91 +   (6,*) 14
   70.92 +   (7,*) 15
   70.93 +   (8,*) 11
   70.94 +   (9,*) 12
   70.95 +  (10,*) 13
   70.96 +  (11,*) 12 15
   70.97 +  (12,*) 13
   70.98 +  (13,*) 14
   70.99 +  (14,*) 15 ;
  70.100 +
  70.101 +end;
    71.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    71.2 +++ b/examples/hashi.mod	Mon Dec 06 13:09:21 2010 +0100
    71.3 @@ -0,0 +1,168 @@
    71.4 +/* A solver for the Japanese number-puzzle Hashiwokakero
    71.5 + * (http://en.wikipedia.org/wiki/Hashiwokakero)
    71.6 + *
    71.7 + * Sebastian Nowozin <nowozin@gmail.com>, 13th January 2009
    71.8 + */
    71.9 +
   71.10 +param n := 25;
   71.11 +set rows := 1..n;
   71.12 +set cols := 1..n;
   71.13 +param givens{rows, cols}, integer, >= 0, <= 8, default 0;
   71.14 +
   71.15 +/* Set of vertices as (row,col) coordinates */
   71.16 +set V := { (i,j) in { rows, cols }: givens[i,j] != 0 };
   71.17 +
   71.18 +/* Set of feasible horizontal edges from (i,j) to (k,l) rightwards */
   71.19 +set Eh := { (i,j,k,l) in { V, V }:
   71.20 +        i = k and j < l and             # Same row and left to right
   71.21 +        card({ (s,t) in V: s = i and t > j and t < l }) = 0             # No vertex inbetween
   71.22 +        };
   71.23 +
   71.24 +/* Set of feasible vertical edges from (i,j) to (k,l) downwards */
   71.25 +set Ev := { (i,j,k,l) in { V, V }:
   71.26 +        j = l and i < k and             # Same column and top to bottom
   71.27 +        card({ (s,t) in V: t = j and s > i and s < k }) = 0             # No vertex inbetween
   71.28 +        };
   71.29 +
   71.30 +set E := Eh union Ev;
   71.31 +
   71.32 +/* Indicators: use edge once/twice */
   71.33 +var xe1{E}, binary;
   71.34 +var xe2{E}, binary;
   71.35 +
   71.36 +/* Constraint: Do not use edge or do use once or do use twice */
   71.37 +s.t. edge_sel{(i,j,k,l) in E}:
   71.38 +        xe1[i,j,k,l] + xe2[i,j,k,l] <= 1;
   71.39 +
   71.40 +/* Constraint: There must be as many edges used as the node value */
   71.41 +s.t. satisfy_vertex_demand{(s,t) in V}:
   71.42 +        sum{(i,j,k,l) in E: (i = s and j = t) or (k = s and l = t)}
   71.43 +                (xe1[i,j,k,l] + 2.0*xe2[i,j,k,l]) = givens[s,t];
   71.44 +
   71.45 +/* Constraint: No crossings */
   71.46 +s.t. no_crossing1{(i,j,k,l) in Eh, (s,t,u,v) in Ev:
   71.47 +        s < i and u > i and j < t and l > t}:
   71.48 +        xe1[i,j,k,l] + xe1[s,t,u,v] <= 1;
   71.49 +s.t. no_crossing2{(i,j,k,l) in Eh, (s,t,u,v) in Ev:
   71.50 +        s < i and u > i and j < t and l > t}:
   71.51 +        xe1[i,j,k,l] + xe2[s,t,u,v] <= 1;
   71.52 +s.t. no_crossing3{(i,j,k,l) in Eh, (s,t,u,v) in Ev:
   71.53 +        s < i and u > i and j < t and l > t}:
   71.54 +        xe2[i,j,k,l] + xe1[s,t,u,v] <= 1;
   71.55 +s.t. no_crossing4{(i,j,k,l) in Eh, (s,t,u,v) in Ev:
   71.56 +        s < i and u > i and j < t and l > t}:
   71.57 +        xe2[i,j,k,l] + xe2[s,t,u,v] <= 1;
   71.58 +
   71.59 +
   71.60 +/* Model connectivity by auxiliary network flow problem:
   71.61 + * One vertex becomes a target node and all other vertices send a unit flow
   71.62 + * to it.  The edge selection variables xe1/xe2 are VUB constraints and
   71.63 + * therefore xe1/xe2 select the feasible graph for the max-flow problems.
   71.64 + */
   71.65 +set node_target := { (s,t) in V:
   71.66 +        card({ (i,j) in V: i < s or (i = s and j < t) }) = 0};
   71.67 +set node_sources := { (s,t) in V: (s,t) not in node_target };
   71.68 +
   71.69 +var flow_forward{ E }, >= 0;
   71.70 +var flow_backward{ E }, >= 0;
   71.71 +s.t. flow_conservation{ (s,t) in node_target, (p,q) in V }:
   71.72 +        /* All incoming flows */
   71.73 +        - sum{(i,j,k,l) in E: k = p and l = q} flow_forward[i,j,k,l]
   71.74 +        - sum{(i,j,k,l) in E: i = p and j = q} flow_backward[i,j,k,l]
   71.75 +        /* All outgoing flows */
   71.76 +        + sum{(i,j,k,l) in E: k = p and l = q} flow_backward[i,j,k,l]
   71.77 +        + sum{(i,j,k,l) in E: i = p and j = q} flow_forward[i,j,k,l]
   71.78 +        = 0 + (if (p = s and q = t) then card(node_sources) else -1);
   71.79 +
   71.80 +/* Variable-Upper-Bound (VUB) constraints: xe1/xe2 bound the flows.
   71.81 + */
   71.82 +s.t. connectivity_vub1{(i,j,k,l) in E}:
   71.83 +        flow_forward[i,j,k,l] <= card(node_sources)*(xe1[i,j,k,l] + xe2[i,j,k,l]);
   71.84 +s.t. connectivity_vub2{(i,j,k,l) in E}:
   71.85 +        flow_backward[i,j,k,l] <= card(node_sources)*(xe1[i,j,k,l] + xe2[i,j,k,l]);
   71.86 +
   71.87 +/* A feasible solution is enough
   71.88 + */
   71.89 +minimize cost: 0;
   71.90 +
   71.91 +solve;
   71.92 +
   71.93 +/* Output solution graphically */
   71.94 +printf "\nSolution:\n";
   71.95 +for { row in rows } {
   71.96 +        for { col in cols } {
   71.97 +                /* First print this cell information: givens or space */
   71.98 +                printf{0..0: givens[row,col] != 0} "%d", givens[row,col];
   71.99 +                printf{0..0: givens[row,col] = 0 and
  71.100 +                        card({(i,j,k,l) in Eh: i = row and col >= j and col < l and
  71.101 +                                xe1[i,j,k,l] = 1}) = 1} "-";
  71.102 +                printf{0..0: givens[row,col] = 0 and
  71.103 +                        card({(i,j,k,l) in Eh: i = row and col >= j and col < l and
  71.104 +                                xe2[i,j,k,l] = 1}) = 1} "=";
  71.105 +                printf{0..0: givens[row,col] = 0
  71.106 +                        and card({(i,j,k,l) in Ev: j = col and row >= i and row < k and
  71.107 +                                xe1[i,j,k,l] = 1}) = 1} "|";
  71.108 +                printf{0..0: givens[row,col] = 0
  71.109 +                        and card({(i,j,k,l) in Ev: j = col and row >= i and row < k and
  71.110 +                                xe2[i,j,k,l] = 1}) = 1} '"';
  71.111 +                printf{0..0: givens[row,col] = 0
  71.112 +                        and card({(i,j,k,l) in Eh: i = row and col >= j and col < l and
  71.113 +                                (xe1[i,j,k,l] = 1 or xe2[i,j,k,l] = 1)}) = 0
  71.114 +                        and card({(i,j,k,l) in Ev: j = col and row >= i and row < k and
  71.115 +                                (xe1[i,j,k,l] = 1 or xe2[i,j,k,l] = 1)}) = 0} " ";
  71.116 +
  71.117 +                /* Now print any edges */
  71.118 +                printf{(i,j,k,l) in Eh: i = row and col >= j and col < l and xe1[i,j,k,l] = 1} "-";
  71.119 +                printf{(i,j,k,l) in Eh: i = row and col >= j and col < l and xe2[i,j,k,l] = 1} "=";
  71.120 +
  71.121 +                printf{(i,j,k,l) in Eh: i = row and col >= j and col < l and
  71.122 +                        xe1[i,j,k,l] = 0 and xe2[i,j,k,l] = 0} " ";
  71.123 +                printf{0..0: card({(i,j,k,l) in Eh: i = row and col >= j and col < l}) = 0} " ";
  71.124 +        }
  71.125 +        printf "\n";
  71.126 +        for { col in cols } {
  71.127 +                printf{(i,j,k,l) in Ev: j = col and row >= i and row < k and xe1[i,j,k,l] = 1} "|";
  71.128 +                printf{(i,j,k,l) in Ev: j = col and row >= i and row < k and xe2[i,j,k,l] = 1} '"';
  71.129 +                printf{(i,j,k,l) in Ev: j = col and row >= i and row < k and
  71.130 +                        xe1[i,j,k,l] = 0 and xe2[i,j,k,l] = 0} " ";
  71.131 +                /* No vertical edges: skip also a field */
  71.132 +                printf{0..0: card({(i,j,k,l) in Ev: j = col and row >= i and row < k}) = 0} " ";
  71.133 +                printf " ";
  71.134 +        }
  71.135 +        printf "\n";
  71.136 +}
  71.137 +
  71.138 +data;
  71.139 +
  71.140 +/* This is a difficult 25x25 Hashiwokakero.
  71.141 + */
  71.142 +param givens : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
  71.143 +25 :=
  71.144 +           1   2 . 2 . 2 . . 2 . 2 . . 2 . . . . 2 . 2 . 2 . 2 .
  71.145 +           2   . 1 . . . . 2 . . . 4 . . 5 . 2 . . 1 . 2 . 2 . 1
  71.146 +           3   2 . . 5 . 4 . . 3 . . . . . 1 . . 4 . 5 . 1 . 1 .
  71.147 +           4   . . . . . . . . . . . 1 . 3 . . 1 . . . . . . . .
  71.148 +           5   2 . . 6 . 6 . . 8 . 5 . 2 . . 3 . 5 . 7 . . 2 . .
  71.149 +           6   . 1 . . . . . . . . . 1 . . 2 . . . . . 1 . . . 3
  71.150 +           7   2 . . . . 5 . . 6 . 4 . . 2 . . . 2 . 5 . 4 . 2 .
  71.151 +           8   . 2 . 2 . . . . . . . . . . . 3 . . 3 . . . 1 . 2
  71.152 +           9   . . . . . . . . . . 4 . 2 . 2 . . 1 . . . 3 . 1 .
  71.153 +          10   2 . 3 . . 6 . . 2 . . . . . . . . . . 3 . . . . .
  71.154 +          11   . . . . 1 . . 2 . . 5 . . 1 . 4 . 3 . . . . 2 . 4
  71.155 +          12   . . 2 . . 1 . . . . . . 5 . 4 . . . . 4 . 3 . . .
  71.156 +          13   2 . . . 3 . 1 . . . . . . . . 3 . . 5 . 5 . . 2 .
  71.157 +          14   . . . . . 2 . 5 . . 7 . 5 . 3 . 1 . . 1 . . 1 . 4
  71.158 +          15   2 . 5 . 3 . . . . 1 . 2 . 1 . . . . 2 . 4 . . 2 .
  71.159 +          16   . . . . . 1 . . . . . . . . . . 2 . . 2 . 1 . . 3
  71.160 +          17   2 . 6 . 6 . . 2 . . 2 . 2 . 5 . . . . . 2 . . . .
  71.161 +          18   . . . . . 1 . . . 3 . . . . . 1 . . 1 . . 4 . 3 .
  71.162 +          19   . . 4 . 5 . . 2 . . . 2 . . 6 . 6 . . 3 . . . . 3
  71.163 +          20   2 . . . . . . . . . 2 . . 1 . . . . . . 1 . . 1 .
  71.164 +          21   . . 3 . . 3 . 5 . 5 . . 4 . 6 . 7 . . 4 . 6 . . 4
  71.165 +          22   2 . . . 3 . 5 . 2 . 1 . . . . . . . . . . . . . .
  71.166 +          23   . . . . . . . . . 1 . . . . . . 3 . 2 . . 5 . . 5
  71.167 +          24   2 . 3 . 3 . 5 . 4 . 3 . 3 . 4 . . 2 . 2 . . . 1 .
  71.168 +          25   . 1 . 2 . 2 . . . 2 . 2 . . . 2 . . . . 2 . 2 . 2
  71.169 +           ;
  71.170 +
  71.171 +end;
    72.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    72.2 +++ b/examples/huge.mod	Mon Dec 06 13:09:21 2010 +0100
    72.3 @@ -0,0 +1,25 @@
    72.4 +/*Arithmetic Mean of a large number of Integers
    72.5 +  - or - solve a very large constraint matrix
    72.6 +         over 1 million rows and columns
    72.7 +  Nigel_Galloway@operamail.com
    72.8 +  March 18th., 2008.
    72.9 +*/
   72.10 +
   72.11 +param e := 20;
   72.12 +/* set Sample := {-2**e..2**e-1}; */
   72.13 +set Sample := {1..2**e-1};
   72.14 +
   72.15 +var Mean;
   72.16 +var E{z in Sample};
   72.17 +
   72.18 +/* sum of variances is zero */
   72.19 +zumVariance: sum{z in Sample} E[z] = 0;
   72.20 +
   72.21 +/* Mean + variance[n] = Sample[n] */
   72.22 +variances{z in Sample}: Mean + E[z] = z;
   72.23 +
   72.24 +solve;
   72.25 +
   72.26 +printf "The arithmetic mean of the integers from 1 to %d is %f\n", 2**e-1, Mean;
   72.27 +
   72.28 +end;
    73.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    73.2 +++ b/examples/iptsamp.c	Mon Dec 06 13:09:21 2010 +0100
    73.3 @@ -0,0 +1,17 @@
    73.4 +/* iptsamp.c */
    73.5 +
    73.6 +#include <stdio.h>
    73.7 +#include <stdlib.h>
    73.8 +#include <glpk.h>
    73.9 +
   73.10 +int main(void)
   73.11 +{     glp_prob *P;
   73.12 +      P = glp_create_prob();
   73.13 +      glp_read_mps(P, GLP_MPS_DECK, NULL, "25fv47.mps");
   73.14 +      glp_interior(P, NULL);
   73.15 +      glp_print_ipt(P, "25fv47.txt");
   73.16 +      glp_delete_prob(P);
   73.17 +      return 0;
   73.18 +}
   73.19 +
   73.20 +/* eof */
    74.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    74.2 +++ b/examples/jssp.mod	Mon Dec 06 13:09:21 2010 +0100
    74.3 @@ -0,0 +1,114 @@
    74.4 +/* JSSP, Job-Shop Scheduling Problem */
    74.5 +
    74.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
    74.7 +
    74.8 +/* The Job-Shop Scheduling Problem (JSSP) is to schedule a set of jobs
    74.9 +   on a set of machines, subject to the constraint that each machine can
   74.10 +   handle at most one job at a time and the fact that each job has a
   74.11 +   specified processing order through the machines. The objective is to
   74.12 +   schedule the jobs so as to minimize the maximum of their completion
   74.13 +   times.
   74.14 +
   74.15 +   Reference:
   74.16 +   D. Applegate and W. Cook, "A Computational Study of the Job-Shop
   74.17 +   Scheduling Problem", ORSA J. On Comput., Vol. 3, No. 2, Spring 1991,
   74.18 +   pp. 149-156. */
   74.19 +
   74.20 +param n, integer, > 0;
   74.21 +/* number of jobs */
   74.22 +
   74.23 +param m, integer, > 0;
   74.24 +/* number of machines */
   74.25 +
   74.26 +set J := 1..n;
   74.27 +/* set of jobs */
   74.28 +
   74.29 +set M := 1..m;
   74.30 +/* set of machines */
   74.31 +
   74.32 +param sigma{j in J, t in 1..m}, in M;
   74.33 +/* permutation of the machines, which represents the processing order
   74.34 +   of j through the machines: j must be processed first on sigma[j,1],
   74.35 +   then on sigma[j,2], etc. */
   74.36 +
   74.37 +check{j in J, t1 in 1..m, t2 in 1..m: t1 <> t2}:
   74.38 +      sigma[j,t1] != sigma[j,t2];
   74.39 +/* sigma must be permutation */
   74.40 +
   74.41 +param p{j in J, a in M}, >= 0;
   74.42 +/* processing time of j on a */
   74.43 +
   74.44 +var x{j in J, a in M}, >= 0;
   74.45 +/* starting time of j on a */
   74.46 +
   74.47 +s.t. ord{j in J, t in 2..m}:
   74.48 +      x[j, sigma[j,t]] >= x[j, sigma[j,t-1]] + p[j, sigma[j,t-1]];
   74.49 +/* j can be processed on sigma[j,t] only after it has been completely
   74.50 +   processed on sigma[j,t-1] */
   74.51 +
   74.52 +/* The disjunctive condition that each machine can handle at most one
   74.53 +   job at a time is the following:
   74.54 +
   74.55 +      x[i,a] >= x[j,a] + p[j,a]  or  x[j,a] >= x[i,a] + p[i,a]
   74.56 +
   74.57 +   for all i, j in J, a in M. This condition is modeled through binary
   74.58 +   variables Y as shown below. */
   74.59 +
   74.60 +var Y{i in J, j in J, a in M}, binary;
   74.61 +/* Y[i,j,a] is 1 if i scheduled before j on machine a, and 0 if j is
   74.62 +   scheduled before i */
   74.63 +
   74.64 +param K := sum{j in J, a in M} p[j,a];
   74.65 +/* some large constant */
   74.66 +
   74.67 +display K;
   74.68 +
   74.69 +s.t. phi{i in J, j in J, a in M: i <> j}:
   74.70 +      x[i,a] >= x[j,a] + p[j,a] - K * Y[i,j,a];
   74.71 +/* x[i,a] >= x[j,a] + p[j,a] iff Y[i,j,a] is 0 */
   74.72 +
   74.73 +s.t. psi{i in J, j in J, a in M: i <> j}:
   74.74 +      x[j,a] >= x[i,a] + p[i,a] - K * (1 - Y[i,j,a]);
   74.75 +/* x[j,a] >= x[i,a] + p[i,a] iff Y[i,j,a] is 1 */
   74.76 +
   74.77 +var z;
   74.78 +/* so-called makespan */
   74.79 +
   74.80 +s.t. fin{j in J}: z >= x[j, sigma[j,m]] + p[j, sigma[j,m]];
   74.81 +/* which is the maximum of the completion times of all the jobs */
   74.82 +
   74.83 +minimize obj: z;
   74.84 +/* the objective is to make z as small as possible */
   74.85 +
   74.86 +data;
   74.87 +
   74.88 +/* These data correspond to the instance ft06 (mt06) from:
   74.89 +
   74.90 +   H. Fisher, G.L. Thompson (1963), Probabilistic learning combinations
   74.91 +   of local job-shop scheduling rules, J.F. Muth, G.L. Thompson (eds.),
   74.92 +   Industrial Scheduling, Prentice Hall, Englewood Cliffs, New Jersey,
   74.93 +   225-251 */
   74.94 +
   74.95 +/* The optimal solution is 55 */
   74.96 +
   74.97 +param n := 6;
   74.98 +
   74.99 +param m := 6;
  74.100 +
  74.101 +param sigma :  1  2  3  4  5  6 :=
  74.102 +          1    3  1  2  4  6  5
  74.103 +          2    2  3  5  6  1  4
  74.104 +          3    3  4  6  1  2  5
  74.105 +          4    2  1  3  4  5  6
  74.106 +          5    3  2  5  6  1  4
  74.107 +          6    2  4  6  1  5  3 ;
  74.108 +
  74.109 +param p     :  1  2  3  4  5  6 :=
  74.110 +          1    3  6  1  7  6  3
  74.111 +          2   10  8  5  4 10 10
  74.112 +          3    9  1  5  4  7  8
  74.113 +          4    5  5  5  3  8  9
  74.114 +          5    3  3  9  1  5  4
  74.115 +          6   10  3  1  3  4  9 ;
  74.116 +
  74.117 +end;
    75.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    75.2 +++ b/examples/magic.mod	Mon Dec 06 13:09:21 2010 +0100
    75.3 @@ -0,0 +1,54 @@
    75.4 +/* MAGIC, Magic Square */
    75.5 +
    75.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
    75.7 +
    75.8 +/* In recreational mathematics, a magic square of order n is an
    75.9 +   arrangement of n^2 numbers, usually distinct integers, in a square,
   75.10 +   such that n numbers in all rows, all columns, and both diagonals sum
   75.11 +   to the same constant. A normal magic square contains the integers
   75.12 +   from 1 to n^2.
   75.13 +
   75.14 +   (From Wikipedia, the free encyclopedia.) */
   75.15 +
   75.16 +param n, integer, > 0, default 4;
   75.17 +/* square order */
   75.18 +
   75.19 +set N := 1..n^2;
   75.20 +/* integers to be placed */
   75.21 +
   75.22 +var x{i in 1..n, j in 1..n, k in N}, binary;
   75.23 +/* x[i,j,k] = 1 means that cell (i,j) contains integer k */
   75.24 +
   75.25 +s.t. a{i in 1..n, j in 1..n}: sum{k in N} x[i,j,k] = 1;
   75.26 +/* each cell must be assigned exactly one integer */
   75.27 +
   75.28 +s.t. b{k in N}: sum{i in 1..n, j in 1..n} x[i,j,k] = 1;
   75.29 +/* each integer must be assigned exactly to one cell */
   75.30 +
   75.31 +var s;
   75.32 +/* the magic sum */
   75.33 +
   75.34 +s.t. r{i in 1..n}: sum{j in 1..n, k in N} k * x[i,j,k] = s;
   75.35 +/* the sum in each row must be the magic sum */
   75.36 +
   75.37 +s.t. c{j in 1..n}: sum{i in 1..n, k in N} k * x[i,j,k] = s;
   75.38 +/* the sum in each column must be the magic sum */
   75.39 +
   75.40 +s.t. d: sum{i in 1..n, k in N} k * x[i,i,k] = s;
   75.41 +/* the sum in the diagonal must be the magic sum */
   75.42 +
   75.43 +s.t. e: sum{i in 1..n, k in N} k * x[i,n-i+1,k] = s;
   75.44 +/* the sum in the co-diagonal must be the magic sum */
   75.45 +
   75.46 +solve;
   75.47 +
   75.48 +printf "\n";
   75.49 +printf "Magic sum is %d\n", s;
   75.50 +printf "\n";
   75.51 +for{i in 1..n}
   75.52 +{  printf{j in 1..n} "%3d", sum{k in N} k * x[i,j,k];
   75.53 +   printf "\n";
   75.54 +}
   75.55 +printf "\n";
   75.56 +
   75.57 +end;
    76.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    76.2 +++ b/examples/maxcut.mod	Mon Dec 06 13:09:21 2010 +0100
    76.3 @@ -0,0 +1,85 @@
    76.4 +/* MAXCUT, Maximum Cut Problem */
    76.5 +
    76.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
    76.7 +
    76.8 +/* The Maximum Cut Problem in a network G = (V, E), where V is a set
    76.9 +   of nodes, E is a set of edges, is to find the partition of V into
   76.10 +   disjoint sets V1 and V2, which maximizes the sum of edge weights
   76.11 +   w(e), where edge e has one endpoint in V1 and other endpoint in V2.
   76.12 +
   76.13 +   Reference:
   76.14 +   Garey, M.R., and Johnson, D.S. (1979), Computers and Intractability:
   76.15 +   A guide to the theory of NP-completeness [Network design, Cuts and
   76.16 +   Connectivity, Maximum Cut, ND16]. */
   76.17 +
   76.18 +set E, dimen 2;
   76.19 +/* set of edges */
   76.20 +
   76.21 +param w{(i,j) in E}, >= 0, default 1;
   76.22 +/* w[i,j] is weight of edge (i,j) */
   76.23 +
   76.24 +set V := (setof{(i,j) in E} i) union (setof{(i,j) in E} j);
   76.25 +/* set of nodes */
   76.26 +
   76.27 +var x{i in V}, binary;
   76.28 +/* x[i] = 0 means that node i is in set V1
   76.29 +   x[i] = 1 means that node i is in set V2 */
   76.30 +
   76.31 +/* We need to include in the objective function only that edges (i,j)
   76.32 +   from E, for which x[i] != x[j]. This can be modeled through binary
   76.33 +   variables s[i,j] as follows:
   76.34 +
   76.35 +      s[i,j] = x[i] xor x[j] = (x[i] + x[j]) mod 2,                  (1)
   76.36 +
   76.37 +   where s[i,j] = 1 iff x[i] != x[j], that leads to the following
   76.38 +   objective function:
   76.39 +
   76.40 +      z = sum{(i,j) in E} w[i,j] * s[i,j].                           (2)
   76.41 +
   76.42 +   To describe "exclusive or" (1) we could think that s[i,j] is a minor
   76.43 +   bit of the sum x[i] + x[j]. Then introducing binary variables t[i,j],
   76.44 +   which represent a major bit of the sum x[i] + x[j], we can write:
   76.45 +
   76.46 +      x[i] + x[j] = s[i,j] + 2 * t[i,j].                             (3)
   76.47 +
   76.48 +   An easy check shows that conditions (1) and (3) are equivalent.
   76.49 +
   76.50 +   Note that condition (3) can be simplified by eliminating variables
   76.51 +   s[i,j]. Indeed, from (3) it follows that:
   76.52 +
   76.53 +      s[i,j] = x[i] + x[j] - 2 * t[i,j].                             (4)
   76.54 +
   76.55 +   Since the expression in the right-hand side of (4) is integral, this
   76.56 +   condition can be rewritten in the equivalent form:
   76.57 +
   76.58 +      0 <= x[i] + x[j] - 2 * t[i,j] <= 1.                            (5)
   76.59 +
   76.60 +   (One might note that (5) means t[i,j] = x[i] and x[j].)
   76.61 +
   76.62 +   Substituting s[i,j] from (4) to (2) leads to the following objective
   76.63 +   function:
   76.64 +
   76.65 +      z = sum{(i,j) in E} w[i,j] * (x[i] + x[j] - 2 * t[i,j]),       (6)
   76.66 +
   76.67 +   which does not include variables s[i,j]. */
   76.68 +
   76.69 +var t{(i,j) in E}, binary;
   76.70 +/* t[i,j] = x[i] and x[j] = (x[i] + x[j]) div 2 */
   76.71 +
   76.72 +s.t. xor{(i,j) in E}: 0 <= x[i] + x[j] - 2 * t[i,j] <= 1;
   76.73 +/* see (4) */
   76.74 +
   76.75 +maximize z: sum{(i,j) in E} w[i,j] * (x[i] + x[j] - 2 * t[i,j]);
   76.76 +/* see (6) */
   76.77 +
   76.78 +data;
   76.79 +
   76.80 +/* In this example the network has 15 nodes and 22 edges. */
   76.81 +
   76.82 +/* Optimal solution is 20 */
   76.83 +
   76.84 +set E :=
   76.85 +   1 2, 1 5, 2 3, 2 6, 3 4, 3 8, 4 9, 5 6, 5 7, 6 8, 7 8, 7 12, 8 9,
   76.86 +   8 12, 9 10, 9 14, 10 11, 10 14, 11 15, 12 13, 13 14, 14 15;
   76.87 +
   76.88 +end;
    77.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    77.2 +++ b/examples/maxflow.mod	Mon Dec 06 13:09:21 2010 +0100
    77.3 @@ -0,0 +1,83 @@
    77.4 +/* MAXFLOW, Maximum Flow Problem */
    77.5 +
    77.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
    77.7 +
    77.8 +/* The Maximum Flow Problem in a network G = (V, E), where V is a set
    77.9 +   of nodes, E within V x V is a set of arcs, is to maximize the flow
   77.10 +   from one given node s (source) to another given node t (sink) subject
   77.11 +   to conservation of flow constraints at each node and flow capacities
   77.12 +   on each arc. */
   77.13 +
   77.14 +param n, integer, >= 2;
   77.15 +/* number of nodes */
   77.16 +
   77.17 +set V, default {1..n};
   77.18 +/* set of nodes */
   77.19 +
   77.20 +set E, within V cross V;
   77.21 +/* set of arcs */
   77.22 +
   77.23 +param a{(i,j) in E}, > 0;
   77.24 +/* a[i,j] is capacity of arc (i,j) */
   77.25 +
   77.26 +param s, symbolic, in V, default 1;
   77.27 +/* source node */
   77.28 +
   77.29 +param t, symbolic, in V, != s, default n;
   77.30 +/* sink node */
   77.31 +
   77.32 +var x{(i,j) in E}, >= 0, <= a[i,j];
   77.33 +/* x[i,j] is elementary flow through arc (i,j) to be found */
   77.34 +
   77.35 +var flow, >= 0;
   77.36 +/* total flow from s to t */
   77.37 +
   77.38 +s.t. node{i in V}:
   77.39 +/* node[i] is conservation constraint for node i */
   77.40 +
   77.41 +   sum{(j,i) in E} x[j,i] + (if i = s then flow)
   77.42 +   /* summary flow into node i through all ingoing arcs */
   77.43 +
   77.44 +   = /* must be equal to */
   77.45 +
   77.46 +   sum{(i,j) in E} x[i,j] + (if i = t then flow);
   77.47 +   /* summary flow from node i through all outgoing arcs */
   77.48 +
   77.49 +maximize obj: flow;
   77.50 +/* objective is to maximize the total flow through the network */
   77.51 +
   77.52 +solve;
   77.53 +
   77.54 +printf{1..56} "="; printf "\n";
   77.55 +printf "Maximum flow from node %s to node %s is %g\n\n", s, t, flow;
   77.56 +printf "Starting node   Ending node   Arc capacity   Flow in arc\n";
   77.57 +printf "-------------   -----------   ------------   -----------\n";
   77.58 +printf{(i,j) in E: x[i,j] != 0}: "%13s   %11s   %12g   %11g\n", i, j,
   77.59 +   a[i,j], x[i,j];
   77.60 +printf{1..56} "="; printf "\n";
   77.61 +
   77.62 +data;
   77.63 +
   77.64 +/* These data correspond to an example from [Christofides]. */
   77.65 +
   77.66 +/* Optimal solution is 29 */
   77.67 +
   77.68 +param n := 9;
   77.69 +
   77.70 +param : E :   a :=
   77.71 +       1 2   14
   77.72 +       1 4   23
   77.73 +       2 3   10
   77.74 +       2 4    9
   77.75 +       3 5   12
   77.76 +       3 8   18
   77.77 +       4 5   26
   77.78 +       5 2   11
   77.79 +       5 6   25
   77.80 +       5 7    4
   77.81 +       6 7    7
   77.82 +       6 8    8
   77.83 +       7 9   15
   77.84 +       8 9   20;
   77.85 +
   77.86 +end;
    78.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    78.2 +++ b/examples/mfasp.mod	Mon Dec 06 13:09:21 2010 +0100
    78.3 @@ -0,0 +1,62 @@
    78.4 +/* MFASP, Minimum Feedback Arc Set Problem */
    78.5 +
    78.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
    78.7 +
    78.8 +/* The Minimum Feedback Arc Set Problem for a given directed graph
    78.9 +   G = (V, E), where V is a set of vertices and E is a set of arcs, is
   78.10 +   to find a minimal subset of arcs, which being removed from the graph
   78.11 +   make it acyclic.
   78.12 +
   78.13 +   Reference:
   78.14 +   Garey, M.R., and Johnson, D.S. (1979), Computers and Intractability:
   78.15 +   A guide to the theory of NP-completeness [Graph Theory, Covering and
   78.16 +   Partitioning, Minimum Feedback Arc Set, GT9]. */
   78.17 +
   78.18 +param n, integer, >= 0;
   78.19 +/* number of vertices */
   78.20 +
   78.21 +set V, default 1..n;
   78.22 +/* set of vertices */
   78.23 +
   78.24 +set E, within V cross V,
   78.25 +default setof{i in V, j in V: i <> j and Uniform(0,1) <= 0.15} (i,j);
   78.26 +/* set of arcs */
   78.27 +
   78.28 +printf "Graph has %d vertices and %d arcs\n", card(V), card(E);
   78.29 +
   78.30 +var x{(i,j) in E}, binary;
   78.31 +/* x[i,j] = 1 means that (i->j) is a feedback arc */
   78.32 +
   78.33 +/* It is known that a digraph G = (V, E) is acyclic if and only if its
   78.34 +   vertices can be assigned numbers from 1 to |V| in such a way that
   78.35 +   k[i] + 1 <= k[j] for every arc (i->j) in E, where k[i] is a number
   78.36 +   assigned to vertex i. We may use this condition to require that the
   78.37 +   digraph G = (V, E \ E'), where E' is a subset of feedback arcs, is
   78.38 +   acyclic. */
   78.39 +
   78.40 +var k{i in V}, >= 1, <= card(V);
   78.41 +/* k[i] is a number assigned to vertex i */
   78.42 +
   78.43 +s.t. r{(i,j) in E}: k[j] - k[i] >= 1 - card(V) * x[i,j];
   78.44 +/* note that x[i,j] = 1 leads to a redundant constraint */
   78.45 +
   78.46 +minimize obj: sum{(i,j) in E} x[i,j];
   78.47 +/* the objective is to minimize the cardinality of a subset of feedback
   78.48 +   arcs */
   78.49 +
   78.50 +solve;
   78.51 +
   78.52 +printf "Minimum feedback arc set:\n";
   78.53 +printf{(i,j) in E: x[i,j]} "%d %d\n", i, j;
   78.54 +
   78.55 +data;
   78.56 +
   78.57 +/* The optimal solution is 3 */
   78.58 +
   78.59 +param n := 15;
   78.60 +
   78.61 +set E := 1 2, 2 3, 3 4, 3 8, 4 9, 5 1, 6 5, 7 5, 8 6, 8 7, 8 9, 9 10,
   78.62 +         10 11, 10 14, 11 15, 12 7, 12 8, 12 13, 13 8, 13 12, 13 14,
   78.63 +         14 9, 15 14;
   78.64 +
   78.65 +end;
    79.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    79.2 +++ b/examples/mfvsp.mod	Mon Dec 06 13:09:21 2010 +0100
    79.3 @@ -0,0 +1,62 @@
    79.4 +/* MFVSP, Minimum Feedback Vertex Set Problem */
    79.5 +
    79.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
    79.7 +
    79.8 +/* The Minimum Feedback Vertex Set Problem for a given directed graph
    79.9 +   G = (V, E), where V is a set of vertices and E is a set of arcs, is
   79.10 +   to find a minimal subset of vertices, which being removed from the
   79.11 +   graph make it acyclic.
   79.12 +
   79.13 +   Reference:
   79.14 +   Garey, M.R., and Johnson, D.S. (1979), Computers and Intractability:
   79.15 +   A guide to the theory of NP-completeness [Graph Theory, Covering and
   79.16 +   Partitioning, Minimum Feedback Vertex Set, GT8]. */
   79.17 +
   79.18 +param n, integer, >= 0;
   79.19 +/* number of vertices */
   79.20 +
   79.21 +set V, default 1..n;
   79.22 +/* set of vertices */
   79.23 +
   79.24 +set E, within V cross V,
   79.25 +default setof{i in V, j in V: i <> j and Uniform(0,1) <= 0.15} (i,j);
   79.26 +/* set of arcs */
   79.27 +
   79.28 +printf "Graph has %d vertices and %d arcs\n", card(V), card(E);
   79.29 +
   79.30 +var x{i in V}, binary;
   79.31 +/* x[i] = 1 means that i is a feedback vertex */
   79.32 +
   79.33 +/* It is known that a digraph G = (V, E) is acyclic if and only if its
   79.34 +   vertices can be assigned numbers from 1 to |V| in such a way that
   79.35 +   k[i] + 1 <= k[j] for every arc (i->j) in E, where k[i] is a number
   79.36 +   assigned to vertex i. We may use this condition to require that the
   79.37 +   digraph G = (V, E \ E'), where E' is a subset of feedback arcs, is
   79.38 +   acyclic. */
   79.39 +
   79.40 +var k{i in V}, >= 1, <= card(V);
   79.41 +/* k[i] is a number assigned to vertex i */
   79.42 +
   79.43 +s.t. r{(i,j) in E}: k[j] - k[i] >= 1 - card(V) * (x[i] + x[j]);
   79.44 +/* note that x[i] = 1 or x[j] = 1 leads to a redundant constraint */
   79.45 +
   79.46 +minimize obj: sum{i in V} x[i];
   79.47 +/* the objective is to minimize the cardinality of a subset of feedback
   79.48 +   vertices */
   79.49 +
   79.50 +solve;
   79.51 +
   79.52 +printf "Minimum feedback vertex set:\n";
   79.53 +printf{i in V: x[i]} "%d\n", i;
   79.54 +
   79.55 +data;
   79.56 +
   79.57 +/* The optimal solution is 3 */
   79.58 +
   79.59 +param n := 15;
   79.60 +
   79.61 +set E := 1 2, 2 3, 3 4, 3 8, 4 9, 5 1, 6 5, 7 5, 8 6, 8 7, 8 9, 9 10,
   79.62 +         10 11, 10 14, 11 15, 12 7, 12 8, 12 13, 13 8, 13 12, 13 14,
   79.63 +         14 9, 15 14;
   79.64 +
   79.65 +end;
    80.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    80.2 +++ b/examples/min01ks.mod	Mon Dec 06 13:09:21 2010 +0100
    80.3 @@ -0,0 +1,111 @@
    80.4 +/* min01ks.mod - finding minimal equivalent 0-1 knapsack inequality */
    80.5 +
    80.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
    80.7 +
    80.8 +/* It is obvious that for a given 0-1 knapsack inequality
    80.9 +
   80.10 +      a[1] x[1] + ... + a[n] x[n] <= b,  x[j] in {0, 1}              (1)
   80.11 +
   80.12 +   there exist infinitely many equivalent inequalities with exactly the
   80.13 +   same feasible solutions.
   80.14 +
   80.15 +   Given a[j]'s and b this model allows to find an inequality
   80.16 +
   80.17 +      alfa[1] x[1] + ... + alfa[n] x[n] <= beta,  x[j] in {0, 1},    (2)
   80.18 +
   80.19 +   which is equivalent to (1) and where alfa[j]'s and beta are smallest
   80.20 +   non-negative integers.
   80.21 +
   80.22 +   This model has the following formulation:
   80.23 +
   80.24 +      minimize
   80.25 +
   80.26 +         z = |alfa[1]| + ... + |alfa[n]| + |beta| =                  (3)
   80.27 +
   80.28 +           = alfa[1] + ... + alfa[n] + beta
   80.29 +
   80.30 +      subject to
   80.31 +
   80.32 +         alfa[1] x[1] + ... + alfa[n] x[n] <= beta                   (4)
   80.33 +
   80.34 +                              for all x satisfying to (1)
   80.35 +
   80.36 +         alfa[1] x[1] + ... + alfa[n] x[n] >= beta + 1               (5)
   80.37 +
   80.38 +                              for all x not satisfying to (1)
   80.39 +
   80.40 +         alfa[1], ..., alfa[n], beta are non-negative integers.
   80.41 +
   80.42 +   Note that this model has n+1 variables and 2^n constraints.
   80.43 +
   80.44 +   It is interesting, as noticed in [1] and explained in [2], that
   80.45 +   in most cases LP relaxation of the MIP formulation above has integer
   80.46 +   optimal solution.
   80.47 +
   80.48 +   References
   80.49 +
   80.50 +   1. G.H.Bradley, P.L.Hammer, L.Wolsey, "Coefficient Reduction for
   80.51 +      Inequalities in 0-1 Variables", Math.Prog.7 (1974), 263-282.
   80.52 +
   80.53 +   2. G.J.Koehler, "A Study on Coefficient Reduction of Binary Knapsack
   80.54 +      Inequalities", University of Florida, 2001. */
   80.55 +
   80.56 +param n, integer, > 0;
   80.57 +/* number of variables in the knapsack inequality */
   80.58 +
   80.59 +set N := 1..n;
   80.60 +/* set of knapsack items */
   80.61 +
   80.62 +/* all binary n-vectors are numbered by 0, 1, ..., 2^n-1, where vector
   80.63 +   0 is 00...00, vector 1 is 00...01, etc. */
   80.64 +
   80.65 +set U := 0..2^n-1;
   80.66 +/* set of numbers of all binary n-vectors */
   80.67 +
   80.68 +param x{i in U, j in N}, binary, := (i div 2^(j-1)) mod 2;
   80.69 +/* x[i,j] is j-th component of i-th binary n-vector */
   80.70 +
   80.71 +param a{j in N}, >= 0;
   80.72 +/* original coefficients */
   80.73 +
   80.74 +param b, >= 0;
   80.75 +/* original right-hand side */
   80.76 +
   80.77 +set D := setof{i in U: sum{j in N} a[j] * x[i,j] <= b} i;
   80.78 +/* set of numbers of binary n-vectors, which (vectors) are feasible,
   80.79 +   i.e. satisfy to the original knapsack inequality (1) */
   80.80 +
   80.81 +var alfa{j in N}, integer, >= 0;
   80.82 +/* coefficients to be found */
   80.83 +
   80.84 +var beta, integer, >= 0;
   80.85 +/* right-hand side to be found */
   80.86 +
   80.87 +minimize z: sum{j in N} alfa[j] + beta; /* (3) */
   80.88 +
   80.89 +phi{i in D}: sum{j in N} alfa[j] * x[i,j] <= beta; /* (4) */
   80.90 +
   80.91 +psi{i in U diff D}: sum{j in N} alfa[j] * x[i,j] >= beta + 1; /* (5) */
   80.92 +
   80.93 +solve;
   80.94 +
   80.95 +printf "\nOriginal 0-1 knapsack inequality:\n";
   80.96 +for {j in 1..n} printf (if j = 1 then "" else " + ") & "%g x%d",
   80.97 +   a[j], j;
   80.98 +printf " <= %g\n", b;
   80.99 +printf "\nMinimized equivalent inequality:\n";
  80.100 +for {j in 1..n} printf (if j = 1 then "" else " + ") & "%g x%d",
  80.101 +   alfa[j], j;
  80.102 +printf " <= %g\n\n", beta;
  80.103 +
  80.104 +data;
  80.105 +
  80.106 +/* These data correspond to the very first example from [1]. */
  80.107 +
  80.108 +param n := 8;
  80.109 +
  80.110 +param a := [1]65, [2]64, [3]41, [4]22, [5]13, [6]12, [7]8, [8]2;
  80.111 +
  80.112 +param b := 80;
  80.113 +
  80.114 +end;
    81.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    81.2 +++ b/examples/misp.mod	Mon Dec 06 13:09:21 2010 +0100
    81.3 @@ -0,0 +1,665 @@
    81.4 +/* MISP, Maximum Independent Set Problem */
    81.5 +
    81.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
    81.7 +
    81.8 +/* Let G = (V,E) be an undirected graph with vertex set V and edge set
    81.9 +   E. Vertices u, v in V are non-adjacent if (u,v) not in E. A subset
   81.10 +   of the vertices S within V is independent if all vertices in S are
   81.11 +   pairwise non-adjacent. The Maximum Independent Set Problem (MISP) is
   81.12 +   to find an independent set having the largest cardinality. */
   81.13 +
   81.14 +param n, integer, > 0;
   81.15 +/* number of vertices */
   81.16 +
   81.17 +set V := 1..n;
   81.18 +/* set of vertices */
   81.19 +
   81.20 +set E within V cross V;
   81.21 +/* set of edges */
   81.22 +
   81.23 +var x{i in V}, binary;
   81.24 +/* x[i] = 1 means vertex i belongs to independent set */
   81.25 +
   81.26 +s.t. edge{(i,j) in E}: x[i] + x[j] <= 1;
   81.27 +/* if there is edge (i,j), vertices i and j cannot belong to the same
   81.28 +   independent set */
   81.29 +
   81.30 +maximize obj: sum{i in V} x[i];
   81.31 +/* the objective is to maximize the cardinality of independent set */
   81.32 +
   81.33 +data;
   81.34 +
   81.35 +/* These data corresponds to the test instance from:
   81.36 +
   81.37 +   M.G.C. Resende, T.A.Feo, S.H.Smith, "Algorithm 787 -- FORTRAN
   81.38 +   subroutines for approximate solution of the maximum independent set
   81.39 +   problem using GRASP," Trans. on Math. Softw., Vol. 24, No. 4,
   81.40 +   December 1998, pp. 386-394. */
   81.41 +
   81.42 +/* The optimal solution is 7 */
   81.43 +
   81.44 +param n := 50;
   81.45 +
   81.46 +set E :=
   81.47 + 1 2
   81.48 + 1 3
   81.49 + 1 5
   81.50 + 1 7
   81.51 + 1 8
   81.52 + 1 12
   81.53 + 1 15
   81.54 + 1 16
   81.55 + 1 19
   81.56 + 1 20
   81.57 + 1 21
   81.58 + 1 22
   81.59 + 1 28
   81.60 + 1 30
   81.61 + 1 34
   81.62 + 1 35
   81.63 + 1 37
   81.64 + 1 41
   81.65 + 1 42
   81.66 + 1 47
   81.67 + 1 50
   81.68 + 2 3
   81.69 + 2 5
   81.70 + 2 6
   81.71 + 2 7
   81.72 + 2 8
   81.73 + 2 9
   81.74 + 2 10
   81.75 + 2 13
   81.76 + 2 17
   81.77 + 2 19
   81.78 + 2 20
   81.79 + 2 21
   81.80 + 2 23
   81.81 + 2 25
   81.82 + 2 26
   81.83 + 2 29
   81.84 + 2 31
   81.85 + 2 35
   81.86 + 2 36
   81.87 + 2 44
   81.88 + 2 45
   81.89 + 2 46
   81.90 + 2 50
   81.91 + 3 5
   81.92 + 3 6
   81.93 + 3 8
   81.94 + 3 9
   81.95 + 3 10
   81.96 + 3 11
   81.97 + 3 14
   81.98 + 3 16
   81.99 + 3 23
  81.100 + 3 24
  81.101 + 3 26
  81.102 + 3 27
  81.103 + 3 28
  81.104 + 3 29
  81.105 + 3 30
  81.106 + 3 31
  81.107 + 3 34
  81.108 + 3 35
  81.109 + 3 36
  81.110 + 3 39
  81.111 + 3 41
  81.112 + 3 42
  81.113 + 3 43
  81.114 + 3 44
  81.115 + 3 50
  81.116 + 4 6
  81.117 + 4 7
  81.118 + 4 9
  81.119 + 4 10
  81.120 + 4 11
  81.121 + 4 13
  81.122 + 4 14
  81.123 + 4 15
  81.124 + 4 17
  81.125 + 4 21
  81.126 + 4 22
  81.127 + 4 23
  81.128 + 4 24
  81.129 + 4 25
  81.130 + 4 27
  81.131 + 4 28
  81.132 + 4 30
  81.133 + 4 31
  81.134 + 4 33
  81.135 + 4 34
  81.136 + 4 35
  81.137 + 4 36
  81.138 + 4 37
  81.139 + 4 38
  81.140 + 4 40
  81.141 + 4 41
  81.142 + 4 42
  81.143 + 4 46
  81.144 + 4 49
  81.145 + 5 6
  81.146 + 5 11
  81.147 + 5 14
  81.148 + 5 21
  81.149 + 5 24
  81.150 + 5 25
  81.151 + 5 28
  81.152 + 5 35
  81.153 + 5 38
  81.154 + 5 39
  81.155 + 5 41
  81.156 + 5 44
  81.157 + 5 49
  81.158 + 5 50
  81.159 + 6 8
  81.160 + 6 9
  81.161 + 6 10
  81.162 + 6 13
  81.163 + 6 14
  81.164 + 6 16
  81.165 + 6 17
  81.166 + 6 19
  81.167 + 6 22
  81.168 + 6 23
  81.169 + 6 26
  81.170 + 6 27
  81.171 + 6 30
  81.172 + 6 34
  81.173 + 6 35
  81.174 + 6 38
  81.175 + 6 39
  81.176 + 6 40
  81.177 + 6 41
  81.178 + 6 44
  81.179 + 6 45
  81.180 + 6 47
  81.181 + 6 50
  81.182 + 7 8
  81.183 + 7 9
  81.184 + 7 10
  81.185 + 7 11
  81.186 + 7 13
  81.187 + 7 15
  81.188 + 7 16
  81.189 + 7 18
  81.190 + 7 20
  81.191 + 7 22
  81.192 + 7 23
  81.193 + 7 24
  81.194 + 7 25
  81.195 + 7 33
  81.196 + 7 35
  81.197 + 7 36
  81.198 + 7 38
  81.199 + 7 43
  81.200 + 7 45
  81.201 + 7 46
  81.202 + 7 47
  81.203 + 8 10
  81.204 + 8 11
  81.205 + 8 13
  81.206 + 8 16
  81.207 + 8 17
  81.208 + 8 18
  81.209 + 8 19
  81.210 + 8 20
  81.211 + 8 21
  81.212 + 8 22
  81.213 + 8 23
  81.214 + 8 24
  81.215 + 8 25
  81.216 + 8 26
  81.217 + 8 33
  81.218 + 8 35
  81.219 + 8 36
  81.220 + 8 39
  81.221 + 8 42
  81.222 + 8 44
  81.223 + 8 48
  81.224 + 8 49
  81.225 + 9 12
  81.226 + 9 14
  81.227 + 9 17
  81.228 + 9 19
  81.229 + 9 20
  81.230 + 9 23
  81.231 + 9 28
  81.232 + 9 30
  81.233 + 9 31
  81.234 + 9 32
  81.235 + 9 33
  81.236 + 9 34
  81.237 + 9 38
  81.238 + 9 39
  81.239 + 9 42
  81.240 + 9 44
  81.241 + 9 45
  81.242 + 9 46
  81.243 + 10 11
  81.244 + 10 13
  81.245 + 10 15
  81.246 + 10 16
  81.247 + 10 17
  81.248 + 10 20
  81.249 + 10 21
  81.250 + 10 22
  81.251 + 10 23
  81.252 + 10 25
  81.253 + 10 26
  81.254 + 10 27
  81.255 + 10 28
  81.256 + 10 30
  81.257 + 10 31
  81.258 + 10 32
  81.259 + 10 37
  81.260 + 10 38
  81.261 + 10 41
  81.262 + 10 43
  81.263 + 10 44
  81.264 + 10 45
  81.265 + 10 50
  81.266 + 11 12
  81.267 + 11 14
  81.268 + 11 15
  81.269 + 11 18
  81.270 + 11 21
  81.271 + 11 24
  81.272 + 11 25
  81.273 + 11 26
  81.274 + 11 29
  81.275 + 11 32
  81.276 + 11 33
  81.277 + 11 35
  81.278 + 11 36
  81.279 + 11 37
  81.280 + 11 39
  81.281 + 11 40
  81.282 + 11 42
  81.283 + 11 43
  81.284 + 11 45
  81.285 + 11 47
  81.286 + 11 49
  81.287 + 11 50
  81.288 + 12 13
  81.289 + 12 16
  81.290 + 12 17
  81.291 + 12 19
  81.292 + 12 24
  81.293 + 12 25
  81.294 + 12 26
  81.295 + 12 30
  81.296 + 12 31
  81.297 + 12 32
  81.298 + 12 34
  81.299 + 12 36
  81.300 + 12 37
  81.301 + 12 39
  81.302 + 12 41
  81.303 + 12 44
  81.304 + 12 47
  81.305 + 12 48
  81.306 + 12 49
  81.307 + 13 15
  81.308 + 13 16
  81.309 + 13 18
  81.310 + 13 19
  81.311 + 13 20
  81.312 + 13 22
  81.313 + 13 23
  81.314 + 13 24
  81.315 + 13 27
  81.316 + 13 28
  81.317 + 13 29
  81.318 + 13 31
  81.319 + 13 33
  81.320 + 13 35
  81.321 + 13 36
  81.322 + 13 37
  81.323 + 13 44
  81.324 + 13 47
  81.325 + 13 49
  81.326 + 13 50
  81.327 + 14 15
  81.328 + 14 16
  81.329 + 14 17
  81.330 + 14 18
  81.331 + 14 19
  81.332 + 14 20
  81.333 + 14 21
  81.334 + 14 26
  81.335 + 14 28
  81.336 + 14 29
  81.337 + 14 30
  81.338 + 14 31
  81.339 + 14 32
  81.340 + 14 34
  81.341 + 14 35
  81.342 + 14 36
  81.343 + 14 38
  81.344 + 14 39
  81.345 + 14 41
  81.346 + 14 44
  81.347 + 14 46
  81.348 + 14 47
  81.349 + 14 48
  81.350 + 15 18
  81.351 + 15 21
  81.352 + 15 22
  81.353 + 15 23
  81.354 + 15 25
  81.355 + 15 28
  81.356 + 15 29
  81.357 + 15 30
  81.358 + 15 33
  81.359 + 15 34
  81.360 + 15 36
  81.361 + 15 37
  81.362 + 15 38
  81.363 + 15 39
  81.364 + 15 40
  81.365 + 15 43
  81.366 + 15 44
  81.367 + 15 46
  81.368 + 15 50
  81.369 + 16 17
  81.370 + 16 19
  81.371 + 16 20
  81.372 + 16 25
  81.373 + 16 26
  81.374 + 16 29
  81.375 + 16 35
  81.376 + 16 38
  81.377 + 16 39
  81.378 + 16 40
  81.379 + 16 41
  81.380 + 16 42
  81.381 + 16 44
  81.382 + 17 18
  81.383 + 17 19
  81.384 + 17 21
  81.385 + 17 22
  81.386 + 17 23
  81.387 + 17 25
  81.388 + 17 26
  81.389 + 17 28
  81.390 + 17 29
  81.391 + 17 33
  81.392 + 17 37
  81.393 + 17 44
  81.394 + 17 45
  81.395 + 17 48
  81.396 + 18 20
  81.397 + 18 24
  81.398 + 18 27
  81.399 + 18 28
  81.400 + 18 31
  81.401 + 18 32
  81.402 + 18 34
  81.403 + 18 35
  81.404 + 18 36
  81.405 + 18 37
  81.406 + 18 38
  81.407 + 18 45
  81.408 + 18 48
  81.409 + 18 49
  81.410 + 18 50
  81.411 + 19 22
  81.412 + 19 24
  81.413 + 19 28
  81.414 + 19 29
  81.415 + 19 36
  81.416 + 19 37
  81.417 + 19 39
  81.418 + 19 41
  81.419 + 19 43
  81.420 + 19 45
  81.421 + 19 48
  81.422 + 19 49
  81.423 + 20 21
  81.424 + 20 22
  81.425 + 20 24
  81.426 + 20 25
  81.427 + 20 26
  81.428 + 20 27
  81.429 + 20 29
  81.430 + 20 30
  81.431 + 20 31
  81.432 + 20 33
  81.433 + 20 34
  81.434 + 20 35
  81.435 + 20 38
  81.436 + 20 39
  81.437 + 20 41
  81.438 + 20 42
  81.439 + 20 43
  81.440 + 20 44
  81.441 + 20 45
  81.442 + 20 46
  81.443 + 20 48
  81.444 + 20 49
  81.445 + 21 22
  81.446 + 21 23
  81.447 + 21 29
  81.448 + 21 31
  81.449 + 21 35
  81.450 + 21 38
  81.451 + 21 42
  81.452 + 21 46
  81.453 + 21 47
  81.454 + 22 23
  81.455 + 22 26
  81.456 + 22 27
  81.457 + 22 28
  81.458 + 22 29
  81.459 + 22 30
  81.460 + 22 39
  81.461 + 22 40
  81.462 + 22 41
  81.463 + 22 42
  81.464 + 22 44
  81.465 + 22 45
  81.466 + 22 46
  81.467 + 22 47
  81.468 + 22 49
  81.469 + 22 50
  81.470 + 23 28
  81.471 + 23 31
  81.472 + 23 32
  81.473 + 23 33
  81.474 + 23 34
  81.475 + 23 35
  81.476 + 23 36
  81.477 + 23 39
  81.478 + 23 40
  81.479 + 23 41
  81.480 + 23 42
  81.481 + 23 44
  81.482 + 23 45
  81.483 + 23 48
  81.484 + 23 49
  81.485 + 23 50
  81.486 + 24 25
  81.487 + 24 27
  81.488 + 24 29
  81.489 + 24 30
  81.490 + 24 31
  81.491 + 24 33
  81.492 + 24 34
  81.493 + 24 38
  81.494 + 24 42
  81.495 + 24 43
  81.496 + 24 44
  81.497 + 24 49
  81.498 + 24 50
  81.499 + 25 26
  81.500 + 25 27
  81.501 + 25 29
  81.502 + 25 30
  81.503 + 25 33
  81.504 + 25 34
  81.505 + 25 36
  81.506 + 25 38
  81.507 + 25 40
  81.508 + 25 41
  81.509 + 25 42
  81.510 + 25 44
  81.511 + 25 46
  81.512 + 25 47
  81.513 + 25 48
  81.514 + 25 49
  81.515 + 26 28
  81.516 + 26 31
  81.517 + 26 32
  81.518 + 26 33
  81.519 + 26 37
  81.520 + 26 38
  81.521 + 26 39
  81.522 + 26 40
  81.523 + 26 41
  81.524 + 26 42
  81.525 + 26 45
  81.526 + 26 47
  81.527 + 26 48
  81.528 + 26 49
  81.529 + 27 29
  81.530 + 27 30
  81.531 + 27 33
  81.532 + 27 34
  81.533 + 27 35
  81.534 + 27 39
  81.535 + 27 40
  81.536 + 27 46
  81.537 + 27 48
  81.538 + 28 29
  81.539 + 28 37
  81.540 + 28 40
  81.541 + 28 42
  81.542 + 28 44
  81.543 + 28 46
  81.544 + 28 47
  81.545 + 28 50
  81.546 + 29 35
  81.547 + 29 38
  81.548 + 29 39
  81.549 + 29 41
  81.550 + 29 42
  81.551 + 29 48
  81.552 + 30 31
  81.553 + 30 32
  81.554 + 30 35
  81.555 + 30 37
  81.556 + 30 38
  81.557 + 30 40
  81.558 + 30 43
  81.559 + 30 45
  81.560 + 30 46
  81.561 + 30 47
  81.562 + 30 48
  81.563 + 31 33
  81.564 + 31 35
  81.565 + 31 38
  81.566 + 31 40
  81.567 + 31 41
  81.568 + 31 42
  81.569 + 31 44
  81.570 + 31 46
  81.571 + 31 47
  81.572 + 31 50
  81.573 + 32 33
  81.574 + 32 35
  81.575 + 32 39
  81.576 + 32 40
  81.577 + 32 46
  81.578 + 32 49
  81.579 + 32 50
  81.580 + 33 34
  81.581 + 33 36
  81.582 + 33 37
  81.583 + 33 40
  81.584 + 33 42
  81.585 + 33 43
  81.586 + 33 44
  81.587 + 33 45
  81.588 + 33 50
  81.589 + 34 35
  81.590 + 34 36
  81.591 + 34 37
  81.592 + 34 38
  81.593 + 34 40
  81.594 + 34 43
  81.595 + 34 44
  81.596 + 34 49
  81.597 + 34 50
  81.598 + 35 36
  81.599 + 35 38
  81.600 + 35 41
  81.601 + 35 42
  81.602 + 35 43
  81.603 + 35 45
  81.604 + 35 46
  81.605 + 35 47
  81.606 + 35 49
  81.607 + 35 50
  81.608 + 36 37
  81.609 + 36 39
  81.610 + 36 40
  81.611 + 36 41
  81.612 + 36 42
  81.613 + 36 43
  81.614 + 36 48
  81.615 + 36 50
  81.616 + 37 38
  81.617 + 37 41
  81.618 + 37 43
  81.619 + 37 46
  81.620 + 37 47
  81.621 + 37 48
  81.622 + 37 49
  81.623 + 37 50
  81.624 + 38 41
  81.625 + 38 45
  81.626 + 38 46
  81.627 + 38 48
  81.628 + 38 49
  81.629 + 38 50
  81.630 + 39 43
  81.631 + 39 46
  81.632 + 39 47
  81.633 + 39 48
  81.634 + 39 49
  81.635 + 40 43
  81.636 + 40 45
  81.637 + 40 48
  81.638 + 40 50
  81.639 + 41 42
  81.640 + 41 43
  81.641 + 41 44
  81.642 + 41 45
  81.643 + 41 46
  81.644 + 41 48
  81.645 + 41 49
  81.646 + 42 43
  81.647 + 42 44
  81.648 + 42 46
  81.649 + 42 48
  81.650 + 42 49
  81.651 + 43 45
  81.652 + 43 46
  81.653 + 43 48
  81.654 + 43 50
  81.655 + 44 45
  81.656 + 44 48
  81.657 + 45 46
  81.658 + 45 47
  81.659 + 45 48
  81.660 + 46 49
  81.661 + 47 49
  81.662 + 47 50
  81.663 + 48 49
  81.664 + 48 50
  81.665 + 49 50
  81.666 +;
  81.667 +
  81.668 +end;
    82.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    82.2 +++ b/examples/money.mod	Mon Dec 06 13:09:21 2010 +0100
    82.3 @@ -0,0 +1,62 @@
    82.4 +/* MONEY, a crypto-arithmetic puzzle */
    82.5 +
    82.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
    82.7 +
    82.8 +/* This is the classic example of a crypto-arithmetic puzzle published
    82.9 +   in the Strand Magazine by Henry Dudeney:
   82.10 +
   82.11 +        S E N D
   82.12 +      +
   82.13 +        M O R E
   82.14 +      ---------
   82.15 +      M O N E Y
   82.16 +
   82.17 +   In this puzzle the same letters mean the same digits. The question
   82.18 +   is: how to replace all the letters with the respective digits that
   82.19 +   makes the calculation correct?
   82.20 +
   82.21 +   The solution to this puzzle is:
   82.22 +   O = 0, M = 1, Y = 2, E = 5, N = 6, D = 7, R = 8, and S = 9.
   82.23 +
   82.24 +   References:
   82.25 +   H. E. Dudeney, in Strand Magazine vol. 68 (July 1924), pp. 97, 214.
   82.26 +
   82.27 +   (From Wikipedia, the free encyclopedia.) */
   82.28 +
   82.29 +set LETTERS := { 'D', 'E', 'M', 'N', 'O', 'R', 'S', 'Y' };
   82.30 +/* set of letters */
   82.31 +
   82.32 +set DIGITS := 0..9;
   82.33 +/* set of digits */
   82.34 +
   82.35 +var x{i in LETTERS, d in DIGITS}, binary;
   82.36 +/* x[i,d] = 1 means that letter i is digit d */
   82.37 +
   82.38 +s.t. one{i in LETTERS}: sum{d in DIGITS} x[i,d] = 1;
   82.39 +/* each letter must correspond exactly to one digit */
   82.40 +
   82.41 +s.t. alldiff{d in DIGITS}: sum{i in LETTERS} x[i,d] <= 1;
   82.42 +/* different letters must correspond to different digits; note that
   82.43 +   some digits may not correspond to any letters at all */
   82.44 +
   82.45 +var dig{i in LETTERS};
   82.46 +/* dig[i] is a digit corresponding to letter i */
   82.47 +
   82.48 +s.t. map{i in LETTERS}: dig[i] = sum{d in DIGITS} d * x[i,d];
   82.49 +
   82.50 +var carry{1..3}, binary;
   82.51 +/* carry bits */
   82.52 +
   82.53 +s.t. sum1: dig['D'] + dig['E']            = dig['Y'] + 10 * carry[1];
   82.54 +s.t. sum2: dig['N'] + dig['R'] + carry[1] = dig['E'] + 10 * carry[2];
   82.55 +s.t. sum3: dig['E'] + dig['O'] + carry[2] = dig['N'] + 10 * carry[3];
   82.56 +s.t. sum4: dig['S'] + dig['M'] + carry[3] = dig['O'] + 10 * dig['M'];
   82.57 +s.t. note: dig['M'] >= 1; /* M must not be 0 */
   82.58 +
   82.59 +solve;
   82.60 +/* solve the puzzle */
   82.61 +
   82.62 +display dig;
   82.63 +/* and display its solution */
   82.64 +
   82.65 +end;
    83.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    83.2 +++ b/examples/mplsamp1.c	Mon Dec 06 13:09:21 2010 +0100
    83.3 @@ -0,0 +1,32 @@
    83.4 +/* mplsamp1.c */
    83.5 +
    83.6 +#include <stdio.h>
    83.7 +#include <stdlib.h>
    83.8 +#include <glpk.h>
    83.9 +
   83.10 +int main(void)
   83.11 +{     glp_prob *lp;
   83.12 +      glp_tran *tran;
   83.13 +      int ret;
   83.14 +      lp = glp_create_prob();
   83.15 +      tran = glp_mpl_alloc_wksp();
   83.16 +      ret = glp_mpl_read_model(tran, "egypt.mod", 0);
   83.17 +      if (ret != 0)
   83.18 +      {  fprintf(stderr, "Error on translating model\n");
   83.19 +         goto skip;
   83.20 +      }
   83.21 +      ret = glp_mpl_generate(tran, NULL);
   83.22 +      if (ret != 0)
   83.23 +      {  fprintf(stderr, "Error on generating model\n");
   83.24 +         goto skip;
   83.25 +      }
   83.26 +      glp_mpl_build_prob(tran, lp);
   83.27 +      ret = glp_write_mps(lp, GLP_MPS_FILE, NULL, "egypt.mps");
   83.28 +      if (ret != 0)
   83.29 +         fprintf(stderr, "Error on writing MPS file\n");
   83.30 +skip: glp_mpl_free_wksp(tran);
   83.31 +      glp_delete_prob(lp);
   83.32 +      return 0;
   83.33 +}
   83.34 +
   83.35 +/* eof */
    84.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    84.2 +++ b/examples/mplsamp2.c	Mon Dec 06 13:09:21 2010 +0100
    84.3 @@ -0,0 +1,39 @@
    84.4 +/* mplsamp2.c */
    84.5 +
    84.6 +#include <stdio.h>
    84.7 +#include <stdlib.h>
    84.8 +#include <glpk.h>
    84.9 +
   84.10 +int main(void)
   84.11 +{     glp_prob *mip;
   84.12 +      glp_tran *tran;
   84.13 +      int ret;
   84.14 +      mip = glp_create_prob();
   84.15 +      tran = glp_mpl_alloc_wksp();
   84.16 +      ret = glp_mpl_read_model(tran, "sudoku.mod", 1);
   84.17 +      if (ret != 0)
   84.18 +      {  fprintf(stderr, "Error on translating model\n");
   84.19 +         goto skip;
   84.20 +      }
   84.21 +      ret = glp_mpl_read_data(tran, "sudoku.dat");
   84.22 +      if (ret != 0)
   84.23 +      {  fprintf(stderr, "Error on translating data\n");
   84.24 +         goto skip;
   84.25 +      }
   84.26 +      ret = glp_mpl_generate(tran, NULL);
   84.27 +      if (ret != 0)
   84.28 +      {  fprintf(stderr, "Error on generating model\n");
   84.29 +         goto skip;
   84.30 +      }
   84.31 +      glp_mpl_build_prob(tran, mip);
   84.32 +      glp_simplex(mip, NULL);
   84.33 +      glp_intopt(mip, NULL);
   84.34 +      ret = glp_mpl_postsolve(tran, mip, GLP_MIP);
   84.35 +      if (ret != 0)
   84.36 +         fprintf(stderr, "Error on postsolving model\n");
   84.37 +skip: glp_mpl_free_wksp(tran);
   84.38 +      glp_delete_prob(mip);
   84.39 +      return 0;
   84.40 +}
   84.41 +
   84.42 +/* eof */
    85.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    85.2 +++ b/examples/murtagh.mps	Mon Dec 06 13:09:21 2010 +0100
    85.3 @@ -0,0 +1,600 @@
    85.4 +*NAME:         OIL
    85.5 +*ROWS:         74
    85.6 +*COLUMNS:      81
    85.7 +*NONZERO:      504
    85.8 +*OPT SOLN:     126.057
    85.9 +*SOURCE:       Bruce Murtagh, "Advanced Linear Programming"
   85.10 +*APPLICATION:  oil refinery model
   85.11 +*COMMENTS:     problem is maximization
   85.12 +*
   85.13 +NAME          OIL REFINERY  EXAMPLE
   85.14 +ROWS
   85.15 + N  PROFIT
   85.16 + L  MVOLBOL
   85.17 + L  MVOLCOL
   85.18 + E  MVOLLNC
   85.19 + E  MVOLLNB
   85.20 + E  MVOLSRK
   85.21 + E  MVOLSRD
   85.22 + E  MVOLVBB
   85.23 + E  MVOLVBC
   85.24 + E  MVOLRCR
   85.25 + E  MVOLHVO
   85.26 + E  UBALKWH
   85.27 + E  UBALH2O
   85.28 + E  UBALSTM
   85.29 + E  UBALFUL
   85.30 + E  MVOLB95
   85.31 + E  MVOLB90
   85.32 + E  MVOLLHG
   85.33 + E  MVOLC3S
   85.34 + E  MVOLNC4
   85.35 + E  MVOLLSR
   85.36 + E  MVOLHSR
   85.37 + E  MVOLIC4
   85.38 + L  VCAPSGP
   85.39 + E  MVOLRFG
   85.40 + E  MSCFHYL
   85.41 + E  MVOLR90
   85.42 + E  MVOLR95
   85.43 + E  MVOLF90
   85.44 + E  MVOLF95
   85.45 + L  VCAPRFG
   85.46 + E  MVOLLCO
   85.47 + E  MVOLHHG
   85.48 + E  MVOLHCD
   85.49 + L  VCAPHVO
   85.50 + L  VCAPHOL
   85.51 + E  MVOLC3U
   85.52 + E  MVOLC4U
   85.53 + E  MVOLFCG
   85.54 + E  MVOLSLR
   85.55 + L  VCAPCCU
   85.56 + E  MVOLLA3
   85.57 + E  MVOLLA4
   85.58 + L  VCAPALK
   85.59 + L  XLPRPRE
   85.60 + L  XHPRPRE
   85.61 + L  XTELPRE
   85.62 + L  XRVPPRE
   85.63 + L  X200PRE
   85.64 + L  X230PRE
   85.65 + E  EVOLPRE
   85.66 + L  XPSCPRE
   85.67 + L  XRSCREG
   85.68 + L  XLPRINT
   85.69 + L  XHPRINT
   85.70 + L  XTELINT
   85.71 + L  XRVPINT
   85.72 + L  X200INT
   85.73 + L  X230INT
   85.74 + E  EVOLINT
   85.75 + L  XLPRREG
   85.76 + L  XHPRREG
   85.77 + L  XTELREG
   85.78 + L  XRVPREG
   85.79 + L  X200REG
   85.80 + L  X230REG
   85.81 + E  EVOLREG
   85.82 + E  EVOLLPG
   85.83 + E  EVOLJP4
   85.84 + L  XRVXJP4
   85.85 + L  XRVNJP4
   85.86 + E  EVOLDSL
   85.87 + E  EVOLRSD
   85.88 + L  XVISRSD
   85.89 +COLUMNS
   85.90 +    VCRDBOL   MVOLBOL   1.0
   85.91 +    VCRDBOL   MVOLLNB   -.537
   85.92 +    VCRDBOL   MVOLSRK   -.131
   85.93 +    VCRDBOL   MVOLSRD   -.1155
   85.94 +    VCRDBOL   MVOLVBB   -.037
   85.95 +    VCRDBOL   MVOLRCR   -.0365
   85.96 +    VCRDBOL   MVOLHVO   -.143
   85.97 +    VCRDBOL   UBALKWH   .302
   85.98 +    VCRDBOL   UBALH2O   .150
   85.99 +    VCRDBOL   UBALSTM   .003
  85.100 +    VCRDBOL   UBALFUL   .0587
  85.101 +    VCRDBOL   PROFIT    -12.8
  85.102 +    VCRDCOL   MVOLCOL   1.
  85.103 +    VCRDCOL   MVOLLNC   -.2931
  85.104 +    VCRDCOL   MVOLSRK   -.1170
  85.105 +    VCRDCOL   MVOLSRD   -.0649
  85.106 +    VCRDCOL   MVOLVBC   -.18
  85.107 +    VCRDCOL   MVOLRCR   -.1233
  85.108 +    VCRDCOL   MVOLHVO   -.2217
  85.109 +    VCRDCOL   UBALKWH   .384
  85.110 +    VCRDCOL   UBALH2O   .185
  85.111 +    VCRDCOL   UBALSTM   .003
  85.112 +    VCRDCOL   UBALFUL   .1053
  85.113 +    VCRDCOL   PROFIT    -11.48
  85.114 +    VSGPLNC   MVOLLNC   1.
  85.115 +    VSGPLNC   MVOLC3S   -.0112
  85.116 +    VSGPLNC   MVOLNC4   -.0378
  85.117 +    VSGPLNC   MVOLLSR   -.1502
  85.118 +    VSGPLNC   MVOLHSR   -.7953
  85.119 +    VSGPLNC   MVOLIC4   -.0099
  85.120 +    VSGPLNC   UBALKWH   .721
  85.121 +    VSGPLNC   UBALH2O   .185
  85.122 +    VSGPLNC   UBALSTM   .013
  85.123 +    VSGPLNC   UBALFUL   .0488
  85.124 +    VSGPLNC   VCAPSGP   1.
  85.125 +    VSGPLNB   MVOLLNB   1.
  85.126 +    VSGPLNB   MVOLC3S   -.0277
  85.127 +    VSGPLNB   MVOLNC4   -.0563
  85.128 +    VSGPLNB   MVOLLSR   -.199
  85.129 +    VSGPLNB   MVOLHSR   -.6873
  85.130 +    VSGPLNB   MVOLIC4   -.017
  85.131 +    VSGPLNB   UBALKWH   .495
  85.132 +    VSGPLNB   UBALH2O   .209
  85.133 +    VSGPLNB   UBALSTM   .013
  85.134 +    VSGPLNB   UBALFUL   .0506
  85.135 +    VSGPLNB   VCAPSGP   1.
  85.136 +    VSGPLHG   MVOLLHG   1.0
  85.137 +    VSGPLHG   MVOLC3S   -.175
  85.138 +    VSGPLHG   MVOLNC4   -.27
  85.139 +    VSGPLHG   MVOLLSR   -.028
  85.140 +    VSGPLHG   MVOLIC4   -.455
  85.141 +    VSGPLHG   UBALKWH   .495
  85.142 +    VSGPLHG   UBALH2O   .209
  85.143 +    VSGPLHG   UBALSTM   .013
  85.144 +    VSGPLHG   UBALFUL   .0448
  85.145 +    VSGPB95   MVOLB95   1.
  85.146 +    VSGPB95   MVOLC3S   -.2836
  85.147 +    VSGPB95   MVOLNC4   -.3285
  85.148 +    VSGPB95   MVOLLSR   -.0241
  85.149 +    VSGPB95   MVOLIC4   -.2502
  85.150 +    VSGPB95   UBALKWH   .495
  85.151 +    VSGPB95   UBALH2O   .209
  85.152 +    VSGPB95   UBALSTM   .013
  85.153 +    VSGPB95   UBALFUL   .0506
  85.154 +    VSGPB90   MVOLB90   1.
  85.155 +    VSGPB90   MVOLC3S   -.271
  85.156 +    VSGPB90   MVOLNC4   -.3289
  85.157 +    VSGPB90   MVOLLSR   -.0255
  85.158 +    VSGPB90   MVOLIC4   -.2656
  85.159 +    VSGPB90   UBALKWH   .495
  85.160 +    VSGPB90   UBALH2O   .209
  85.161 +    VSGPB90   UBALSTM   .013
  85.162 +    VSGPB90   UBALFUL   .0506
  85.163 +    VH2RHSR   MVOLHSR   1.
  85.164 +    VH2RHSR   MVOLRFG   -1.
  85.165 +    VH2RHSR   MSCFHYL   .0327
  85.166 +    VH2RHSR   UBALKWH   .793
  85.167 +    VH2RHSR   UBALH2O   .045
  85.168 +    VH2RHSR   UBALFUL   .094
  85.169 +    VH2RHSR   PROFIT    -.0176
  85.170 +    VRFFRF1   MVOLRFG   1.0
  85.171 +    VRFFRF1   MVOLR90   -1.0
  85.172 +    VRFFRF2   MVOLRFG   1.0
  85.173 +    VRFFRF2   MVOLR95   -1.0
  85.174 +    VRFFHH1   MVOLR90   -1.0
  85.175 +    VRFFHH1   MVOLHHG   1.0
  85.176 +    VRFFHH2   MVOLR95   -1.0
  85.177 +    VRFFHH2   MVOLHHG   1.0
  85.178 +    VRFGR90   MVOLR90   1.0
  85.179 +    VRFGR90   MVOLB90   -.0404
  85.180 +    VRFGR90   MVOLF90   -0.8564
  85.181 +    VRFGR90   MSCFHYL   -0.8239
  85.182 +    VRFGR90   UBALKWH   .792
  85.183 +    VRFGR90   UBALH2O   .297
  85.184 +    VRFGR90   UBALSTM   0.0063
  85.185 +    VRFGR90   UBALFUL   -0.156
  85.186 +    VRFGR90   VCAPRFG   1.0
  85.187 +    VRFGR90   PROFIT    -0.1512
  85.188 +    VRFGR95   MVOLR95   1.0
  85.189 +    VRFGR95   MVOLB95   -0.0588
  85.190 +    VRFGR95   MVOLF95   -0.8145
  85.191 +    VRFGR95   MSCFHYL   -.7689
  85.192 +    VRFGR95   UBALKWH   1.03
  85.193 +    VRFGR95   UBALH2O   .387
  85.194 +    VRFGR95   UBALSTM   0.008
  85.195 +    VRFGR95   UBALFUL   -.2112
  85.196 +    VRFGR95   VCAPRFG   1.3
  85.197 +    VRFGR95   PROFIT    -0.304
  85.198 +    VHOLLCO   MVOLLCO   1.0
  85.199 +    VHOLLCO   MVOLHHG   -.6627
  85.200 +    VHOLLCO   MVOLLHG   -0.2414
  85.201 +    VHOLLCO   MVOLHCD   -.2930
  85.202 +    VHOLLCO   MSCFHYL   2.3
  85.203 +    VHOLLCO   UBALFUL   -.2054
  85.204 +    VHOLLCO   UBALH2O   0.826
  85.205 +    VHOLLCO   UBALKWH   14.61
  85.206 +    VHOLLCO   VCAPHOL   1.0
  85.207 +    VHOLLCO   PROFIT    -0.2112
  85.208 +    VHOLSRD   MVOLSRD   1.0
  85.209 +    VHOLSRD   MVOLHHG   -.6627
  85.210 +    VHOLSRD   MVOLLHG   -0.2414
  85.211 +    VHOLSRD   MVOLHCD   -.2930
  85.212 +    VHOLSRD   MSCFHYL   2.3
  85.213 +    VHOLSRD   UBALFUL   -.2054
  85.214 +    VHOLSRD   UBALH2O   0.826
  85.215 +    VHOLSRD   UBALKWH   14.61
  85.216 +    VHOLSRD   VCAPHOL   1.0
  85.217 +    VHOLSRD   PROFIT    -0.2112
  85.218 +    VHOLRCR   MVOLRCR   1.0
  85.219 +    VHOLRCR   MVOLHHG   -.5875
  85.220 +    VHOLRCR   MVOLLHG   -0.3321
  85.221 +    VHOLRCR   MVOLHCD   -.3620
  85.222 +    VHOLRCR   MSCFHYL   2.3
  85.223 +    VHOLRCR   UBALFUL   -.2054
  85.224 +    VHOLRCR   UBALH2O   0.826
  85.225 +    VHOLRCR   UBALKWH   14.61
  85.226 +    VHOLRCR   VCAPHOL   1.0
  85.227 +    VHOLRCR   PROFIT    -0.2112
  85.228 +    VHOLHVO   MVOLHVO   1.0
  85.229 +    VHOLHVO   MVOLHHG   -.5875
  85.230 +    VHOLHVO   MVOLLHG   -0.3321
  85.231 +    VHOLHVO   MVOLHCD   -.3620
  85.232 +    VHOLHVO   MSCFHYL   2.3
  85.233 +    VHOLHVO   UBALFUL   -.2054
  85.234 +    VHOLHVO   UBALH2O   0.826
  85.235 +    VHOLHVO   UBALKWH   14.61
  85.236 +    VHOLHVO   VCAPHVO   1.0
  85.237 +    VHOLHVO   VCAPHOL   1.0
  85.238 +    VHOLHVO   PROFIT    -0.2112
  85.239 +    VCCUSRK   MVOLSRK   1.0
  85.240 +    VCCUSRK   MVOLNC4   -0.0184
  85.241 +    VCCUSRK   MVOLC3S   -0.0303
  85.242 +    VCCUSRK   MVOLIC4   -0.0564
  85.243 +    VCCUSRK   MVOLC3U   -0.0655
  85.244 +    VCCUSRK   MVOLC4U   -0.0780
  85.245 +    VCCUSRK   MVOLFCG   -0.4750
  85.246 +    VCCUSRK   MVOLLCO   -0.3050
  85.247 +    VCCUSRK   UBALSTM   -.0654
  85.248 +    VCCUSRK   UBALFUL   -.2703
  85.249 +    VCCUSRK   UBALH2O   .632
  85.250 +    VCCUSRK   UBALKWH   .6807
  85.251 +    VCCUSRK   VCAPCCU   1.
  85.252 +    VCCUSRK   PROFIT    -.2112
  85.253 +    VCCUSRD   MVOLSRD   1.
  85.254 +    VCCUSRD   MVOLNC4   -.0184
  85.255 +    VCCUSRD   MVOLC3S   -.0303
  85.256 +    VCCUSRD   MVOLIC4   -.0564
  85.257 +    VCCUSRD   MVOLC3U   -.0655
  85.258 +    VCCUSRD   MVOLC4U   -.0780
  85.259 +    VCCUSRD   MVOLFCG   -.4750
  85.260 +    VCCUSRD   MVOLLCO   -.3050
  85.261 +    VCCUSRD   UBALSTM   -.0654
  85.262 +    VCCUSRD   UBALFUL   -.2703
  85.263 +    VCCUSRD   UBALH2O   0.632
  85.264 +    VCCUSRD   UBALKWH   .6807
  85.265 +    VCCUSRD   VCAPCCU   1.
  85.266 +    VCCUSRD   PROFIT    -.2112
  85.267 +    VCCURCR   MVOLRCR   1.0
  85.268 +    VCCURCR   MVOLNC4   -.0185
  85.269 +    VCCURCR   MVOLC3S   -.0328
  85.270 +    VCCURCR   MVOLIC4   -.0568
  85.271 +    VCCURCR   MVOLC3U   -.0658
  85.272 +    VCCURCR   MVOLC4U   -.0806
  85.273 +    VCCURCR   MVOLFCG   -.4934
  85.274 +    VCCURCR   MVOLLCO   -.2922
  85.275 +    VCCURCR   MVOLSLR   -.0096
  85.276 +    VCCURCR   UBALSTM   -.0654
  85.277 +    VCCURCR   UBALFUL   -.2703
  85.278 +    VCCURCR   UBALH2O   0.632
  85.279 +    VCCURCR   UBALKWH   .6807
  85.280 +    VCCURCR   VCAPCCU   1.
  85.281 +    VCCURCR   PROFIT    -.2112
  85.282 +    VCCUHVO   MVOLHVO   1.0
  85.283 +    VCCUHVO   MVOLNC4   -.0185
  85.284 +    VCCUHVO   MVOLC3S   -.0328
  85.285 +    VCCUHVO   MVOLIC4   -.0568
  85.286 +    VCCUHVO   MVOLC3U   -.0658
  85.287 +    VCCUHVO   MVOLC4U   -.0806
  85.288 +    VCCUHVO   MVOLFCG   -.4934
  85.289 +    VCCUHVO   MVOLLCO   -.2922
  85.290 +    VCCUHVO   MVOLSLR   -.0096
  85.291 +    VCCUHVO   UBALSTM   -.0654
  85.292 +    VCCUHVO   UBALFUL   -.2703
  85.293 +    VCCUHVO   UBALH2O   0.632
  85.294 +    VCCUHVO   UBALKWH   .6807
  85.295 +    VCCUHVO   VCAPHVO   1.
  85.296 +    VCCUHVO   VCAPCCU   1.
  85.297 +    VCCUHVO   PROFIT    -.2112
  85.298 +    VALKLA3   MVOLIC4   .7600
  85.299 +    VALKLA3   MVOLC3U   .5714
  85.300 +    VALKLA3   MVOLLA3   -1.0
  85.301 +    VALKLA3   UBALSTM   .1869
  85.302 +    VALKLA3   UBALFUL   .2796
  85.303 +    VALKLA3   UBALH2O   2.241
  85.304 +    VALKLA3   UBALKWH   2.766
  85.305 +    VALKLA3   VCAPALK   1.0
  85.306 +    VALKLA3   PROFIT    -.512
  85.307 +    VALKLA4   MVOLIC4   .6571
  85.308 +    VALKLA4   MVOLC4U   .5714
  85.309 +    VALKLA4   MVOLC3S   -.0571
  85.310 +    VALKLA4   MVOLNC4   -.0114
  85.311 +    VALKLA4   MVOLLA4   -1.0
  85.312 +    VALKLA4   UBALSTM   .1724
  85.313 +    VALKLA4   UBALFUL   .2579
  85.314 +    VALKLA4   UBALH2O   2.067
  85.315 +    VALKLA4   UBALKWH   2.552
  85.316 +    VALKLA4   VCAPALK   1.0
  85.317 +    VALKLA4   PROFIT    -.472
  85.318 +    VALKIC4   MVOLIC4   1.0
  85.319 +    VALKIC4   MVOLNC4   -1.0
  85.320 +    VALKC3U   MVOLC3U   1.0
  85.321 +    VALKC3U   MVOLC3S   -1.0
  85.322 +    VALKC4U   MVOLC4U   1.0
  85.323 +    VALKC4U   MVOLNC4   -1.0
  85.324 +    UTILC3S   MVOLC3S   1.
  85.325 +    UTILC3S   UBALFUL   -3.814
  85.326 +    UTILNC4   MVOLNC4   1.
  85.327 +    UTILNC4   UBALFUL   -4.316
  85.328 +    UTILIC4   MVOLIC4   1.
  85.329 +    UTILIC4   UBALFUL   -4.153
  85.330 +    UTILC3U   MVOLC3U   1.
  85.331 +    UTILC3U   UBALFUL   -3.808
  85.332 +    UTILC4U   MVOLC4U   1.
  85.333 +    UTILC4U   UBALFUL   -4.44
  85.334 +    UTILHYL   MSCFHYL   1.
  85.335 +    UTILHYL   UBALFUL   -.305
  85.336 +    UTILSTM   UBALSTM   -1.
  85.337 +    UTILSTM   UBALFUL   1.42
  85.338 +    UTILSTM   PROFIT    -.16
  85.339 +    PURCPC4   MVOLIC4   -.5
  85.340 +    PURCPC4   MVOLNC4   -.5
  85.341 +    PURCPC4   PROFIT    -12.
  85.342 +    PURCH2O   UBALH2O   -1.
  85.343 +    PURCH2O   PROFIT    -.0528
  85.344 +    PURCKWH   UBALKWH   -1.
  85.345 +    PURCKWH   PROFIT    -.04
  85.346 +    PURCFUL   UBALFUL   -1.
  85.347 +    PURCFUL   PROFIT    -1.6
  85.348 +    PURCFLR   UBALFUL   1.
  85.349 +    BLPGC3S   MVOLC3S   1.0
  85.350 +    BLPGC3S   EVOLLPG   -1.0
  85.351 +    BLPGNC4   MVOLNC4   1.0
  85.352 +    BLPGNC4   EVOLLPG   -1.0
  85.353 +    SELLLPG   EVOLLPG   1.0
  85.354 +    SELLLPG   PROFIT    11.0
  85.355 +    BUP4LSR   MVOLLSR   1.0
  85.356 +    BUP4LSR   EVOLJP4   -1.0
  85.357 +    BUP4LSR   XRVXJP4   14.0
  85.358 +    BUP4LSR   XRVNJP4   -14.0
  85.359 +    BUP4HSR   MVOLHSR   1.0
  85.360 +    BUP4HSR   EVOLJP4   -1.0
  85.361 +    BUP4HSR   XRVXJP4   0.8
  85.362 +    BUP4HSR   XRVNJP4   -0.8
  85.363 +    SELLJP4   EVOLJP4   1.0
  85.364 +    SELLJP4   XRVXJP4   -3.0
  85.365 +    SELLJP4   XRVNJP4   2.0
  85.366 +    SELLJP4   PROFIT    16.8
  85.367 +    BDSLSRK   MVOLSRK   1.0
  85.368 +    BDSLSRK   EVOLDSL   -1.0
  85.369 +    BDSLSRD   MVOLSRD   1.0
  85.370 +    BDSLSRD   EVOLDSL   -1.0
  85.371 +    SELLDSL   EVOLDSL   1.0
  85.372 +    SELLDSL   PROFIT    14.4
  85.373 +    BPRELSR   MVOLLSR   1.
  85.374 +    BPRELSR   XLPRPRE   -7.95
  85.375 +    BPRELSR   XHPRPRE   -8.70
  85.376 +    BPRELSR   XTELPRE   -3.00
  85.377 +    BPRELSR   XRVPPRE   14.00
  85.378 +    BPRELSR   X200PRE   1.
  85.379 +    BPRELSR   X230PRE   -1.
  85.380 +    BPRELSR   EVOLPRE   -1.
  85.381 +    BPREHCD   MVOLHCD   1.0
  85.382 +    BPREHCD   XLPRPRE   -8.84
  85.383 +    BPREHCD   XHPRPRE   -9.45
  85.384 +    BPREHCD   XTELPRE   -3.00
  85.385 +    BPREHCD   XRVPPRE   12.00
  85.386 +    BPREHCD   X200PRE   1.
  85.387 +    BPREHCD   X230PRE   -1.
  85.388 +    BPREHCD   EVOLPRE   -1.
  85.389 +    BPREF95   MVOLF95   1.0
  85.390 +    BPREF95   XLPRPRE   -9.43
  85.391 +    BPREF95   XHPRPRE   -9.57
  85.392 +    BPREF95   XTELPRE   -3.
  85.393 +    BPREF95   XRVPPRE   3.5
  85.394 +    BPREF95   X200PRE   .233
  85.395 +    BPREF95   X230PRE   -.358
  85.396 +    BPREF95   EVOLPRE   -1.
  85.397 +    BPREF90   MVOLF90   1.0
  85.398 +    BPREF90   XLPRPRE   -9.03
  85.399 +    BPREF90   XHPRPRE   -9.32
  85.400 +    BPREF90   XTELPRE   -3.0
  85.401 +    BPREF90   XRVPPRE   3.5
  85.402 +    BPREF90   X200PRE   .205
  85.403 +    BPREF90   X230PRE   -.333
  85.404 +    BPREF90   EVOLPRE   -1.
  85.405 +    BPREFCG   MVOLFCG   1.0
  85.406 +    BPREFCG   XLPRPRE   -9.23
  85.407 +    BPREFCG   XHPRPRE   -9.22
  85.408 +    BPREFCG   XTELPRE   -3.
  85.409 +    BPREFCG   XRVPPRE   6.
  85.410 +    BPREFCG   X200PRE   .381
  85.411 +    BPREFCG   X230PRE   -.509
  85.412 +    BPREFCG   EVOLPRE   -1.
  85.413 +    BPRELA3   MVOLLA3   1.0
  85.414 +    BPRELA3   XLPRPRE   -9.4
  85.415 +    BPRELA3   XHPRPRE   -9.85
  85.416 +    BPRELA3   XTELPRE   -3.0
  85.417 +    BPRELA3   XRVPPRE   2.5
  85.418 +    BPRELA3   X200PRE   0.39
  85.419 +    BPRELA3   X230PRE   -0.77
  85.420 +    BPRELA3   EVOLPRE   -1.0
  85.421 +    BPRELA4   MVOLLA4   1.0
  85.422 +    BPRELA4   XLPRPRE   -9.74
  85.423 +    BPRELA4   XHPRPRE   -10.1
  85.424 +    BPRELA4   XTELPRE   -3.0
  85.425 +    BPRELA4   XRVPPRE   3.3
  85.426 +    BPRELA4   X200PRE   0.233
  85.427 +    BPRELA4   X230PRE   -0.58
  85.428 +    BPRELA4   EVOLPRE   -1.0
  85.429 +    BPRENC4   MVOLNC4   1.0
  85.430 +    BPRENC4   XLPRPRE   -9.74
  85.431 +    BPRENC4   XHPRPRE   -9.9
  85.432 +    BPRENC4   XTELPRE   -3.0
  85.433 +    BPRENC4   XRVPPRE   66.0
  85.434 +    BPRENC4   X200PRE   1.0
  85.435 +    BPRENC4   X230PRE   -1.0
  85.436 +    BPRENC4   EVOLPRE   -1.0
  85.437 +    BPRETEL   XLPRPRE   -0.493
  85.438 +    BPRETEL   XHPRPRE   -0.165
  85.439 +    BPRETEL   XTELPRE   1.0
  85.440 +    BPRETEL   PROFIT    -0.3696
  85.441 +    SELLPRE   XLPRPRE   10.03
  85.442 +    SELLPRE   XHPRPRE   10.03
  85.443 +    SELLPRE   XRVPPRE   -9.5
  85.444 +    SELLPRE   X200PRE   -0.5
  85.445 +    SELLPRE   X230PRE   0.5
  85.446 +    SELLPRE   XPSCPRE   0.64
  85.447 +    SELLPRE   XRSCREG   0.35
  85.448 +    SELLPRE   EVOLPRE   1.0
  85.449 +    SELLPRE   PROFIT    21.44
  85.450 +    BINTLSR   MVOLLSR   1.0
  85.451 +    BINTLSR   XLPRINT   -7.98
  85.452 +    BINTLSR   XHPRINT   -8.58
  85.453 +    BINTLSR   XTELINT   -3.0
  85.454 +    BINTLSR   XRVPINT   14.0
  85.455 +    BINTLSR   X200INT   1.0
  85.456 +    BINTLSR   X230INT   -1.0
  85.457 +    BINTLSR   EVOLINT   -1.0
  85.458 +    BINTHCD   MVOLHCD   1.
  85.459 +    BINTHCD   XLPRINT   -8.87
  85.460 +    BINTHCD   XHPRINT   -9.33
  85.461 +    BINTHCD   XTELINT   -3.0
  85.462 +    BINTHCD   XRVPINT   12.0
  85.463 +    BINTHCD   X200INT   1.0
  85.464 +    BINTHCD   X230INT   -1.
  85.465 +    BINTHCD   EVOLINT   -1.0
  85.466 +    BINTF95   MVOLF95   1.
  85.467 +    BINTF95   XLPRINT   -9.46
  85.468 +    BINTF95   XHPRINT   -9.45
  85.469 +    BINTF95   XTELINT   -3.0
  85.470 +    BINTF95   XRVPINT   3.5
  85.471 +    BINTF95   X200INT   .233
  85.472 +    BINTF95   X230INT   -.358
  85.473 +    BINTF95   EVOLINT   -1.0
  85.474 +    BINTF90   MVOLF90   1.
  85.475 +    BINTF90   XLPRINT   -9.06
  85.476 +    BINTF90   XHPRINT   -9.20
  85.477 +    BINTF90   XTELINT   -3.0
  85.478 +    BINTF90   XRVPINT   3.5
  85.479 +    BINTF90   X200INT   .205
  85.480 +    BINTF90   X230INT   -.333
  85.481 +    BINTF90   EVOLINT   -1.0
  85.482 +    BINTFCG   MVOLFCG   1.
  85.483 +    BINTFCG   XLPRINT   -9.26
  85.484 +    BINTFCG   XHPRINT   -9.13
  85.485 +    BINTFCG   XTELINT   -3.0
  85.486 +    BINTFCG   XRVPINT   6.
  85.487 +    BINTFCG   X200INT   .318
  85.488 +    BINTFCG   X230INT   -.509
  85.489 +    BINTFCG   EVOLINT   -1.0
  85.490 +    BINTNC4   MVOLNC4   1.
  85.491 +    BINTNC4   XLPRINT   -9.77
  85.492 +    BINTNC4   XHPRINT   -9.78
  85.493 +    BINTNC4   XTELINT   -3.0
  85.494 +    BINTNC4   XRVPINT   66.
  85.495 +    BINTNC4   X200INT   1.0
  85.496 +    BINTNC4   X230INT   -1.
  85.497 +    BINTNC4   EVOLINT   -1.0
  85.498 +    BINTTEL   XLPRINT   -.435
  85.499 +    BINTTEL   XHPRINT   -.208
  85.500 +    BINTTEL   XTELINT   1.
  85.501 +    BINTTEL   PROFIT    -.3696
  85.502 +    SELLINT   XLPRINT   9.65
  85.503 +    SELLINT   XHPRINT   9.65
  85.504 +    SELLINT   XRVPINT   -9.5
  85.505 +    SELLINT   X200INT   -0.5
  85.506 +    SELLINT   X230INT   0.5
  85.507 +    SELLINT   XPSCPRE   -.36
  85.508 +    SELLINT   XRSCREG   0.35
  85.509 +    SELLINT   EVOLINT   1.0
  85.510 +    SELLINT   PROFIT    20.32
  85.511 +    BREGLSR   MVOLLSR   1.0
  85.512 +    BREGLSR   XLPRREG   -7.99
  85.513 +    BREGLSR   XHPRREG   -8.59
  85.514 +    BREGLSR   XTELREG   -3.0
  85.515 +    BREGLSR   XRVPREG   14.0
  85.516 +    BREGLSR   X200REG   1.0
  85.517 +    BREGLSR   X230REG   -1.0
  85.518 +    BREGLSR   EVOLREG   -1.0
  85.519 +    BREGHCD   MVOLHCD   1.0
  85.520 +    BREGHCD   XLPRREG   -8.88
  85.521 +    BREGHCD   XHPRREG   -9.34
  85.522 +    BREGHCD   XTELREG   -3.0
  85.523 +    BREGHCD   XRVPREG   12.0
  85.524 +    BREGHCD   X200REG   1.0
  85.525 +    BREGHCD   X230REG   -1.0
  85.526 +    BREGHCD   EVOLREG   -1.0
  85.527 +    BREGF95   MVOLF95   1.0
  85.528 +    BREGF95   XLPRREG   -9.47
  85.529 +    BREGF95   XHPRREG   -9.46
  85.530 +    BREGF95   XTELREG   -3.0
  85.531 +    BREGF95   XRVPREG   3.5
  85.532 +    BREGF95   X200REG   .233
  85.533 +    BREGF95   X230REG   -0.358
  85.534 +    BREGF95   EVOLREG   -1.0
  85.535 +    BREGF90   MVOLF90   1.0
  85.536 +    BREGF90   XLPRREG   -9.07
  85.537 +    BREGF90   XHPRREG   -9.21
  85.538 +    BREGF90   XTELREG   -3.0
  85.539 +    BREGF90   XRVPREG   3.5
  85.540 +    BREGF90   X200REG   .205
  85.541 +    BREGF90   X230REG   -0.333
  85.542 +    BREGF90   EVOLREG   -1.0
  85.543 +    BREGFCG   MVOLFCG   1.0
  85.544 +    BREGFCG   XLPRREG   -9.27
  85.545 +    BREGFCG   XHPRREG   -9.14
  85.546 +    BREGFCG   XTELREG   -3.0
  85.547 +    BREGFCG   XRVPREG   6.0
  85.548 +    BREGFCG   X200REG   0.318
  85.549 +    BREGFCG   X230REG   -0.509
  85.550 +    BREGFCG   EVOLREG   -1.0
  85.551 +    BREGNC4   MVOLNC4   1.0
  85.552 +    BREGNC4   XLPRREG   -9.78
  85.553 +    BREGNC4   XHPRREG   -9.79
  85.554 +    BREGNC4   XTELREG   -3.0
  85.555 +    BREGNC4   XRVPREG   66.0
  85.556 +    BREGNC4   X200REG   1.0
  85.557 +    BREGNC4   X230REG   -1.0
  85.558 +    BREGNC4   EVOLREG   -1.0
  85.559 +    BREGTEL   XLPRREG   -0.426
  85.560 +    BREGTEL   XHPRREG   -.204
  85.561 +    BREGTEL   XTELREG   1.0
  85.562 +    BREGTEL   PROFIT    -0.3696
  85.563 +    SELLREG   XLPRREG   9.05
  85.564 +    SELLREG   XHPRREG   9.05
  85.565 +    SELLREG   XRVPREG   -9.5
  85.566 +    SELLREG   X200REG   -0.5
  85.567 +    SELLREG   X230REG   0.5
  85.568 +    SELLREG   XPSCPRE   -0.36
  85.569 +    SELLREG   XRSCREG   -0.65
  85.570 +    SELLREG   EVOLREG   1.0
  85.571 +    SELLREG   PROFIT    18.04
  85.572 +    BRSDVBB   MVOLVBB   1.0
  85.573 +    BRSDVBB   EVOLRSD   -1.0
  85.574 +    BRSDVBB   XVISRSD   10.1
  85.575 +    BRSDVBC   MVOLVBC   1.0
  85.576 +    BRSDVBC   EVOLRSD   -1.0
  85.577 +    BRSDVBC   XVISRSD   12.63
  85.578 +    BRSDRCR   MVOLRCR   1.0
  85.579 +    BRSDRCR   EVOLRSD   -1.0
  85.580 +    BRSDRCR   XVISRSD   6.9
  85.581 +    BRSDHVO   MVOLHVO   1.0
  85.582 +    BRSDHVO   EVOLRSD   -1.0
  85.583 +    BRSDHVO   XVISRSD   8.05
  85.584 +    BRSDHVO   VCAPHVO   1.0
  85.585 +    BRSDSLR   MVOLSLR   1.0
  85.586 +    BRSDSLR   EVOLRSD   -1.0
  85.587 +    BRSDSLR   XVISRSD   8.05
  85.588 +    BRSDLCO   MVOLLCO   1.0
  85.589 +    BRSDLCO   EVOLRSD   -1.0
  85.590 +    BRSDLCO   XVISRSD   4.4
  85.591 +    SELLRSD   EVOLRSD   1.0
  85.592 +    SELLRSD   XVISRSD   -10.1
  85.593 +    SELLRSD   PROFIT    8.00
  85.594 +RHS
  85.595 +    LIMITMAX  MVOLBOL   26.316
  85.596 +    LIMITMAX  MVOLCOL   21.052
  85.597 +    LIMITMAX  VCAPSGP   23.25
  85.598 +    LIMITMAX  VCAPHVO   5.25
  85.599 +    LIMITMAX  VCAPRFG   13.455
  85.600 +    LIMITMAX  VCAPHOL   3.87
  85.601 +    LIMITMAX  VCAPCCU   7.26
  85.602 +    LIMITMAX  VCAPALK   10.
  85.603 +ENDATA
    86.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    86.2 +++ b/examples/mvcp.mod	Mon Dec 06 13:09:21 2010 +0100
    86.3 @@ -0,0 +1,43 @@
    86.4 +/* MVCP, Minimum Vertex Cover Problem */
    86.5 +
    86.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
    86.7 +
    86.8 +/* The Minimum Vertex Cover Problem in a network G = (V, E), where V
    86.9 +   is a set of nodes, E is a set of arcs, is to find a subset V' within
   86.10 +   V such that each edge (i,j) in E has at least one its endpoint in V'
   86.11 +   and which minimizes the sum of node weights w(i) over V'.
   86.12 +
   86.13 +   Reference:
   86.14 +   Garey, M.R., and Johnson, D.S. (1979), Computers and Intractability:
   86.15 +   A guide to the theory of NP-completeness [Graph Theory, Covering and
   86.16 +   Partitioning, Minimum Vertex Cover, GT1]. */
   86.17 +
   86.18 +set E, dimen 2;
   86.19 +/* set of edges */
   86.20 +
   86.21 +set V := (setof{(i,j) in E} i) union (setof{(i,j) in E} j);
   86.22 +/* set of nodes */
   86.23 +
   86.24 +param w{i in V}, >= 0, default 1;
   86.25 +/* w[i] is weight of vertex i */
   86.26 +
   86.27 +var x{i in V}, binary;
   86.28 +/* x[i] = 1 means that node i is included into V' */
   86.29 +
   86.30 +s.t. cov{(i,j) in E}: x[i] + x[j] >= 1;
   86.31 +/* each edge (i,j) must have node i or j (or both) in V' */
   86.32 +
   86.33 +minimize z: sum{i in V} w[i] * x[i];
   86.34 +/* we need to minimize the sum of node weights over V' */
   86.35 +
   86.36 +data;
   86.37 +
   86.38 +/* These data correspond to an example from [Papadimitriou]. */
   86.39 +
   86.40 +/* Optimal solution is 6 (greedy heuristic gives 13) */
   86.41 +
   86.42 +set E := a1 b1, b1 c1, a1 b2, b2 c2, a2 b3, b3 c3, a2 b4, b4 c4, a3 b5,
   86.43 +         b5 c5, a3 b6, b6 c6, a4 b1, a4 b2, a4 b3, a5 b4, a5 b5, a5 b6,
   86.44 +         a6 b1, a6 b2, a6 b3, a6 b4, a7 b2, a7 b3, a7 b4, a7 b5, a7 b6;
   86.45 +
   86.46 +end;
    87.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    87.2 +++ b/examples/netgen.c	Mon Dec 06 13:09:21 2010 +0100
    87.3 @@ -0,0 +1,141 @@
    87.4 +/* netgen.c */
    87.5 +
    87.6 +/* This main program generates 50 original NETGEN instances of the
    87.7 +   minimum cost flow problem and writes them in DIMACS format to the
    87.8 +   current directory. */
    87.9 +
   87.10 +#include <stddef.h>
   87.11 +#include <stdio.h>
   87.12 +#include <stdlib.h>
   87.13 +#include <glpk.h>
   87.14 +
   87.15 +static int parm[50][15] =
   87.16 +{    {13502460, 101,
   87.17 +      5000, 2500, 2500, 25000, 1, 100, 250000, 0, 0, 0, 100, 1, 1000,
   87.18 +   },{4281922, 102,
   87.19 +      5000, 2500, 2500, 25000, 1, 100, 2500000, 0, 0, 0, 100, 1, 1000,
   87.20 +   },{44820113, 103,
   87.21 +      5000, 2500, 2500, 25000, 1, 100, 6250000, 0, 0, 0, 100, 1, 1000,
   87.22 +   },{13450451, 104,
   87.23 +      5000, 2500, 2500, 25000, -100, -1, 250000, 0, 0, 0, 100, 1, 1000,
   87.24 +   },{14719436, 105,
   87.25 +      5000, 2500, 2500, 25000, 101, 200, 250000, 0, 0, 0, 100, 1, 1000,
   87.26 +   },{17365786, 106,
   87.27 +      5000, 2500, 2500, 12500, 1, 100, 125000, 0, 0, 0, 100, 1, 1000,
   87.28 +   },{19540113, 107,
   87.29 +      5000, 2500, 2500, 37500, 1, 100, 375000, 0, 0, 0, 100, 1, 1000,
   87.30 +   },{19560313, 108,
   87.31 +      5000, 2500, 2500, 50000, 1, 100, 500000, 0, 0, 0, 100, 1, 1000,
   87.32 +   },{2403509, 109,
   87.33 +      5000, 2500, 2500, 75000, 1, 100, 750000, 0, 0, 0, 100, 1, 1000,
   87.34 +   },{92480414, 110,
   87.35 +      5000, 2500, 2500, 12500, 1, 100, 250000, 0, 0, 0, 100, 1, 1000,
   87.36 +   },{4230140, 111,
   87.37 +      5000, 2500, 2500, 37500, 1, 100, 250000, 0, 0, 0, 100, 1, 1000,
   87.38 +   },{10032490, 112,
   87.39 +      5000, 2500, 2500, 50000, 1, 100, 250000, 0, 0, 0, 100, 1, 1000,
   87.40 +   },{17307474, 113,
   87.41 +      5000, 2500, 2500, 75000, 1, 100, 250000, 0, 0, 0, 100, 1, 1000,
   87.42 +   },{4925114, 114,
   87.43 +      5000, 500, 4500, 25000, 1, 100, 250000, 0, 0, 0, 100, 1, 1000,
   87.44 +   },{19842704, 115,
   87.45 +      5000, 1500, 3500, 25000, 1, 100, 250000, 0, 0, 0, 100, 1, 1000,
   87.46 +   },{88392060, 116,
   87.47 +      5000, 2500, 2500, 25000, 1, 100, 250000, 0, 0, 0, 0, 1, 1000,
   87.48 +   },{12904407, 117,
   87.49 +      5000, 2500, 2500, 12500, 1, 100, 125000, 0, 0, 0, 0, 1, 1000,
   87.50 +   },{11811811, 118,
   87.51 +      5000, 2500, 2500, 37500, 1, 100, 375000, 0, 0, 0, 0, 1, 1000,
   87.52 +   },{90023593, 119,
   87.53 +      5000, 2500, 2500, 50000, 1, 100, 500000, 0, 0, 0, 0, 1, 1000,
   87.54 +   },{93028922, 120,
   87.55 +      5000, 2500, 2500, 75000, 1, 100, 750000, 0, 0, 0, 0, 1, 1000,
   87.56 +   },{72707401, 121,
   87.57 +      5000, 50, 50, 25000, 1, 100, 250000, 50, 50, 0, 100, 1, 1000,
   87.58 +   },{93040771, 122,
   87.59 +      5000, 250, 250, 25000, 1, 100, 250000, 250, 250, 0, 100, 1, 1000,
   87.60 +   },{70220611, 123,
   87.61 +      5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
   87.62 +   },{52774811, 124,
   87.63 +      5000, 1000, 1000, 25000, 1, 100, 250000, 1000, 1000, 0, 100, 1,
   87.64 +      1000,
   87.65 +   },{22492311, 125,
   87.66 +      5000, 1500, 1500, 25000, 1, 100, 250000, 1500, 1500, 0, 100, 1,
   87.67 +      1000,
   87.68 +   },{35269337, 126,
   87.69 +      5000, 500, 500, 12500, 1, 100, 125000, 500, 500, 0, 100, 1, 1000,
   87.70 +   },{30140502, 127,
   87.71 +      5000, 500, 500, 37500, 1, 100, 375000, 500, 500, 0, 100, 1, 1000,
   87.72 +   },{49205455, 128,
   87.73 +      5000, 500, 500, 50000, 1, 100, 500000, 500, 500, 0, 100, 1, 1000,
   87.74 +   },{42958341, 129,
   87.75 +      5000, 500, 500, 75000, 1, 100, 750000, 500, 500, 0, 100, 1, 1000,
   87.76 +   },{25440925, 130,
   87.77 +      5000, 500, 500, 12500, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
   87.78 +   },{75294924, 131,
   87.79 +      5000, 500, 500, 37500, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
   87.80 +   },{4463965, 132,
   87.81 +      5000, 500, 500, 50000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
   87.82 +   },{13390427, 133,
   87.83 +      5000, 500, 500, 75000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
   87.84 +   },{95250971, 134,
   87.85 +      1000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
   87.86 +   },{54830522, 135,
   87.87 +      2500, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
   87.88 +   },{520593, 136,
   87.89 +      7500, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
   87.90 +   },{52900925, 137,
   87.91 +      10000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
   87.92 +   },{22603395, 138,
   87.93 +      5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 50,
   87.94 +   },{55253099, 139,
   87.95 +      5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 250,
   87.96 +   },{75357001, 140,
   87.97 +      5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 500,
   87.98 +   },{10072459, 141,
   87.99 +      5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 2500,
  87.100 +   },{55728492, 142,
  87.101 +      5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 5000,
  87.102 +   },{593043, 143,
  87.103 +      5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 0, 1, 1000,
  87.104 +   },{94236572, 144,
  87.105 +      5000, 500, 500, 25000, 1, 10, 250000, 500, 500, 0, 100, 1, 1000,
  87.106 +   },{94882955, 145,
  87.107 +      5000, 500, 500, 25000, 1, 1000, 250000, 500, 500, 0, 100, 1, 1000,
  87.108 +   },{48489922, 146,
  87.109 +      5000, 500, 500, 25000, 1, 10000, 250000, 500, 500, 0, 100, 1,
  87.110 +      1000,
  87.111 +   },{75578374, 147,
  87.112 +      5000, 500, 500, 25000, -100, -1, 250000, 500, 500, 0, 100, 1,
  87.113 +      1000,
  87.114 +   },{44821152, 148,
  87.115 +      5000, 500, 500, 25000, -50, 49, 250000, 500, 500, 0, 100, 1, 1000,
  87.116 +   },{45224103, 149,
  87.117 +      5000, 500, 500, 25000, 101, 200, 250000, 500, 500, 0, 100, 1,
  87.118 +      1000,
  87.119 +   },{63491741, 150,
  87.120 +      5000, 500, 500, 25000, 1001, 1100, 250000, 500, 500, 0, 100, 1,
  87.121 +      1000,
  87.122 +   }
  87.123 +};
  87.124 +
  87.125 +typedef struct { double rhs; } v_data;
  87.126 +typedef struct { double cap, cost; } a_data;
  87.127 +
  87.128 +int main(void)
  87.129 +{     glp_graph *G;
  87.130 +      int k;
  87.131 +      char fname[100+1];
  87.132 +      G = glp_create_graph(sizeof(v_data), sizeof(a_data));
  87.133 +      for (k = 1; k <= 50; k++)
  87.134 +      {  sprintf(fname, "netgn%03d.min", parm[k-1][1]);
  87.135 +         glp_netgen(G, offsetof(v_data, rhs), offsetof(a_data, cap),
  87.136 +            offsetof(a_data, cost), &parm[k-1][-1]);
  87.137 +         glp_write_mincost(G, offsetof(v_data, rhs), -1,
  87.138 +            offsetof(a_data, cap), offsetof(a_data, cost), fname);
  87.139 +      }
  87.140 +      glp_delete_graph(G);
  87.141 +      return 0;
  87.142 +}
  87.143 +
  87.144 +/* eof */
    88.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    88.2 +++ b/examples/numbrix.mod	Mon Dec 06 13:09:21 2010 +0100
    88.3 @@ -0,0 +1,84 @@
    88.4 +/* Numbrix, Number Placement Puzzle */
    88.5 +
    88.6 +/* Written in GNU MathProg by Robert Wood <rwood@targus.com>  */
    88.7 +
    88.8 +/* Numbrix is a logic-based number-placement puzzle.[1]
    88.9 + * The objective is to fill the grid so that each cell contains
   88.10 + * digits in sequential order taking a horizontal or vertical
   88.11 + * path; diagonal paths are not allowed. The puzzle setter
   88.12 + * provides a grid often with the outer most cells completed.
   88.13 + *
   88.14 + * Completed Numbrix puzzles are usually a square of numbers
   88.15 + * in order from 1 to 64 (8x8 grid) or from 1 to 81 (9x9 grid),
   88.16 + * following a continuous path in sequence.
   88.17 + *
   88.18 + * The modern puzzle was invented by Marilyn vos Savant in 2008
   88.19 + * and published by Parade Magazine under the name "Numbrix",
   88.20 + * near her weekly Ask Marilyn article.
   88.21 + *
   88.22 + *    http://en.wikipedia.org/wiki/Numbrix  */
   88.23 +
   88.24 +set I := {1..9};
   88.25 +set J := {1..9};
   88.26 +set VALS := {1..81};
   88.27 +
   88.28 +param givens{I, J}, integer, >= 0, <= 81, default 0;
   88.29 +/* the "givens" */
   88.30 +
   88.31 +param neighbors{i in I,j in J, i2 in I, j2 in J} , binary :=
   88.32 +(if abs(i - i2) + abs(j -j2) == 1 then
   88.33 +     1
   88.34 + else
   88.35 +     0
   88.36 +);
   88.37 +/*  defines which spots are the boards are neighbors */
   88.38 +
   88.39 +var x{i in I, j in J, k in VALS}, binary;
   88.40 +/* x[i,j,k] = 1 means cell [i,j] is assigned number k */
   88.41 +
   88.42 +s.t. fa{i in I, j in J, k in VALS: givens[i,j] != 0}:
   88.43 +     x[i,j,k] = (if givens[i,j] = k then 1 else 0);
   88.44 +/* assign pre-defined numbers using the "givens" */
   88.45 +
   88.46 +s.t. fb{i in I, j in J}: sum{k in VALS} x[i,j,k] = 1;
   88.47 +/* each cell must be assigned exactly one number */
   88.48 +
   88.49 +s.t. singleNum {k in VALS}:  sum{i in I, j in J} x[i,j,k] = 1;
   88.50 +/*  a value can only occur once */
   88.51 +
   88.52 +s.t. neighborContraint {i in I, j in J, k in 1..80}:
   88.53 +        x[i,j,k] <= sum{i2 in I, j2 in J} x[i2,j2,k+1] * neighbors[i,j,i2,j2];
   88.54 +/* each cell must have a neighbor with the next higher value */
   88.55 +
   88.56 +
   88.57 +/* there is no need for an objective function here */
   88.58 +
   88.59 +
   88.60 +solve;
   88.61 +
   88.62 +for {i in I}
   88.63 +{  for {0..0: i = 1 or i = 4 or i = 7}
   88.64 +      printf " +----------+----------+----------+\n";
   88.65 +   for {j in J}
   88.66 +   {  for {0..0: j = 1 or j = 4 or j = 7} printf(" |");
   88.67 +      printf " %2d", sum{k in VALS} x[i,j,k] * k;
   88.68 +      for {0..0: j = 9} printf(" |\n");
   88.69 +   }
   88.70 +   for {0..0: i = 9}
   88.71 +      printf " +----------+----------+----------+\n";
   88.72 +}
   88.73 +
   88.74 +data;
   88.75 +
   88.76 +param givens : 1 2 3 4 5 6 7 8 9 :=
   88.77 +           1   . . . . . . . . .
   88.78 +           2   . 11 12 15 18 21 62 61 .
   88.79 +           3   .  6 . . . . . 60 .
   88.80 +           4   . 33 . . . . . 57 .
   88.81 +           5   . 32 . . . . . 56 .
   88.82 +           6   . 37 . . . . . 73 .
   88.83 +           7   . 38 . . . . . 72 .
   88.84 +           8   . 43 44 47 48 51 76 77 .
   88.85 +           9   . . . . . . . . . ;
   88.86 +
   88.87 +end;
    89.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    89.2 +++ b/examples/pbn.mod	Mon Dec 06 13:09:21 2010 +0100
    89.3 @@ -0,0 +1,194 @@
    89.4 +/* PBN, Paint-By-Numbers Puzzle */
    89.5 +
    89.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
    89.7 +
    89.8 +/* A paint-by-number puzzle consists of an m*n grid of pixels (the
    89.9 +   canvas) together with m+n cluster-size sequences, one for each row
   89.10 +   and column. The goal is to paint the canvas with a picture that
   89.11 +   satisfies the following constraints:
   89.12 +
   89.13 +   1. Each pixel must be blank or white.
   89.14 +
   89.15 +   2. If a row or column has cluster-size sequence s1, s2, ..., sk,
   89.16 +      then it must contain k clusters of black pixels - the first with
   89.17 +      s1 black pixels, the second with s2 black pixels, and so on.
   89.18 +
   89.19 +   It should be noted that "first" means "leftmost" for rows and
   89.20 +   "topmost" for columns, and that rows and columns need not begin or
   89.21 +   end with black pixels.
   89.22 +
   89.23 +   Example:
   89.24 +                  1   1
   89.25 +                  1   1
   89.26 +              2 1 1 1 1 1 2 3
   89.27 +              3 2 1 2 1 2 3 4 8 9
   89.28 +
   89.29 +        3 6   # # # . # # # # # #
   89.30 +        1 4   # . . . . . # # # #
   89.31 +      1 1 3   . . # . # . . # # #
   89.32 +          2   . . . . . . . . # #
   89.33 +        3 3   . . # # # . . # # #
   89.34 +        1 4   # . . . . . # # # #
   89.35 +        2 5   # # . . . # # # # #
   89.36 +        2 5   # # . . . # # # # #
   89.37 +        1 1   . . . # . . . . . #
   89.38 +          3   . . # # # . . . . .
   89.39 +
   89.40 +   (In Russia this sort of puzzles is known as "Japanese crossword".)
   89.41 +
   89.42 +   References:
   89.43 +   Robert A. Bosch, "Painting by Numbers", 2000.
   89.44 +   <http://www.oberlin.edu/~math/faculty/bosch/pbn-page.html> */
   89.45 +
   89.46 +param m, integer, >= 1;
   89.47 +/* the number of rows */
   89.48 +
   89.49 +param n, integer, >= 1;
   89.50 +/* the number of columns */
   89.51 +
   89.52 +param row{i in 1..m, 1..n div 2}, integer, >= 0, default 0;
   89.53 +/* the cluster-size sequence for row i (raw data) */
   89.54 +
   89.55 +param col{j in 1..n, 1..m div 2}, integer, >= 0, default 0;
   89.56 +/* the cluster-size sequence for column j (raw data) */
   89.57 +
   89.58 +param kr{i in 1..m} := sum{t in 1..n div 2: row[i,t] > 0} 1;
   89.59 +/* the number of clusters in row i */
   89.60 +
   89.61 +param kc{j in 1..n} := sum{t in 1..m div 2: col[j,t] > 0} 1;
   89.62 +/* the number of clusters in column j */
   89.63 +
   89.64 +param sr{i in 1..m, t in 1..kr[i]} := row[i,t], integer, >= 1;
   89.65 +/* the cluster-size sequence for row i */
   89.66 +
   89.67 +param sc{j in 1..n, t in 1..kc[j]} := col[j,t], integer, >= 1;
   89.68 +/* the cluster-size sequence for column j */
   89.69 +
   89.70 +check{i in 1..m}: sum{t in 1..kr[i]} sr[i,t] <= n - (kr[i] - 1);
   89.71 +/* check that the sum of the cluster sizes in each row is valid */
   89.72 +
   89.73 +check{j in 1..n}: sum{t in 1..kc[j]} sc[j,t] <= m - (kc[j] - 1);
   89.74 +/* check that the sum of the cluster sizes in each column is valid */
   89.75 +
   89.76 +check: sum{i in 1..m, t in 1..kr[i]} sr[i,t] =
   89.77 +       sum{j in 1..n, t in 1..kc[j]} sc[j,t];
   89.78 +/* check that the sum of the cluster sizes in all rows is equal to the
   89.79 +   sum of the cluster sizes in all columns */
   89.80 +
   89.81 +param er{i in 1..m, t in 1..kr[i]} :=
   89.82 +   if t = 1 then 1 else er[i,t-1] + sr[i,t-1] + 1;
   89.83 +/* the smallest value of j such that row i's t-th cluster can be
   89.84 +   placed in row i with its leftmost pixel occupying pixel j */
   89.85 +
   89.86 +param lr{i in 1..m, t in 1..kr[i]} :=
   89.87 +   if t = kr[i] then n + 1 - sr[i,t] else lr[i,t+1] - sr[i,t] - 1;
   89.88 +/* the largest value of j such that row i's t-th cluster can be
   89.89 +   placed in row i with its leftmost pixel occupying pixel j */
   89.90 +
   89.91 +param ec{j in 1..n, t in 1..kc[j]} :=
   89.92 +   if t = 1 then 1 else ec[j,t-1] + sc[j,t-1] + 1;
   89.93 +/* the smallest value of i such that column j's t-th cluster can be
   89.94 +   placed in column j with its topmost pixel occupying pixel i */
   89.95 +
   89.96 +param lc{j in 1..n, t in 1..kc[j]} :=
   89.97 +   if t = kc[j] then m + 1 - sc[j,t] else lc[j,t+1] - sc[j,t] - 1;
   89.98 +/* the largest value of i such that column j's t-th cluster can be
   89.99 +   placed in column j with its topmost pixel occupying pixel i */
  89.100 +
  89.101 +var z{i in 1..m, j in 1..n}, binary;
  89.102 +/* z[i,j] = 1, if row i's j-th pixel is painted black
  89.103 +   z[i,j] = 0, if row i's j-th pixel is painted white */
  89.104 +
  89.105 +var y{i in 1..m, t in 1..kr[i], j in er[i,t]..lr[i,t]}, binary;
  89.106 +/* y[i,t,j] = 1, if row i's t-th cluster is placed in row i with its
  89.107 +                 leftmost pixel occupying pixel j
  89.108 +   y[i,t,j] = 0, if not */
  89.109 +
  89.110 +var x{j in 1..n, t in 1..kc[j], i in ec[j,t]..lc[j,t]}, binary;
  89.111 +/* x[j,t,i] = 1, if column j's t-th cluster is placed in column j with
  89.112 +                 its topmost pixel occupying pixel i
  89.113 +   x[j,t,i] = 0, if not */
  89.114 +
  89.115 +s.t. fa{i in 1..m, t in 1..kr[i]}:
  89.116 +     sum{j in er[i,t]..lr[i,t]} y[i,t,j] = 1;
  89.117 +/* row i's t-th cluster must appear in row i exactly once */
  89.118 +
  89.119 +s.t. fb{i in 1..m, t in 1..kr[i]-1, j in er[i,t]..lr[i,t]}:
  89.120 +     y[i,t,j] <= sum{jp in j+sr[i,t]+1..lr[i,t+1]} y[i,t+1,jp];
  89.121 +/* row i's (t+1)-th cluster must be placed to the right of its t-th
  89.122 +   cluster */
  89.123 +
  89.124 +s.t. fc{j in 1..n, t in 1..kc[j]}:
  89.125 +     sum{i in ec[j,t]..lc[j,t]} x[j,t,i] = 1;
  89.126 +/* column j's t-th cluster must appear in column j exactly once */
  89.127 +
  89.128 +s.t. fd{j in 1..n, t in 1..kc[j]-1, i in ec[j,t]..lc[j,t]}:
  89.129 +     x[j,t,i] <= sum{ip in i+sc[j,t]+1..lc[j,t+1]} x[j,t+1,ip];
  89.130 +/* column j's (t+1)-th cluster must be placed below its t-th cluster */
  89.131 +
  89.132 +s.t. fe{i in 1..m, j in 1..n}:
  89.133 +     z[i,j] <= sum{t in 1..kr[i], jp in er[i,t]..lr[i,t]:
  89.134 +                   j-sr[i,t]+1 <= jp and jp <= j} y[i,t,jp];
  89.135 +/* the double coverage constraint stating that if row i's j-th pixel
  89.136 +   is painted black, then at least one of row i's clusters must be
  89.137 +   placed in such a way that it covers row i's j-th pixel */
  89.138 +
  89.139 +s.t. ff{i in 1..m, j in 1..n}:
  89.140 +     z[i,j] <= sum{t in 1..kc[j], ip in ec[j,t]..lc[j,t]:
  89.141 +                   i-sc[j,t]+1 <= ip and ip <= i} x[j,t,ip];
  89.142 +/* the double coverage constraint making sure that if row i's j-th
  89.143 +   pixel is painted black, then at least one of column j's clusters
  89.144 +   covers it */
  89.145 +
  89.146 +s.t. fg{i in 1..m, j in 1..n, t in 1..kr[i], jp in er[i,t]..lr[i,t]:
  89.147 +     j-sr[i,t]+1 <= jp and jp <= j}: z[i,j] >= y[i,t,jp];
  89.148 +/* the constraint to prevent white pixels from being covered by the
  89.149 +   row clusters */
  89.150 +
  89.151 +s.t. fh{i in 1..m, j in 1..n, t in 1..kc[j], ip in ec[j,t]..lc[j,t]:
  89.152 +     i-sc[j,t]+1 <= ip and ip <= i}: z[i,j] >= x[j,t,ip];
  89.153 +/* the constraint to prevent white pixels from being covered by the
  89.154 +   column clusters */
  89.155 +
  89.156 +/* there is no need for an objective function here */
  89.157 +
  89.158 +solve;
  89.159 +
  89.160 +for {i in 1..m}
  89.161 +{  printf{j in 1..n} " %s", if z[i,j] then "#" else ".";
  89.162 +   printf "\n";
  89.163 +}
  89.164 +
  89.165 +data;
  89.166 +
  89.167 +/* These data correspond to the example above. */
  89.168 +
  89.169 +param m := 10;
  89.170 +
  89.171 +param n := 10;
  89.172 +
  89.173 +param row : 1 2 3 4 :=
  89.174 +         1  3 6 . .
  89.175 +         2  1 4 . .
  89.176 +         3  1 1 3 .
  89.177 +         4  2 . . .
  89.178 +         5  3 3 . .
  89.179 +         6  1 4 . .
  89.180 +         7  2 5 . .
  89.181 +         8  2 5 . .
  89.182 +         9  1 1 . .
  89.183 +        10  3 . . . ;
  89.184 +
  89.185 +param col : 1 2 3 4 :=
  89.186 +         1  2 3 . .
  89.187 +         2  1 2 . .
  89.188 +         3  1 1 1 1
  89.189 +         4  1 2 . .
  89.190 +         5  1 1 1 1
  89.191 +         6  1 2 . .
  89.192 +         7  2 3 . .
  89.193 +         8  3 4 . .
  89.194 +         9  8 . . .
  89.195 +        10  9 . . . ;
  89.196 +
  89.197 +end;
    90.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    90.2 +++ b/examples/plan.lp	Mon Dec 06 13:09:21 2010 +0100
    90.3 @@ -0,0 +1,39 @@
    90.4 +\* plan.lp *\
    90.5 +
    90.6 +Minimize
    90.7 +   value: .03 bin1 + .08 bin2 + .17 bin3 + .12 bin4 + .15 bin5 +
    90.8 +          .21 alum + .38 silicon
    90.9 +
   90.10 +Subject To
   90.11 +   yield:     bin1 +     bin2 +     bin3 +     bin4 +     bin5 +
   90.12 +              alum +     silicon                                 =  2000
   90.13 +
   90.14 +   fe:    .15 bin1 + .04 bin2 + .02 bin3 + .04 bin4 + .02 bin5 +
   90.15 +          .01 alum + .03 silicon                                 <=   60
   90.16 +
   90.17 +   cu:    .03 bin1 + .05 bin2 + .08 bin3 + .02 bin4 + .06 bin5 +
   90.18 +          .01 alum                                               <=  100
   90.19 +
   90.20 +   mn:    .02 bin1 + .04 bin2 + .01 bin3 + .02 bin4 + .02 bin5   <=   40
   90.21 +
   90.22 +   mg:    .02 bin1 + .03 bin2                       + .01 bin5   <=   30
   90.23 +
   90.24 +   al:    .70 bin1 + .75 bin2 + .80 bin3 + .75 bin4 + .80 bin5 +
   90.25 +          .97 alum                                               >= 1500
   90.26 +
   90.27 +   si1:   .02 bin1 + .06 bin2 + .08 bin3 + .12 bin4 + .02 bin5 +
   90.28 +          .01 alum + .97 silicon                                 >=  250
   90.29 +
   90.30 +   si2:   .02 bin1 + .06 bin2 + .08 bin3 + .12 bin4 + .02 bin5 +
   90.31 +          .01 alum + .97 silicon                                 <=  300
   90.32 +
   90.33 +Bounds
   90.34 +          bin1 <=  200
   90.35 +          bin2 <= 2500
   90.36 +   400 <= bin3 <=  800
   90.37 +   100 <= bin4 <=  700
   90.38 +          bin5 <= 1500
   90.39 +
   90.40 +End
   90.41 +
   90.42 +\* eof *\
    91.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    91.2 +++ b/examples/plan.mod	Mon Dec 06 13:09:21 2010 +0100
    91.3 @@ -0,0 +1,39 @@
    91.4 +/* plan.mod */
    91.5 +
    91.6 +var bin1, >= 0, <= 200;
    91.7 +var bin2, >= 0, <= 2500;
    91.8 +var bin3, >= 400, <= 800;
    91.9 +var bin4, >= 100, <= 700;
   91.10 +var bin5, >= 0, <= 1500;
   91.11 +var alum, >= 0;
   91.12 +var silicon, >= 0;
   91.13 +
   91.14 +minimize
   91.15 +
   91.16 +value: .03 * bin1 + .08 * bin2 + .17 * bin3 + .12 * bin4 + .15 * bin5 +
   91.17 +       .21 * alum + .38 * silicon;
   91.18 +
   91.19 +subject to
   91.20 +
   91.21 +yield: bin1 + bin2 + bin3 + bin4 + bin5 + alum + silicon = 2000;
   91.22 +
   91.23 +fe: .15 * bin1 + .04 * bin2 + .02 * bin3 + .04 * bin4 + .02 * bin5 +
   91.24 +    .01 * alum + .03 * silicon <= 60;
   91.25 +
   91.26 +cu: .03 * bin1 + .05 * bin2 + .08 * bin3 + .02 * bin4 + .06 * bin5 +
   91.27 +    .01 * alum <= 100;
   91.28 +
   91.29 +mn: .02 * bin1 + .04 * bin2 + .01 * bin3 + .02 * bin4 + .02 * bin5
   91.30 +    <= 40;
   91.31 +
   91.32 +mg: .02 * bin1 + .03 * bin2 + .01 * bin5 <= 30;
   91.33 +
   91.34 +al: .70 * bin1 + .75 * bin2 + .80 * bin3 + .75 * bin4 + .80 * bin5 +
   91.35 +    .97 * alum >= 1500;
   91.36 +
   91.37 +si: 250 <= .02 * bin1 + .06 * bin2 + .08 * bin3 + .12 * bin4 +
   91.38 +    .02 * bin5 + .01 * alum + .97 * silicon <= 300;
   91.39 +
   91.40 +end;
   91.41 +
   91.42 +/* eof */
    92.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    92.2 +++ b/examples/plan.mps	Mon Dec 06 13:09:21 2010 +0100
    92.3 @@ -0,0 +1,54 @@
    92.4 +*000000001111111111222222222233333333334444444444555555555566
    92.5 +*234567890123456789012345678901234567890123456789012345678901
    92.6 +NAME          PLAN
    92.7 +ROWS
    92.8 + N  VALUE
    92.9 + E  YIELD
   92.10 + L  FE
   92.11 + L  CU
   92.12 + L  MN
   92.13 + L  MG
   92.14 + G  AL
   92.15 + L  SI
   92.16 +COLUMNS
   92.17 +    BIN1      VALUE           .03000   YIELD          1.00000
   92.18 +              FE              .15000   CU              .03000
   92.19 +              MN              .02000   MG              .02000
   92.20 +              AL              .70000   SI              .02000
   92.21 +    BIN2      VALUE           .08000   YIELD          1.00000
   92.22 +              FE              .04000   CU              .05000
   92.23 +              MN              .04000   MG              .03000
   92.24 +              AL              .75000   SI              .06000
   92.25 +    BIN3      VALUE           .17000   YIELD          1.00000
   92.26 +              FE              .02000   CU              .08000
   92.27 +              MN              .01000   AL              .80000
   92.28 +              SI              .08000
   92.29 +    BIN4      VALUE           .12000   YIELD          1.00000
   92.30 +              FE              .04000   CU              .02000
   92.31 +              MN              .02000   AL              .75000
   92.32 +              SI              .12000
   92.33 +    BIN5      VALUE           .15000   YIELD          1.00000
   92.34 +              FE              .02000   CU              .06000
   92.35 +              MN              .02000   MG              .01000
   92.36 +              AL              .80000   SI              .02000
   92.37 +    ALUM      VALUE           .21000   YIELD          1.00000
   92.38 +              FE              .01000   CU              .01000
   92.39 +              AL              .97000   SI              .01000
   92.40 +    SILICON   VALUE           .38000   YIELD          1.00000
   92.41 +              FE              .03000   SI              .97000
   92.42 +RHS
   92.43 +    RHS1      YIELD       2000.00000   FE            60.00000
   92.44 +              CU           100.00000   MN            40.00000
   92.45 +              SI           300.00000
   92.46 +              MG            30.00000   AL          1500.00000
   92.47 +RANGES
   92.48 +    RNG1      SI            50.00000
   92.49 +BOUNDS
   92.50 + UP BND1      BIN1         200.00000
   92.51 + UP           BIN2        2500.00000
   92.52 + LO           BIN3         400.00000
   92.53 + UP           BIN3         800.00000
   92.54 + LO           BIN4         100.00000
   92.55 + UP           BIN4         700.00000
   92.56 + UP           BIN5        1500.00000
   92.57 +ENDATA
    93.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    93.2 +++ b/examples/prod.mod	Mon Dec 06 13:09:21 2010 +0100
    93.3 @@ -0,0 +1,331 @@
    93.4 +# PROD, a multiperiod production model
    93.5 +#
    93.6 +# References:
    93.7 +# Robert Fourer, David M. Gay and Brian W. Kernighan, "A Modeling Language
    93.8 +# for Mathematical Programming." Management Science 36 (1990) 519-554.
    93.9 +
   93.10 +###  PRODUCTION SETS AND PARAMETERS  ###
   93.11 +
   93.12 +set prd 'products';    # Members of the product group
   93.13 +
   93.14 +param pt 'production time' {prd} > 0;
   93.15 +
   93.16 +                        # Crew-hours to produce 1000 units
   93.17 +
   93.18 +param pc 'production cost' {prd} > 0;
   93.19 +
   93.20 +                        # Nominal production cost per 1000, used
   93.21 +                        # to compute inventory and shortage costs
   93.22 +
   93.23 +###  TIME PERIOD SETS AND PARAMETERS  ###
   93.24 +
   93.25 +param first > 0 integer;
   93.26 +                        # Index of first production period to be modeled
   93.27 +
   93.28 +param last > first integer;
   93.29 +
   93.30 +                        # Index of last production period to be modeled
   93.31 +
   93.32 +set time 'planning horizon' := first..last;
   93.33 +
   93.34 +###  EMPLOYMENT PARAMETERS  ###
   93.35 +
   93.36 +param cs 'crew size' > 0 integer;
   93.37 +
   93.38 +                        # Workers per crew
   93.39 +
   93.40 +param sl 'shift length' > 0;
   93.41 +
   93.42 +                        # Regular-time hours per shift
   93.43 +
   93.44 +param rtr 'regular time rate' > 0;
   93.45 +
   93.46 +                        # Wage per hour for regular-time labor
   93.47 +
   93.48 +param otr 'overtime rate' > rtr;
   93.49 +
   93.50 +                        # Wage per hour for overtime labor
   93.51 +
   93.52 +param iw 'initial workforce' >= 0 integer;
   93.53 +
   93.54 +                        # Crews employed at start of first period
   93.55 +
   93.56 +param dpp 'days per period' {time} > 0;
   93.57 +
   93.58 +                        # Regular working days in a production period
   93.59 +
   93.60 +param ol 'overtime limit' {time} >= 0;
   93.61 +
   93.62 +                        # Maximum crew-hours of overtime in a period
   93.63 +
   93.64 +param cmin 'crew minimum' {time} >= 0;
   93.65 +
   93.66 +                        # Lower limit on average employment in a period
   93.67 +
   93.68 +param cmax 'crew maximum' {t in time} >= cmin[t];
   93.69 +
   93.70 +                        # Upper limit on average employment in a period
   93.71 +
   93.72 +param hc 'hiring cost' {time} >= 0;
   93.73 +
   93.74 +                        # Penalty cost of hiring a crew
   93.75 +
   93.76 +param lc 'layoff cost' {time} >= 0;
   93.77 +
   93.78 +                        # Penalty cost of laying off a crew
   93.79 +
   93.80 +###  DEMAND PARAMETERS  ###
   93.81 +
   93.82 +param dem 'demand' {prd,first..last+1} >= 0;
   93.83 +
   93.84 +                        # Requirements (in 1000s)
   93.85 +                        # to be met from current production and inventory
   93.86 +
   93.87 +param pro 'promoted' {prd,first..last+1} logical;
   93.88 +
   93.89 +                        # true if product will be the subject
   93.90 +                        # of a special promotion in the period
   93.91 +
   93.92 +###  INVENTORY AND SHORTAGE PARAMETERS  ###
   93.93 +
   93.94 +param rir 'regular inventory ratio' >= 0;
   93.95 +
   93.96 +                        # Proportion of non-promoted demand
   93.97 +                        # that must be in inventory the previous period
   93.98 +
   93.99 +param pir 'promotional inventory ratio' >= 0;
  93.100 +
  93.101 +                        # Proportion of promoted demand
  93.102 +                        # that must be in inventory the previous period
  93.103 +
  93.104 +param life 'inventory lifetime' > 0 integer;
  93.105 +
  93.106 +                        # Upper limit on number of periods that
  93.107 +                        # any product may sit in inventory
  93.108 +
  93.109 +param cri 'inventory cost ratio' {prd} > 0;
  93.110 +
  93.111 +                        # Inventory cost per 1000 units is
  93.112 +                        # cri times nominal production cost
  93.113 +
  93.114 +param crs 'shortage cost ratio' {prd} > 0;
  93.115 +
  93.116 +                        # Shortage cost per 1000 units is
  93.117 +                        # crs times nominal production cost
  93.118 +
  93.119 +param iinv 'initial inventory' {prd} >= 0;
  93.120 +
  93.121 +                        # Inventory at start of first period; age unknown
  93.122 +
  93.123 +param iil 'initial inventory left' {p in prd, t in time}
  93.124 +              := iinv[p] less sum {v in first..t} dem[p,v];
  93.125 +
  93.126 +                        # Initial inventory still available for allocation
  93.127 +                        # at end of period t
  93.128 +
  93.129 +param minv 'minimum inventory' {p in prd, t in time}
  93.130 +              := dem[p,t+1] * (if pro[p,t+1] then pir else rir);
  93.131 +
  93.132 +                        # Lower limit on inventory at end of period t
  93.133 +
  93.134 +###  VARIABLES  ###
  93.135 +
  93.136 +var Crews{first-1..last} >= 0;
  93.137 +
  93.138 +                        # Average number of crews employed in each period
  93.139 +
  93.140 +var Hire{time} >= 0;    # Crews hired from previous to current period
  93.141 +
  93.142 +var Layoff{time} >= 0;  # Crews laid off from previous to current period
  93.143 +
  93.144 +var Rprd 'regular production' {prd,time} >= 0;
  93.145 +
  93.146 +                        # Production using regular-time labor, in 1000s
  93.147 +
  93.148 +var Oprd 'overtime production' {prd,time} >= 0;
  93.149 +
  93.150 +                        # Production using overtime labor, in 1000s
  93.151 +
  93.152 +var Inv 'inventory' {prd,time,1..life} >= 0;
  93.153 +
  93.154 +                        # Inv[p,t,a] is the amount of product p that is
  93.155 +                        # a periods old -- produced in period (t+1)-a --
  93.156 +                        # and still in storage at the end of period t
  93.157 +
  93.158 +var Short 'shortage' {prd,time} >= 0;
  93.159 +
  93.160 +                        # Accumulated unsatisfied demand at the end of period t
  93.161 +
  93.162 +###  OBJECTIVE  ###
  93.163 +
  93.164 +minimize cost:
  93.165 +
  93.166 +    sum {t in time} rtr * sl * dpp[t] * cs * Crews[t] +
  93.167 +    sum {t in time} hc[t] * Hire[t] +
  93.168 +    sum {t in time} lc[t] * Layoff[t] +
  93.169 +    sum {t in time, p in prd} otr * cs * pt[p] * Oprd[p,t] +
  93.170 +    sum {t in time, p in prd, a in 1..life} cri[p] * pc[p] * Inv[p,t,a] +
  93.171 +    sum {t in time, p in prd} crs[p] * pc[p] * Short[p,t];
  93.172 +
  93.173 +                        # Full regular wages for all crews employed, plus
  93.174 +                        # penalties for hiring and layoffs, plus
  93.175 +                        # wages for any overtime worked, plus
  93.176 +                        # inventory and shortage costs
  93.177 +
  93.178 +                        # (All other production costs are assumed
  93.179 +                        # to depend on initial inventory and on demands,
  93.180 +                        # and so are not included explicitly.)
  93.181 +
  93.182 +###  CONSTRAINTS  ###
  93.183 +
  93.184 +rlim 'regular-time limit' {t in time}:
  93.185 +
  93.186 +    sum {p in prd} pt[p] * Rprd[p,t] <= sl * dpp[t] * Crews[t];
  93.187 +
  93.188 +                        # Hours needed to accomplish all regular-time
  93.189 +                        # production in a period must not exceed
  93.190 +                        # hours available on all shifts
  93.191 +
  93.192 +olim 'overtime limit' {t in time}:
  93.193 +
  93.194 +    sum {p in prd} pt[p] * Oprd[p,t] <= ol[t];
  93.195 +
  93.196 +                        # Hours needed to accomplish all overtime
  93.197 +                        # production in a period must not exceed
  93.198 +                        # the specified overtime limit
  93.199 +
  93.200 +empl0 'initial crew level':  Crews[first-1] = iw;
  93.201 +
  93.202 +                        # Use given initial workforce
  93.203 +
  93.204 +empl 'crew levels' {t in time}:  Crews[t] = Crews[t-1] + Hire[t] - Layoff[t];
  93.205 +
  93.206 +                        # Workforce changes by hiring or layoffs
  93.207 +
  93.208 +emplbnd 'crew limits' {t in time}:  cmin[t] <= Crews[t] <= cmax[t];
  93.209 +
  93.210 +                        # Workforce must remain within specified bounds
  93.211 +
  93.212 +dreq1 'first demand requirement' {p in prd}:
  93.213 +
  93.214 +    Rprd[p,first] + Oprd[p,first] + Short[p,first]
  93.215 +                             - Inv[p,first,1] = dem[p,first] less iinv[p];
  93.216 +
  93.217 +dreq 'demand requirements' {p in prd, t in first+1..last}:
  93.218 +
  93.219 +    Rprd[p,t] + Oprd[p,t] + Short[p,t] - Short[p,t-1]
  93.220 +                          + sum {a in 1..life} (Inv[p,t-1,a] - Inv[p,t,a])
  93.221 +                                                  = dem[p,t] less iil[p,t-1];
  93.222 +
  93.223 +                        # Production plus increase in shortage plus
  93.224 +                        # decrease in inventory must equal demand
  93.225 +
  93.226 +ireq 'inventory requirements' {p in prd, t in time}:
  93.227 +
  93.228 +    sum {a in 1..life} Inv[p,t,a] + iil[p,t] >= minv[p,t];
  93.229 +
  93.230 +                        # Inventory in storage at end of period t
  93.231 +                        # must meet specified minimum
  93.232 +
  93.233 +izero 'impossible inventories' {p in prd, v in 1..life-1, a in v+1..life}:
  93.234 +
  93.235 +    Inv[p,first+v-1,a] = 0;
  93.236 +
  93.237 +                        # In the vth period (starting from first)
  93.238 +                        # no inventory may be more than v periods old
  93.239 +                        # (initial inventories are handled separately)
  93.240 +
  93.241 +ilim1 'new-inventory limits' {p in prd, t in time}:
  93.242 +
  93.243 +    Inv[p,t,1] <= Rprd[p,t] + Oprd[p,t];
  93.244 +
  93.245 +                        # New inventory cannot exceed
  93.246 +                        # production in the most recent period
  93.247 +
  93.248 +ilim 'inventory limits' {p in prd, t in first+1..last, a in 2..life}:
  93.249 +
  93.250 +    Inv[p,t,a] <= Inv[p,t-1,a-1];
  93.251 +
  93.252 +                        # Inventory left from period (t+1)-p
  93.253 +                        # can only decrease as time goes on
  93.254 +
  93.255 +###  DATA  ###
  93.256 +
  93.257 +data;
  93.258 +
  93.259 +set prd := 18REG 24REG 24PRO ;
  93.260 +
  93.261 +param first :=  1 ;
  93.262 +param last  := 13 ;
  93.263 +param life  :=  2 ;
  93.264 +
  93.265 +param cs := 18 ;
  93.266 +param sl :=  8 ;
  93.267 +param iw :=  8 ;
  93.268 +
  93.269 +param rtr := 16.00 ;
  93.270 +param otr := 43.85 ;
  93.271 +param rir :=  0.75 ;
  93.272 +param pir :=  0.80 ;
  93.273 +
  93.274 +param :         pt       pc        cri       crs      iinv   :=
  93.275 +
  93.276 +  18REG      1.194     2304.     0.015     1.100      82.0
  93.277 +  24REG      1.509     2920.     0.015     1.100     792.2
  93.278 +  24PRO      1.509     2910.     0.015     1.100       0.0   ;
  93.279 +
  93.280 +param :     dpp        ol      cmin      cmax        hc        lc   :=
  93.281 +
  93.282 +  1        19.5      96.0       0.0       8.0      7500      7500
  93.283 +  2        19.0      96.0       0.0       8.0      7500      7500
  93.284 +  3        20.0      96.0       0.0       8.0      7500      7500
  93.285 +  4        19.0      96.0       0.0       8.0      7500      7500
  93.286 +  5        19.5      96.0       0.0       8.0     15000     15000
  93.287 +  6        19.0      96.0       0.0       8.0     15000     15000
  93.288 +  7        19.0      96.0       0.0       8.0     15000     15000
  93.289 +  8        20.0      96.0       0.0       8.0     15000     15000
  93.290 +  9        19.0      96.0       0.0       8.0     15000     15000
  93.291 + 10        20.0      96.0       0.0       8.0     15000     15000
  93.292 + 11        20.0      96.0       0.0       8.0      7500      7500
  93.293 + 12        18.0      96.0       0.0       8.0      7500      7500
  93.294 + 13        18.0      96.0       0.0       8.0      7500      7500   ;
  93.295 +
  93.296 +param dem (tr) :
  93.297 +
  93.298 +          18REG     24REG     24PRO   :=
  93.299 +
  93.300 +  1        63.8    1212.0       0.0
  93.301 +  2        76.0     306.2       0.0
  93.302 +  3        88.4     319.0       0.0
  93.303 +  4       913.8     208.4       0.0
  93.304 +  5       115.0     298.0       0.0
  93.305 +  6       133.8     328.2       0.0
  93.306 +  7        79.6     959.6       0.0
  93.307 +  8       111.0     257.6       0.0
  93.308 +  9       121.6     335.6       0.0
  93.309 + 10       470.0     118.0    1102.0
  93.310 + 11        78.4     284.8       0.0
  93.311 + 12        99.4     970.0       0.0
  93.312 + 13       140.4     343.8       0.0
  93.313 + 14        63.8    1212.0       0.0   ;
  93.314 +
  93.315 +param pro (tr) :
  93.316 +
  93.317 +          18REG     24REG     24PRO   :=
  93.318 +
  93.319 +  1           0         1         0
  93.320 +  2           0         0         0
  93.321 +  3           0         0         0
  93.322 +  4           1         0         0
  93.323 +  5           0         0         0
  93.324 +  6           0         0         0
  93.325 +  7           0         1         0
  93.326 +  8           0         0         0
  93.327 +  9           0         0         0
  93.328 + 10           1         0         1
  93.329 + 11           0         0         0
  93.330 + 12           0         0         0
  93.331 + 13           0         1         0
  93.332 + 14           0         1         0   ;
  93.333 +
  93.334 +end;
    94.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    94.2 +++ b/examples/qfit.mod	Mon Dec 06 13:09:21 2010 +0100
    94.3 @@ -0,0 +1,49 @@
    94.4 +/*Quadratic Curve Fitting Solution
    94.5 +
    94.6 +  Find a plausable quadratic fit to a sample of points
    94.7 +
    94.8 +  Nigel_Galloway@operamail.com
    94.9 +  February 1st., 2009
   94.10 +*/
   94.11 +set Sample;
   94.12 +param Sx {z in Sample};
   94.13 +param Sy {z in Sample};
   94.14 +
   94.15 +var a;
   94.16 +var b;
   94.17 +var c;
   94.18 +
   94.19 +equalz1 :sum{z in Sample} a*Sx[z]*Sx[z]*Sx[z]*Sx[z] + sum{z in Sample} b*Sx[z]*Sx[z]*Sx[z] + sum{z in Sample} c*Sx[z]*Sx[z] = sum{z in Sample} Sy[z]*Sx[z]*Sx[z];
   94.20 +equalz2 :sum{z in Sample} a*Sx[z]*Sx[z]*Sx[z] + sum{z in Sample} b*Sx[z]*Sx[z] + sum{z in Sample} c*Sx[z] = sum{z in Sample} Sy[z]*Sx[z];
   94.21 +equalz3 :sum{z in Sample} a*Sx[z]*Sx[z] + sum{z in Sample} b*Sx[z] + sum{z in Sample} c = sum{z in Sample} Sy[z];
   94.22 +
   94.23 +solve;
   94.24 +
   94.25 +printf "\nbest quadratic fit is:\n\ty = %f %s %fx %s %fx^2\n\n", c, if b < 0 then "-" else "+", abs(b), if a < 0 then "-" else "+", abs(a);
   94.26 +
   94.27 +data;
   94.28 +
   94.29 +param:
   94.30 +Sample:   Sx    Sy :=
   94.31 +  1         0    1
   94.32 +  2       0.5  0.9
   94.33 +  3         1  0.7
   94.34 +  4       1.5  1.5
   94.35 +  5       1.9    2
   94.36 +  6       2.5  2.4
   94.37 +  7         3  3.2
   94.38 +  8       3.5    2
   94.39 +  9         4  2.7
   94.40 + 10       4.5  3.5
   94.41 + 11         5    1
   94.42 + 12       5.5    4
   94.43 + 13         6  3.6
   94.44 + 14       6.6  2.7
   94.45 + 15         7  5.7
   94.46 + 16       7.6  4.6
   94.47 + 17       8.5    6
   94.48 + 18         9  6.8
   94.49 + 19        10  7.3
   94.50 +;
   94.51 +
   94.52 +end;
    95.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    95.2 +++ b/examples/queens.mod	Mon Dec 06 13:09:21 2010 +0100
    95.3 @@ -0,0 +1,41 @@
    95.4 +/* QUEENS, a classic combinatorial optimization problem */
    95.5 +
    95.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
    95.7 +
    95.8 +/* The Queens Problem is to place as many queens as possible on the 8x8
    95.9 +   (or more generally, nxn) chess board in a way that they do not fight
   95.10 +   each other. This problem is probably as old as the chess game itself,
   95.11 +   and thus its origin is not known, but it is known that Gauss studied
   95.12 +   this problem. */
   95.13 +
   95.14 +param n, integer, > 0, default 8;
   95.15 +/* size of the chess board */
   95.16 +
   95.17 +var x{1..n, 1..n}, binary;
   95.18 +/* x[i,j] = 1 means that a queen is placed in square [i,j] */
   95.19 +
   95.20 +s.t. a{i in 1..n}: sum{j in 1..n} x[i,j] <= 1;
   95.21 +/* at most one queen can be placed in each row */
   95.22 +
   95.23 +s.t. b{j in 1..n}: sum{i in 1..n} x[i,j] <= 1;
   95.24 +/* at most one queen can be placed in each column */
   95.25 +
   95.26 +s.t. c{k in 2-n..n-2}: sum{i in 1..n, j in 1..n: i-j == k} x[i,j] <= 1;
   95.27 +/* at most one queen can be placed in each "\"-diagonal */
   95.28 +
   95.29 +s.t. d{k in 3..n+n-1}: sum{i in 1..n, j in 1..n: i+j == k} x[i,j] <= 1;
   95.30 +/* at most one queen can be placed in each "/"-diagonal */
   95.31 +
   95.32 +maximize obj: sum{i in 1..n, j in 1..n} x[i,j];
   95.33 +/* objective is to place as many queens as possible */
   95.34 +
   95.35 +/* solve the problem */
   95.36 +solve;
   95.37 +
   95.38 +/* and print its optimal solution */
   95.39 +for {i in 1..n}
   95.40 +{  for {j in 1..n} printf " %s", if x[i,j] then "Q" else ".";
   95.41 +   printf("\n");
   95.42 +}
   95.43 +
   95.44 +end;
    96.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    96.2 +++ b/examples/samp1.mps	Mon Dec 06 13:09:21 2010 +0100
    96.3 @@ -0,0 +1,29 @@
    96.4 +NAME          SAMP1
    96.5 +ROWS
    96.6 + N  Z
    96.7 + G  R1
    96.8 + G  R2
    96.9 + G  R3
   96.10 +COLUMNS
   96.11 +    X1        R1                2.0    R2                 1.0
   96.12 +    X1        R3                5.0    Z                  3.0
   96.13 +    MARK0001  'MARKER'                 'INTORG'
   96.14 +    X2        R1               -1.0    R2                -1.0
   96.15 +    X2        R3                3.0    Z                  7.0
   96.16 +    X3        R1                1.0    R2                -6.0
   96.17 +    X3        Z                -1.0
   96.18 +    MARK0002  'MARKER'                 'INTEND'
   96.19 +    X4        R1               -1.0    R2                 4.0
   96.20 +    X4        R3                1.0    Z                  1.0
   96.21 +RHS
   96.22 +    RHS1      R1                1.0
   96.23 +    RHS1      R2                8.0
   96.24 +    RHS1      R3                5.0
   96.25 +BOUNDS
   96.26 + UP BND1      X1                4.0
   96.27 + LO BND1      X2                2.0
   96.28 + UP BND1      X2                5.0
   96.29 + UP BND1      X3                1.0
   96.30 + LO BND1      X4                3.0
   96.31 + UP BND1      X4                8.0
   96.32 +ENDATA
    97.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    97.2 +++ b/examples/samp2.mps	Mon Dec 06 13:09:21 2010 +0100
    97.3 @@ -0,0 +1,27 @@
    97.4 +NAME          SAMP2
    97.5 +ROWS
    97.6 + N  Z
    97.7 + G  R1
    97.8 + G  R2
    97.9 + G  R3
   97.10 +COLUMNS
   97.11 +    X1        R1                2.0    R2                 1.0
   97.12 +    X1        R3                5.0    Z                  3.0
   97.13 +    X2        R1               -1.0    R2                -1.0
   97.14 +    X2        R3                3.0    Z                  7.0
   97.15 +    X3        R1                1.0    R2                -6.0
   97.16 +    X3        Z                -1.0
   97.17 +    X4        R1               -1.0    R2                 4.0
   97.18 +    X4        R3                1.0    Z                  1.0
   97.19 +RHS
   97.20 +    RHS1      R1                1.0
   97.21 +    RHS1      R2                8.0
   97.22 +    RHS1      R3                5.0
   97.23 +BOUNDS
   97.24 + UP BND1      X1                4.0
   97.25 + LO BND1      X2                2.0
   97.26 + UI BND1      X2                5.0
   97.27 + BV BND1      X3
   97.28 + LO BND1      X4                3.0
   97.29 + UP BND1      X4                8.0
   97.30 +ENDATA
    98.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    98.2 +++ b/examples/sample.asn	Mon Dec 06 13:09:21 2010 +0100
    98.3 @@ -0,0 +1,40 @@
    98.4 +c sample.asn
    98.5 +c
    98.6 +c This is an example of the assignment problem data
    98.7 +c in DIMACS format.
    98.8 +c
    98.9 +p asn 17 22
   98.10 +c
   98.11 +n 1
   98.12 +n 2
   98.13 +n 3
   98.14 +n 4
   98.15 +n 5
   98.16 +n 6
   98.17 +n 7
   98.18 +n 8
   98.19 +c
   98.20 +a 1  9 13
   98.21 +a 1 10 21
   98.22 +a 1 12 20
   98.23 +a 2 10 12
   98.24 +a 2 12  8
   98.25 +a 2 13 26
   98.26 +a 3 11 22
   98.27 +a 3 13 11
   98.28 +a 4  9 12
   98.29 +a 4 12 36
   98.30 +a 4 14 25
   98.31 +a 5 11 41
   98.32 +a 5 12 40
   98.33 +a 5 13 11
   98.34 +a 5 14  4
   98.35 +a 5 15  8
   98.36 +a 5 16 35
   98.37 +a 5 17 32
   98.38 +a 6  9 13
   98.39 +a 7 10 19
   98.40 +a 8 10 39
   98.41 +a 8 11 15
   98.42 +c
   98.43 +c eof
    99.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    99.2 +++ b/examples/sample.c	Mon Dec 06 13:09:21 2010 +0100
    99.3 @@ -0,0 +1,52 @@
    99.4 +/* sample.c */
    99.5 +
    99.6 +#include <stdio.h>
    99.7 +#include <stdlib.h>
    99.8 +#include <glpk.h>
    99.9 +
   99.10 +int main(void)
   99.11 +{     glp_prob *lp;
   99.12 +      int ia[1+1000], ja[1+1000];
   99.13 +      double ar[1+1000], z, x1, x2, x3;
   99.14 +s1:   lp = glp_create_prob();
   99.15 +s2:   glp_set_prob_name(lp, "sample");
   99.16 +s3:   glp_set_obj_dir(lp, GLP_MAX);
   99.17 +s4:   glp_add_rows(lp, 3);
   99.18 +s5:   glp_set_row_name(lp, 1, "p");
   99.19 +s6:   glp_set_row_bnds(lp, 1, GLP_UP, 0.0, 100.0);
   99.20 +s7:   glp_set_row_name(lp, 2, "q");
   99.21 +s8:   glp_set_row_bnds(lp, 2, GLP_UP, 0.0, 600.0);
   99.22 +s9:   glp_set_row_name(lp, 3, "r");
   99.23 +s10:  glp_set_row_bnds(lp, 3, GLP_UP, 0.0, 300.0);
   99.24 +s11:  glp_add_cols(lp, 3);
   99.25 +s12:  glp_set_col_name(lp, 1, "x1");
   99.26 +s13:  glp_set_col_bnds(lp, 1, GLP_LO, 0.0, 0.0);
   99.27 +s14:  glp_set_obj_coef(lp, 1, 10.0);
   99.28 +s15:  glp_set_col_name(lp, 2, "x2");
   99.29 +s16:  glp_set_col_bnds(lp, 2, GLP_LO, 0.0, 0.0);
   99.30 +s17:  glp_set_obj_coef(lp, 2, 6.0);
   99.31 +s18:  glp_set_col_name(lp, 3, "x3");
   99.32 +s19:  glp_set_col_bnds(lp, 3, GLP_LO, 0.0, 0.0);
   99.33 +s20:  glp_set_obj_coef(lp, 3, 4.0);
   99.34 +s21:  ia[1] = 1, ja[1] = 1, ar[1] =  1.0; /* a[1,1] =  1 */
   99.35 +s22:  ia[2] = 1, ja[2] = 2, ar[2] =  1.0; /* a[1,2] =  1 */
   99.36 +s23:  ia[3] = 1, ja[3] = 3, ar[3] =  1.0; /* a[1,3] =  1 */
   99.37 +s24:  ia[4] = 2, ja[4] = 1, ar[4] = 10.0; /* a[2,1] = 10 */
   99.38 +s25:  ia[5] = 3, ja[5] = 1, ar[5] =  2.0; /* a[3,1] =  2 */
   99.39 +s26:  ia[6] = 2, ja[6] = 2, ar[6] =  4.0; /* a[2,2] =  4 */
   99.40 +s27:  ia[7] = 3, ja[7] = 2, ar[7] =  2.0; /* a[3,2] =  2 */
   99.41 +s28:  ia[8] = 2, ja[8] = 3, ar[8] =  5.0; /* a[2,3] =  5 */
   99.42 +s29:  ia[9] = 3, ja[9] = 3, ar[9] =  6.0; /* a[3,3] =  6 */
   99.43 +s30:  glp_load_matrix(lp, 9, ia, ja, ar);
   99.44 +s31:  glp_simplex(lp, NULL);
   99.45 +s32:  z = glp_get_obj_val(lp);
   99.46 +s33:  x1 = glp_get_col_prim(lp, 1);
   99.47 +s34:  x2 = glp_get_col_prim(lp, 2);
   99.48 +s35:  x3 = glp_get_col_prim(lp, 3);
   99.49 +s36:  printf("\nz = %g; x1 = %g; x2 = %g; x3 = %g\n",
   99.50 +         z, x1, x2, x3);
   99.51 +s37:  glp_delete_prob(lp);
   99.52 +      return 0;
   99.53 +}
   99.54 +
   99.55 +/* eof */
   100.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   100.2 +++ b/examples/sample.clq	Mon Dec 06 13:09:21 2010 +0100
   100.3 @@ -0,0 +1,30 @@
   100.4 +c sample.clq
   100.5 +c
   100.6 +c This is an example of the Maximum Weight Clique
   100.7 +c Problem in DIMACS clique/coloring format.
   100.8 +c
   100.9 +p edge 8 16
  100.10 +n 1 3
  100.11 +n 2 4
  100.12 +n 3 8
  100.13 +n 5 5
  100.14 +n 6 2
  100.15 +n 8 3
  100.16 +e 1 4
  100.17 +e 1 5
  100.18 +e 1 6
  100.19 +e 1 8
  100.20 +e 2 3
  100.21 +e 2 6
  100.22 +e 2 7
  100.23 +e 2 8
  100.24 +e 3 4
  100.25 +e 3 6
  100.26 +e 3 7
  100.27 +e 4 5
  100.28 +e 4 8
  100.29 +e 5 7
  100.30 +e 5 8
  100.31 +e 6 7
  100.32 +c
  100.33 +c eof
   101.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   101.2 +++ b/examples/sample.col	Mon Dec 06 13:09:21 2010 +0100
   101.3 @@ -0,0 +1,30 @@
   101.4 +c sample.col
   101.5 +c
   101.6 +c This is an example of the vertex coloring problem data
   101.7 +c in DIMACS format.
   101.8 +c
   101.9 +p edge 10 21
  101.10 +c
  101.11 +e 1 2
  101.12 +e 1 6
  101.13 +e 1 7
  101.14 +e 1 10
  101.15 +e 2 3
  101.16 +e 2 7
  101.17 +e 2 8
  101.18 +e 3 4
  101.19 +e 3 8
  101.20 +e 4 5
  101.21 +e 4 8
  101.22 +e 4 9
  101.23 +e 5 6
  101.24 +e 5 9
  101.25 +e 5 10
  101.26 +e 6 10
  101.27 +e 7 8
  101.28 +e 7 10
  101.29 +e 8 9
  101.30 +e 8 10
  101.31 +e 9 10
  101.32 +c
  101.33 +c eof
   102.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   102.2 +++ b/examples/sample.max	Mon Dec 06 13:09:21 2010 +0100
   102.3 @@ -0,0 +1,26 @@
   102.4 +c sample.max
   102.5 +c
   102.6 +c This is an example of the maximum flow problem data
   102.7 +c in DIMACS format.
   102.8 +c
   102.9 +p max 9 14
  102.10 +c
  102.11 +n 1 s
  102.12 +n 9 t
  102.13 +c
  102.14 +a 1 2 14
  102.15 +a 1 4 23
  102.16 +a 2 3 10
  102.17 +a 2 4  9
  102.18 +a 3 5 12
  102.19 +a 3 8 18
  102.20 +a 4 5 26
  102.21 +a 5 2 11
  102.22 +a 5 6 25
  102.23 +a 5 7  4
  102.24 +a 6 7  7
  102.25 +a 6 8  8
  102.26 +a 7 9 15
  102.27 +a 8 9 20
  102.28 +c
  102.29 +c eof
   103.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   103.2 +++ b/examples/sample.min	Mon Dec 06 13:09:21 2010 +0100
   103.3 @@ -0,0 +1,26 @@
   103.4 +c sample.min
   103.5 +c
   103.6 +c This is an example of the minimum cost flow problem data
   103.7 +c in DIMACS format.
   103.8 +c
   103.9 +p min 9 14
  103.10 +c
  103.11 +n 1 20
  103.12 +n 9 -20
  103.13 +c
  103.14 +a 1 2 0 14 0
  103.15 +a 1 4 0 23 0
  103.16 +a 2 3 0 10 2
  103.17 +a 2 4 0  9 3
  103.18 +a 3 5 2 12 1
  103.19 +a 3 8 0 18 0
  103.20 +a 4 5 0 26 0
  103.21 +a 5 2 0 11 1
  103.22 +a 5 6 0 25 5
  103.23 +a 5 7 0  4 7
  103.24 +a 6 7 0  7 0
  103.25 +a 6 8 4  8 0
  103.26 +a 7 9 0 15 3
  103.27 +a 8 9 0 20 9
  103.28 +c
  103.29 +c eof
   104.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   104.2 +++ b/examples/sat.mod	Mon Dec 06 13:09:21 2010 +0100
   104.3 @@ -0,0 +1,201 @@
   104.4 +/* SAT, Satisfiability Problem */
   104.5 +
   104.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
   104.7 +
   104.8 +param m, integer, > 0;
   104.9 +/* number of clauses */
  104.10 +
  104.11 +param n, integer, > 0;
  104.12 +/* number of variables */
  104.13 +
  104.14 +set C{1..m};
  104.15 +/* clauses; each clause C[i], i = 1, ..., m, is disjunction of some
  104.16 +   variables or their negations; in the data section each clause is
  104.17 +   coded as a set of indices of corresponding variables, where negative
  104.18 +   indices mean negation; for example, the clause (x3 or not x7 or x11)
  104.19 +   is coded as the set { 3, -7, 11 } */
  104.20 +
  104.21 +var x{1..n}, binary;
  104.22 +/* main variables */
  104.23 +
  104.24 +/* To solve the satisfiability problem means to determine all variables
  104.25 +   x[j] such that conjunction of all clauses C[1] and ... and C[m] takes
  104.26 +   on the value true, i.e. all clauses are satisfied.
  104.27 +
  104.28 +   Let the clause C[i] be (t or t' or ... or t''), where t, t', ..., t''
  104.29 +   are either variables or their negations. The condition of satisfying
  104.30 +   C[i] can be most naturally written as:
  104.31 +
  104.32 +      t + t' + ... + t'' >= 1,                                       (1)
  104.33 +
  104.34 +   where t, t', t'' have to be replaced by either x[j] or (1 - x[j]).
  104.35 +   The formulation (1) leads to the mip problem with no objective, i.e.
  104.36 +   to a feasibility problem.
  104.37 +
  104.38 +   Another, more practical way is to write the condition for C[i] as:
  104.39 +
  104.40 +      t + t' + ... + t'' + y[i] >= 1,                                (2)
  104.41 +
  104.42 +   where y[i] is an auxiliary binary variable, and minimize the sum of
  104.43 +   y[i]. If the sum is zero, all y[i] are also zero, and therefore all
  104.44 +   clauses are satisfied. If the sum is minimal but non-zero, its value
  104.45 +   shows the number of clauses which cannot be satisfied. */
  104.46 +
  104.47 +var y{1..m}, binary, >= 0;
  104.48 +/* auxiliary variables */
  104.49 +
  104.50 +s.t. c{i in 1..m}:
  104.51 +      sum{j in C[i]} (if j > 0 then x[j] else (1 - x[-j])) + y[i] >= 1;
  104.52 +/* the condition (2) */
  104.53 +
  104.54 +minimize unsat: sum{i in 1..m} y[i];
  104.55 +/* number of unsatisfied clauses */
  104.56 +
  104.57 +data;
  104.58 +
  104.59 +/* These data correspond to the instance hole6 (pigeon hole problem for
  104.60 +   6 holes) from SATLIB, the Satisfiability Library, which is part of
  104.61 +   the collection at the Forschungsinstitut fuer anwendungsorientierte
  104.62 +   Wissensverarbeitung in Ulm Germany */
  104.63 +
  104.64 +/* The optimal solution is 1 (one clause cannot be satisfied) */
  104.65 +
  104.66 +param m := 133;
  104.67 +
  104.68 +param n := 42;
  104.69 +
  104.70 +set C[1] := -1 -7;
  104.71 +set C[2] := -1 -13;
  104.72 +set C[3] := -1 -19;
  104.73 +set C[4] := -1 -25;
  104.74 +set C[5] := -1 -31;
  104.75 +set C[6] := -1 -37;
  104.76 +set C[7] := -7 -13;
  104.77 +set C[8] := -7 -19;
  104.78 +set C[9] := -7 -25;
  104.79 +set C[10] := -7 -31;
  104.80 +set C[11] := -7 -37;
  104.81 +set C[12] := -13 -19;
  104.82 +set C[13] := -13 -25;
  104.83 +set C[14] := -13 -31;
  104.84 +set C[15] := -13 -37;
  104.85 +set C[16] := -19 -25;
  104.86 +set C[17] := -19 -31;
  104.87 +set C[18] := -19 -37;
  104.88 +set C[19] := -25 -31;
  104.89 +set C[20] := -25 -37;
  104.90 +set C[21] := -31 -37;
  104.91 +set C[22] := -2 -8;
  104.92 +set C[23] := -2 -14;
  104.93 +set C[24] := -2 -20;
  104.94 +set C[25] := -2 -26;
  104.95 +set C[26] := -2 -32;
  104.96 +set C[27] := -2 -38;
  104.97 +set C[28] := -8 -14;
  104.98 +set C[29] := -8 -20;
  104.99 +set C[30] := -8 -26;
 104.100 +set C[31] := -8 -32;
 104.101 +set C[32] := -8 -38;
 104.102 +set C[33] := -14 -20;
 104.103 +set C[34] := -14 -26;
 104.104 +set C[35] := -14 -32;
 104.105 +set C[36] := -14 -38;
 104.106 +set C[37] := -20 -26;
 104.107 +set C[38] := -20 -32;
 104.108 +set C[39] := -20 -38;
 104.109 +set C[40] := -26 -32;
 104.110 +set C[41] := -26 -38;
 104.111 +set C[42] := -32 -38;
 104.112 +set C[43] := -3 -9;
 104.113 +set C[44] := -3 -15;
 104.114 +set C[45] := -3 -21;
 104.115 +set C[46] := -3 -27;
 104.116 +set C[47] := -3 -33;
 104.117 +set C[48] := -3 -39;
 104.118 +set C[49] := -9 -15;
 104.119 +set C[50] := -9 -21;
 104.120 +set C[51] := -9 -27;
 104.121 +set C[52] := -9 -33;
 104.122 +set C[53] := -9 -39;
 104.123 +set C[54] := -15 -21;
 104.124 +set C[55] := -15 -27;
 104.125 +set C[56] := -15 -33;
 104.126 +set C[57] := -15 -39;
 104.127 +set C[58] := -21 -27;
 104.128 +set C[59] := -21 -33;
 104.129 +set C[60] := -21 -39;
 104.130 +set C[61] := -27 -33;
 104.131 +set C[62] := -27 -39;
 104.132 +set C[63] := -33 -39;
 104.133 +set C[64] := -4 -10;
 104.134 +set C[65] := -4 -16;
 104.135 +set C[66] := -4 -22;
 104.136 +set C[67] := -4 -28;
 104.137 +set C[68] := -4 -34;
 104.138 +set C[69] := -4 -40;
 104.139 +set C[70] := -10 -16;
 104.140 +set C[71] := -10 -22;
 104.141 +set C[72] := -10 -28;
 104.142 +set C[73] := -10 -34;
 104.143 +set C[74] := -10 -40;
 104.144 +set C[75] := -16 -22;
 104.145 +set C[76] := -16 -28;
 104.146 +set C[77] := -16 -34;
 104.147 +set C[78] := -16 -40;
 104.148 +set C[79] := -22 -28;
 104.149 +set C[80] := -22 -34;
 104.150 +set C[81] := -22 -40;
 104.151 +set C[82] := -28 -34;
 104.152 +set C[83] := -28 -40;
 104.153 +set C[84] := -34 -40;
 104.154 +set C[85] := -5 -11;
 104.155 +set C[86] := -5 -17;
 104.156 +set C[87] := -5 -23;
 104.157 +set C[88] := -5 -29;
 104.158 +set C[89] := -5 -35;
 104.159 +set C[90] := -5 -41;
 104.160 +set C[91] := -11 -17;
 104.161 +set C[92] := -11 -23;
 104.162 +set C[93] := -11 -29;
 104.163 +set C[94] := -11 -35;
 104.164 +set C[95] := -11 -41;
 104.165 +set C[96] := -17 -23;
 104.166 +set C[97] := -17 -29;
 104.167 +set C[98] := -17 -35;
 104.168 +set C[99] := -17 -41;
 104.169 +set C[100] := -23 -29;
 104.170 +set C[101] := -23 -35;
 104.171 +set C[102] := -23 -41;
 104.172 +set C[103] := -29 -35;
 104.173 +set C[104] := -29 -41;
 104.174 +set C[105] := -35 -41;
 104.175 +set C[106] := -6 -12;
 104.176 +set C[107] := -6 -18;
 104.177 +set C[108] := -6 -24;
 104.178 +set C[109] := -6 -30;
 104.179 +set C[110] := -6 -36;
 104.180 +set C[111] := -6 -42;
 104.181 +set C[112] := -12 -18;
 104.182 +set C[113] := -12 -24;
 104.183 +set C[114] := -12 -30;
 104.184 +set C[115] := -12 -36;
 104.185 +set C[116] := -12 -42;
 104.186 +set C[117] := -18 -24;
 104.187 +set C[118] := -18 -30;
 104.188 +set C[119] := -18 -36;
 104.189 +set C[120] := -18 -42;
 104.190 +set C[121] := -24 -30;
 104.191 +set C[122] := -24 -36;
 104.192 +set C[123] := -24 -42;
 104.193 +set C[124] := -30 -36;
 104.194 +set C[125] := -30 -42;
 104.195 +set C[126] := -36 -42;
 104.196 +set C[127] := 6 5 4 3 2 1;
 104.197 +set C[128] := 12 11 10 9 8 7;
 104.198 +set C[129] := 18 17 16 15 14 13;
 104.199 +set C[130] := 24 23 22 21 20 19;
 104.200 +set C[131] := 30 29 28 27 26 25;
 104.201 +set C[132] := 36 35 34 33 32 31;
 104.202 +set C[133] := 42 41 40 39 38 37;
 104.203 +
 104.204 +end;
   105.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   105.2 +++ b/examples/shiftcover.mod	Mon Dec 06 13:09:21 2010 +0100
   105.3 @@ -0,0 +1,244 @@
   105.4 +/* File: shiftcover.mod */
   105.5 +
   105.6 +/* WORKFORCE SHIFT COVERAGE assignment problem */
   105.7 +
   105.8 +/* Written by Larry D'Agostino <larrydag -at- sbcglobal -dot- com>
   105.9 +     
  105.10 +     Maximize Productivity with Industrial Engineer and Operations Research Tools
  105.11 +     http://industrialengineertools.blogspot.com
  105.12 +
  105.13 +
  105.14 +/* The WORKFORCE SHIFT COVERAGE is an assigment problem that determines
  105.15 +   the schedule of crew given available time and shifts.  
  105.16 +   
  105.17 +   The objective is to cover the available time given hourly demand with the minimum 
  105.18 +    number of crew members.
  105.19 +   
  105.20 +    This is a set covering problem that is very common among finding crew
  105.21 +     and shift allocations.  Notice in the data section the workforce shift allocation
  105.22 +     per day of the week.*/
  105.23 +
  105.24 +
  105.25 +/* ----- Model PARAMTERS and SETS -----*/
  105.26 +
  105.27 +param numhrs;
  105.28 +/* number of hours of operations in a given day */
  105.29 +
  105.30 +param dys;
  105.31 +/* number of days in a week */
  105.32 +
  105.33 +set S;
  105.34 +/* set of crew shifts */
  105.35 +
  105.36 +set H := 1..numhrs;
  105.37 +/* set of hours of a day*/
  105.38 +
  105.39 +set D;
  105.40 +/* set of days of a week*/
  105.41 +
  105.42 +param dmnd{h in H, d in D};
  105.43 +/* demand for crew members given h hour and d day */
  105.44 +
  105.45 +param shifts{d in D, h in H, s in S};
  105.46 +/* shifts to assign to crew members given d day, h hour, and s shift schedule
  105.47 +
  105.48 +/*----- Model VARIABLES -----*/
  105.49 +
  105.50 +var crew{s in S}, integer, >=0;
  105.51 +/*  number of crew assigned to shift S */
  105.52 +
  105.53 +
  105.54 +/*----- Model CONSTRAINTS -----*/
  105.55 +
  105.56 +s.t. Coverage{h in H, d in D}: sum{s in S} crew[s]*shifts[d,h,s] >= dmnd[h,d];
  105.57 +/* number of crew to cover with a shift  given hourly demand and day */
  105.58 +
  105.59 +
  105.60 +/*----- Model OBJECTIVE -----*/
  105.61 +
  105.62 +minimize obj: sum{s in S} crew[s];
  105.63 +/* minimize number of crew to cover demand*/
  105.64 +
  105.65 +solve;
  105.66 +display crew;
  105.67 +
  105.68 +printf "\n";
  105.69 +printf "Total Crew: %3d\n\n", sum{s in S} crew[s];
  105.70 +
  105.71 +
  105.72 +
  105.73 +printf "\n\n";
  105.74 +printf "Weekly Crew Schedule\n\n";
  105.75 +printf "Hour ";
  105.76 +printf{d in D} "  %s  ", d;
  105.77 +printf "\n";
  105.78 +for {h in H} {
  105.79 +  printf " %2s  ",h;
  105.80 +  printf{d in D} " %3d   ", sum{s in S} crew[s]*shifts[d,h,s];
  105.81 +  printf "\n";
  105.82 +}
  105.83 +printf"\n";
  105.84 +
  105.85 +
  105.86 +
  105.87 +data;
  105.88 +
  105.89 +param numhrs := 16;
  105.90 +
  105.91 +set D := SUN, MON, TUE, WED, THU, FRI, SAT;
  105.92 +
  105.93 +set S := Sh1, Sh2, Sh3, Sh4, Sh5, Sh6, Sh7, Sh8, Sh9;
  105.94 +
  105.95 +param dmnd :   SUN  MON     TUE     WED     THU     FRI     SAT :=
  105.96 +1               0   3       3       4       3       2       0
  105.97 +2               0   14      14      16      14      12      12
  105.98 +3               0   24      24      27      24      20      15
  105.99 +4               0   28      28      32      28      23      15
 105.100 +5               0   33      33      37      33      24      16
 105.101 +6               0   34      34      38      34      24      15
 105.102 +7               0   35      35      39      35      25      11
 105.103 +8               0   35      35      40      35      27      0
 105.104 +9               0   34      34      39      34      25      0
 105.105 +10              0   31      31      35      31      24      0
 105.106 +11              2   24      24      27      24      25      0
 105.107 +12              3   19      19      21      19      21      0
 105.108 +13              2   24      24      27      24      13      0
 105.109 +14              2   16      16      18      16      0       0
 105.110 +15              0   7       7       7       7       0       0
 105.111 +16              0   5       5       5       5       0       0;
 105.112 +
 105.113 +
 105.114 +param shifts := 
 105.115 +['SUN',*,*]:
 105.116 +                   Sh1  Sh2  Sh3  Sh4  Sh5  Sh6  Sh7  Sh8  Sh9 :=
 105.117 +1                   0    0    0    0    0    0    0    0    0
 105.118 +2                   0    0    0    0    0    0    0    0    0
 105.119 +3                   0    0    0    0    0    0    0    0    0
 105.120 +4                   0    0    0    0    0    0    0    0    0
 105.121 +5                   0    0    0    0    0    0    0    0    0
 105.122 +6                   0    0    0    0    0    0    0    0    0
 105.123 +7                   0    0    0    0    0    0    0    0    0
 105.124 +8                   0    0    0    0    0    0    0    0    0
 105.125 +9                   0    0    0    0    0    0    0    0    0
 105.126 +10                  0    0    0    0    0    0    0    0    0
 105.127 +11                  0    0    0    0    0    0    0    0    1
 105.128 +12                  0    0    0    0    0    0    0    0    1
 105.129 +13                  0    0    0    0    0    0    0    0    1
 105.130 +14                  0    0    0    0    0    0    0    0    1
 105.131 +15                  0    0    0    0    0    0    0    0    0
 105.132 +16                  0    0    0    0    0    0    0    0    0
 105.133 +
 105.134 +
 105.135 +['MON',*,*]:
 105.136 +                   Sh1  Sh2  Sh3  Sh4  Sh5  Sh6  Sh7  Sh8  Sh9 :=
 105.137 +1                   1    0    0    0    0    0    0    0    0
 105.138 +2                   1    1    0    0    0    0    0    0    0
 105.139 +3                   1    1    1    0    0    0    0    0    0
 105.140 +4                   1    1    1    1    0    0    0    0    0
 105.141 +5                   0    1    1    1    1    0    0    0    0
 105.142 +6                   1    0    1    1    1    1    0    0    1
 105.143 +7                   1    1    0    1    1    1    1    0    1
 105.144 +8                   1    1    1    0    1    1    1    1    1
 105.145 +9                   1    1    1    1    0    1    1    1    1
 105.146 +10                  0    1    1    1    1    0    1    1    1
 105.147 +11                  0    0    1    1    1    1    0    1    0
 105.148 +12                  0    0    0    1    1    1    1    0    1
 105.149 +13                  0    0    0    0    1    1    1    1    1
 105.150 +14                  0    0    0    0    0    1    1    1    1
 105.151 +15                  0    0    0    0    0    0    1    1    1
 105.152 +16                  0    0    0    0    0    0    0    1    1
 105.153 +
 105.154 +['TUE',*,*]:
 105.155 +                   Sh1  Sh2  Sh3  Sh4  Sh5  Sh6  Sh7  Sh8  Sh9 :=
 105.156 +1                   1    0    0    0    0    0    0    0    0
 105.157 +2                   1    1    0    0    0    0    0    0    0
 105.158 +3                   1    1    1    0    0    0    0    0    0
 105.159 +4                   1    1    1    1    0    0    0    0    0
 105.160 +5                   0    1    1    1    1    0    0    0    0
 105.161 +6                   1    0    1    1    1    1    0    0    1
 105.162 +7                   1    1    0    1    1    1    1    0    1
 105.163 +8                   1    1    1    0    1    1    1    1    1
 105.164 +9                   1    1    1    1    0    1    1    1    1
 105.165 +10                  0    1    1    1    1    0    1    1    1
 105.166 +11                  0    0    1    1    1    1    0    1    0
 105.167 +12                  0    0    0    1    1    1    1    0    1
 105.168 +13                  0    0    0    0    1    1    1    1    1
 105.169 +14                  0    0    0    0    0    1    1    1    1
 105.170 +15                  0    0    0    0    0    0    1    1    1
 105.171 +16                  0    0    0    0    0    0    0    1    1
 105.172 +
 105.173 +['WED',*,*]:
 105.174 +                   Sh1  Sh2  Sh3  Sh4  Sh5  Sh6  Sh7  Sh8  Sh9 :=
 105.175 +1                   1    0    0    0    0    0    0    0    0
 105.176 +2                   1    1    0    0    0    0    0    0    0
 105.177 +3                   1    1    1    0    0    0    0    0    0
 105.178 +4                   1    1    1    1    0    0    0    0    0
 105.179 +5                   0    1    1    1    1    0    0    0    0
 105.180 +6                   1    0    1    1    1    1    0    0    1
 105.181 +7                   1    1    0    1    1    1    1    0    1
 105.182 +8                   1    1    1    0    1    1    1    1    1
 105.183 +9                   1    1    1    1    0    1    1    1    1
 105.184 +10                  0    1    1    1    1    0    1    1    1
 105.185 +11                  0    0    1    1    1    1    0    1    0
 105.186 +12                  0    0    0    1    1    1    1    0    1
 105.187 +13                  0    0    0    0    1    1    1    1    1
 105.188 +14                  0    0    0    0    0    1    1    1    1
 105.189 +15                  0    0    0    0    0    0    1    1    1
 105.190 +16                  0    0    0    0    0    0    0    1    1
 105.191 +
 105.192 +['THU',*,*]:
 105.193 +                   Sh1  Sh2  Sh3  Sh4  Sh5  Sh6  Sh7  Sh8  Sh9 :=
 105.194 +1                   1    0    0    0    0    0    0    0    0
 105.195 +2                   1    1    0    0    0    0    0    0    0
 105.196 +3                   1    1    1    0    0    0    0    0    0
 105.197 +4                   1    1    1    1    0    0    0    0    0
 105.198 +5                   0    1    1    1    1    0    0    0    0
 105.199 +6                   1    0    1    1    1    1    0    0    0
 105.200 +7                   1    1    0    1    1    1    1    0    0
 105.201 +8                   1    1    1    0    1    1    1    1    0
 105.202 +9                   1    1    1    1    0    1    1    1    0
 105.203 +10                  0    1    1    1    1    0    1    1    0
 105.204 +11                  0    0    1    1    1    1    0    1    0
 105.205 +12                  0    0    0    1    1    1    1    0    0
 105.206 +13                  0    0    0    0    1    1    1    1    0
 105.207 +14                  0    0    0    0    0    1    1    1    0
 105.208 +15                  0    0    0    0    0    0    1    1    0
 105.209 +16                  0    0    0    0    0    0    0    1    0
 105.210 +
 105.211 +['FRI',*,*]:
 105.212 +                   Sh1  Sh2  Sh3  Sh4  Sh5  Sh6  Sh7  Sh8  Sh9 :=
 105.213 +1                   1    0    0    0    0    0    0    0    0
 105.214 +2                   1    1    0    0    0    0    0    0    0
 105.215 +3                   1    1    1    0    0    0    0    0    0
 105.216 +4                   1    1    1    1    0    0    0    0    0
 105.217 +5                   0    1    1    1    1    0    0    0    0
 105.218 +6                   1    0    1    1    1    1    0    0    0
 105.219 +7                   1    1    0    1    1    1    1    0    0
 105.220 +8                   1    1    1    0    1    1    1    1    0
 105.221 +9                   1    1    1    1    0    1    1    1    0
 105.222 +10                  0    1    1    1    1    0    1    1    0
 105.223 +11                  0    0    1    1    1    1    0    1    0
 105.224 +12                  0    0    0    1    1    1    1    0    0
 105.225 +13                  0    0    0    0    1    1    1    1    0
 105.226 +14                  0    0    0    0    0    1    1    1    0
 105.227 +15                  0    0    0    0    0    0    1    1    0
 105.228 +16                  0    0    0    0    0    0    0    1    0
 105.229 +
 105.230 +['SAT',*,*]:
 105.231 +                   Sh1  Sh2  Sh3  Sh4  Sh5  Sh6  Sh7  Sh8  Sh9 :=
 105.232 +1                   0    0    0    0    0    0    0    0    0
 105.233 +2                   0    0    0    0    0    0    0    0    1
 105.234 +3                   0    0    0    0    0    0    0    0    1
 105.235 +4                   0    0    0    0    0    0    0    0    1
 105.236 +5                   0    0    0    0    0    0    0    0    1
 105.237 +6                   0    0    0    0    0    0    0    0    1
 105.238 +7                   0    0    0    0    0    0    0    0    1
 105.239 +8                   0    0    0    0    0    0    0    0    0
 105.240 +9                   0    0    0    0    0    0    0    0    0
 105.241 +10                  0    0    0    0    0    0    0    0    0
 105.242 +11                  0    0    0    0    0    0    0    0    0
 105.243 +12                  0    0    0    0    0    0    0    0    0
 105.244 +13                  0    0    0    0    0    0    0    0    0
 105.245 +14                  0    0    0    0    0    0    0    0    0
 105.246 +15                  0    0    0    0    0    0    0    0    0
 105.247 +16                  0    0    0    0    0    0    0    0    0;
   106.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   106.2 +++ b/examples/shikaku.mod	Mon Dec 06 13:09:21 2010 +0100
   106.3 @@ -0,0 +1,107 @@
   106.4 +/* A solver for the Japanese number-puzzle Shikaku
   106.5 + * http://en.wikipedia.org/wiki/Shikaku
   106.6 + *
   106.7 + * Sebastian Nowozin <nowozin@gmail.com>, 27th January 2009
   106.8 + */
   106.9 +
  106.10 +param ndim := 10;
  106.11 +set rows := 1..ndim;
  106.12 +set rows1 := 1..(ndim+1);
  106.13 +set cols := 1..ndim;
  106.14 +set cols1 := 1..(ndim+1);
  106.15 +param givens{rows, cols}, integer, >= 0, default 0;
  106.16 +
  106.17 +/* Set of vertices as (row,col) coordinates */
  106.18 +set V := { (i,j) in { rows, cols }: givens[i,j] != 0 };
  106.19 +
  106.20 +/* Set of all feasible boxes of the right size: only this boxes are possible.
  106.21 + * The box contains (i,j) and ranges from (k,l) to (m,n)
  106.22 + */
  106.23 +set B := { (i,j,k,l,m,n) in { V, rows, cols, rows1, cols1 }:
  106.24 +    i >= k and i < m and j >= l and j < n and   /* Contains (i,j) */
  106.25 +    ((m-k)*(n-l)) = givens[i,j] and /* Right size */
  106.26 +    card({ (s,t) in V: s >= k and s < m and t >= l and t < n }) = 1
  106.27 +        /* Contains only (i,j), no other number */
  106.28 +};
  106.29 +
  106.30 +var x{B}, binary;
  106.31 +
  106.32 +/* Cover each square exactly once */
  106.33 +s.t. cover_once{ (s,t) in { rows, cols } }:
  106.34 +    sum{(i,j,k,l,m,n) in B: s >= k and s < m and t >= l and t < n}
  106.35 +        x[i,j,k,l,m,n] = 1;
  106.36 +
  106.37 +minimize cost: 0;
  106.38 +
  106.39 +solve;
  106.40 +
  106.41 +/* Output solution graphically */
  106.42 +printf "\nSolution:\n";
  106.43 +for { row in rows1 } {
  106.44 +    for { col in cols1 } {
  106.45 +        printf{0..0: card({(i,j,k,l,m,n) in B:
  106.46 +                col >= l and col <= n and (row = k or row = m) and
  106.47 +                x[i,j,k,l,m,n] = 1}) > 0 and
  106.48 +            card({(i,j,k,l,m,n) in B:
  106.49 +                row >= k and row <= m and (col = l or col = n) and
  106.50 +                x[i,j,k,l,m,n] = 1}) > 0} "+";
  106.51 +        printf{0..0: card({(i,j,k,l,m,n) in B:
  106.52 +                col >= l and col <= n and (row = k or row = m) and
  106.53 +                x[i,j,k,l,m,n] = 1}) = 0 and
  106.54 +            card({(i,j,k,l,m,n) in B:
  106.55 +                row >= k and row <= m and (col = l or col = n) and
  106.56 +                x[i,j,k,l,m,n] = 1}) > 0} "|";
  106.57 +        printf{0..0: card({(i,j,k,l,m,n) in B:
  106.58 +                row >= k and row <= m and (col = l or col = n) and
  106.59 +                x[i,j,k,l,m,n] = 1}) = 0 and
  106.60 +            card({(i,j,k,l,m,n) in B:
  106.61 +                col >= l and col <= n and (row = k or row = m) and
  106.62 +                x[i,j,k,l,m,n] = 1}) > 0} "-";
  106.63 +        printf{0..0: card({(i,j,k,l,m,n) in B:
  106.64 +                row >= k and row <= m and (col = l or col = n) and
  106.65 +                x[i,j,k,l,m,n] = 1}) = 0 and
  106.66 +            card({(i,j,k,l,m,n) in B:
  106.67 +                col >= l and col <= n and (row = k or row = m) and
  106.68 +                x[i,j,k,l,m,n] = 1}) = 0} " ";
  106.69 +
  106.70 +        printf{0..0: card({(i,j,k,l,m,n) in B:
  106.71 +            col >= l and col < n and (row = k or row = m) and
  106.72 +            x[i,j,k,l,m,n] = 1}) > 0} "---";
  106.73 +        printf{0..0: card({(i,j,k,l,m,n) in B:
  106.74 +            col >= l and col < n and (row = k or row = m) and
  106.75 +            x[i,j,k,l,m,n] = 1}) = 0} "   ";
  106.76 +    }
  106.77 +    printf "\n";
  106.78 +
  106.79 +    for { (col,p) in { cols, 1 }: card({ s in rows: s = row }) = 1 } {
  106.80 +        printf{0..0: card({(i,j,k,l,m,n) in B:
  106.81 +            row >= k and row < m and (col = l or col = n) and
  106.82 +            x[i,j,k,l,m,n] = 1}) > 0} "|";
  106.83 +        printf{0..0: card({(i,j,k,l,m,n) in B:
  106.84 +            row >= k and row < m and (col = l or col = n) and
  106.85 +            x[i,j,k,l,m,n] = 1}) = 0} " ";
  106.86 +        printf{0..0: card({ (i,j) in V: i = row and j = col}) > 0} " %2d", givens[row,col];
  106.87 +        printf{0..0: card({ (i,j) in V: i = row and j = col}) = 0} "  .";
  106.88 +    }
  106.89 +    printf{0..0: card({ r in rows: r = row }) = 1} "|\n";
  106.90 +}
  106.91 +
  106.92 +data;
  106.93 +
  106.94 +/* This Shikaku is from
  106.95 + * http://www.emn.fr/x-info/sdemasse/gccat/KShikaku.html#uid5449
  106.96 + */
  106.97 +param givens : 1 2 3 4 5 6 7 8 9 10 :=
  106.98 +           1   9 . . . 12 . . 5 . .
  106.99 +           2   . . . . . . . . . .
 106.100 +           3   . . . . . . . . . 6
 106.101 +           4   8 . 6 . 8 . . . . .
 106.102 +           5   . . . . . . . . . .
 106.103 +           6   . . . . . . . . . .
 106.104 +           7   . . . . . 6 . 8 . 12
 106.105 +           8   4 . . . . . . . . .
 106.106 +           9   . . . . . . . . . .
 106.107 +          10   . . 3 . . 9 . . . 4
 106.108 +           ;
 106.109 +
 106.110 +end;
   107.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   107.2 +++ b/examples/sorting.mod	Mon Dec 06 13:09:21 2010 +0100
   107.3 @@ -0,0 +1,67 @@
   107.4 +/* sorting.mod - how to sort arrays in MathProg */
   107.5 +
   107.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
   107.7 +
   107.8 +#  Sometimes it is necessary to print parameters or variables in the
   107.9 +#  order of ascending or descending their values. Suppose, for example,
  107.10 +#  that we have the following subscripted parameter:
  107.11 +
  107.12 +set I := 1..12;
  107.13 +
  107.14 +param a{i in I} := Uniform(2, 7);
  107.15 +
  107.16 +#  If we print all its members:
  107.17 +
  107.18 +printf{i in I} "a[%d] = %g\n", i, a[i];
  107.19 +
  107.20 +#  the output may look like follows:
  107.21 +#
  107.22 +#  a[1]  = 2.64156
  107.23 +#  a[2]  = 2.04798
  107.24 +#  a[3]  = 2.14843
  107.25 +#  a[4]  = 4.76896
  107.26 +#  a[5]  = 6.09132
  107.27 +#  a[6]  = 3.27780
  107.28 +#  a[7]  = 4.06113
  107.29 +#  a[8]  = 4.05898
  107.30 +#  a[9]  = 6.63120
  107.31 +#  a[10] = 6.50318
  107.32 +#  a[11] = 3.46065
  107.33 +#  a[12] = 4.69845
  107.34 +#
  107.35 +#  However, we would like the parameter members to appear in the order
  107.36 +#  of ascending their values.
  107.37 +#
  107.38 +#  Introduce the following auxiliary parameter:
  107.39 +
  107.40 +param pos{i in I} :=
  107.41 +      1 + card({j in I: a[j] < a[i] or a[j] = a[i] and j < i});
  107.42 +
  107.43 +#  where pos[i] = k means that in the sorted list member a[i] would
  107.44 +#  have k-th position, 1 <= k <= |I|. Then introduce another auxiliary
  107.45 +#  parameter:
  107.46 +
  107.47 +param ind{k in 1..card(I)} := sum{i in I: pos[i] = k} i;
  107.48 +
  107.49 +#  where ind[k] = i iff pos[k] = i.
  107.50 +#
  107.51 +#  Now, the following statement:
  107.52 +
  107.53 +printf{k in 1..card(I)} "a[%d] = %g\n", ind[k], a[ind[k]];
  107.54 +
  107.55 +#  prints the parameter members in the desired order:
  107.56 +#
  107.57 +#  a[2]  = 2.04798
  107.58 +#  a[3]  = 2.14843
  107.59 +#  a[1]  = 2.64156
  107.60 +#  a[6]  = 3.27780
  107.61 +#  a[11] = 3.46065
  107.62 +#  a[8]  = 4.05898
  107.63 +#  a[7]  = 4.06113
  107.64 +#  a[12] = 4.69845
  107.65 +#  a[4]  = 4.76896
  107.66 +#  a[5]  = 6.09132
  107.67 +#  a[10] = 6.50318
  107.68 +#  a[9]  = 6.63120
  107.69 +
  107.70 +end;
   108.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   108.2 +++ b/examples/spp.mod	Mon Dec 06 13:09:21 2010 +0100
   108.3 @@ -0,0 +1,67 @@
   108.4 +/* SPP, Shortest Path Problem */
   108.5 +
   108.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
   108.7 +
   108.8 +/* Given a directed graph G = (V,E), its edge lengths c(i,j) for all
   108.9 +   (i,j) in E, and two nodes s, t in V, the Shortest Path Problem (SPP)
  108.10 +   is to find a directed path from s to t whose length is minimal. */
  108.11 +
  108.12 +param n, integer, > 0;
  108.13 +/* number of nodes */
  108.14 +
  108.15 +set E, within {i in 1..n, j in 1..n};
  108.16 +/* set of edges */
  108.17 +
  108.18 +param c{(i,j) in E};
  108.19 +/* c[i,j] is length of edge (i,j); note that edge lengths are allowed
  108.20 +   to be of any sign (positive, negative, or zero) */
  108.21 +
  108.22 +param s, in {1..n};
  108.23 +/* source node */
  108.24 +
  108.25 +param t, in {1..n};
  108.26 +/* target node */
  108.27 +
  108.28 +var x{(i,j) in E}, >= 0;
  108.29 +/* x[i,j] = 1 means that edge (i,j) belong to shortest path;
  108.30 +   x[i,j] = 0 means that edge (i,j) does not belong to shortest path;
  108.31 +   note that variables x[i,j] are binary, however, there is no need to
  108.32 +   declare them so due to the totally unimodular constraint matrix */
  108.33 +
  108.34 +s.t. r{i in 1..n}: sum{(j,i) in E} x[j,i] + (if i = s then 1) =
  108.35 +                   sum{(i,j) in E} x[i,j] + (if i = t then 1);
  108.36 +/* conservation conditions for unity flow from s to t; every feasible
  108.37 +   solution is a path from s to t */
  108.38 +
  108.39 +minimize Z: sum{(i,j) in E} c[i,j] * x[i,j];
  108.40 +/* objective function is the path length to be minimized */
  108.41 +
  108.42 +data;
  108.43 +
  108.44 +/* Optimal solution is 20 that corresponds to the following shortest
  108.45 +   path: s = 1 -> 2 -> 4 -> 8 -> 6 = t */
  108.46 +
  108.47 +param n := 8;
  108.48 +
  108.49 +param s := 1;
  108.50 +
  108.51 +param t := 6;
  108.52 +
  108.53 +param : E :   c :=
  108.54 +       1 2    1
  108.55 +       1 4    8
  108.56 +       1 7    6
  108.57 +       2 4    2
  108.58 +       3 2   14
  108.59 +       3 4   10
  108.60 +       3 5    6
  108.61 +       3 6   19
  108.62 +       4 5    8
  108.63 +       4 8   13
  108.64 +       5 8   12
  108.65 +       6 5    7
  108.66 +       7 4    5
  108.67 +       8 6    4
  108.68 +       8 7   10;
  108.69 +
  108.70 +end;
   109.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   109.2 +++ b/examples/spxsamp1.c	Mon Dec 06 13:09:21 2010 +0100
   109.3 @@ -0,0 +1,18 @@
   109.4 +/* spxsamp1.c */
   109.5 +
   109.6 +#include <stdio.h>
   109.7 +#include <stdlib.h>
   109.8 +#include <glpk.h>
   109.9 +
  109.10 +int main(void)
  109.11 +{     glp_prob *P;
  109.12 +      P = glp_create_prob();
  109.13 +      glp_read_mps(P, GLP_MPS_DECK, NULL, "25fv47.mps");
  109.14 +      glp_adv_basis(P, 0);
  109.15 +      glp_simplex(P, NULL);
  109.16 +      glp_print_sol(P, "25fv47.txt");
  109.17 +      glp_delete_prob(P);
  109.18 +      return 0;
  109.19 +}
  109.20 +
  109.21 +/* eof */
   110.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   110.2 +++ b/examples/spxsamp2.c	Mon Dec 06 13:09:21 2010 +0100
   110.3 @@ -0,0 +1,20 @@
   110.4 +/* spxsamp2.c */
   110.5 +
   110.6 +#include <stdio.h>
   110.7 +#include <stdlib.h>
   110.8 +#include <glpk.h>
   110.9 +
  110.10 +int main(void)
  110.11 +{     glp_prob *P;
  110.12 +      glp_smcp parm;
  110.13 +      P = glp_create_prob();
  110.14 +      glp_read_mps(P, GLP_MPS_DECK, NULL, "25fv47.mps");
  110.15 +      glp_init_smcp(&parm);
  110.16 +      parm.meth = GLP_DUAL;
  110.17 +      glp_simplex(P, &parm);
  110.18 +      glp_print_sol(P, "25fv47.txt");
  110.19 +      glp_delete_prob(P);
  110.20 +      return 0;
  110.21 +}
  110.22 +
  110.23 +/* eof */
   111.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   111.2 +++ b/examples/sql/README	Mon Dec 06 13:09:21 2010 +0100
   111.3 @@ -0,0 +1,5 @@
   111.4 +This subdirectory contains files which demonstrate using data tables
   111.5 +in MathProg models for MySQL and iODBC.
   111.6 +
   111.7 +Script mysql_setup.sh is used to load the data from the *.sql files to
   111.8 +a MySQL database. Change the username, if necessary.
   112.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   112.2 +++ b/examples/sql/mysql_setup.sh	Mon Dec 06 13:09:21 2010 +0100
   112.3 @@ -0,0 +1,6 @@
   112.4 +#!/bin/sh
   112.5 +# This file can be used to create database glpk in MySQL.
   112.6 +echo MySQL is called for user root. 
   112.7 +mysql -f -u root -p < sudoku.sql
   112.8 +echo MySQL is called for user root.
   112.9 +mysql -f -u root -p < transp.sql
   113.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   113.2 +++ b/examples/sql/sudoku.sql	Mon Dec 06 13:09:21 2010 +0100
   113.3 @@ -0,0 +1,101 @@
   113.4 +CREATE DATABASE glpk;
   113.5 +CREATE USER glpk@localhost IDENTIFIED BY 'gnu';
   113.6 +GRANT ALL PRIVILEGES ON glpk.* TO glpk@localhost;
   113.7 +USE glpk;
   113.8 +DROP TABLE sudoku;
   113.9 +CREATE TABLE sudoku (
  113.10 +  ID   INT ,
  113.11 +  COL  INT ,
  113.12 +  LIN  INT ,
  113.13 +  VAL  INT ,
  113.14 +  PRIMARY KEY ( ID, COL, LIN )
  113.15 +  );
  113.16 +DROP TABLE sudoku_solution;
  113.17 +CREATE TABLE sudoku_solution (
  113.18 +  ID   INT ,
  113.19 +  COL  INT ,
  113.20 +  LIN  INT ,
  113.21 +  VAL  INT ,
  113.22 +  PRIMARY KEY ( ID, COL, LIN )
  113.23 +  );
  113.24 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 1, 5);
  113.25 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 2, 0);
  113.26 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 3, 0);
  113.27 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 4, 0);
  113.28 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 5, 4);
  113.29 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 6, 0);
  113.30 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 7, 0);
  113.31 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 8, 0);
  113.32 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 9, 0);
  113.33 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 1, 0);
  113.34 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 2, 0);
  113.35 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 3, 3);
  113.36 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 4, 0);
  113.37 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 5, 0);
  113.38 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 6, 0);
  113.39 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 7, 6);
  113.40 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 8, 2);
  113.41 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 9, 0);
  113.42 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 1, 0);
  113.43 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 2, 0);
  113.44 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 3, 0);
  113.45 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 4, 0);
  113.46 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 5, 0);
  113.47 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 6, 9);
  113.48 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 7, 0);
  113.49 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 8, 0);
  113.50 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 9, 4);
  113.51 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 1, 0);
  113.52 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 2, 0);
  113.53 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 3, 6);
  113.54 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 4, 0);
  113.55 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 5, 0);
  113.56 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 6, 7);
  113.57 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 7, 2);
  113.58 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 8, 0);
  113.59 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 9, 0);
  113.60 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 1, 8);
  113.61 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 2, 1);
  113.62 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 3, 0);
  113.63 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 4, 0);
  113.64 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 5, 0);
  113.65 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 6, 0);
  113.66 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 7, 0);
  113.67 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 8, 4);
  113.68 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 9, 3);
  113.69 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 1, 0);
  113.70 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 2, 0);
  113.71 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 3, 9);
  113.72 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 4, 1);
  113.73 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 5, 0);
  113.74 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 6, 0);
  113.75 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 7, 0);
  113.76 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 8, 0);
  113.77 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 9, 0);
  113.78 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 1, 7);
  113.79 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 2, 0);
  113.80 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 3, 0);
  113.81 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 4, 5);
  113.82 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 5, 0);
  113.83 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 6, 0);
  113.84 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 7, 0);
  113.85 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 8, 0);
  113.86 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 9, 0);
  113.87 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 1, 0);
  113.88 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 2, 9);
  113.89 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 3, 2);
  113.90 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 4, 0);
  113.91 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 5, 0);
  113.92 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 6, 0);
  113.93 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 7, 8);
  113.94 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 8, 0);
  113.95 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 9, 0);
  113.96 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 1, 0);
  113.97 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 2, 0);
  113.98 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 3, 0);
  113.99 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 4, 0);
 113.100 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 5, 3);
 113.101 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 6, 0);
 113.102 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 7, 0);
 113.103 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 8, 0);
 113.104 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 9, 6);
   114.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   114.2 +++ b/examples/sql/sudoku_mysql.mod	Mon Dec 06 13:09:21 2010 +0100
   114.3 @@ -0,0 +1,113 @@
   114.4 +/* SUDOKU, Number Placement Puzzle */
   114.5 +
   114.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@mai2.rcnet.ru> */
   114.7 +
   114.8 +/* This example shows how to use the table statement.
   114.9 +   The sudoku to be solves is read from file sudoku_in.csv.
  114.10 +   The solution is written to sudoku_out.csv.
  114.11 +   The file format is CSV as defined in
  114.12 +     RFC 4180 - Common Format and MIME Type for
  114.13 +     Comma-Separated Values (CSV) Files */
  114.14 +
  114.15 +/* Sudoku, also known as Number Place, is a logic-based placement
  114.16 +   puzzle. The aim of the canonical puzzle is to enter a numerical
  114.17 +   digit from 1 through 9 in each cell of a 9x9 grid made up of 3x3
  114.18 +   subgrids (called "regions"), starting with various digits given in
  114.19 +   some cells (the "givens"). Each row, column, and region must contain
  114.20 +   only one instance of each numeral.
  114.21 +
  114.22 +   Example:
  114.23 +
  114.24 +   +-------+-------+-------+
  114.25 +   | 5 3 . | . 7 . | . . . |
  114.26 +   | 6 . . | 1 9 5 | . . . |
  114.27 +   | . 9 8 | . . . | . 6 . |
  114.28 +   +-------+-------+-------+
  114.29 +   | 8 . . | . 6 . | . . 3 |
  114.30 +   | 4 . . | 8 . 3 | . . 1 |
  114.31 +   | 7 . . | . 2 . | . . 6 |
  114.32 +   +-------+-------+-------+
  114.33 +   | . 6 . | . . . | 2 8 . |
  114.34 +   | . . . | 4 1 9 | . . 5 |
  114.35 +   | . . . | . 8 . | . 7 9 |
  114.36 +   +-------+-------+-------+
  114.37 +
  114.38 +   (From Wikipedia, the free encyclopedia.) */
  114.39 +set fields dimen 2;
  114.40 +
  114.41 +param id;
  114.42 +
  114.43 +param givens{1..9, 1..9}, integer, >= 0, <= 9, default 0;
  114.44 +/* the "givens" */
  114.45 +
  114.46 +/*
  114.47 +table ti IN 'MySQL' 'Database=glpk;UID=glpk;PWD=gnu'
  114.48 +  'sudoku' :
  114.49 +  fields <- [COL, LIN], givens ~ VAL;
  114.50 +*/
  114.51 +table ti IN 'MySQL' 'Database=glpk;UID=glpk;PWD=gnu'
  114.52 +  'SELECT * FROM sudoku WHERE ID = ' & id :
  114.53 +  fields <- [COL, LIN], givens ~ VAL;
  114.54 +
  114.55 +var x{i in 1..9, j in 1..9, k in 1..9}, binary;
  114.56 +/* x[i,j,k] = 1 means cell [i,j] is assigned number k */
  114.57 +
  114.58 +s.t. fa{i in 1..9, j in 1..9, k in 1..9: givens[i,j] != 0}:
  114.59 +     x[i,j,k] = (if givens[i,j] = k then 1 else 0);
  114.60 +/* assign pre-defined numbers using the "givens" */
  114.61 +
  114.62 +s.t. fb{i in 1..9, j in 1..9}: sum{k in 1..9} x[i,j,k] = 1;
  114.63 +/* each cell must be assigned exactly one number */
  114.64 +
  114.65 +s.t. fc{i in 1..9, k in 1..9}: sum{j in 1..9} x[i,j,k] = 1;
  114.66 +/* cells in the same row must be assigned distinct numbers */
  114.67 +
  114.68 +s.t. fd{j in 1..9, k in 1..9}: sum{i in 1..9} x[i,j,k] = 1;
  114.69 +/* cells in the same column must be assigned distinct numbers */
  114.70 +
  114.71 +s.t. fe{I in 1..9 by 3, J in 1..9 by 3, k in 1..9}:
  114.72 +     sum{i in I..I+2, j in J..J+2} x[i,j,k] = 1;
  114.73 +/* cells in the same region must be assigned distinct numbers */
  114.74 +
  114.75 +/* there is no need for an objective function here */
  114.76 +
  114.77 +solve;
  114.78 +
  114.79 +table ta{(i,j) in fields} OUT
  114.80 +  'MySQL' 'Database=glpk;UID=glpk;PWD=gnu'
  114.81 +  'DELETE FROM sudoku_solution'
  114.82 +  'WHERE ID = ' & id & ';'
  114.83 +  'INSERT INTO sudoku_solution'
  114.84 +  '(ID, COL, LIN, VAL)'
  114.85 +  'VALUES(?, ?, ?, ?);' :
  114.86 +  id ~ ID, i ~ COL, j ~ LIN, (sum{k in 1..9} x[i,j,k] * k) ~ VAL;
  114.87 +
  114.88 +printf "\nSudoku to be solved\n";
  114.89 +for {i in 1..9}
  114.90 +{  for {0..0: i = 1 or i = 4 or i = 7}
  114.91 +     printf " +-------+-------+-------+\n";
  114.92 +   for {j in 1..9}
  114.93 +   {  for {0..0: j = 1 or j = 4 or j = 7} printf(" |");
  114.94 +      printf " %d", givens[i,j];
  114.95 +      for {0..0: j = 9} printf(" |\n");
  114.96 +   }
  114.97 +   for {0..0: i = 9}
  114.98 +   printf " +-------+-------+-------+\n";
  114.99 +   }
 114.100 +printf "\nSolution\n";
 114.101 +for {i in 1..9}
 114.102 +{  for {0..0: i = 1 or i = 4 or i = 7}
 114.103 +      printf " +-------+-------+-------+\n";
 114.104 +   for {j in 1..9}
 114.105 +   {  for {0..0: j = 1 or j = 4 or j = 7} printf(" |");
 114.106 +      printf " %d", sum{k in 1..9} x[i,j,k] * k;
 114.107 +      for {0..0: j = 9} printf(" |\n");
 114.108 +   }
 114.109 +   for {0..0: i = 9}
 114.110 +      printf " +-------+-------+-------+\n";
 114.111 +}
 114.112 +
 114.113 +data;
 114.114 +
 114.115 +param id := 1;
 114.116 +end;
   115.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   115.2 +++ b/examples/sql/sudoku_odbc.mod	Mon Dec 06 13:09:21 2010 +0100
   115.3 @@ -0,0 +1,111 @@
   115.4 +/* SUDOKU, Number Placement Puzzle */
   115.5 +
   115.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@mai2.rcnet.ru> */
   115.7 +
   115.8 +/* This example shows how to use the table statement.
   115.9 +   The sudoku to be solves is read from file sudoku_in.csv.
  115.10 +   The solution is written to sudoku_out.csv.
  115.11 +   The file format is CSV as defined in
  115.12 +     RFC 4180 - Common Format and MIME Type for
  115.13 +     Comma-Separated Values (CSV) Files */
  115.14 +
  115.15 +/* Sudoku, also known as Number Place, is a logic-based placement
  115.16 +   puzzle. The aim of the canonical puzzle is to enter a numerical
  115.17 +   digit from 1 through 9 in each cell of a 9x9 grid made up of 3x3
  115.18 +   subgrids (called "regions"), starting with various digits given in
  115.19 +   some cells (the "givens"). Each row, column, and region must contain
  115.20 +   only one instance of each numeral.
  115.21 +
  115.22 +   Example:
  115.23 +
  115.24 +   +-------+-------+-------+
  115.25 +   | 5 3 . | . 7 . | . . . |
  115.26 +   | 6 . . | 1 9 5 | . . . |
  115.27 +   | . 9 8 | . . . | . 6 . |
  115.28 +   +-------+-------+-------+
  115.29 +   | 8 . . | . 6 . | . . 3 |
  115.30 +   | 4 . . | 8 . 3 | . . 1 |
  115.31 +   | 7 . . | . 2 . | . . 6 |
  115.32 +   +-------+-------+-------+
  115.33 +   | . 6 . | . . . | 2 8 . |
  115.34 +   | . . . | 4 1 9 | . . 5 |
  115.35 +   | . . . | . 8 . | . 7 9 |
  115.36 +   +-------+-------+-------+
  115.37 +
  115.38 +   (From Wikipedia, the free encyclopedia.) */
  115.39 +set fields dimen 2;
  115.40 +
  115.41 +param id;
  115.42 +
  115.43 +param givens{1..9, 1..9}, integer, >= 0, <= 9, default 0;
  115.44 +/* the "givens" */
  115.45 +
  115.46 +table ti IN 'iODBC'
  115.47 +  'DSN=glpk;UID=glpk;PWD=gnu'
  115.48 +  'SELECT * FROM sudoku'
  115.49 +  'WHERE ID = ' & id :
  115.50 +  fields <- [COL, LIN], givens ~ VAL;
  115.51 +
  115.52 +var x{i in 1..9, j in 1..9, k in 1..9}, binary;
  115.53 +/* x[i,j,k] = 1 means cell [i,j] is assigned number k */
  115.54 +
  115.55 +s.t. fa{i in 1..9, j in 1..9, k in 1..9: givens[i,j] != 0}:
  115.56 +     x[i,j,k] = (if givens[i,j] = k then 1 else 0);
  115.57 +/* assign pre-defined numbers using the "givens" */
  115.58 +
  115.59 +s.t. fb{i in 1..9, j in 1..9}: sum{k in 1..9} x[i,j,k] = 1;
  115.60 +/* each cell must be assigned exactly one number */
  115.61 +
  115.62 +s.t. fc{i in 1..9, k in 1..9}: sum{j in 1..9} x[i,j,k] = 1;
  115.63 +/* cells in the same row must be assigned distinct numbers */
  115.64 +
  115.65 +s.t. fd{j in 1..9, k in 1..9}: sum{i in 1..9} x[i,j,k] = 1;
  115.66 +/* cells in the same column must be assigned distinct numbers */
  115.67 +
  115.68 +s.t. fe{I in 1..9 by 3, J in 1..9 by 3, k in 1..9}:
  115.69 +     sum{i in I..I+2, j in J..J+2} x[i,j,k] = 1;
  115.70 +/* cells in the same region must be assigned distinct numbers */
  115.71 +
  115.72 +/* there is no need for an objective function here */
  115.73 +
  115.74 +
  115.75 +solve;
  115.76 +
  115.77 +table ta {(i, j) in {i1 in 1..9} cross {i2 in 1..9}} OUT
  115.78 +  'iODBC' 'DSN=glpk;UID=glpk;PWD=gnu'
  115.79 +  'DELETE FROM sudoku_solution'
  115.80 +  'WHERE ID = ' & id & ';'
  115.81 +  'INSERT INTO sudoku_solution'
  115.82 +  '(ID, COL, LIN, VAL)'
  115.83 +  'VALUES(?, ?, ?, ?);' :
  115.84 +  id ~ ID, i ~ COL, j ~ LIN, (sum{k in 1..9} x[i,j,k] * k) ~ VAL;
  115.85 +
  115.86 +printf "\nSudoku to be solved\n";
  115.87 +for {i in 1..9}
  115.88 +{  for {0..0: i = 1 or i = 4 or i = 7}
  115.89 +     printf " +-------+-------+-------+\n";
  115.90 +   for {j in 1..9}
  115.91 +   {  for {0..0: j = 1 or j = 4 or j = 7} printf(" |");
  115.92 +      printf " %d", givens[i,j];
  115.93 +      for {0..0: j = 9} printf(" |\n");
  115.94 +   }
  115.95 +   for {0..0: i = 9}
  115.96 +   printf " +-------+-------+-------+\n";
  115.97 +   }
  115.98 +printf "\nSolution\n";
  115.99 +for {i in 1..9}
 115.100 +{  for {0..0: i = 1 or i = 4 or i = 7}
 115.101 +      printf " +-------+-------+-------+\n";
 115.102 +   for {j in 1..9}
 115.103 +   {  for {0..0: j = 1 or j = 4 or j = 7} printf(" |");
 115.104 +      printf " %d", sum{k in 1..9} x[i,j,k] * k;
 115.105 +      for {0..0: j = 9} printf(" |\n");
 115.106 +   }
 115.107 +   for {0..0: i = 9}
 115.108 +      printf " +-------+-------+-------+\n";
 115.109 +}
 115.110 +
 115.111 +data;
 115.112 +
 115.113 +param id := 1;
 115.114 +end;
   116.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   116.2 +++ b/examples/sql/transp.sql	Mon Dec 06 13:09:21 2010 +0100
   116.3 @@ -0,0 +1,45 @@
   116.4 +CREATE DATABASE glpk;
   116.5 +CREATE USER glpk@localhost IDENTIFIED BY 'gnu';
   116.6 +GRANT ALL PRIVILEGES ON glpk.* TO glpk@localhost;
   116.7 +USE glpk;
   116.8 +# production capacity
   116.9 +DROP TABLE transp_capa;
  116.10 +CREATE TABLE transp_capa (
  116.11 +  PLANT TEXT(127),
  116.12 +  CAPA  REAL,
  116.13 +  PRIMARY KEY ( PLANT(127) )
  116.14 +  );
  116.15 +INSERT INTO transp_capa ( PLANT, CAPA ) VALUES ( 'Seattle',   350 );
  116.16 +INSERT INTO transp_capa ( PLANT, CAPA ) VALUES ( 'San Diego', 600 );
  116.17 +# demand
  116.18 +DROP TABLE transp_demand;
  116.19 +CREATE TABLE transp_demand (
  116.20 +  MARKET TEXT(127),
  116.21 +  DEMAND REAL,
  116.22 +  PRIMARY KEY ( MARKET(127) )
  116.23 +  );
  116.24 +INSERT INTO transp_demand ( MARKET, DEMAND ) VALUES ( 'New York', 325 );
  116.25 +INSERT INTO transp_demand ( MARKET, DEMAND ) VALUES ( 'Chicago', 300 );
  116.26 +INSERT INTO transp_demand ( MARKET, DEMAND ) VALUES ( 'Topeka', 275 );
  116.27 +# distance
  116.28 +DROP TABLE transp_dist;
  116.29 +CREATE TABLE transp_dist (
  116.30 +  LOC1 TEXT(127),
  116.31 +  LOC2 TEXT(127),
  116.32 +  DIST REAL,
  116.33 +  PRIMARY KEY ( LOC1(127), LOC2(127) )
  116.34 +  );
  116.35 +INSERT INTO transp_dist ( LOC1, LOC2, DIST ) VALUES ( 'Seattle',   'New York', 2.5 );
  116.36 +INSERT INTO transp_dist ( LOC1, LOC2, DIST ) VALUES ( 'Seattle',   'Chicago', 1.7 );
  116.37 +INSERT INTO transp_dist ( LOC1, LOC2, DIST ) VALUES ( 'Seattle',   'Topeka', 1.8 );
  116.38 +INSERT INTO transp_dist ( LOC1, LOC2, DIST ) VALUES ( 'San Diego', 'New York', 2.5 );
  116.39 +INSERT INTO transp_dist ( LOC1, LOC2, DIST ) VALUES ( 'San Diego', 'Chicago', 1.8 );
  116.40 +INSERT INTO transp_dist ( LOC1, LOC2, DIST ) VALUES ( 'San Diego', 'Topeka', 1.4 );
  116.41 +# result
  116.42 +DROP TABLE transp_result;
  116.43 +CREATE TABLE transp_result (
  116.44 +  LOC1     TEXT(127),
  116.45 +  LOC2     TEXT(127),
  116.46 +  QUANTITY REAL,
  116.47 +  PRIMARY KEY ( LOC1(127), LOC2(127) )
  116.48 +  );
   117.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   117.2 +++ b/examples/sql/transp_mysql.mod	Mon Dec 06 13:09:21 2010 +0100
   117.3 @@ -0,0 +1,71 @@
   117.4 +# A TRANSPORTATION PROBLEM
   117.5 +#
   117.6 +# This problem finds a least cost shipping schedule that meets
   117.7 +# requirements at markets and supplies at factories.
   117.8 +#
   117.9 +#  References:
  117.10 +#              Dantzig G B, "Linear Programming and Extensions."
  117.11 +#              Princeton University Press, Princeton, New Jersey, 1963,
  117.12 +#              Chapter 3-3.
  117.13 +
  117.14 +set I;
  117.15 +/* canning plants */
  117.16 +
  117.17 +param a{i in I};
  117.18 +/* capacity of plant i in cases */
  117.19 +
  117.20 +table plants IN "MySQL"
  117.21 +  'Database=glpk;UID=glpk;PWD=gnu'
  117.22 +  'SELECT PLANT, CAPA AS CAPACITY FROM transp_capa' :
  117.23 +   I <- [ PLANT ], a ~ CAPACITY;
  117.24 +
  117.25 +set J;
  117.26 +/* markets */
  117.27 +
  117.28 +param b{j in J};
  117.29 +/* demand at market j in cases */
  117.30 +
  117.31 +table markets IN "MySQL"
  117.32 +  'Database=glpk;UID=glpk;PWD=gnu'
  117.33 +  'transp_demand' :
  117.34 +  J <- [ MARKET ], b ~ DEMAND;
  117.35 +
  117.36 +param d{i in I, j in J};
  117.37 +/* distance in thousands of miles */
  117.38 +
  117.39 +table dist IN "MySQL"
  117.40 +  'Database=glpk;UID=glpk;PWD=gnu'
  117.41 +  'transp_dist' :
  117.42 +  [ LOC1, LOC2 ], d ~ DIST;
  117.43 +
  117.44 +param f;
  117.45 +/* freight in dollars per case per thousand miles */
  117.46 +
  117.47 +param c{i in I, j in J} := f * d[i,j] / 1000;
  117.48 +/* transport cost in thousands of dollars per case */
  117.49 +
  117.50 +var x{i in I, j in J} >= 0;
  117.51 +/* shipment quantities in cases */
  117.52 +
  117.53 +minimize cost: sum{i in I, j in J} c[i,j] * x[i,j];
  117.54 +/* total transportation costs in thousands of dollars */
  117.55 +
  117.56 +s.t. supply{i in I}: sum{j in J} x[i,j] <= a[i];
  117.57 +/* observe supply limit at plant i */
  117.58 +
  117.59 +s.t. demand{j in J}: sum{i in I} x[i,j] >= b[j];
  117.60 +/* satisfy demand at market j */
  117.61 +
  117.62 +solve;
  117.63 +
  117.64 +table result{i in I, j in J: x[i,j]} OUT "MySQL"
  117.65 +  'Database=glpk;UID=glpk;PWD=gnu'
  117.66 +  'DELETE FROM transp_result;'
  117.67 +  'INSERT INTO transp_result VALUES (?,?,?)' :
  117.68 +  i ~ LOC1, j ~ LOC2, x[i,j] ~ QUANTITY;
  117.69 +
  117.70 +data;
  117.71 +
  117.72 +param f := 90;
  117.73 +
  117.74 +end;
   118.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   118.2 +++ b/examples/sql/transp_odbc.mod	Mon Dec 06 13:09:21 2010 +0100
   118.3 @@ -0,0 +1,72 @@
   118.4 +# A TRANSPORTATION PROBLEM
   118.5 +#
   118.6 +# This problem finds a least cost shipping schedule that meets
   118.7 +# requirements at markets and supplies at factories.
   118.8 +#
   118.9 +#  References:
  118.10 +#              Dantzig G B, "Linear Programming and Extensions."
  118.11 +#              Princeton University Press, Princeton, New Jersey, 1963,
  118.12 +#              Chapter 3-3.
  118.13 +
  118.14 +set I;
  118.15 +/* canning plants */
  118.16 +
  118.17 +param a{i in I};
  118.18 +/* capacity of plant i in cases */
  118.19 +
  118.20 +table plants IN "iODBC"
  118.21 +  'DSN=glpk;UID=glpk;PWD=gnu'
  118.22 +  'SELECT PLANT, CAPA AS CAPACITY'
  118.23 +  'FROM transp_capa' :
  118.24 +   I <- [ PLANT ], a ~ CAPACITY;
  118.25 +
  118.26 +set J;
  118.27 +/* markets */
  118.28 +
  118.29 +param b{j in J};
  118.30 +/* demand at market j in cases */
  118.31 +
  118.32 +table markets IN "iODBC"
  118.33 +  'DSN=glpk;UID=glpk;PWD=gnu'
  118.34 +  'transp_demand' :
  118.35 +  J <- [ MARKET ], b ~ DEMAND;
  118.36 +
  118.37 +param d{i in I, j in J};
  118.38 +/* distance in thousands of miles */
  118.39 +
  118.40 +table dist IN "iODBC"
  118.41 +  'DSN=glpk;UID=glpk;PWD=gnu'
  118.42 +  'transp_dist' :
  118.43 +  [ LOC1, LOC2 ], d ~ DIST;
  118.44 +
  118.45 +param f;
  118.46 +/* freight in dollars per case per thousand miles */
  118.47 +
  118.48 +param c{i in I, j in J} := f * d[i,j] / 1000;
  118.49 +/* transport cost in thousands of dollars per case */
  118.50 +
  118.51 +var x{i in I, j in J} >= 0;
  118.52 +/* shipment quantities in cases */
  118.53 +
  118.54 +minimize cost: sum{i in I, j in J} c[i,j] * x[i,j];
  118.55 +/* total transportation costs in thousands of dollars */
  118.56 +
  118.57 +s.t. supply{i in I}: sum{j in J} x[i,j] <= a[i];
  118.58 +/* observe supply limit at plant i */
  118.59 +
  118.60 +s.t. demand{j in J}: sum{i in I} x[i,j] >= b[j];
  118.61 +/* satisfy demand at market j */
  118.62 +
  118.63 +solve;
  118.64 +
  118.65 +table result{i in I, j in J: x[i,j]} OUT "iODBC"
  118.66 +  'DSN=glpk;UID=glpk;PWD=gnu'
  118.67 +  'DELETE FROM transp_result;'
  118.68 +  'INSERT INTO transp_result VALUES (?,?,?)' :
  118.69 +  i ~ LOC1, j ~ LOC2, x[i,j] ~ QUANTITY;
  118.70 +
  118.71 +data;
  118.72 +
  118.73 +param f := 90;
  118.74 +
  118.75 +end;
   119.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   119.2 +++ b/examples/stigler.mod	Mon Dec 06 13:09:21 2010 +0100
   119.3 @@ -0,0 +1,411 @@
   119.4 +/* STIGLER, original Stigler's 1939 diet problem */
   119.5 +
   119.6 +/* The Stigler Diet is an optimization problem named for George Stigler,
   119.7 +   a 1982 Nobel Laureate in economics, who posed the following problem:
   119.8 +   For a moderately active man weighing 154 pounds, how much of each of
   119.9 +   77 foods should be eaten on a daily basis so that the man's intake of
  119.10 +   nine nutrients will be at least equal to the recommended dietary
  119.11 +   allowances (RDSs) suggested by the National Research Council in 1943,
  119.12 +   with the cost of the diet being minimal?
  119.13 +
  119.14 +   The nutrient RDAs required to be met in Stigler's experiment were
  119.15 +   calories, protein, calcium, iron, vitamin A, thiamine, riboflavin,
  119.16 +   niacin, and ascorbic acid. The result was an annual budget allocated
  119.17 +   to foods such as evaporated milk, cabbage, dried navy beans, and beef
  119.18 +   liver at a cost of approximately $0.11 a day in 1939 U.S. dollars.
  119.19 +
  119.20 +   While the name "Stigler Diet" was applied after the experiment by
  119.21 +   outsiders, according to Stigler, "No one recommends these diets for
  119.22 +   anyone, let alone everyone." The Stigler diet has been much ridiculed
  119.23 +   for its lack of variety and palatability, however his methodology has
  119.24 +   received praise and is considered to be some of the earliest work in
  119.25 +   linear programming.
  119.26 +
  119.27 +   The Stigler diet question is a linear programming problem. Lacking
  119.28 +   any sophisticated method of solving such a problem, Stigler was
  119.29 +   forced to utilize heuristic methods in order to find a solution. The
  119.30 +   diet question originally asked in which quantities a 154 pound male
  119.31 +   would have to consume 77 different foods in order to fulfill the
  119.32 +   recommended intake of 9 different nutrients while keeping expense at
  119.33 +   a minimum. Through "trial and error, mathematical insight and
  119.34 +   agility," Stigler was able to eliminate 62 of the foods from the
  119.35 +   original 77 (these foods were removed based because they lacked
  119.36 +   nutrients in comparison to the remaining 15). From the reduced list,
  119.37 +   Stigler calculated the required amounts of each of the remaining 15
  119.38 +   foods to arrive at a cost-minimizing solution to his question.
  119.39 +   According to Stigler's calculations, the annual cost of his solution
  119.40 +   was $39.93 in 1939 dollars. When corrected for inflation using the
  119.41 +   consumer price index, the cost of the diet in 2005 dollars is
  119.42 +   $561.43. The specific combination of foods and quantities is as
  119.43 +   follows:
  119.44 +
  119.45 +   Stigler's 1939 Diet
  119.46 +
  119.47 +   Food             Annual Quantities Annual Cost
  119.48 +   ---------------- ----------------- -----------
  119.49 +   Wheat Flour           370 lb.         $13.33
  119.50 +   Evaporated Milk        57 cans          3.84
  119.51 +   Cabbage               111 lb.           4.11
  119.52 +   Spinach                23 lb.           1.85
  119.53 +   Dried Navy Beans      285 lb.          16.80
  119.54 +   ----------------------------------------------
  119.55 +   Total Annual Cost                     $39.93
  119.56 +
  119.57 +   The 9 nutrients that Stigler's diet took into consideration and their
  119.58 +   respective recommended daily amounts were:
  119.59 +
  119.60 +   Table of nutrients considered in Stigler's diet
  119.61 +
  119.62 +   Nutrient                  Daily Recommended Intake
  119.63 +   ------------------------- ------------------------
  119.64 +   Calories                       3,000 Calories
  119.65 +   Protein                           70 grams
  119.66 +   Calcium                           .8 grams
  119.67 +   Iron                              12 milligrams
  119.68 +   Vitamin A                      5,000 IU
  119.69 +   Thiamine (Vitamin B1)            1.8 milligrams
  119.70 +   Riboflavin (Vitamin B2)          2.7 milligrams
  119.71 +   Niacin                            18 milligrams
  119.72 +   Ascorbic Acid (Vitamin C)         75 milligrams
  119.73 +
  119.74 +   Seven years after Stigler made his initial estimates, the development
  119.75 +   of George Dantzig's Simplex algorithm made it possible to solve the
  119.76 +   problem without relying on heuristic methods. The exact value was
  119.77 +   determined to be $39.69 (using the original 1939 data). Dantzig's
  119.78 +   algorithm describes a method of traversing the vertices of a polytope
  119.79 +   of N+1 dimensions in order to find the optimal solution to a specific
  119.80 +   situation.
  119.81 +
  119.82 +   (From Wikipedia, the free encyclopedia.) */
  119.83 +
  119.84 +/* Translated from GAMS by Andrew Makhorin <mao@gnu.org>.
  119.85 +
  119.86 +   For the original GAMS model stigler1939.gms see [3].
  119.87 +
  119.88 +   References:
  119.89 +
  119.90 +   1. George J. Stigler, "The Cost of Subsistence," J. Farm Econ. 27,
  119.91 +      1945, pp. 303-14.
  119.92 +
  119.93 +   2. National Research Council, "Recommended Daily Allowances," Reprint
  119.94 +      and Circular Series No. 115, January, 1943.
  119.95 +
  119.96 +   3. Erwin Kalvelagen, "Model building with GAMS," Chapter 2, "Building
  119.97 +      linear programming models," pp. 128-34. */
  119.98 +
  119.99 +set C;
 119.100 +/* commodities */
 119.101 +
 119.102 +check card(C) = 77;
 119.103 +/* there must be 77 commodities */
 119.104 +
 119.105 +set N;
 119.106 +/* nutrients */
 119.107 +
 119.108 +param data{c in C, {"price", "weight"} union N};
 119.109 +/* nutritive values per dollar of expenditure */
 119.110 +
 119.111 +param allowance{n in N};
 119.112 +/* recommended daily allowance for a moderately active man */
 119.113 +
 119.114 +var x{c in C}, >= 0;
 119.115 +/* dollars of food to be purchased daily */
 119.116 +
 119.117 +s.t. nb{n in N}: sum{c in C} data[c,n] * x[c] >= allowance[n];
 119.118 +/* nutrient balance */
 119.119 +
 119.120 +minimize cost: sum{c in C} x[c];
 119.121 +/* total food bill */
 119.122 +
 119.123 +solve;
 119.124 +
 119.125 +param days := 365.25;
 119.126 +/* days in a year */
 119.127 +
 119.128 +param commodity{c in C}, symbolic;
 119.129 +
 119.130 +param unit{c in C}, symbolic;
 119.131 +
 119.132 +printf "\n";
 119.133 +printf "MINIMUM COST ANNUAL DIET\n";
 119.134 +printf "\n";
 119.135 +printf "        Commodity            Unit     Quantity     Cost   \n";
 119.136 +printf "------------------------- ---------- ---------- ----------\n";
 119.137 +printf{c in C: x[c] != 0} "%-25s %10s %10.2f   $%7.2f\n", commodity[c],
 119.138 +   unit[c], 100 * days * x[c] / data[c,"price"], days * x[c];
 119.139 +printf "                                         -----------------\n";
 119.140 +printf "                                         Total:   $%7.2f\n",
 119.141 +   days * sum{c in C} x[c];
 119.142 +printf "\n";
 119.143 +
 119.144 +data;
 119.145 +
 119.146 +param : C :    commodity                   unit :=
 119.147 +flour          "Wheat Flour (Enriched)"    "10 lb."
 119.148 +macaroni       "Macaroni"                  "1 lb."
 119.149 +cereal         "Wheat Cereal (Enriched)"   "28 oz."
 119.150 +cornflakes     "Corn Flakes"               "8 oz."
 119.151 +cornmeal       "Corn Meal"                 "1 lb."
 119.152 +grits          "Hominy Grits"              "24 oz."
 119.153 +rice           "Rice"                      "1 lb."
 119.154 +oats           "Rolled Oats"               "1 lb."
 119.155 +whitebread     "White Bread (Enriched)"    "1 lb."
 119.156 +wheatbread     "Whole Wheat Bread"         "1 lb."
 119.157 +ryebread       "Rye Bread"                 "1 lb."
 119.158 +poundcake      "Pound Cake"                "1 lb."
 119.159 +crackers       "Soda Crackers"             "1 lb."
 119.160 +milk           "Milk"                      "1 qt."
 119.161 +evapmild       "Evaporated Milk (can)"     "14.5 oz."
 119.162 +butter         "Butter"                    "1 lb."
 119.163 +margarine      "Oleomargarine"             "1 lb."
 119.164 +eggs           "Eggs"                      "1 doz."
 119.165 +cheese         "Cheese (Cheddar)"          "1 lb."
 119.166 +cream          "Cream"                     "1/2 pt."
 119.167 +peanutbutter   "Peanut Butter"             "1 lb."
 119.168 +mayonnaise     "Mayonnaise"                "1/2 pt."
 119.169 +crisco         "Crisco"                    "1 lb."
 119.170 +lard           "Lard"                      "1 lb."
 119.171 +sirloinsteak   "Sirloin Steak"             "1 lb."
 119.172 +roundsteak     "Round Steak"               "1 lb."
 119.173 +ribroast       "Rib Roast"                 "1 lb."
 119.174 +chuckroast     "Chuck Roast"               "1 lb."
 119.175 +plate          "Plate"                     "1 lb."
 119.176 +liver          "Liver (Beef)"              "1 lb."
 119.177 +lambleg        "Leg of Lamb"               "1 lb."
 119.178 +lambchops      "Lamb Chops (Rib)"          "1 lb."
 119.179 +porkchops      "Pork Chops"                "1 lb."
 119.180 +porkroast      "Pork Loin Roast"           "1 lb."
 119.181 +bacon          "Bacon"                     "1 lb."
 119.182 +ham            "Ham - smoked"              "1 lb."
 119.183 +saltpork       "Salt Pork"                 "1 lb."
 119.184 +chicken        "Roasting Chicken"          "1 lb."
 119.185 +veal           "Veal Cutlets"              "1 lb."
 119.186 +salmon         "Salmon, Pink (can)"        "16 oz."
 119.187 +apples         "Apples"                    "1 lb."
 119.188 +bananas        "Bananas"                   "1 lb."
 119.189 +lemons         "Lemons"                    "1 doz."
 119.190 +oranges        "Oranges"                   "1 doz."
 119.191 +greenbeans     "Green Beans"               "1 lb."
 119.192 +cabbage        "Cabbage"                   "1 lb."
 119.193 +carrots        "Carrots"                   "1 bunch"
 119.194 +celery         "Celery"                    "1 stalk"
 119.195 +lettuce        "Lettuce"                   "1 head"
 119.196 +onions         "Onions"                    "1 lb."
 119.197 +potatoes       "Potatoes"                  "15 lb."
 119.198 +spinach        "Spinach"                   "1 lb."
 119.199 +sweetpotato    "Sweet Potatoes"            "1 lb."
 119.200 +peaches        "Peaches (can)"             "No. 2 1/2"
 119.201 +pears          "Pears (can)"               "No. 2 1/2"
 119.202 +pineapple      "Pineapple (can)"           "No. 2 1/2"
 119.203 +asparagus      "Asparagus (can)"           "No. 2"
 119.204 +cannedgrbn     "Grean Beans (can)"         "No. 2"
 119.205 +porkbeans      "Pork and Beans (can)"      "16 oz."
 119.206 +corn           "Corn (can)"                "No. 2"
 119.207 +peas           "Peas (can)"                "No. 2"
 119.208 +tomatoes       "Tomatoes (can)"            "No. 2"
 119.209 +tomatosoup     "Tomato Soup (can)"         "10 1/2 oz."
 119.210 +driedpeach     "Peaches, Dried"            "1 lb."
 119.211 +prunes         "Prunes, Dried"             "1 lb."
 119.212 +raisins        "Raisins, Dried"            "15 oz."
 119.213 +driedpeas      "Peas, Dried"               "1 lb."
 119.214 +limabeans      "Lima Beans, Dried"         "1 lb."
 119.215 +navybeans      "Navy Beans, Dried"         "1 lb."
 119.216 +coffee         "Coffee"                    "1 lb."
 119.217 +tea            "Tea"                       "1/4 lb."
 119.218 +cocoa          "Cocoa"                     "8 oz."
 119.219 +chocolate      "Chocolate"                 "8 oz."
 119.220 +sugar          "Sugar"                     "10 lb."
 119.221 +cornsirup      "Corn Sirup"                "24 oz."
 119.222 +molasses       "Molasses"                  "18 oz."
 119.223 +stawberry      "Strawberry Preserve"       "1 lb."
 119.224 +;
 119.225 +
 119.226 +set N :=
 119.227 +calories       /* Calories, unit = 1000 */
 119.228 +protein        /* Protein, unit = grams */
 119.229 +calcium        /* Calcium, unit = grams */
 119.230 +iron           /* Iron, unit = milligrams */
 119.231 +vitaminA       /* Vitamin A, unit = 1000 International Units */
 119.232 +thiamine       /* Thiamine, Vit. B1, unit = milligrams */
 119.233 +riboflavin     /* Riboflavin, Vit. B2, unit = milligrams */
 119.234 +niacin         /* Niacin (Nicotinic Acid), unit = milligrams */
 119.235 +ascorbicAcid   /* Ascorbic Acid, Vit. C, unit = milligrams */
 119.236 +;
 119.237 +
 119.238 +param data
 119.239 +:             price   weight calories protein  calcium   iron :=
 119.240 +#            aug. 15  edible
 119.241 +#             1939    per $1
 119.242 +#           (cents)   (grams) (1000)  (grams)  (grams)   (mg.)
 119.243 +flour         36.0    12600    44.7     1411     2.0      365
 119.244 +macaroni      14.1     3217    11.6      418      .7       54
 119.245 +cereal        24.2     3280    11.8      377    14.4      175
 119.246 +cornflakes     7.1     3194    11.4      252      .1       56
 119.247 +cornmeal       4.6     9861    36.0      897     1.7       99
 119.248 +grits          8.5     8005    28.6      680      .8       80
 119.249 +rice           7.5     6048    21.2      460      .6       41
 119.250 +oats           7.1     6389    25.3      907     5.1      341
 119.251 +whitebread     7.9     5742    15.6      488     2.5      115
 119.252 +wheatbread     9.1     4985    12.2      484     2.7      125
 119.253 +ryebread       9.2     4930    12.4      439     1.1       82
 119.254 +poundcake     24.8     1829     8.0      130      .4       31
 119.255 +crackers      15.1     3004    12.5      288      .5       50
 119.256 +milk          11.0     8867     6.1      310    10.5       18
 119.257 +evapmild       6.7     6035     8.4      422    15.1        9
 119.258 +butter        20.8     1473    10.8        9      .2        3
 119.259 +margarine     16.1     2817    20.6       17      .6        6
 119.260 +eggs          32.6     1857     2.9      238     1.0       52
 119.261 +cheese        24.2     1874     7.4      448    16.4       19
 119.262 +cream         14.1     1689     3.5       49     1.7        3
 119.263 +peanutbutter  17.9     2534    15.7      661     1.0       48
 119.264 +mayonnaise    16.7     1198     8.6       18      .2        8
 119.265 +crisco        20.3     2234    20.1        0      .0        0
 119.266 +lard           9.8     4628    41.7        0      .0        0
 119.267 +sirloinsteak  39.6     1145     2.9      166      .1       34
 119.268 +roundsteak    36.4     1246     2.2      214      .1       32
 119.269 +ribroast      29.2     1553     3.4      213      .1       33
 119.270 +chuckroast    22.6     2007     3.6      309      .2       46
 119.271 +plate         14.6     3107     8.5      404      .2       62
 119.272 +liver         26.8     1692     2.2      333      .2      139
 119.273 +lambleg       27.6     1643     3.1      245      .1       20
 119.274 +lambchops     36.6     1239     3.3      140      .1       15
 119.275 +porkchops     30.7     1477     3.5      196      .2       80
 119.276 +porkroast     24.2     1874     4.4      249      .3       37
 119.277 +bacon         25.6     1772    10.4      152      .2       23
 119.278 +ham           27.4     1655     6.7      212      .2       31
 119.279 +saltpork      16.0     2835    18.8      164      .1       26
 119.280 +chicken       30.3     1497     1.8      184      .1       30
 119.281 +veal          42.3     1072     1.7      156      .1       24
 119.282 +salmon        13.0     3489     5.8      705     6.8       45
 119.283 +apples         4.4     9072     5.8       27      .5       36
 119.284 +bananas        6.1     4982     4.9       60      .4       30
 119.285 +lemons        26.0     2380     1.0       21      .5       14
 119.286 +oranges       30.9     4439     2.2       40     1.1       18
 119.287 +greenbeans     7.1     5750     2.4      138     3.7       80
 119.288 +cabbage        3.7     8949     2.6      125     4.0       36
 119.289 +carrots        4.7     6080     2.7       73     2.8       43
 119.290 +celery         7.3     3915      .9       51     3.0       23
 119.291 +lettuce        8.2     2247      .4       27     1.1       22
 119.292 +onions         3.6    11844     5.8      166     3.8       59
 119.293 +potatoes      34.0    16810    14.3      336     1.8      118
 119.294 +spinach        8.1     4592     1.1      106      .0      138
 119.295 +sweetpotato    5.1     7649     9.6      138     2.7       54
 119.296 +peaches       16.8     4894     3.7       20      .4       10
 119.297 +pears         20.4     4030     3.0        8      .3        8
 119.298 +pineapple     21.3     3993     2.4       16      .4        8
 119.299 +asparagus     27.7     1945      .4       33      .3       12
 119.300 +cannedgrbn    10.0     5386     1.0       54     2.0       65
 119.301 +porkbeans      7.1     6389     7.5      364     4.0      134
 119.302 +corn          10.4     5452     5.2      136      .2       16
 119.303 +peas          13.8     4109     2.3      136      .6       45
 119.304 +tomatoes       8.6     6263     1.3       63      .7       38
 119.305 +tomatosoup     7.6     3917     1.6       71      .6       43
 119.306 +driedpeach    15.7     2889     8.5       87     1.7      173
 119.307 +prunes         9.0     4284    12.8       99     2.5      154
 119.308 +raisins        9.4     4524    13.5      104     2.5      136
 119.309 +driedpeas      7.9     5742    20.0     1367     4.2      345
 119.310 +limabeans      8.9     5097    17.4     1055     3.7      459
 119.311 +navybeans      5.9     7688    26.9     1691    11.4      792
 119.312 +coffee        22.4     2025      .0        0      .0        0
 119.313 +tea           17.4      652      .0        0      .0        0
 119.314 +cocoa          8.6     2637     8.7      237     3.0       72
 119.315 +chocolate     16.2     1400     8.0       77     1.3       39
 119.316 +sugar         51.7     8773    34.9        0      .0        0
 119.317 +cornsirup     13.7     4996    14.7        0      .5       74
 119.318 +molasses      13.6     3752     9.0        0    10.3      244
 119.319 +stawberry     20.5     2213     6.4       11      .4        7
 119.320 +
 119.321 +:           vitaminA thiamine riboflavin  niacin  ascorbicAcid :=
 119.322 +#          (1000 IU)  (mg.)      (mg.)     (mg.)     (mg.)
 119.323 +flour           .0    55.4       33.3       441         0
 119.324 +macaroni        .0     3.2        1.9        68         0
 119.325 +cereal          .0    14.4        8.8       114         0
 119.326 +cornflakes      .0    13.5        2.3        68         0
 119.327 +cornmeal      30.9    17.4        7.9       106         0
 119.328 +grits           .0    10.6        1.6       110         0
 119.329 +rice            .0     2.0        4.8        60         0
 119.330 +oats            .0    37.1        8.9        64         0
 119.331 +whitebread      .0    13.8        8.5       126         0
 119.332 +wheatbread      .0    13.9        6.4       160         0
 119.333 +ryebread        .0     9.9        3.0        66         0
 119.334 +poundcake     18.9     2.8        3.0        17         0
 119.335 +crackers        .0      .0         .0         0         0
 119.336 +milk          16.8     4.0       16.0         7       177
 119.337 +evapmild      26.0     3.0       23.5        11        60
 119.338 +butter        44.2      .0         .2         2         0
 119.339 +margarine     55.8      .2         .0         0         0
 119.340 +eggs          18.6     2.8        6.5         1         0
 119.341 +cheese        28.1      .8       10.3         4         0
 119.342 +cream         16.9      .6        2.5         0        17
 119.343 +peanutbutter    .0     9.6        8.1       471         0
 119.344 +mayonnaise     2.7      .4         .5         0         0
 119.345 +crisco          .0      .0         .0         0         0
 119.346 +lard            .2      .0         .5         5         0
 119.347 +sirloinsteak    .2     2.1        2.9        69         0
 119.348 +roundsteak      .4     2.5        2.4        87         0
 119.349 +ribroast        .0      .0        2.0         0         0
 119.350 +chuckroast      .4     1.0        4.0       120         0
 119.351 +plate           .0      .9         .0         0         0
 119.352 +liver        169.2     6.4       50.8       316       525
 119.353 +lambleg         .0     2.8        3.0        86         0
 119.354 +lambchops       .0     1.7        2.7        54         0
 119.355 +porkchops       .0    17.4        2.7        60         0
 119.356 +porkroast       .0    18.2        3.6        79         0
 119.357 +bacon           .0     1.8        1.8        71         0
 119.358 +ham             .0     9.9        3.3        50         0
 119.359 +saltpork        .0     1.4        1.8         0         0
 119.360 +chicken         .1      .9        1.8        68        46
 119.361 +veal            .0     1.4        2.4        57         0
 119.362 +salmon         3.5     1.0        4.9       209         0
 119.363 +apples         7.3     3.6        2.7         5       544
 119.364 +bananas       17.4     2.5        3.5        28       498
 119.365 +lemons          .0      .5         .0         4       952
 119.366 +oranges       11.1     3.6        1.3        10      1993
 119.367 +greenbeans    69.0     4.3        5.8        37       862
 119.368 +cabbage        7.2     9.0        4.5        26      5369
 119.369 +carrots      188.5     6.1        4.3        89       608
 119.370 +celery          .9     1.4        1.4         9       313
 119.371 +lettuce      112.4     1.8        3.4        11       449
 119.372 +onions        16.6     4.7        5.9        21      1184
 119.373 +potatoes       6.7    29.4        7.1       198      2522
 119.374 +spinach      918.4     5.7       13.8        33      2755
 119.375 +sweetpotato  290.7     8.4        5.4        83      1912
 119.376 +peaches       21.5      .5        1.0        31       196
 119.377 +pears           .8      .8         .8         5        81
 119.378 +pineapple      2.0     2.8         .8         7       399
 119.379 +asparagus     16.3     1.4        2.1        17       272
 119.380 +cannedgrbn    53.9     1.6        4.3        32       431
 119.381 +porkbeans      3.5     8.3        7.7        56         0
 119.382 +corn          12.0     1.6        2.7        42       218
 119.383 +peas          34.9     4.9        2.5        37       370
 119.384 +tomatoes      53.2     3.4        2.5        36      1253
 119.385 +tomatosoup    57.9     3.5        2.4        67       862
 119.386 +driedpeach    86.8     1.2        4.3        55        57
 119.387 +prunes        85.7     3.9        4.3        65       257
 119.388 +raisins        4.5     6.3        1.4        24       136
 119.389 +driedpeas      2.9    28.7       18.4       162         0
 119.390 +limabeans      5.1    26.9       38.2        93         0
 119.391 +navybeans       .0    38.4       24.6       217         0
 119.392 +coffee          .0     4.0        5.1        50         0
 119.393 +tea             .0      .0        2.3        42         0
 119.394 +cocoa           .0     2.0       11.9        40         0
 119.395 +chocolate       .0      .9        3.4        14         0
 119.396 +sugar           .0      .0         .0         0         0
 119.397 +cornsirup       .0      .0         .0         5         0
 119.398 +molasses        .0     1.9        7.5       146         0
 119.399 +stawberry       .2      .2         .4         3         0
 119.400 +;
 119.401 +
 119.402 +param allowance :=
 119.403 +calories       3
 119.404 +protein       70
 119.405 +calcium         .8
 119.406 +iron          12
 119.407 +vitaminA       5
 119.408 +thiamine       1.8
 119.409 +riboflavin     2.7
 119.410 +niacin        18
 119.411 +ascorbicAcid  75
 119.412 +;
 119.413 +
 119.414 +end;
   120.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   120.2 +++ b/examples/sudoku.dat	Mon Dec 06 13:09:21 2010 +0100
   120.3 @@ -0,0 +1,16 @@
   120.4 +/* sudoku.dat, a hard Sudoku puzzle which causes branching */
   120.5 +
   120.6 +data;
   120.7 +
   120.8 +param givens : 1 2 3 4 5 6 7 8 9 :=
   120.9 +           1   1 . . . . . 7 . .
  120.10 +           2   . 2 . . . . 5 . .
  120.11 +           3   6 . . 3 8 . . . .
  120.12 +           4   . 7 8 . . . . . .
  120.13 +           5   . . . 6 . 9 . . .
  120.14 +           6   . . . . . . 1 4 .
  120.15 +           7   . . . . 2 5 . . 9
  120.16 +           8   . . 3 . . . . 6 .
  120.17 +           9   . . 4 . . . . . 2 ;
  120.18 +
  120.19 +end;
   121.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   121.2 +++ b/examples/sudoku.mod	Mon Dec 06 13:09:21 2010 +0100
   121.3 @@ -0,0 +1,84 @@
   121.4 +/* SUDOKU, Number Placement Puzzle */
   121.5 +
   121.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
   121.7 +
   121.8 +/* Sudoku, also known as Number Place, is a logic-based placement
   121.9 +   puzzle. The aim of the canonical puzzle is to enter a numerical
  121.10 +   digit from 1 through 9 in each cell of a 9x9 grid made up of 3x3
  121.11 +   subgrids (called "regions"), starting with various digits given in
  121.12 +   some cells (the "givens"). Each row, column, and region must contain
  121.13 +   only one instance of each numeral.
  121.14 +
  121.15 +   Example:
  121.16 +
  121.17 +   +-------+-------+-------+
  121.18 +   | 5 3 . | . 7 . | . . . |
  121.19 +   | 6 . . | 1 9 5 | . . . |
  121.20 +   | . 9 8 | . . . | . 6 . |
  121.21 +   +-------+-------+-------+
  121.22 +   | 8 . . | . 6 . | . . 3 |
  121.23 +   | 4 . . | 8 . 3 | . . 1 |
  121.24 +   | 7 . . | . 2 . | . . 6 |
  121.25 +   +-------+-------+-------+
  121.26 +   | . 6 . | . . . | 2 8 . |
  121.27 +   | . . . | 4 1 9 | . . 5 |
  121.28 +   | . . . | . 8 . | . 7 9 |
  121.29 +   +-------+-------+-------+
  121.30 +
  121.31 +   (From Wikipedia, the free encyclopedia.) */
  121.32 +
  121.33 +param givens{1..9, 1..9}, integer, >= 0, <= 9, default 0;
  121.34 +/* the "givens" */
  121.35 +
  121.36 +var x{i in 1..9, j in 1..9, k in 1..9}, binary;
  121.37 +/* x[i,j,k] = 1 means cell [i,j] is assigned number k */
  121.38 +
  121.39 +s.t. fa{i in 1..9, j in 1..9, k in 1..9: givens[i,j] != 0}:
  121.40 +     x[i,j,k] = (if givens[i,j] = k then 1 else 0);
  121.41 +/* assign pre-defined numbers using the "givens" */
  121.42 +
  121.43 +s.t. fb{i in 1..9, j in 1..9}: sum{k in 1..9} x[i,j,k] = 1;
  121.44 +/* each cell must be assigned exactly one number */
  121.45 +
  121.46 +s.t. fc{i in 1..9, k in 1..9}: sum{j in 1..9} x[i,j,k] = 1;
  121.47 +/* cells in the same row must be assigned distinct numbers */
  121.48 +
  121.49 +s.t. fd{j in 1..9, k in 1..9}: sum{i in 1..9} x[i,j,k] = 1;
  121.50 +/* cells in the same column must be assigned distinct numbers */
  121.51 +
  121.52 +s.t. fe{I in 1..9 by 3, J in 1..9 by 3, k in 1..9}:
  121.53 +     sum{i in I..I+2, j in J..J+2} x[i,j,k] = 1;
  121.54 +/* cells in the same region must be assigned distinct numbers */
  121.55 +
  121.56 +/* there is no need for an objective function here */
  121.57 +
  121.58 +solve;
  121.59 +
  121.60 +for {i in 1..9}
  121.61 +{  for {0..0: i = 1 or i = 4 or i = 7}
  121.62 +      printf " +-------+-------+-------+\n";
  121.63 +   for {j in 1..9}
  121.64 +   {  for {0..0: j = 1 or j = 4 or j = 7} printf(" |");
  121.65 +      printf " %d", sum{k in 1..9} x[i,j,k] * k;
  121.66 +      for {0..0: j = 9} printf(" |\n");
  121.67 +   }
  121.68 +   for {0..0: i = 9}
  121.69 +      printf " +-------+-------+-------+\n";
  121.70 +}
  121.71 +
  121.72 +data;
  121.73 +
  121.74 +/* These data correspond to the example above. */
  121.75 +
  121.76 +param givens : 1 2 3 4 5 6 7 8 9 :=
  121.77 +           1   5 3 . . 7 . . . .
  121.78 +           2   6 . . 1 9 5 . . .
  121.79 +           3   . 9 8 . . . . 6 .
  121.80 +           4   8 . . . 6 . . . 3
  121.81 +           5   4 . . 8 . 3 . . 1
  121.82 +           6   7 . . . 2 . . . 6
  121.83 +           7   . 6 . . . . 2 8 .
  121.84 +           8   . . . 4 1 9 . . 5
  121.85 +           9   . . . . 8 . . 7 9 ;
  121.86 +
  121.87 +end;
   122.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   122.2 +++ b/examples/t1.cs	Mon Dec 06 13:09:21 2010 +0100
   122.3 @@ -0,0 +1,99 @@
   122.4 +/*Find the minimum value which satisfies the linear inequality:
   122.5 +    a*x + b*y >= 1 {a,b,x,y Integers} {a,b > 0} {a,b entered on command line}
   122.6 +
   122.7 +  Nigel_Galloway@operamail.com
   122.8 +  February 2008
   122.9 +*/
  122.10 +using System;
  122.11 +using System.Runtime.InteropServices;
  122.12 +
  122.13 +unsafe class GLPK{
  122.14 +  double *lp;
  122.15 +  public int a;
  122.16 +  public int b;
  122.17 +
  122.18 +  const string glpkLibrary = "libglpk.so";
  122.19 +  readonly int GLP_FR = 1;
  122.20 +  readonly int GLP_IV = 2;
  122.21 +  readonly int GLP_DB = 4;
  122.22 +  struct ConstraintMatrix{
  122.23 +    public fixed int ia[3];
  122.24 +    public fixed int ja[3];
  122.25 +    public fixed double ar[3];
  122.26 +  }
  122.27 +  [DllImport(glpkLibrary, SetLastError=true)]
  122.28 +  static extern double* glp_create_prob();
  122.29 +  [DllImport(glpkLibrary, SetLastError=true)]
  122.30 +  static extern void glp_add_rows(double* lp, int rows);
  122.31 +  [DllImport(glpkLibrary, SetLastError=true)]
  122.32 +  static extern void glp_add_cols(double* lp, int cols);
  122.33 +  [DllImport(glpkLibrary, SetLastError=true)]
  122.34 +  static extern void glp_set_col_bnds(double* lp, int col, int bound_type, double lower_bound, double upper_bound);
  122.35 +  [DllImport(glpkLibrary, SetLastError=true)]
  122.36 +  static extern void glp_set_col_kind(double* lp, int col, int kind);
  122.37 +  [DllImport(glpkLibrary, SetLastError=true)]
  122.38 +  static extern void glp_load_matrix(double* lp, int elements, int* ia, int* ja, double* ar);
  122.39 +  public GLPK(int a, int b){
  122.40 +    this.a = a;
  122.41 +    this.b = b;
  122.42 +    lp = glp_create_prob();
  122.43 +    //Col 1 is x, Col 2 is y
  122.44 +    glp_add_rows(lp, 1);
  122.45 +    glp_add_cols(lp, 2);
  122.46 +    glp_set_col_bnds(lp, 1, GLP_FR, 0.0, 0.0);
  122.47 +    glp_set_col_bnds(lp, 2, GLP_FR, 0.0, 0.0);
  122.48 +    glp_set_col_kind(lp, 1, GLP_IV);
  122.49 +    glp_set_col_kind(lp, 2, GLP_IV);
  122.50 +    //Row 1 is a*x + b*y
  122.51 +    ConstraintMatrix CM = new ConstraintMatrix();
  122.52 +    CM.ia[1]=1; CM.ja[1]=1; CM.ar[1]=a;
  122.53 +    CM.ia[2]=1; CM.ja[2]=2; CM.ar[2]=b;
  122.54 +    glp_load_matrix(lp, 2, CM.ia, CM.ja, CM.ar);
  122.55 +    Console.WriteLine("Hello Nigel");
  122.56 +  }
  122.57 +
  122.58 +  [DllImport(glpkLibrary, SetLastError=true)]
  122.59 +  static extern void glp_set_row_bnds(double* lp, int row, int bound_type, double lower_bound, double upper_bound);
  122.60 +  [DllImport(glpkLibrary, SetLastError=true)]
  122.61 +  static extern void glp_simplex(double* lp, void* options);
  122.62 +  [DllImport(glpkLibrary, SetLastError=true)]
  122.63 +  static extern void glp_intopt(double* lp, void* options);
  122.64 +  [DllImport(glpkLibrary, SetLastError=true)]
  122.65 +  static extern double glp_mip_col_val(double* lp, int col);
  122.66 +  public int betterGuess(int upper_bound){
  122.67 +    //Find a new guess less than the old guess: 1 <= (a*x + b*y) <= (old guess - 1)
  122.68 +    glp_set_row_bnds(lp, 1, GLP_DB, 1.0, ((double)upper_bound)-0.5);
  122.69 +    glp_simplex(lp, null);
  122.70 +    glp_intopt(lp, null);
  122.71 +    int x = (int)glp_mip_col_val(lp, 1);
  122.72 +    int y = (int)glp_mip_col_val(lp, 2);
  122.73 +    int nextGuess = a*x + b*y;
  122.74 +    Console.WriteLine("x = {0}, y = {1}, a*x + b*y = {2}",x,y,nextGuess);
  122.75 +    return nextGuess;
  122.76 +  }
  122.77 +
  122.78 +  [DllImport(glpkLibrary, SetLastError=true)]
  122.79 +  static extern void glp_delete_prob(double* lp);
  122.80 +  ~GLPK(){
  122.81 +    glp_delete_prob(lp);
  122.82 +    Console.WriteLine("Goodbye Nigel");
  122.83 +  }
  122.84 +
  122.85 +}
  122.86 +
  122.87 +class test{
  122.88 +  static bool isMinimum(int a, int b, int guess){
  122.89 +    Console.WriteLine("Trying {0}",guess);
  122.90 +    if (a%guess > 0) return false;
  122.91 +    if (b%guess > 0) return false;
  122.92 +    Console.WriteLine("Solution is {0}",guess);
  122.93 +    return true;
  122.94 +  }
  122.95 +
  122.96 +  public static void Main(string[] args){
  122.97 +    Console.WriteLine("a = {0}, b = {1}",args[0], args[1]);
  122.98 +    GLPK lp = new GLPK(Int32.Parse(args[0]),Int32.Parse(args[1]));
  122.99 +    int guess = (lp.a > lp.b) ? lp.b : lp.a;
 122.100 +    while (!isMinimum(lp.a,lp.b,guess)) guess = lp.betterGuess(guess);
 122.101 +  }
 122.102 +}
   123.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   123.2 +++ b/examples/tas.mod	Mon Dec 06 13:09:21 2010 +0100
   123.3 @@ -0,0 +1,486 @@
   123.4 +/* TAS, Tail Assignment Problem */
   123.5 +
   123.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
   123.7 +
   123.8 +/* The Tail Assignment Problem (TAS) is to construct rosters for a set
   123.9 +   of aircrafts (tails), which cover all flights for a given scheduling
  123.10 +   period.
  123.11 +
  123.12 +   This model includes only flight connection constraints while other
  123.13 +   constraints (for example, maintenance constraints) are ignored. Such
  123.14 +   simplification allows using a single commodity network to model the
  123.15 +   problem, where commodity corresponds to the set of aircrafts.
  123.16 +
  123.17 +   Nodes of the network are activities. They include all flights plus
  123.18 +   two dummy nodes (activities): source node, s, corresponding to
  123.19 +   initial activity of each aircraft, and sink node t, corresponding to
  123.20 +   final activity of each aircraft. Arc v->v' exists in the network if
  123.21 +   and only if the same aircraft is able to operate activity v and then
  123.22 +   immediately activity v'. In partucular, arcs s->f and f->t exist for
  123.23 +   all flights f. Arcs f->f', where f and f' are some flights, exist
  123.24 +   only if the connection time (which is the difference between the
  123.25 +   departure time of f' and the arrival time of f) is not less than a
  123.26 +   given minimal connection time.
  123.27 +
  123.28 +   Reference:
  123.29 +   M. Groenkvist, "The Tail Assignment Problem," Dept. of Comp. Sci.
  123.30 +   and Eng., Chalmers University of Technology and Goeteborg University,
  123.31 +   Goeteborg, Sweden, August 2005. */
  123.32 +
  123.33 +########################################################################
  123.34 +
  123.35 +param nf, integer, > 0;
  123.36 +/* number of flights */
  123.37 +
  123.38 +set F := 1..nf;
  123.39 +/* set of flights (for a given period from timetable) */
  123.40 +
  123.41 +param hub{f in F}, in {1, 2};
  123.42 +/* hub[f] = 1: Sheremetyevo-1
  123.43 +   hub[f] = 2: Sheremetyevo-2 */
  123.44 +
  123.45 +param dest{f in F}, symbolic;
  123.46 +/* destination airport (IATA code) */
  123.47 +
  123.48 +param fno1{f in F}, integer;
  123.49 +/* first leg flight number */
  123.50 +
  123.51 +param dep1{f in F}, integer, >= 0;
  123.52 +/* departure time from Sheremetyevo airport, in minutes */
  123.53 +
  123.54 +check{f in F: f < nf}: dep1[f] <= dep1[f+1];
  123.55 +/* all flights must be ordered by ascending of the departure time */
  123.56 +
  123.57 +param arr1{f in F}, integer, >= 0;
  123.58 +/* arrival time to destination airport, in minutes */
  123.59 +
  123.60 +param fno2{f in F}, integer;
  123.61 +/* second leg flight number */
  123.62 +
  123.63 +param dep2{f in F}, integer, >= 0;
  123.64 +/* departure time from destination airport, in minutes */
  123.65 +
  123.66 +param arr2{f in F}, integer, >= 0;
  123.67 +/* arrival time to Sheremetyevo airport, in minutes */
  123.68 +
  123.69 +param mct1, integer, >= 0, default 80;
  123.70 +/* minimal connection time (within SVO1 or SVO2), in minutes */
  123.71 +
  123.72 +param mct2, integer, >= 0, default 150;
  123.73 +/* minimal connection time (between SVO1 and SVO2), in minutes */
  123.74 +
  123.75 +set E := setof{f in F, ff in F: arr2[f] + (if hub[f] = hub[ff] then
  123.76 +   mct1 else mct2) <= dep1[ff]} (f, ff);
  123.77 +/* connection network; arc f->ff is in E, iff the same aircraft can be
  123.78 +   assigned to flight f and then immediately to flight ff */
  123.79 +
  123.80 +var s{f in F}, >= 0;
  123.81 +/* s[f] is a flow from source node to node f */
  123.82 +
  123.83 +var x{(f,ff) in E}, >= 0;
  123.84 +/* x[f,ff] is a flow from node f to node ff */
  123.85 +
  123.86 +var t{f in F}, >= 0;
  123.87 +/* t[f] is a flow from node f to sink node */
  123.88 +
  123.89 +s.t. into{f in F}: s[f] + sum{(ff,f) in E} x[ff,f] = 1;
  123.90 +/* exactly one aircraft must come into each node f */
  123.91 +
  123.92 +s.t. from{f in F}: t[f] + sum{(f,ff) in E} x[f,ff] = 1;
  123.93 +/* exactly one aircraft must come from each node f */
  123.94 +
  123.95 +minimize obj: sum{f in F} s[f];
  123.96 +/* minimize the number aircrafts sufficient to cover all flights */
  123.97 +
  123.98 +solve;
  123.99 +
 123.100 +########################################################################
 123.101 +
 123.102 +param na := floor(sum{f in F} s[f] + .5);
 123.103 +/* minimal number of aircrafts found */
 123.104 +
 123.105 +printf "At least %d aircrafts needed\n", na;
 123.106 +
 123.107 +set A := 1..na;
 123.108 +/* set of aircrafts */
 123.109 +
 123.110 +printf "Building rosters...\n";
 123.111 +
 123.112 +param tail{f in F}, in A, :=
 123.113 +/* tail[f] is the number of an aircraft assigned to flight f */
 123.114 +
 123.115 +   if f = 1 then 1
 123.116 +   /* assign aircraft 1 to the earliest flight */
 123.117 +
 123.118 +   else if s[f] >= 0.9 then (max{ff in 1..f-1} tail[ff]) + 1
 123.119 +   /* if f is the first flight in a roster, assign to it a next
 123.120 +      aircraft */
 123.121 +
 123.122 +   else sum{(ff,f) in E} tail[ff] * (if x[ff,f] >= 0.9 then 1);
 123.123 +   /* otherwise, assign to flight f the same aircraft, which is
 123.124 +      assigned to a preceding flight in the roster */
 123.125 +
 123.126 +########################################################################
 123.127 +
 123.128 +param file, symbolic, default "tas.ps";
 123.129 +/* file to output the assignment chart in postscript format */
 123.130 +
 123.131 +param title, symbolic, default "(no title)";
 123.132 +/* chart title */
 123.133 +
 123.134 +param left, default 25;
 123.135 +/* left margin, in mm */
 123.136 +
 123.137 +param top, default 25;
 123.138 +/* top margin, in mm */
 123.139 +
 123.140 +param right, default 20;
 123.141 +/* right margin, in mm */
 123.142 +
 123.143 +param bottom, default 15;
 123.144 +/* bottom margin, in mm */
 123.145 +
 123.146 +param sx := 297 - left - right;
 123.147 +/* chart area horizontal size, in mm */
 123.148 +
 123.149 +param sy := 210 - top - bottom;
 123.150 +/* chart area vertical size, in mm */
 123.151 +
 123.152 +param gap, default sy / (na - 1);
 123.153 +/* gap between rosters, in mm */
 123.154 +
 123.155 +printf "Writing assignment chart to %s...\n", file;
 123.156 +
 123.157 +printf "%%!PS-Adobe-3.0\n" > file;
 123.158 +printf "%%%%Title: Tail Assignment Chart\n" >> file;
 123.159 +printf "%%%%Creator: GLPK MathProg\n" >> file;
 123.160 +printf "%%%%BoundingBox: 0 0 595 842\n" >> file;
 123.161 +printf "%%%%EndComments\n" >> file;
 123.162 +printf "<</PageSize [595 842]>> setpagedevice\n" >> file;
 123.163 +printf "72 25.4 div dup scale\n" >> file;
 123.164 +printf "210 %.3f sub %.3f translate\n", bottom, left >> file;
 123.165 +printf "90 rotate\n" >> file;
 123.166 +
 123.167 +printf "/HelveticaBold findfont 5 scalefont setfont\n" >> file;
 123.168 +printf "%.3f %.3f moveto (%s) dup show\n", 0, sy + 5, title >> file;
 123.169 +
 123.170 +param period := floor((max{f in F} arr2[f]) / 60. + .5);
 123.171 +/* period duration, in hours */
 123.172 +
 123.173 +/* vertical bars */
 123.174 +printf ".8 .8 .8 setrgbcolor\n" >> file;
 123.175 +for {tt in 0..period}
 123.176 +{  printf "%s setlinewidth\n",
 123.177 +      if tt mod 24 = 0 then ".5" else "0" >> file;
 123.178 +   printf "newpath %.3f %.3f moveto %.3f %.3f lineto stroke\n",
 123.179 +      tt * (sx / period), 0, tt * (sx / period),
 123.180 +      sy + (if tt mod 24 = 0 then 2) >> file;
 123.181 +}
 123.182 +
 123.183 +/* rosters */
 123.184 +for {a in A}
 123.185 +{  printf "0 0 0 setrgbcolor\n" >> file;
 123.186 +   printf "0 setlinewidth\n" >> file;
 123.187 +   printf "newpath %.3f %.3f moveto %.3f %.3f lineto stroke\n",
 123.188 +      0, sy - gap * (a - 1), sx, sy - gap * (a - 1) >> file;
 123.189 +   printf "/Dingbats findfont 4 scalefont setfont\n" >> file;
 123.190 +   printf "%.3f %.3f moveto <28> dup show\n",
 123.191 +      -4, sy - gap * (a - 1) - 1.4, a >> file;
 123.192 +   printf "/Helvetica findfont 3 scalefont setfont\n" >> file;
 123.193 +   printf "%.3f %.3f moveto (%2d) dup show\n",
 123.194 +      -9, sy - gap * (a - 1) - 1.2, a >> file;
 123.195 +   for {f in F: tail[f] == a}
 123.196 +   {  printf "0 0 %s setrgbcolor\n",
 123.197 +         if hub[f] = 1 then "0" else ".8" >> file;
 123.198 +      printf "1 setlinewidth\n" >> file;
 123.199 +      printf "newpath %.3f %.3f moveto %.3f %.3f lineto stroke\n",
 123.200 +         dep1[f] / 60 * (sx / period), sy - gap * (a - 1),
 123.201 +         arr2[f] / 60 * (sx / period), sy - gap * (a - 1) >> file;
 123.202 +      printf "/Helvetica findfont 1.8 scalefont setfont\n" >> file;
 123.203 +      printf "%.3f %.3f moveto (%02d:%02d %s) dup show\n",
 123.204 +         dep1[f] / 60 * (sx / period), sy - gap * (a - 1) + .8,
 123.205 +         (dep1[f] mod 1440) div 60, (dep1[f] mod 1440) mod 60,
 123.206 +         dest[f] >> file;
 123.207 +      printf "%.3f %.3f moveto (%d %02d:%02d) dup show\n",
 123.208 +         dep1[f] / 60 * (sx / period), sy - gap * (a - 1) - 2.1,
 123.209 +         fno1[f],
 123.210 +         (arr2[f] mod 1440) div 60, (arr2[f] mod 1440) mod 60 >> file;
 123.211 +   }
 123.212 +}
 123.213 +
 123.214 +printf "showpage\n" >> file;
 123.215 +printf "%%%%EOF\n" >> file;
 123.216 +
 123.217 +########################################################################
 123.218 +
 123.219 +data;
 123.220 +
 123.221 +param title := "Tu-154 [from 2008-08-18 to 2008-08-24]";
 123.222 +
 123.223 +param nf := 261;
 123.224 +
 123.225 +param : hub dest fno1 dep1  arr1  fno2 dep2  arr2 :=
 123.226 +      1  1  IKT  743   195   520  744   610   970
 123.227 +      2  1  OMS  815   205   405  816   485   700
 123.228 +      3  1  CEK  897   205   360  898   430   595
 123.229 +      4  1  KRR  763   260   400  764   480   610
 123.230 +      5  2  SIP  133   280   420  134   500   620
 123.231 +      6  2  BUD  131   290   450  132   520   675
 123.232 +      7  1  AAQ  701   305   440  702   510   640
 123.233 +      8  1  MRV  785   310   440  786   520   650
 123.234 +      9  2  WAW  101   355   475  102   540   660
 123.235 +     10  2  GYD  147   370   550  148   675   860
 123.236 +     11  1  AER  869   385   530  870   655   795
 123.237 +     12  1  KRR  765   430   560  766   630   760
 123.238 +     13  1  AAQ  703   520   660  704   740   850
 123.239 +     14  1  LED  845   530   620  846   690   775
 123.240 +     15  1  KRR  767   540   675  768   765   895
 123.241 +     16  2  KBP  183   665   760  184   850   940
 123.242 +     17  1  MRV  787   755   905  788   985  1135
 123.243 +     18  1  KRR  771   810   940  772  1030  1165
 123.244 +     19  1  LED  849   825   900  850   960  1095
 123.245 +     20  2  IST  209   880  1050  210  1120  1280
 123.246 +     21  1  AER  873   885  1030  874  1760  1900
 123.247 +     22  1  ASF  711   995  1145  712  1640  1795
 123.248 +     23  2  ULN  563   995  1335  564  1415  1815
 123.249 +     24  2  OTP  151  1020  1175  152  1800  1940
 123.250 +     25  2  BEY  509  1025  1265  510  1350  1580
 123.251 +     26  2  OSL  211  1060  1220  212  1860  2015
 123.252 +     27  1  IKT  739  1085  1420  740  1510  1870
 123.253 +     28  1  KRR  773  1095  1240  774  1620  1765
 123.254 +     29  1  SGC  877  1120  1315  878  1395  1625
 123.255 +     30  1  LED  857  1150  1230  858  1610  1690
 123.256 +     31  1  CEK  899  1230  1385  900  1455  1620
 123.257 +     32  1  PEE  821  1235  1390  822  1450  1600
 123.258 +     33  2  TBS  197  1240  1405  198  1560  1715
 123.259 +     34  1  UFA  891  1275  1405  892  1475  1610
 123.260 +     35  1  KJA  781  1300  1570  782  1680  1990
 123.261 +     36  1  IKT  743  1635  1960  744  2050  2410
 123.262 +     37  1  OMS  815  1645  1845  816  1925  2140
 123.263 +     38  1  CEK  897  1645  1800  898  1870  2035
 123.264 +     39  1  KRR  763  1700  1840  764  1920  2050
 123.265 +     40  2  SIP  133  1720  1860  134  1940  2060
 123.266 +     41  2  BUD  131  1730  1890  132  1960  2115
 123.267 +     42  1  AAQ  701  1745  1880  702  1950  2080
 123.268 +     43  1  MRV  785  1750  1880  786  1960  2090
 123.269 +     44  2  WAW  101  1795  1915  102  1980  2100
 123.270 +     45  2  GYD  147  1810  1990  148  2115  2300
 123.271 +     46  1  AER  869  1825  1970  870  2095  2235
 123.272 +     47  2  EVN  193  1850  2030  194  2105  2275
 123.273 +     48  1  KRR  765  1870  2000  766  2070  2200
 123.274 +     49  1  AAQ  703  1960  2100  704  2180  2290
 123.275 +     50  1  LED  845  1970  2060  846  2130  2215
 123.276 +     51  1  KRR  767  1980  2115  768  2205  2335
 123.277 +     52  2  KBP  183  2105  2200  184  2290  2380
 123.278 +     53  1  MRV  787  2195  2345  788  2425  2575
 123.279 +     54  1  KRR  771  2250  2380  772  2470  2605
 123.280 +     55  1  LED  849  2265  2340  850  2400  2535
 123.281 +     56  2  IST  209  2320  2490  210  2560  2720
 123.282 +     57  1  AER  873  2325  2470  874  3200  3340
 123.283 +     58  2  ULN  563  2435  2775  564  2855  3255
 123.284 +     59  1  ASF  711  2435  2585  712  3080  3235
 123.285 +     60  2  DAM  517  2465  2705  518  2790  3020
 123.286 +     61  2  OSL  211  2500  2660  212  3300  3455
 123.287 +     62  2  KBP  185  2510  2610  186  3160  3250
 123.288 +     63  1  IKT  739  2525  2860  740  2950  3310
 123.289 +     64  1  KRR  773  2535  2680  774  3060  3205
 123.290 +     65  1  SGC  877  2560  2755  878  2835  3065
 123.291 +     66  1  LED  857  2590  2670  858  3050  3130
 123.292 +     67  1  CEK  899  2670  2825  900  2895  3060
 123.293 +     68  1  PEE  821  2675  2830  822  2890  3040
 123.294 +     69  2  TBS  197  2680  2845  198  3000  3155
 123.295 +     70  1  UFA  891  2715  2845  892  2915  3050
 123.296 +     71  1  KJA  781  2740  3010  782  3120  3430
 123.297 +     72  1  IKT  743  3075  3400  744  3490  3850
 123.298 +     73  1  CEK  897  3085  3240  898  3310  3475
 123.299 +     74  1  OMS  815  3085  3285  816  3365  3580
 123.300 +     75  1  KRR  763  3140  3280  764  3360  3490
 123.301 +     76  2  SIP  133  3160  3300  134  3380  3500
 123.302 +     77  2  BUD  131  3170  3330  132  3400  3555
 123.303 +     78  1  AAQ  701  3185  3320  702  3390  3520
 123.304 +     79  1  MRV  785  3190  3320  786  3400  3530
 123.305 +     80  2  WAW  101  3235  3355  102  3420  3540
 123.306 +     81  2  FRU  181  3245  3495  182  3590  3860
 123.307 +     82  2  GYD  147  3250  3430  148  3555  3740
 123.308 +     83  1  AER  869  3265  3410  870  3535  3675
 123.309 +     84  1  KRR  765  3310  3440  766  3510  3640
 123.310 +     85  1  AAQ  703  3400  3540  704  3620  3730
 123.311 +     86  1  LED  845  3410  3500  846  3570  3655
 123.312 +     87  1  KRR  767  3420  3555  768  3645  3775
 123.313 +     88  2  KBP  183  3545  3640  184  3730  3820
 123.314 +     89  1  MRV  787  3635  3785  788  3865  4015
 123.315 +     90  1  KRR  771  3690  3820  772  3910  4045
 123.316 +     91  1  LED  849  3705  3780  850  3840  3975
 123.317 +     92  2  IST  209  3760  3930  210  4000  4160
 123.318 +     93  1  AER  873  3765  3910  874  4640  4780
 123.319 +     94  2  ULN  563  3875  4215  564  4295  4695
 123.320 +     95  1  ASF  711  3875  4025  712  4520  4675
 123.321 +     96  2  OTP  151  3900  4055  152  4680  4820
 123.322 +     97  2  BEY  509  3905  4145  510  4230  4460
 123.323 +     98  2  OSL  211  3940  4100  212  4740  4895
 123.324 +     99  2  KBP  185  3950  4050  186  4600  4690
 123.325 +    100  1  IKT  739  3965  4300  740  4390  4750
 123.326 +    101  1  KRR  773  3975  4120  774  4500  4645
 123.327 +    102  1  SGC  877  4000  4195  878  4275  4505
 123.328 +    103  1  LED  857  4030  4110  858  4490  4570
 123.329 +    104  1  CEK  899  4110  4265  900  4335  4500
 123.330 +    105  1  PEE  821  4115  4270  822  4330  4480
 123.331 +    106  2  TBS  197  4120  4285  198  4440  4595
 123.332 +    107  1  UFA  891  4155  4285  892  4355  4490
 123.333 +    108  1  KJA  781  4180  4450  782  4560  4870
 123.334 +    109  1  IKT  743  4515  4840  744  4930  5290
 123.335 +    110  1  OMS  815  4525  4725  816  4805  5020
 123.336 +    111  1  CEK  897  4525  4680  898  4750  4915
 123.337 +    112  1  KRR  763  4580  4720  764  4800  4930
 123.338 +    113  2  SIP  133  4600  4740  134  4820  4940
 123.339 +    114  2  BUD  131  4610  4770  132  4840  4995
 123.340 +    115  1  AAQ  701  4625  4760  702  4830  4960
 123.341 +    116  1  MRV  785  4630  4760  786  4840  4970
 123.342 +    117  2  WAW  101  4675  4795  102  4860  4980
 123.343 +    118  2  GYD  147  4690  4870  148  4995  5180
 123.344 +    119  1  AER  869  4705  4850  870  4975  5115
 123.345 +    120  2  EVN  193  4730  4910  194  4985  5155
 123.346 +    121  1  KRR  765  4750  4880  766  4950  5080
 123.347 +    122  1  AAQ  703  4840  4980  704  5060  5170
 123.348 +    123  1  LED  845  4850  4940  846  5010  5095
 123.349 +    124  1  KRR  767  4860  4995  768  5085  5215
 123.350 +    125  2  KBP  183  4985  5080  184  5170  5260
 123.351 +    126  1  MRV  787  5075  5225  788  5305  5455
 123.352 +    127  1  KRR  771  5130  5260  772  5350  5485
 123.353 +    128  1  LED  849  5145  5220  850  5280  5415
 123.354 +    129  2  IST  209  5200  5370  210  5440  5600
 123.355 +    130  1  AER  873  5205  5350  874  6080  6220
 123.356 +    131  1  ASF  711  5315  5465  712  5960  6115
 123.357 +    132  2  ULN  563  5315  5655  564  5735  6135
 123.358 +    133  2  DAM  517  5345  5585  518  5670  5900
 123.359 +    134  2  OSL  211  5380  5540  212  6180  6335
 123.360 +    135  2  KBP  185  5390  5490  186  6040  6130
 123.361 +    136  1  IKT  739  5405  5740  740  5830  6190
 123.362 +    137  1  KRR  773  5415  5560  774  5940  6085
 123.363 +    138  1  SGC  877  5440  5635  878  5715  5945
 123.364 +    139  1  LED  857  5470  5550  858  5930  6010
 123.365 +    140  1  CEK  899  5550  5705  900  5775  5940
 123.366 +    141  1  PEE  821  5555  5710  822  5770  5920
 123.367 +    142  2  TBS  197  5560  5725  198  5880  6035
 123.368 +    143  1  UFA  891  5595  5725  892  5795  5930
 123.369 +    144  1  KJA  781  5620  5890  782  6000  6310
 123.370 +    145  1  IKT  743  5955  6280  744  6370  6730
 123.371 +    146  1  OMS  815  5965  6165  816  6245  6460
 123.372 +    147  1  CEK  897  5965  6120  898  6190  6355
 123.373 +    148  1  KRR  763  6020  6160  764  6240  6370
 123.374 +    149  2  SIP  133  6040  6180  134  6260  6380
 123.375 +    150  2  BUD  131  6050  6210  132  6280  6435
 123.376 +    151  1  AAQ  701  6065  6200  702  6270  6400
 123.377 +    152  1  MRV  785  6070  6200  786  6280  6410
 123.378 +    153  2  WAW  101  6115  6235  102  6300  6420
 123.379 +    154  2  FRU  181  6125  6375  182  6470  6740
 123.380 +    155  2  GYD  147  6130  6310  148  6435  6620
 123.381 +    156  1  AER  869  6145  6290  870  6415  6555
 123.382 +    157  2  EVN  193  6170  6350  194  6425  6595
 123.383 +    158  1  KRR  765  6190  6320  766  6390  6520
 123.384 +    159  1  AAQ  703  6280  6420  704  6500  6610
 123.385 +    160  1  LED  845  6290  6380  846  6450  6535
 123.386 +    161  1  KRR  767  6300  6435  768  6525  6655
 123.387 +    162  2  KBP  183  6425  6520  184  6610  6700
 123.388 +    163  2  AYT  223  6500  6690  224  6750  6940
 123.389 +    164  1  AER  867  6510  6660  868  6730  6880
 123.390 +    165  1  MRV  787  6515  6665  788  6745  6895
 123.391 +    166  1  KRR  771  6570  6700  772  6790  6925
 123.392 +    167  1  LED  849  6585  6660  850  6720  6855
 123.393 +    168  2  IST  209  6640  6810  210  6880  7040
 123.394 +    169  1  AER  873  6645  6790  874  7520  7660
 123.395 +    170  1  ASF  711  6755  6905  712  7400  7555
 123.396 +    171  2  ULN  563  6755  7095  564  7175  7575
 123.397 +    172  2  OTP  151  6780  6935  152  7560  7700
 123.398 +    173  2  BEY  509  6785  7025  510  7110  7340
 123.399 +    174  2  OSL  211  6820  6980  212  7620  7775
 123.400 +    175  2  KBP  185  6830  6930  186  7480  7570
 123.401 +    176  1  IKT  739  6845  7180  740  7270  7630
 123.402 +    177  1  KRR  773  6855  7000  774  7380  7525
 123.403 +    178  1  SGC  877  6880  7075  878  7155  7385
 123.404 +    179  1  LED  857  6910  6990  858  7370  7450
 123.405 +    180  1  CEK  899  6990  7145  900  7215  7380
 123.406 +    181  1  PEE  821  6995  7150  822  7210  7360
 123.407 +    182  2  TBS  197  7000  7165  198  7320  7475
 123.408 +    183  1  UFA  891  7035  7165  892  7235  7370
 123.409 +    184  1  KJA  781  7060  7330  782  7440  7750
 123.410 +    185  1  IKT  743  7395  7720  744  7810  8170
 123.411 +    186  1  CEK  897  7405  7560  898  7630  7795
 123.412 +    187  1  KRR  763  7460  7600  764  7680  7810
 123.413 +    188  2  SIP  133  7480  7620  134  7700  7820
 123.414 +    189  2  BUD  131  7490  7650  132  7720  7875
 123.415 +    190  1  AAQ  701  7505  7640  702  7710  7840
 123.416 +    191  1  MRV  785  7510  7640  786  7720  7850
 123.417 +    192  2  IST  207  7545  7720  208  7795  7985
 123.418 +    193  2  WAW  101  7555  7675  102  7740  7860
 123.419 +    194  2  GYD  147  7570  7750  148  7875  8060
 123.420 +    195  1  AER  869  7585  7730  870  7855  7995
 123.421 +    196  2  AYT  221  7610  7800  222  7895  8085
 123.422 +    197  2  EVN  193  7610  7790  194  7865  8035
 123.423 +    198  1  KRR  765  7630  7760  766  7830  7960
 123.424 +    199  1  AAQ  703  7720  7860  704  7940  8050
 123.425 +    200  1  LED  845  7730  7820  846  7890  7975
 123.426 +    201  1  KRR  767  7740  7875  768  7965  8095
 123.427 +    202  2  KBP  183  7865  7960  184  8050  8140
 123.428 +    203  2  AYT  223  7940  8130  224  8190  8380
 123.429 +    204  1  MRV  787  7955  8105  788  8185  8335
 123.430 +    205  1  KRR  771  8010  8140  772  8230  8365
 123.431 +    206  1  LED  849  8025  8100  850  8160  8295
 123.432 +    207  2  IST  209  8080  8250  210  8320  8480
 123.433 +    208  1  AER  873  8085  8230  874  8960  9100
 123.434 +    209  1  ASF  711  8195  8345  712  8840  8995
 123.435 +    210  2  ULN  563  8195  8535  564  8615  9015
 123.436 +    211  1  KJA  779  8230  8500  780  8575  8870
 123.437 +    212  2  OSL  211  8260  8420  212  9060  9215
 123.438 +    213  2  KBP  185  8270  8370  186  8920  9010
 123.439 +    214  1  IKT  739  8285  8620  740  8710  9070
 123.440 +    215  1  KRR  773  8295  8440  774  8820  8965
 123.441 +    216  1  SGC  877  8320  8515  878  8595  8825
 123.442 +    217  1  LED  857  8350  8430  858  8810  8890
 123.443 +    218  1  CEK  899  8430  8585  900  8655  8820
 123.444 +    219  1  PEE  821  8435  8590  822  8650  8800
 123.445 +    220  2  TBS  197  8440  8605  198  8760  8915
 123.446 +    221  1  UFA  891  8475  8605  892  8675  8810
 123.447 +    222  1  KJA  781  8500  8770  782  8880  9190
 123.448 +    223  1  IKT  743  8835  9160  744  9250  9610
 123.449 +    224  1  OMS  815  8845  9045  816  9125  9340
 123.450 +    225  1  CEK  897  8845  9000  898  9070  9235
 123.451 +    226  1  KRR  763  8900  9040  764  9120  9250
 123.452 +    227  2  SIP  133  8920  9060  134  9140  9260
 123.453 +    228  2  BUD  131  8930  9090  132  9160  9315
 123.454 +    229  1  AAQ  701  8945  9080  702  9150  9280
 123.455 +    230  1  MRV  785  8950  9080  786  9160  9290
 123.456 +    231  2  IST  207  8985  9160  208  9235  9425
 123.457 +    232  2  WAW  101  8995  9115  102  9180  9300
 123.458 +    233  2  FRU  181  9005  9255  182  9350  9620
 123.459 +    234  2  GYD  147  9010  9190  148  9315  9500
 123.460 +    235  1  AER  869  9025  9170  870  9295  9435
 123.461 +    236  2  EVN  193  9050  9230  194  9305  9475
 123.462 +    237  1  KRR  765  9070  9200  766  9270  9400
 123.463 +    238  1  AAQ  703  9160  9300  704  9380  9490
 123.464 +    239  1  LED  845  9170  9260  846  9330  9415
 123.465 +    240  1  KRR  767  9180  9315  768  9405  9535
 123.466 +    241  2  KBP  183  9305  9400  184  9490  9580
 123.467 +    242  2  AYT  223  9380  9570  224  9630  9820
 123.468 +    243  1  MRV  787  9395  9545  788  9625  9775
 123.469 +    244  1  KRR  771  9450  9580  772  9670  9805
 123.470 +    245  1  LED  849  9465  9540  850  9600  9735
 123.471 +    246  2  IST  209  9520  9690  210  9760  9920
 123.472 +    247  1  AER  873  9525  9670  874 10400 10540
 123.473 +    248  1  ASF  711  9635  9785  712 10280 10435
 123.474 +    249  2  ULN  563  9635  9975  564 10055 10455
 123.475 +    250  2  OTP  151  9660  9815  152 10440 10580
 123.476 +    251  2  DAM  517  9665  9905  518  9990 10220
 123.477 +    252  2  OSL  211  9700  9860  212 10500 10655
 123.478 +    253  2  KBP  185  9710  9810  186 10360 10450
 123.479 +    254  1  IKT  739  9725 10060  740 10150 10510
 123.480 +    255  1  KRR  773  9735  9880  774 10260 10405
 123.481 +    256  1  SGC  877  9760  9955  878 10035 10265
 123.482 +    257  1  LED  857  9790  9870  858 10250 10330
 123.483 +    258  1  CEK  899  9870 10025  900 10095 10260
 123.484 +    259  1  PEE  821  9875 10030  822 10090 10240
 123.485 +    260  1  UFA  891  9915 10045  892 10115 10250
 123.486 +    261  1  KJA  781  9940 10210  782 10320 10630
 123.487 +;
 123.488 +
 123.489 +end;
   124.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   124.2 +++ b/examples/todd.mod	Mon Dec 06 13:09:21 2010 +0100
   124.3 @@ -0,0 +1,36 @@
   124.4 +/* TODD, a class of hard instances of zero-one knapsack problems */
   124.5 +
   124.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
   124.7 +
   124.8 +/* Chvatal describes a class of instances of zero-one knapsack problems
   124.9 +   due to Todd. He shows that a wide class of algorithms - including all
  124.10 +   based on branch and bound or dynamic programming - find it difficult
  124.11 +   to solve problems in the Todd class. More exactly, the time required
  124.12 +   by these algorithms to solve instances of problems that belong to the
  124.13 +   Todd class grows as an exponential function of the problem size.
  124.14 +
  124.15 +   Reference:
  124.16 +   Chvatal V. (1980), Hard knapsack problems, Op. Res. 28, 1402-1411. */
  124.17 +
  124.18 +param n > 0 integer;
  124.19 +
  124.20 +param log2_n := log(n) / log(2);
  124.21 +
  124.22 +param k := floor(log2_n);
  124.23 +
  124.24 +param a{j in 1..n} := 2 ** (k + n + 1) + 2 ** (k + n + 1 - j) + 1;
  124.25 +
  124.26 +param b := 0.5 * floor(sum{j in 1..n} a[j]);
  124.27 +
  124.28 +var x{1..n} binary;
  124.29 +
  124.30 +maximize obj: sum{j in 1..n} a[j] * x[j];
  124.31 +
  124.32 +s.t. cap: sum{j in 1..n} a[j] * x[j] <= b;
  124.33 +
  124.34 +data;
  124.35 +
  124.36 +param n := 15;
  124.37 +/* change this parameter to choose a particular instance */
  124.38 +
  124.39 +end;
   125.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   125.2 +++ b/examples/train.mod	Mon Dec 06 13:09:21 2010 +0100
   125.3 @@ -0,0 +1,281 @@
   125.4 +# TRAIN, a model of railroad passenger car allocation
   125.5 +#
   125.6 +# References:
   125.7 +# Robert Fourer, David M. Gay and Brian W. Kernighan, "A Modeling Language
   125.8 +# for Mathematical Programming." Management Science 36 (1990) 519-554.
   125.9 +
  125.10 +###  SCHEDULE SETS AND PARAMETERS  ###
  125.11 +
  125.12 +set cities;
  125.13 +
  125.14 +set links within {c1 in cities, c2 in cities: c1 <> c2};
  125.15 +
  125.16 +                        # Set of cities, and set of intercity links
  125.17 +
  125.18 +param last > 0 integer; # Number of time intervals in a day
  125.19 +
  125.20 +set times := 1..last;   # Set of time intervals in a day
  125.21 +
  125.22 +set schedule within
  125.23 +      {c1 in cities, t1 in times,
  125.24 +       c2 in cities, t2 in times: (c1,c2) in links};
  125.25 +
  125.26 +                        # Member (c1,t1,c2,t2) of this set represents
  125.27 +                        # a train that leaves city c1 at time t1
  125.28 +                        # and arrives in city c2 at time t2
  125.29 +
  125.30 +###  DEMAND PARAMETERS  ###
  125.31 +
  125.32 +param section > 0 integer;
  125.33 +
  125.34 +                        # Maximum number of cars in one section of a train
  125.35 +
  125.36 +param demand {schedule} > 0;
  125.37 +
  125.38 +                        # For each scheduled train:
  125.39 +                        # the smallest number of cars that
  125.40 +                        # can meet demand for the train
  125.41 +
  125.42 +param low {(c1,t1,c2,t2) in schedule} := ceil(demand[c1,t1,c2,t2]);
  125.43 +
  125.44 +                        # Minimum number of cars needed to meet demand
  125.45 +
  125.46 +param high {(c1,t1,c2,t2) in schedule}
  125.47 +
  125.48 +   := max (2, min (ceil(2*demand[c1,t1,c2,t2]),
  125.49 +                   section*ceil(demand[c1,t1,c2,t2]/section) ));
  125.50 +
  125.51 +                        # Maximum number of cars allowed on a train:
  125.52 +                        # 2 if demand is for less than one car;
  125.53 +                        # otherwise, lesser of
  125.54 +                        # number of cars needed to hold twice the demand, and
  125.55 +                        # number of cars in minimum number of sections needed
  125.56 +
  125.57 +###  DISTANCE PARAMETERS  ###
  125.58 +
  125.59 +param dist_table {links} >= 0 default 0.0;
  125.60 +
  125.61 +param distance {(c1,c2) in links} > 0
  125.62 +   := if dist_table[c1,c2] > 0 then dist_table[c1,c2] else dist_table[c2,c1];
  125.63 +
  125.64 +                        # Inter-city distances: distance[c1,c2] is miles
  125.65 +                        # between city c1 and city c2
  125.66 +
  125.67 +###  VARIABLES  ###
  125.68 +
  125.69 +var U 'cars stored' {cities,times} >= 0;
  125.70 +
  125.71 +                        # u[c,t] is the number of unused cars stored
  125.72 +                        # at city c in the interval beginning at time t
  125.73 +
  125.74 +var X 'cars in train' {schedule} >= 0;
  125.75 +
  125.76 +                        # x[c1,t1,c2,t2] is the number of cars assigned to
  125.77 +                        # the scheduled train that leaves c1 at t1 and
  125.78 +                        # arrives in c2 at t2
  125.79 +
  125.80 +###  OBJECTIVES  ###
  125.81 +
  125.82 +minimize cars:
  125.83 +       sum {c in cities} U[c,last] +
  125.84 +       sum {(c1,t1,c2,t2) in schedule: t2 < t1} X[c1,t1,c2,t2];
  125.85 +
  125.86 +                        # Number of cars in the system:
  125.87 +                        # sum of unused cars and cars in trains during
  125.88 +                        # the last time interval of the day
  125.89 +
  125.90 +minimize miles:
  125.91 +       sum {(c1,t1,c2,t2) in schedule} distance[c1,c2] * X[c1,t1,c2,t2];
  125.92 +
  125.93 +                        # Total car-miles run by all scheduled trains in a day
  125.94 +
  125.95 +###  CONSTRAINTS  ###
  125.96 +
  125.97 +account {c in cities, t in times}:
  125.98 +
  125.99 +  U[c,t] = U[c, if t > 1 then t-1 else last] +
 125.100 +
 125.101 +      sum {(c1,t1,c,t) in schedule} X[c1,t1,c,t] -
 125.102 +      sum {(c,t,c2,t2) in schedule} X[c,t,c2,t2];
 125.103 +
 125.104 +                        # For every city and time:
 125.105 +                        # unused cars in the present interval must equal
 125.106 +                        # unused cars in the previous interval,
 125.107 +                        # plus cars just arriving in trains,
 125.108 +                        # minus cars just leaving in trains
 125.109 +
 125.110 +satisfy {(c1,t1,c2,t2) in schedule}:
 125.111 +
 125.112 +       low[c1,t1,c2,t2] <= X[c1,t1,c2,t2] <= high[c1,t1,c2,t2];
 125.113 +
 125.114 +                        # For each scheduled train:
 125.115 +                        # number of cars must meet demand,
 125.116 +                        # but must not be so great that unnecessary
 125.117 +                        # sections are run
 125.118 +
 125.119 +###  DATA  ###
 125.120 +
 125.121 +data;
 125.122 +
 125.123 +set cities := BO NY PH WA ;
 125.124 +
 125.125 +set links := (BO,NY) (NY,PH) (PH,WA)
 125.126 +             (NY,BO) (PH,NY) (WA,PH) ;
 125.127 +
 125.128 +param dist_table := [*,*]  BO NY  232
 125.129 +                           NY PH   90
 125.130 +                           PH WA  135 ;
 125.131 +
 125.132 +param last := 48 ;
 125.133 +
 125.134 +param section := 14 ;
 125.135 +
 125.136 +set schedule :=
 125.137 +
 125.138 +   (WA,*,PH,*)   2  5     6  9     8 11    10 13
 125.139 +                12 15    13 16    14 17    15 18
 125.140 +                16 19    17 20    18 21    19 22
 125.141 +                20 23    21 24    22 25    23 26
 125.142 +                24 27    25 28    26 29    27 30
 125.143 +                28 31    29 32    30 33    31 34
 125.144 +                32 35    33 36    34 37    35 38
 125.145 +                36 39    37 40    38 41    39 42
 125.146 +                40 43    41 44    42 45    44 47
 125.147 +                46  1
 125.148 +
 125.149 +   (PH,*,NY,*)   1  3     5  7     9 11    11 13
 125.150 +                13 15    14 16    15 17    16 18
 125.151 +                17 19    18 20    19 21    20 22
 125.152 +                21 23    22 24    23 25    24 26
 125.153 +                25 27    26 28    27 29    28 30
 125.154 +                29 31    30 32    31 33    32 34
 125.155 +                33 35    34 36    35 37    36 38
 125.156 +                37 39    38 40    39 41    40 42
 125.157 +                41 43    42 44    43 45    44 46
 125.158 +                45 47    47  1
 125.159 +
 125.160 +   (NY,*,BO,*)  10 16    12 18    14 20    15 21
 125.161 +                16 22    17 23    18 24    19 25
 125.162 +                20 26    21 27    22 28    23 29
 125.163 +                24 30    25 31    26 32    27 33
 125.164 +                28 34    29 35    30 36    31 37
 125.165 +                32 38    33 39    34 40    35 41
 125.166 +                36 42    37 43    38 44    39 45
 125.167 +                40 46    41 47    42 48    43  1
 125.168 +                44  2    45  3    46  4    48  6
 125.169 +
 125.170 +   (BO,*,NY,*)   7 13     9 15    11 17    12 18
 125.171 +                13 19    14 20    15 21    16 22
 125.172 +                17 23    18 24    19 25    20 26
 125.173 +                21 27    22 28    23 29    24 30
 125.174 +                25 31    26 32    27 33    28 34
 125.175 +                29 35    30 36    31 37    32 38
 125.176 +                33 39    34 40    35 41    36 42
 125.177 +                37 43    38 44    39 45    40 46
 125.178 +                41 47    43  1    45  3    47  5
 125.179 +
 125.180 +   (NY,*,PH,*)   1  3    12 14    13 15    14 16
 125.181 +                15 17    16 18    17 19    18 20
 125.182 +                19 21    20 22    21 23    22 24
 125.183 +                23 25    24 26    25 27    26 28
 125.184 +                27 29    28 30    29 31    30 32
 125.185 +                31 33    32 34    33 35    34 36
 125.186 +                35 37    36 38    37 39    38 40
 125.187 +                39 41    40 42    41 43    42 44
 125.188 +                43 45    44 46    45 47    46 48
 125.189 +                47  1
 125.190 +
 125.191 +   (PH,*,WA,*)   1  4    14 17    15 18    16 19
 125.192 +                17 20    18 21    19 22    20 23
 125.193 +                21 24    22 25    23 26    24 27
 125.194 +                25 28    26 29    27 30    28 31
 125.195 +                29 32    30 33    31 34    32 35
 125.196 +                33 36    34 37    35 38    36 39
 125.197 +                37 40    38 41    39 42    40 43
 125.198 +                41 44    42 45    43 46    44 47
 125.199 +                45 48    46  1    47  2    ;
 125.200 +
 125.201 +param demand :=
 125.202 +
 125.203 + [WA,*,PH,*]   2  5    .55      6  9    .01      8 11    .01
 125.204 +              10 13    .13     12 15   1.59     13 16   1.69
 125.205 +              14 17   5.19     15 18   3.55     16 19   6.29
 125.206 +              17 20   4.00     18 21   5.80     19 22   3.40
 125.207 +              20 23   4.88     21 24   2.92     22 25   4.37
 125.208 +              23 26   2.80     24 27   4.23     25 28   2.88
 125.209 +              26 29   4.33     27 30   3.11     28 31   4.64
 125.210 +              29 32   3.44     30 33   4.95     31 34   3.73
 125.211 +              32 35   5.27     33 36   3.77     34 37   4.80
 125.212 +              35 38   3.31     36 39   3.89     37 40   2.65
 125.213 +              38 41   3.01     39 42   2.04     40 43   2.31
 125.214 +              41 44   1.52     42 45   1.75     44 47   1.88
 125.215 +              46  1   1.05
 125.216 +
 125.217 + [PH,*,NY,*]   1  3   1.05      5  7    .43      9 11    .20
 125.218 +              11 13    .21     13 15    .40     14 16   6.49
 125.219 +              15 17  16.40     16 18   9.48     17 19  17.15
 125.220 +              18 20   9.31     19 21  15.20     20 22   8.21
 125.221 +              21 23  13.32     22 24   7.35     23 25  11.83
 125.222 +              24 26   6.61     25 27  10.61     26 28   6.05
 125.223 +              27 29   9.65     28 30   5.61     29 31   9.25
 125.224 +              30 32   5.40     31 33   8.24     32 34   4.84
 125.225 +              33 35   7.44     34 36   4.44     35 37   6.80
 125.226 +              36 38   4.11     37 39   6.25     38 40   3.69
 125.227 +              39 41   5.55     40 42   3.29     41 43   4.77
 125.228 +              42 44   2.91     43 45   4.19     44 46   2.53
 125.229 +              45 47   4.00     47 1    1.65
 125.230 +
 125.231 + [NY,*,BO,*]  10 16   1.23     12 18   3.84     14 20   4.08
 125.232 +              15 21   1.47     16 22   2.96     17 23   1.60
 125.233 +              18 24   2.95     19 25   1.71     20 26   2.81
 125.234 +              21 27   1.77     22 28   2.87     23 29   1.84
 125.235 +              24 30   2.95     25 31   1.91     26 32   3.12
 125.236 +              27 33   1.93     28 34   3.31     29 35   2.00
 125.237 +              30 36   3.40     31 37   2.08     32 38   3.41
 125.238 +              33 39   2.69     34 40   4.45     35 41   2.32
 125.239 +              36 42   3.40     37 43   1.80     38 44   2.63
 125.240 +              39 45   1.52     40 46   2.23     41 47   1.25
 125.241 +              42 48   1.79     43  1    .97     44  2   1.28
 125.242 +              45  3    .48     46  4    .68     48  6    .08
 125.243 +
 125.244 + [BO,*,NY,*]   7 13    .03      9 15   1.29     11 17   4.59
 125.245 +              12 18   2.56     13 19   3.92     14 20   2.37
 125.246 +              15 21   3.81     16 22   2.24     17 23   3.51
 125.247 +              18 24   2.13     19 25   3.28     20 26   2.05
 125.248 +              21 27   3.15     22 28   1.99     23 29   3.09
 125.249 +              24 30   1.93     25 31   3.19     26 32   1.91
 125.250 +              27 33   3.21     28 34   1.85     29 35   3.21
 125.251 +              30 36   1.71     31 37   3.04     32 38   2.08
 125.252 +              33 39   3.13     34 40   1.96     35 41   2.53
 125.253 +              36 42   1.43     37 43   2.04     38 44   1.12
 125.254 +              39 45   1.71     40 46    .91     41 47   1.32
 125.255 +              43  1   1.80     45  3   1.13     47  5    .23
 125.256 +
 125.257 + [NY,*,PH,*]   1  3    .04     12 14   4.68     13 15   5.61
 125.258 +              14 16   3.56     15 17   5.81     16 18   3.81
 125.259 +              17 19   6.31     18 20   4.07     19 21   7.33
 125.260 +              20 22   4.55     21 23   7.37     22 24   4.73
 125.261 +              23 25   7.61     24 26   4.92     25 27   7.91
 125.262 +              26 28   5.19     27 29   8.40     28 30   5.53
 125.263 +              29 31   9.32     30 32   5.51     31 33  10.33
 125.264 +              32 34   9.21     33 35  18.95     34 36  11.23
 125.265 +              35 37  16.85     36 38   7.29     37 39  10.89
 125.266 +              38 40   5.41     39 41   8.21     40 42   4.52
 125.267 +              41 43   6.99     42 44   3.92     43 45   6.21
 125.268 +              44 46   3.44     45 47   5.17     46 48   2.55
 125.269 +              47  1   1.24
 125.270 +
 125.271 + [PH,*,WA,*]   1  4    .20     14 17   4.49     15 18   3.53
 125.272 +              16 19   2.67     17 20   3.83     18 21   3.01
 125.273 +              19 22   4.12     20 23   3.15     21 24   4.67
 125.274 +              22 25   3.20     23 26   4.23     24 27   2.87
 125.275 +              25 28   3.84     26 29   2.60     27 30   3.80
 125.276 +              28 31   2.77     29 32   4.31     30 33   3.16
 125.277 +              31 34   4.88     32 35   3.45     33 36   5.55
 125.278 +              34 37   3.52     35 38   6.11     36 39   3.32
 125.279 +              37 40   5.53     38 41   3.03     39 42   4.51
 125.280 +              40 43   2.53     41 44   3.39     42 45   1.93
 125.281 +              43 46   2.52     44 47   1.20     45 48   1.75
 125.282 +              46  1    .88     47  2    .87     ;
 125.283 +
 125.284 +end;
   126.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   126.2 +++ b/examples/transp.mod	Mon Dec 06 13:09:21 2010 +0100
   126.3 @@ -0,0 +1,63 @@
   126.4 +# A TRANSPORTATION PROBLEM
   126.5 +#
   126.6 +# This problem finds a least cost shipping schedule that meets
   126.7 +# requirements at markets and supplies at factories.
   126.8 +#
   126.9 +#  References:
  126.10 +#              Dantzig G B, "Linear Programming and Extensions."
  126.11 +#              Princeton University Press, Princeton, New Jersey, 1963,
  126.12 +#              Chapter 3-3.
  126.13 +
  126.14 +set I;
  126.15 +/* canning plants */
  126.16 +
  126.17 +set J;
  126.18 +/* markets */
  126.19 +
  126.20 +param a{i in I};
  126.21 +/* capacity of plant i in cases */
  126.22 +
  126.23 +param b{j in J};
  126.24 +/* demand at market j in cases */
  126.25 +
  126.26 +param d{i in I, j in J};
  126.27 +/* distance in thousands of miles */
  126.28 +
  126.29 +param f;
  126.30 +/* freight in dollars per case per thousand miles */
  126.31 +
  126.32 +param c{i in I, j in J} := f * d[i,j] / 1000;
  126.33 +/* transport cost in thousands of dollars per case */
  126.34 +
  126.35 +var x{i in I, j in J} >= 0;
  126.36 +/* shipment quantities in cases */
  126.37 +
  126.38 +minimize cost: sum{i in I, j in J} c[i,j] * x[i,j];
  126.39 +/* total transportation costs in thousands of dollars */
  126.40 +
  126.41 +s.t. supply{i in I}: sum{j in J} x[i,j] <= a[i];
  126.42 +/* observe supply limit at plant i */
  126.43 +
  126.44 +s.t. demand{j in J}: sum{i in I} x[i,j] >= b[j];
  126.45 +/* satisfy demand at market j */
  126.46 +
  126.47 +data;
  126.48 +
  126.49 +set I := Seattle San-Diego;
  126.50 +
  126.51 +set J := New-York Chicago Topeka;
  126.52 +
  126.53 +param a := Seattle     350
  126.54 +           San-Diego   600;
  126.55 +
  126.56 +param b := New-York    325
  126.57 +           Chicago     300
  126.58 +           Topeka      275;
  126.59 +
  126.60 +param d :              New-York   Chicago   Topeka :=
  126.61 +           Seattle     2.5        1.7       1.8
  126.62 +           San-Diego   2.5        1.8       1.4  ;
  126.63 +
  126.64 +param f := 90;
  126.65 +
  126.66 +end;
   127.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   127.2 +++ b/examples/trick.mod	Mon Dec 06 13:09:21 2010 +0100
   127.3 @@ -0,0 +1,72 @@
   127.4 +/* TRICK, A Transportation Design Problem */
   127.5 +
   127.6 +/* Translated from the Mosel modeling language to GNU MathProg by
   127.7 +   Andrew Makhorin <mao@gnu.org> */
   127.8 +
   127.9 +/* This example model is described in the article "Formulations and
  127.10 +   Reformulations in Integer Programming" by Michael Trick (it is
  127.11 +   publicly available at http://mat.gsia.cmu.edu/trick/formul04.pdf).
  127.12 +
  127.13 +   This model demonstrates an amazing effect when including in the
  127.14 +   formulation an additional constraint, which is redundant even for
  127.15 +   LP relaxation, makes the model easy for solving with the B&B. */
  127.16 +
  127.17 +set TRUCKS := 1..10;
  127.18 +
  127.19 +set PACKAGES := 1..20;
  127.20 +
  127.21 +param capacity{TRUCKS};
  127.22 +
  127.23 +param size{PACKAGES};
  127.24 +
  127.25 +param cost{TRUCKS};
  127.26 +
  127.27 +param can_use{PACKAGES, TRUCKS};
  127.28 +
  127.29 +var x{PACKAGES, TRUCKS}, binary;
  127.30 +
  127.31 +var y{TRUCKS}, binary;
  127.32 +
  127.33 +minimize total: sum{i in TRUCKS} cost[i] * y[i];
  127.34 +
  127.35 +f1{i in TRUCKS}:
  127.36 +      sum{j in PACKAGES} size[j] * x[j,i] <= capacity[i] * y[i];
  127.37 +
  127.38 +f2{i in TRUCKS, j in PACKAGES}:
  127.39 +      x[j,i] <= y[i];
  127.40 +
  127.41 +f3{j in PACKAGES}:
  127.42 +      sum{i in TRUCKS} can_use[j,i] * x[j,i] = 1;
  127.43 +
  127.44 +redundant_constraint:
  127.45 +      sum{i in TRUCKS} capacity[i] * y[i] >= sum{j in PACKAGES} size[j];
  127.46 +
  127.47 +data;
  127.48 +
  127.49 +param capacity :=
  127.50 +      [1] 100 [2] 200 [3] 100 [4] 200 [5] 100 [6] 200 [7] 100 [8] 200
  127.51 +      [9] 100 [10] 200;
  127.52 +
  127.53 +param size :=
  127.54 +      [1] 17 [2] 21 [3] 54 [4] 45 [5] 87 [6] 34 [7] 23 [8] 45 [9] 12
  127.55 +      [10] 43 [11] 54 [12] 39 [13] 31 [14] 26 [15] 75 [16] 48 [17] 16
  127.56 +      [18] 32 [19] 45 [20] 55;
  127.57 +
  127.58 +param cost :=
  127.59 +      [1] 1 [2] 1.8 [3] 1 [4] 1.8 [5] 1 [6] 1.8 [7] 1 [8] 1.8 [9] 1
  127.60 +      [10] 1.8;
  127.61 +
  127.62 +param can_use (tr):
  127.63 +      1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 :=
  127.64 +   1  1  1  1  1  1  1  0  0  0  0  1  1  1  1  0  0  0  0  0  0
  127.65 +   2  1  1  1  1  1  1  1  1  0  0  1  1  1  1  1  1  1  0  0  0
  127.66 +   3  0  1  1  1  1  0  0  0  0  0  0  1  1  1  1  1  1  0  0  0
  127.67 +   4  0  0  1  1  1  1  1  1  1  1  0  0  1  1  1  1  1  1  0  0
  127.68 +   5  0  0  1  1  1  1  0  0  0  0  0  0  0  1  1  1  1  1  1  0
  127.69 +   6  0  0  0  1  1  1  1  0  0  0  0  0  0  1  1  1  0  0  0  0
  127.70 +   7  0  0  0  0  1  1  1  1  1  0  0  0  0  0  1  1  1  1  0  0
  127.71 +   8  0  0  0  0  1  1  1  1  1  1  0  0  0  0  0  1  1  1  1  1
  127.72 +   9  0  0  0  0  0  1  1  1  1  0  0  0  0  0  0  0  1  1  1  1
  127.73 +  10  0  0  0  0  0  0  0  1  1  1  0  0  0  0  0  0  0  0  1  1;
  127.74 +
  127.75 +end;
   128.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   128.2 +++ b/examples/tsp.mod	Mon Dec 06 13:09:21 2010 +0100
   128.3 @@ -0,0 +1,335 @@
   128.4 +/* TSP, Traveling Salesman Problem */
   128.5 +
   128.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
   128.7 +
   128.8 +/* The Traveling Salesman Problem (TSP) is stated as follows.
   128.9 +   Let a directed graph G = (V, E) be given, where V = {1, ..., n} is
  128.10 +   a set of nodes, E <= V x V is a set of arcs. Let also each arc
  128.11 +   e = (i,j) be assigned a number c[i,j], which is the length of the
  128.12 +   arc e. The problem is to find a closed path of minimal length going
  128.13 +   through each node of G exactly once. */
  128.14 +
  128.15 +param n, integer, >= 3;
  128.16 +/* number of nodes */
  128.17 +
  128.18 +set V := 1..n;
  128.19 +/* set of nodes */
  128.20 +
  128.21 +set E, within V cross V;
  128.22 +/* set of arcs */
  128.23 +
  128.24 +param c{(i,j) in E};
  128.25 +/* distance from node i to node j */
  128.26 +
  128.27 +var x{(i,j) in E}, binary;
  128.28 +/* x[i,j] = 1 means that the salesman goes from node i to node j */
  128.29 +
  128.30 +minimize total: sum{(i,j) in E} c[i,j] * x[i,j];
  128.31 +/* the objective is to make the path length as small as possible */
  128.32 +
  128.33 +s.t. leave{i in V}: sum{(i,j) in E} x[i,j] = 1;
  128.34 +/* the salesman leaves each node i exactly once */
  128.35 +
  128.36 +s.t. enter{j in V}: sum{(i,j) in E} x[i,j] = 1;
  128.37 +/* the salesman enters each node j exactly once */
  128.38 +
  128.39 +/* Constraints above are not sufficient to describe valid tours, so we
  128.40 +   need to add constraints to eliminate subtours, i.e. tours which have
  128.41 +   disconnected components. Although there are many known ways to do
  128.42 +   that, I invented yet another way. The general idea is the following.
  128.43 +   Let the salesman sells, say, cars, starting the travel from node 1,
  128.44 +   where he has n cars. If we require the salesman to sell exactly one
  128.45 +   car in each node, he will need to go through all nodes to satisfy
  128.46 +   this requirement, thus, all subtours will be eliminated. */
  128.47 +
  128.48 +var y{(i,j) in E}, >= 0;
  128.49 +/* y[i,j] is the number of cars, which the salesman has after leaving
  128.50 +   node i and before entering node j; in terms of the network analysis,
  128.51 +   y[i,j] is a flow through arc (i,j) */
  128.52 +
  128.53 +s.t. cap{(i,j) in E}: y[i,j] <= (n-1) * x[i,j];
  128.54 +/* if arc (i,j) does not belong to the salesman's tour, its capacity
  128.55 +   must be zero; it is obvious that on leaving a node, it is sufficient
  128.56 +   to have not more than n-1 cars */
  128.57 +
  128.58 +s.t. node{i in V}:
  128.59 +/* node[i] is a conservation constraint for node i */
  128.60 +
  128.61 +      sum{(j,i) in E} y[j,i]
  128.62 +      /* summary flow into node i through all ingoing arcs */
  128.63 +
  128.64 +      + (if i = 1 then n)
  128.65 +      /* plus n cars which the salesman has at starting node */
  128.66 +
  128.67 +      = /* must be equal to */
  128.68 +
  128.69 +      sum{(i,j) in E} y[i,j]
  128.70 +      /* summary flow from node i through all outgoing arcs */
  128.71 +
  128.72 +      + 1;
  128.73 +      /* plus one car which the salesman sells at node i */
  128.74 +
  128.75 +solve;
  128.76 +
  128.77 +printf "Optimal tour has length %d\n",
  128.78 +   sum{(i,j) in E} c[i,j] * x[i,j];
  128.79 +printf("From node   To node   Distance\n");
  128.80 +printf{(i,j) in E: x[i,j]} "      %3d       %3d   %8g\n",
  128.81 +   i, j, c[i,j];
  128.82 +
  128.83 +data;
  128.84 +
  128.85 +/* These data correspond to the symmetric instance ulysses16 from:
  128.86 +
  128.87 +   Reinelt, G.: TSPLIB - A travelling salesman problem library.
  128.88 +   ORSA-Journal of the Computing 3 (1991) 376-84;
  128.89 +   http://elib.zib.de/pub/Packages/mp-testdata/tsp/tsplib */
  128.90 +
  128.91 +/* The optimal solution is 6859 */
  128.92 +
  128.93 +param n := 16;
  128.94 +
  128.95 +param : E : c :=
  128.96 +    1  2   509
  128.97 +    1  3   501
  128.98 +    1  4   312
  128.99 +    1  5  1019
 128.100 +    1  6   736
 128.101 +    1  7   656
 128.102 +    1  8    60
 128.103 +    1  9  1039
 128.104 +    1 10   726
 128.105 +    1 11  2314
 128.106 +    1 12   479
 128.107 +    1 13   448
 128.108 +    1 14   479
 128.109 +    1 15   619
 128.110 +    1 16   150
 128.111 +    2  1   509
 128.112 +    2  3   126
 128.113 +    2  4   474
 128.114 +    2  5  1526
 128.115 +    2  6  1226
 128.116 +    2  7  1133
 128.117 +    2  8   532
 128.118 +    2  9  1449
 128.119 +    2 10  1122
 128.120 +    2 11  2789
 128.121 +    2 12   958
 128.122 +    2 13   941
 128.123 +    2 14   978
 128.124 +    2 15  1127
 128.125 +    2 16   542
 128.126 +    3  1   501
 128.127 +    3  2   126
 128.128 +    3  4   541
 128.129 +    3  5  1516
 128.130 +    3  6  1184
 128.131 +    3  7  1084
 128.132 +    3  8   536
 128.133 +    3  9  1371
 128.134 +    3 10  1045
 128.135 +    3 11  2728
 128.136 +    3 12   913
 128.137 +    3 13   904
 128.138 +    3 14   946
 128.139 +    3 15  1115
 128.140 +    3 16   499
 128.141 +    4  1   312
 128.142 +    4  2   474
 128.143 +    4  3   541
 128.144 +    4  5  1157
 128.145 +    4  6   980
 128.146 +    4  7   919
 128.147 +    4  8   271
 128.148 +    4  9  1333
 128.149 +    4 10  1029
 128.150 +    4 11  2553
 128.151 +    4 12   751
 128.152 +    4 13   704
 128.153 +    4 14   720
 128.154 +    4 15   783
 128.155 +    4 16   455
 128.156 +    5  1  1019
 128.157 +    5  2  1526
 128.158 +    5  3  1516
 128.159 +    5  4  1157
 128.160 +    5  6   478
 128.161 +    5  7   583
 128.162 +    5  8   996
 128.163 +    5  9   858
 128.164 +    5 10   855
 128.165 +    5 11  1504
 128.166 +    5 12   677
 128.167 +    5 13   651
 128.168 +    5 14   600
 128.169 +    5 15   401
 128.170 +    5 16  1033
 128.171 +    6  1   736
 128.172 +    6  2  1226
 128.173 +    6  3  1184
 128.174 +    6  4   980
 128.175 +    6  5   478
 128.176 +    6  7   115
 128.177 +    6  8   740
 128.178 +    6  9   470
 128.179 +    6 10   379
 128.180 +    6 11  1581
 128.181 +    6 12   271
 128.182 +    6 13   289
 128.183 +    6 14   261
 128.184 +    6 15   308
 128.185 +    6 16   687
 128.186 +    7  1   656
 128.187 +    7  2  1133
 128.188 +    7  3  1084
 128.189 +    7  4   919
 128.190 +    7  5   583
 128.191 +    7  6   115
 128.192 +    7  8   667
 128.193 +    7  9   455
 128.194 +    7 10   288
 128.195 +    7 11  1661
 128.196 +    7 12   177
 128.197 +    7 13   216
 128.198 +    7 14   207
 128.199 +    7 15   343
 128.200 +    7 16   592
 128.201 +    8  1    60
 128.202 +    8  2   532
 128.203 +    8  3   536
 128.204 +    8  4   271
 128.205 +    8  5   996
 128.206 +    8  6   740
 128.207 +    8  7   667
 128.208 +    8  9  1066
 128.209 +    8 10   759
 128.210 +    8 11  2320
 128.211 +    8 12   493
 128.212 +    8 13   454
 128.213 +    8 14   479
 128.214 +    8 15   598
 128.215 +    8 16   206
 128.216 +    9  1  1039
 128.217 +    9  2  1449
 128.218 +    9  3  1371
 128.219 +    9  4  1333
 128.220 +    9  5   858
 128.221 +    9  6   470
 128.222 +    9  7   455
 128.223 +    9  8  1066
 128.224 +    9 10   328
 128.225 +    9 11  1387
 128.226 +    9 12   591
 128.227 +    9 13   650
 128.228 +    9 14   656
 128.229 +    9 15   776
 128.230 +    9 16   933
 128.231 +   10  1   726
 128.232 +   10  2  1122
 128.233 +   10  3  1045
 128.234 +   10  4  1029
 128.235 +   10  5   855
 128.236 +   10  6   379
 128.237 +   10  7   288
 128.238 +   10  8   759
 128.239 +   10  9   328
 128.240 +   10 11  1697
 128.241 +   10 12   333
 128.242 +   10 13   400
 128.243 +   10 14   427
 128.244 +   10 15   622
 128.245 +   10 16   610
 128.246 +   11  1  2314
 128.247 +   11  2  2789
 128.248 +   11  3  2728
 128.249 +   11  4  2553
 128.250 +   11  5  1504
 128.251 +   11  6  1581
 128.252 +   11  7  1661
 128.253 +   11  8  2320
 128.254 +   11  9  1387
 128.255 +   11 10  1697
 128.256 +   11 12  1838
 128.257 +   11 13  1868
 128.258 +   11 14  1841
 128.259 +   11 15  1789
 128.260 +   11 16  2248
 128.261 +   12  1   479
 128.262 +   12  2   958
 128.263 +   12  3   913
 128.264 +   12  4   751
 128.265 +   12  5   677
 128.266 +   12  6   271
 128.267 +   12  7   177
 128.268 +   12  8   493
 128.269 +   12  9   591
 128.270 +   12 10   333
 128.271 +   12 11  1838
 128.272 +   12 13    68
 128.273 +   12 14   105
 128.274 +   12 15   336
 128.275 +   12 16   417
 128.276 +   13  1   448
 128.277 +   13  2   941
 128.278 +   13  3   904
 128.279 +   13  4   704
 128.280 +   13  5   651
 128.281 +   13  6   289
 128.282 +   13  7   216
 128.283 +   13  8   454
 128.284 +   13  9   650
 128.285 +   13 10   400
 128.286 +   13 11  1868
 128.287 +   13 12    68
 128.288 +   13 14    52
 128.289 +   13 15   287
 128.290 +   13 16   406
 128.291 +   14  1   479
 128.292 +   14  2   978
 128.293 +   14  3   946
 128.294 +   14  4   720
 128.295 +   14  5   600
 128.296 +   14  6   261
 128.297 +   14  7   207
 128.298 +   14  8   479
 128.299 +   14  9   656
 128.300 +   14 10   427
 128.301 +   14 11  1841
 128.302 +   14 12   105
 128.303 +   14 13    52
 128.304 +   14 15   237
 128.305 +   14 16   449
 128.306 +   15  1   619
 128.307 +   15  2  1127
 128.308 +   15  3  1115
 128.309 +   15  4   783
 128.310 +   15  5   401
 128.311 +   15  6   308
 128.312 +   15  7   343
 128.313 +   15  8   598
 128.314 +   15  9   776
 128.315 +   15 10   622
 128.316 +   15 11  1789
 128.317 +   15 12   336
 128.318 +   15 13   287
 128.319 +   15 14   237
 128.320 +   15 16   636
 128.321 +   16  1   150
 128.322 +   16  2   542
 128.323 +   16  3   499
 128.324 +   16  4   455
 128.325 +   16  5  1033
 128.326 +   16  6   687
 128.327 +   16  7   592
 128.328 +   16  8   206
 128.329 +   16  9   933
 128.330 +   16 10   610
 128.331 +   16 11  2248
 128.332 +   16 12   417
 128.333 +   16 13   406
 128.334 +   16 14   449
 128.335 +   16 15   636
 128.336 +;
 128.337 +
 128.338 +end;
   129.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   129.2 +++ b/examples/xyacfs.mod	Mon Dec 06 13:09:21 2010 +0100
   129.3 @@ -0,0 +1,56 @@
   129.4 +/*Extended Yet Another Curve Fitting Solution (The poor man's RMA)
   129.5 +
   129.6 +  An extension of yacfs.mod adding a Weight parameter:
   129.7 +    When set to 1 the model produces best fit by least squares with all error in y and none in x (YonX);
   129.8 +    When set to zero the model produces best fit by least squares with all error in x and none in y (XonY);
   129.9 +    When set to 0.5 the model assumes equal error in x and y producing results similar to fitting by Reduced Major Axis Analysis.
  129.10 +
  129.11 +  Nigel_Galloway@operamail.com
  129.12 +  November 5th., 2009
  129.13 +*/
  129.14 +set Sample;
  129.15 +param Sx {z in Sample};
  129.16 +param Sy {z in Sample};
  129.17 +param Weight := 0.5;
  129.18 +
  129.19 +var a;
  129.20 +var b;
  129.21 +var p;
  129.22 +var q;
  129.23 +
  129.24 +XonY1 :sum{z in Sample} q*Sy[z]*Sy[z] + sum{z in Sample} p*Sy[z] = sum{z in Sample} Sy[z]*Sx[z];
  129.25 +XonY2 :sum{z in Sample} q*Sy[z] + sum{z in Sample} p = sum{z in Sample} Sx[z];
  129.26 +YonX1 :sum{z in Sample} a*Sx[z]*Sx[z] + sum{z in Sample} b*Sx[z] = sum{z in Sample} Sy[z]*Sx[z];
  129.27 +YonX2 :sum{z in Sample} a*Sx[z] + sum{z in Sample} b = sum{z in Sample} Sy[z];
  129.28 +
  129.29 +solve;
  129.30 +
  129.31 +param W := Weight*a + (1-Weight)*(1/q);
  129.32 +printf "\nbest linear fit is:\n\ty = %f %s %fx\n\n", b*Weight - (1-Weight)*(p/q), if W < 0 then "-" else "+", abs(W);
  129.33 +
  129.34 +data;
  129.35 +
  129.36 +param:
  129.37 +Sample:   Sx    Sy :=
  129.38 +  1         0    1
  129.39 +  2       0.5  0.9
  129.40 +  3         1  0.7
  129.41 +  4       1.5  1.5
  129.42 +  5       1.9    2
  129.43 +  6       2.5  2.4
  129.44 +  7         3  3.2
  129.45 +  8       3.5    2
  129.46 +  9         4  2.7
  129.47 + 10       4.5  3.5
  129.48 + 11         5    1
  129.49 + 12       5.5    4
  129.50 + 13         6  3.6
  129.51 + 14       6.6  2.7
  129.52 + 15         7  5.7
  129.53 + 16       7.6  4.6
  129.54 + 17       8.5    6
  129.55 + 18         9  6.8
  129.56 + 19        10  7.3
  129.57 +;
  129.58 +
  129.59 +end;
   130.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   130.2 +++ b/examples/yacfs.mod	Mon Dec 06 13:09:21 2010 +0100
   130.3 @@ -0,0 +1,48 @@
   130.4 +/*Yet Another Curve Fitting Solution
   130.5 +
   130.6 +  Obviously this solution produces the same answer
   130.7 +  as examples/cflsq.mod
   130.8 +
   130.9 +  Nigel_Galloway@operamail.com
  130.10 +  February 1st., 2009
  130.11 +*/
  130.12 +set Sample;
  130.13 +param Sx {z in Sample};
  130.14 +param Sy {z in Sample};
  130.15 +
  130.16 +var a;
  130.17 +var b;
  130.18 +
  130.19 +equalz1 :sum{z in Sample} a*Sx[z]*Sx[z] + sum{z in Sample} b*Sx[z] = sum{z in Sample} Sy[z]*Sx[z];
  130.20 +equalz2 :sum{z in Sample} a*Sx[z] + sum{z in Sample} b = sum{z in Sample} Sy[z];
  130.21 +
  130.22 +solve;
  130.23 +
  130.24 +printf "\nbest linear fit is:\n\ty = %f %s %fx\n\n", b, if a < 0 then "-" else "+", abs(a);
  130.25 +
  130.26 +data;
  130.27 +
  130.28 +param:
  130.29 +Sample:   Sx    Sy :=
  130.30 +  1         0    1
  130.31 +  2       0.5  0.9
  130.32 +  3         1  0.7
  130.33 +  4       1.5  1.5
  130.34 +  5       1.9    2
  130.35 +  6       2.5  2.4
  130.36 +  7         3  3.2
  130.37 +  8       3.5    2
  130.38 +  9         4  2.7
  130.39 + 10       4.5  3.5
  130.40 + 11         5    1
  130.41 + 12       5.5    4
  130.42 + 13         6  3.6
  130.43 + 14       6.6  2.7
  130.44 + 15         7  5.7
  130.45 + 16       7.6  4.6
  130.46 + 17       8.5    6
  130.47 + 18         9  6.8
  130.48 + 19        10  7.3
  130.49 +;
  130.50 +
  130.51 +end;
   131.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   131.2 +++ b/examples/zebra.mod	Mon Dec 06 13:09:21 2010 +0100
   131.3 @@ -0,0 +1,151 @@
   131.4 +/* ZEBRA, Who Owns the Zebra? */
   131.5 +
   131.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
   131.7 +
   131.8 +########################################################################
   131.9 +#  The Zebra Puzzle is a well-known logic puzzle.
  131.10 +#
  131.11 +#  It is often called "Einstein's Puzzle" or "Einstein's Riddle"
  131.12 +#  because it is said to have been invented by Albert Einstein as a boy,
  131.13 +#  with the common claim that Einstein said "only 2 percent of the
  131.14 +#  world's population can solve". It is also sometimes attributed to
  131.15 +#  Lewis Carroll. However, there is no known evidence for Einstein's or
  131.16 +#  Carroll's authorship.
  131.17 +#
  131.18 +#  There are several versions of this puzzle. The version below is
  131.19 +#  quoted from the first known publication in Life International
  131.20 +#  magazine on December 17, 1962.
  131.21 +#
  131.22 +#   1. There are five houses.
  131.23 +#   2. The Englishman lives in the red house.
  131.24 +#   3. The Spaniard owns the dog.
  131.25 +#   4. Coffee is drunk in the green house.
  131.26 +#   5. The Ukrainian drinks tea.
  131.27 +#   6. The green house is immediately to the right of the ivory house.
  131.28 +#   7. The Old Gold smoker owns snails.
  131.29 +#   8. Kools are smoked in the yellow house.
  131.30 +#   9. Milk is drunk in the middle house.
  131.31 +#  10. The Norwegian lives in the first house.
  131.32 +#  11. The man who smokes Chesterfields lives in the house next to the
  131.33 +#      man with the fox.
  131.34 +#  12. Kools are smoked in the house next to the house where the horse
  131.35 +#      is kept.
  131.36 +#  13. The Lucky Strike smoker drinks orange juice.
  131.37 +#  14. The Japanese smokes Parliaments.
  131.38 +#  15. The Norwegian lives next to the blue house.
  131.39 +#
  131.40 +#  Now, who drinks water? Who owns the zebra?
  131.41 +#
  131.42 +#  In the interest of clarity, it must be added that each of the five
  131.43 +#  houses is painted a different color, and their inhabitants are of
  131.44 +#  different national extractions, own different pets, drink different
  131.45 +#  beverages and smoke different brands of American cigarettes. One
  131.46 +#  other thing: In statement 6, right means your right.
  131.47 +#
  131.48 +#  (From Wikipedia, the free encyclopedia.)
  131.49 +########################################################################
  131.50 +
  131.51 +set HOUSE := { 1..5 };
  131.52 +
  131.53 +set COLOR := { "blue", "green", "ivory", "red", "yellow" };
  131.54 +
  131.55 +set NATIONALITY := { "Englishman", "Japanese", "Norwegian", "Spaniard",
  131.56 +      "Ukranian" };
  131.57 +
  131.58 +set DRINK := { "coffee", "milk", "orange_juice", "tea", "water" };
  131.59 +
  131.60 +set SMOKE := { "Chesterfield", "Kools", "Lucky_Strike", "Old_Gold",
  131.61 +      "Parliament" };
  131.62 +
  131.63 +set PET := { "dog", "fox", "horse", "snails", "zebra" };
  131.64 +
  131.65 +var color{HOUSE, COLOR}, binary;
  131.66 +c1{h in HOUSE}: sum{c in COLOR} color[h,c] = 1;
  131.67 +c2{c in COLOR}: sum{h in HOUSE} color[h,c] = 1;
  131.68 +
  131.69 +var nationality{HOUSE, NATIONALITY}, binary;
  131.70 +n1{h in HOUSE}: sum{n in NATIONALITY} nationality[h,n] = 1;
  131.71 +n2{n in NATIONALITY}: sum{h in HOUSE} nationality[h,n] = 1;
  131.72 +
  131.73 +var drink{HOUSE, DRINK}, binary;
  131.74 +d1{h in HOUSE}: sum{d in DRINK} drink[h,d] = 1;
  131.75 +d2{d in DRINK}: sum{h in HOUSE} drink[h,d] = 1;
  131.76 +
  131.77 +var smoke{HOUSE, SMOKE}, binary;
  131.78 +s1{h in HOUSE}: sum{s in SMOKE} smoke[h,s] = 1;
  131.79 +s2{s in SMOKE}: sum{h in HOUSE} smoke[h,s] = 1;
  131.80 +
  131.81 +var pet{HOUSE, PET}, binary;
  131.82 +p1{h in HOUSE}: sum{p in PET} pet[h,p] = 1;
  131.83 +p2{p in PET}: sum{h in HOUSE} pet[h,p] = 1;
  131.84 +
  131.85 +/* the Englishman lives in the red house */
  131.86 +f2{h in HOUSE}: nationality[h,"Englishman"] = color[h,"red"];
  131.87 +
  131.88 +/* the Spaniard owns the dog */
  131.89 +f3{h in HOUSE}: nationality[h,"Spaniard"] = pet[h,"dog"];
  131.90 +
  131.91 +/* coffee is drunk in the green house */
  131.92 +f4{h in HOUSE}: drink[h,"coffee"] = color[h,"green"];
  131.93 +
  131.94 +/* the Ukrainian drinks tea */
  131.95 +f5{h in HOUSE}: nationality[h,"Ukranian"] = drink[h,"tea"];
  131.96 +
  131.97 +/* the green house is immediately to the right of the ivory house */
  131.98 +f6{h in HOUSE}:
  131.99 +   color[h,"green"] = if h = 1 then 0 else color[h-1,"ivory"];
 131.100 +
 131.101 +/* the Old Gold smoker owns snails */
 131.102 +f7{h in HOUSE}: smoke[h,"Old_Gold"] = pet[h,"snails"];
 131.103 +
 131.104 +/* Kools are smoked in the yellow house */
 131.105 +f8{h in HOUSE}: smoke[h,"Kools"] = color[h,"yellow"];
 131.106 +
 131.107 +/* milk is drunk in the middle house */
 131.108 +f9: drink[3,"milk"] = 1;
 131.109 +
 131.110 +/* the Norwegian lives in the first house */
 131.111 +f10: nationality[1,"Norwegian"] = 1;
 131.112 +
 131.113 +/* the man who smokes Chesterfields lives in the house next to the man
 131.114 +   with the fox */
 131.115 +f11{h in HOUSE}:
 131.116 +   (1 - smoke[h,"Chesterfield"]) +
 131.117 +   (if h = 1 then 0 else pet[h-1,"fox"]) +
 131.118 +   (if h = 5 then 0 else pet[h+1,"fox"]) >= 1;
 131.119 +
 131.120 +/* Kools are smoked in the house next to the house where the horse is
 131.121 +   kept */
 131.122 +f12{h in HOUSE}:
 131.123 +   (1 - smoke[h,"Kools"]) +
 131.124 +   (if h = 1 then 0 else pet[h-1,"horse"]) +
 131.125 +   (if h = 5 then 0 else pet[h+1,"horse"]) >= 1;
 131.126 +
 131.127 +/* the Lucky Strike smoker drinks orange juice */
 131.128 +f13{h in HOUSE}: smoke[h,"Lucky_Strike"] = drink[h,"orange_juice"];
 131.129 +
 131.130 +/* the Japanese smokes Parliaments */
 131.131 +f14{h in HOUSE}: nationality[h,"Japanese"] = smoke[h,"Parliament"];
 131.132 +
 131.133 +/* the Norwegian lives next to the blue house */
 131.134 +f15{h in HOUSE}:
 131.135 +   (1 - nationality[h,"Norwegian"]) +
 131.136 +   (if h = 1 then 0 else color[h-1,"blue"]) +
 131.137 +   (if h = 5 then 0 else color[h+1,"blue"]) >= 1;
 131.138 +
 131.139 +solve;
 131.140 +
 131.141 +printf "\n";
 131.142 +printf "HOUSE  COLOR   NATIONALITY  DRINK         SMOKE         PET\n";
 131.143 +for {h in HOUSE}
 131.144 +{  printf "%5d", h;
 131.145 +   printf{c in COLOR: color[h,c]} "  %-6s", c;
 131.146 +   printf{n in NATIONALITY: nationality[h,n]} "  %-11s", n;
 131.147 +   printf{d in DRINK: drink[h,d]} "  %-12s", d;
 131.148 +   printf{s in SMOKE: smoke[h,s]} "  %-12s", s;
 131.149 +   printf{p in PET: pet[h,p]} "  %-6s", p;
 131.150 +   printf "\n";
 131.151 +}
 131.152 +printf "\n";
 131.153 +
 131.154 +end;
   132.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   132.2 +++ b/include/Makefile.am	Mon Dec 06 13:09:21 2010 +0100
   132.3 @@ -0,0 +1,5 @@
   132.4 +## Process this file with automake to produce Makefile.in ##
   132.5 +
   132.6 +include_HEADERS = glpk.h
   132.7 +
   132.8 +## eof ##
   133.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   133.2 +++ b/include/glpk.h	Mon Dec 06 13:09:21 2010 +0100
   133.3 @@ -0,0 +1,1750 @@
   133.4 +/* glpk.h */
   133.5 +
   133.6 +/***********************************************************************
   133.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   133.8 +*
   133.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  133.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  133.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  133.12 +*  E-mail: <mao@gnu.org>.
  133.13 +*
  133.14 +*  GLPK is free software: you can redistribute it and/or modify it
  133.15 +*  under the terms of the GNU General Public License as published by
  133.16 +*  the Free Software Foundation, either version 3 of the License, or
  133.17 +*  (at your option) any later version.
  133.18 +*
  133.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  133.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  133.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  133.22 +*  License for more details.
  133.23 +*
  133.24 +*  You should have received a copy of the GNU General Public License
  133.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  133.26 +***********************************************************************/
  133.27 +
  133.28 +#ifndef GLPK_H
  133.29 +#define GLPK_H
  133.30 +
  133.31 +#include <stdarg.h>
  133.32 +#include <stddef.h>
  133.33 +
  133.34 +#ifdef __cplusplus
  133.35 +extern "C" {
  133.36 +#endif
  133.37 +
  133.38 +/* library version numbers: */
  133.39 +#define GLP_MAJOR_VERSION  4
  133.40 +#define GLP_MINOR_VERSION  45
  133.41 +
  133.42 +#ifndef GLP_PROB_DEFINED
  133.43 +#define GLP_PROB_DEFINED
  133.44 +typedef struct { double _opaque_prob[100]; } glp_prob;
  133.45 +/* LP/MIP problem object */
  133.46 +#endif
  133.47 +
  133.48 +/* optimization direction flag: */
  133.49 +#define GLP_MIN            1  /* minimization */
  133.50 +#define GLP_MAX            2  /* maximization */
  133.51 +
  133.52 +/* kind of structural variable: */
  133.53 +#define GLP_CV             1  /* continuous variable */
  133.54 +#define GLP_IV             2  /* integer variable */
  133.55 +#define GLP_BV             3  /* binary variable */
  133.56 +
  133.57 +/* type of auxiliary/structural variable: */
  133.58 +#define GLP_FR             1  /* free variable */
  133.59 +#define GLP_LO             2  /* variable with lower bound */
  133.60 +#define GLP_UP             3  /* variable with upper bound */
  133.61 +#define GLP_DB             4  /* double-bounded variable */
  133.62 +#define GLP_FX             5  /* fixed variable */
  133.63 +
  133.64 +/* status of auxiliary/structural variable: */
  133.65 +#define GLP_BS             1  /* basic variable */
  133.66 +#define GLP_NL             2  /* non-basic variable on lower bound */
  133.67 +#define GLP_NU             3  /* non-basic variable on upper bound */
  133.68 +#define GLP_NF             4  /* non-basic free variable */
  133.69 +#define GLP_NS             5  /* non-basic fixed variable */
  133.70 +
  133.71 +/* scaling options: */
  133.72 +#define GLP_SF_GM       0x01  /* perform geometric mean scaling */
  133.73 +#define GLP_SF_EQ       0x10  /* perform equilibration scaling */
  133.74 +#define GLP_SF_2N       0x20  /* round scale factors to power of two */
  133.75 +#define GLP_SF_SKIP     0x40  /* skip if problem is well scaled */
  133.76 +#define GLP_SF_AUTO     0x80  /* choose scaling options automatically */
  133.77 +
  133.78 +/* solution indicator: */
  133.79 +#define GLP_SOL            1  /* basic solution */
  133.80 +#define GLP_IPT            2  /* interior-point solution */
  133.81 +#define GLP_MIP            3  /* mixed integer solution */
  133.82 +
  133.83 +/* solution status: */
  133.84 +#define GLP_UNDEF          1  /* solution is undefined */
  133.85 +#define GLP_FEAS           2  /* solution is feasible */
  133.86 +#define GLP_INFEAS         3  /* solution is infeasible */
  133.87 +#define GLP_NOFEAS         4  /* no feasible solution exists */
  133.88 +#define GLP_OPT            5  /* solution is optimal */
  133.89 +#define GLP_UNBND          6  /* solution is unbounded */
  133.90 +
  133.91 +typedef struct
  133.92 +{     /* basis factorization control parameters */
  133.93 +      int msg_lev;            /* (reserved) */
  133.94 +      int type;               /* factorization type: */
  133.95 +#define GLP_BF_FT          1  /* LUF + Forrest-Tomlin */
  133.96 +#define GLP_BF_BG          2  /* LUF + Schur compl. + Bartels-Golub */
  133.97 +#define GLP_BF_GR          3  /* LUF + Schur compl. + Givens rotation */
  133.98 +      int lu_size;            /* luf.sv_size */
  133.99 +      double piv_tol;         /* luf.piv_tol */
 133.100 +      int piv_lim;            /* luf.piv_lim */
 133.101 +      int suhl;               /* luf.suhl */
 133.102 +      double eps_tol;         /* luf.eps_tol */
 133.103 +      double max_gro;         /* luf.max_gro */
 133.104 +      int nfs_max;            /* fhv.hh_max */
 133.105 +      double upd_tol;         /* fhv.upd_tol */
 133.106 +      int nrs_max;            /* lpf.n_max */
 133.107 +      int rs_size;            /* lpf.v_size */
 133.108 +      double foo_bar[38];     /* (reserved) */
 133.109 +} glp_bfcp;
 133.110 +
 133.111 +typedef struct
 133.112 +{     /* simplex method control parameters */
 133.113 +      int msg_lev;            /* message level: */
 133.114 +#define GLP_MSG_OFF        0  /* no output */
 133.115 +#define GLP_MSG_ERR        1  /* warning and error messages only */
 133.116 +#define GLP_MSG_ON         2  /* normal output */
 133.117 +#define GLP_MSG_ALL        3  /* full output */
 133.118 +#define GLP_MSG_DBG        4  /* debug output */
 133.119 +      int meth;               /* simplex method option: */
 133.120 +#define GLP_PRIMAL         1  /* use primal simplex */
 133.121 +#define GLP_DUALP          2  /* use dual; if it fails, use primal */
 133.122 +#define GLP_DUAL           3  /* use dual simplex */
 133.123 +      int pricing;            /* pricing technique: */
 133.124 +#define GLP_PT_STD      0x11  /* standard (Dantzig rule) */
 133.125 +#define GLP_PT_PSE      0x22  /* projected steepest edge */
 133.126 +      int r_test;             /* ratio test technique: */
 133.127 +#define GLP_RT_STD      0x11  /* standard (textbook) */
 133.128 +#define GLP_RT_HAR      0x22  /* two-pass Harris' ratio test */
 133.129 +      double tol_bnd;         /* spx.tol_bnd */
 133.130 +      double tol_dj;          /* spx.tol_dj */
 133.131 +      double tol_piv;         /* spx.tol_piv */
 133.132 +      double obj_ll;          /* spx.obj_ll */
 133.133 +      double obj_ul;          /* spx.obj_ul */
 133.134 +      int it_lim;             /* spx.it_lim */
 133.135 +      int tm_lim;             /* spx.tm_lim (milliseconds) */
 133.136 +      int out_frq;            /* spx.out_frq */
 133.137 +      int out_dly;            /* spx.out_dly (milliseconds) */
 133.138 +      int presolve;           /* enable/disable using LP presolver */
 133.139 +      double foo_bar[36];     /* (reserved) */
 133.140 +} glp_smcp;
 133.141 +
 133.142 +typedef struct
 133.143 +{     /* interior-point solver control parameters */
 133.144 +      int msg_lev;            /* message level (see glp_smcp) */
 133.145 +      int ord_alg;            /* ordering algorithm: */
 133.146 +#define GLP_ORD_NONE       0  /* natural (original) ordering */
 133.147 +#define GLP_ORD_QMD        1  /* quotient minimum degree (QMD) */
 133.148 +#define GLP_ORD_AMD        2  /* approx. minimum degree (AMD) */
 133.149 +#define GLP_ORD_SYMAMD     3  /* approx. minimum degree (SYMAMD) */
 133.150 +      double foo_bar[48];     /* (reserved) */
 133.151 +} glp_iptcp;
 133.152 +
 133.153 +#ifndef GLP_TREE_DEFINED
 133.154 +#define GLP_TREE_DEFINED
 133.155 +typedef struct { double _opaque_tree[100]; } glp_tree;
 133.156 +/* branch-and-bound tree */
 133.157 +#endif
 133.158 +
 133.159 +typedef struct
 133.160 +{     /* integer optimizer control parameters */
 133.161 +      int msg_lev;            /* message level (see glp_smcp) */
 133.162 +      int br_tech;            /* branching technique: */
 133.163 +#define GLP_BR_FFV         1  /* first fractional variable */
 133.164 +#define GLP_BR_LFV         2  /* last fractional variable */
 133.165 +#define GLP_BR_MFV         3  /* most fractional variable */
 133.166 +#define GLP_BR_DTH         4  /* heuristic by Driebeck and Tomlin */
 133.167 +#define GLP_BR_PCH         5  /* hybrid pseudocost heuristic */
 133.168 +      int bt_tech;            /* backtracking technique: */
 133.169 +#define GLP_BT_DFS         1  /* depth first search */
 133.170 +#define GLP_BT_BFS         2  /* breadth first search */
 133.171 +#define GLP_BT_BLB         3  /* best local bound */
 133.172 +#define GLP_BT_BPH         4  /* best projection heuristic */
 133.173 +      double tol_int;         /* mip.tol_int */
 133.174 +      double tol_obj;         /* mip.tol_obj */
 133.175 +      int tm_lim;             /* mip.tm_lim (milliseconds) */
 133.176 +      int out_frq;            /* mip.out_frq (milliseconds) */
 133.177 +      int out_dly;            /* mip.out_dly (milliseconds) */
 133.178 +      void (*cb_func)(glp_tree *T, void *info);
 133.179 +                              /* mip.cb_func */
 133.180 +      void *cb_info;          /* mip.cb_info */
 133.181 +      int cb_size;            /* mip.cb_size */
 133.182 +      int pp_tech;            /* preprocessing technique: */
 133.183 +#define GLP_PP_NONE        0  /* disable preprocessing */
 133.184 +#define GLP_PP_ROOT        1  /* preprocessing only on root level */
 133.185 +#define GLP_PP_ALL         2  /* preprocessing on all levels */
 133.186 +      double mip_gap;         /* relative MIP gap tolerance */
 133.187 +      int mir_cuts;           /* MIR cuts       (GLP_ON/GLP_OFF) */
 133.188 +      int gmi_cuts;           /* Gomory's cuts  (GLP_ON/GLP_OFF) */
 133.189 +      int cov_cuts;           /* cover cuts     (GLP_ON/GLP_OFF) */
 133.190 +      int clq_cuts;           /* clique cuts    (GLP_ON/GLP_OFF) */
 133.191 +      int presolve;           /* enable/disable using MIP presolver */
 133.192 +      int binarize;           /* try to binarize integer variables */
 133.193 +      int fp_heur;            /* feasibility pump heuristic */
 133.194 +#if 1 /* 28/V-2010 */
 133.195 +      int alien;              /* use alien solver */
 133.196 +#endif
 133.197 +      double foo_bar[29];     /* (reserved) */
 133.198 +} glp_iocp;
 133.199 +
 133.200 +typedef struct
 133.201 +{     /* additional row attributes */
 133.202 +      int level;
 133.203 +      /* subproblem level at which the row was added */
 133.204 +      int origin;
 133.205 +      /* row origin flag: */
 133.206 +#define GLP_RF_REG         0  /* regular constraint */
 133.207 +#define GLP_RF_LAZY        1  /* "lazy" constraint */
 133.208 +#define GLP_RF_CUT         2  /* cutting plane constraint */
 133.209 +      int klass;
 133.210 +      /* row class descriptor: */
 133.211 +#define GLP_RF_GMI         1  /* Gomory's mixed integer cut */
 133.212 +#define GLP_RF_MIR         2  /* mixed integer rounding cut */
 133.213 +#define GLP_RF_COV         3  /* mixed cover cut */
 133.214 +#define GLP_RF_CLQ         4  /* clique cut */
 133.215 +      double foo_bar[7];
 133.216 +      /* (reserved) */
 133.217 +} glp_attr;
 133.218 +
 133.219 +/* enable/disable flag: */
 133.220 +#define GLP_ON             1  /* enable something */
 133.221 +#define GLP_OFF            0  /* disable something */
 133.222 +
 133.223 +/* reason codes: */
 133.224 +#define GLP_IROWGEN     0x01  /* request for row generation */
 133.225 +#define GLP_IBINGO      0x02  /* better integer solution found */
 133.226 +#define GLP_IHEUR       0x03  /* request for heuristic solution */
 133.227 +#define GLP_ICUTGEN     0x04  /* request for cut generation */
 133.228 +#define GLP_IBRANCH     0x05  /* request for branching */
 133.229 +#define GLP_ISELECT     0x06  /* request for subproblem selection */
 133.230 +#define GLP_IPREPRO     0x07  /* request for preprocessing */
 133.231 +
 133.232 +/* branch selection indicator: */
 133.233 +#define GLP_NO_BRNCH       0  /* select no branch */
 133.234 +#define GLP_DN_BRNCH       1  /* select down-branch */
 133.235 +#define GLP_UP_BRNCH       2  /* select up-branch */
 133.236 +
 133.237 +/* return codes: */
 133.238 +#define GLP_EBADB       0x01  /* invalid basis */
 133.239 +#define GLP_ESING       0x02  /* singular matrix */
 133.240 +#define GLP_ECOND       0x03  /* ill-conditioned matrix */
 133.241 +#define GLP_EBOUND      0x04  /* invalid bounds */
 133.242 +#define GLP_EFAIL       0x05  /* solver failed */
 133.243 +#define GLP_EOBJLL      0x06  /* objective lower limit reached */
 133.244 +#define GLP_EOBJUL      0x07  /* objective upper limit reached */
 133.245 +#define GLP_EITLIM      0x08  /* iteration limit exceeded */
 133.246 +#define GLP_ETMLIM      0x09  /* time limit exceeded */
 133.247 +#define GLP_ENOPFS      0x0A  /* no primal feasible solution */
 133.248 +#define GLP_ENODFS      0x0B  /* no dual feasible solution */
 133.249 +#define GLP_EROOT       0x0C  /* root LP optimum not provided */
 133.250 +#define GLP_ESTOP       0x0D  /* search terminated by application */
 133.251 +#define GLP_EMIPGAP     0x0E  /* relative mip gap tolerance reached */
 133.252 +#define GLP_ENOFEAS     0x0F  /* no primal/dual feasible solution */
 133.253 +#define GLP_ENOCVG      0x10  /* no convergence */
 133.254 +#define GLP_EINSTAB     0x11  /* numerical instability */
 133.255 +#define GLP_EDATA       0x12  /* invalid data */
 133.256 +#define GLP_ERANGE      0x13  /* result out of range */
 133.257 +
 133.258 +/* condition indicator: */
 133.259 +#define GLP_KKT_PE         1  /* primal equalities */
 133.260 +#define GLP_KKT_PB         2  /* primal bounds */
 133.261 +#define GLP_KKT_DE         3  /* dual equalities */
 133.262 +#define GLP_KKT_DB         4  /* dual bounds */
 133.263 +#define GLP_KKT_CS         5  /* complementary slackness */
 133.264 +
 133.265 +/* MPS file format: */
 133.266 +#define GLP_MPS_DECK       1  /* fixed (ancient) */
 133.267 +#define GLP_MPS_FILE       2  /* free (modern) */
 133.268 +
 133.269 +typedef struct
 133.270 +{     /* MPS format control parameters */
 133.271 +      int blank;
 133.272 +      /* character code to replace blanks in symbolic names */
 133.273 +      char *obj_name;
 133.274 +      /* objective row name */
 133.275 +      double tol_mps;
 133.276 +      /* zero tolerance for MPS data */
 133.277 +      double foo_bar[17];
 133.278 +      /* (reserved for use in the future) */
 133.279 +} glp_mpscp;
 133.280 +
 133.281 +typedef struct
 133.282 +{     /* CPLEX LP format control parameters */
 133.283 +      double foo_bar[20];
 133.284 +      /* (reserved for use in the future) */
 133.285 +} glp_cpxcp;
 133.286 +
 133.287 +#ifndef GLP_TRAN_DEFINED
 133.288 +#define GLP_TRAN_DEFINED
 133.289 +typedef struct { double _opaque_tran[100]; } glp_tran;
 133.290 +/* MathProg translator workspace */
 133.291 +#endif
 133.292 +
 133.293 +glp_prob *glp_create_prob(void);
 133.294 +/* create problem object */
 133.295 +
 133.296 +void glp_set_prob_name(glp_prob *P, const char *name);
 133.297 +/* assign (change) problem name */
 133.298 +
 133.299 +void glp_set_obj_name(glp_prob *P, const char *name);
 133.300 +/* assign (change) objective function name */
 133.301 +
 133.302 +void glp_set_obj_dir(glp_prob *P, int dir);
 133.303 +/* set (change) optimization direction flag */
 133.304 +
 133.305 +int glp_add_rows(glp_prob *P, int nrs);
 133.306 +/* add new rows to problem object */
 133.307 +
 133.308 +int glp_add_cols(glp_prob *P, int ncs);
 133.309 +/* add new columns to problem object */
 133.310 +
 133.311 +void glp_set_row_name(glp_prob *P, int i, const char *name);
 133.312 +/* assign (change) row name */
 133.313 +
 133.314 +void glp_set_col_name(glp_prob *P, int j, const char *name);
 133.315 +/* assign (change) column name */
 133.316 +
 133.317 +void glp_set_row_bnds(glp_prob *P, int i, int type, double lb,
 133.318 +      double ub);
 133.319 +/* set (change) row bounds */
 133.320 +
 133.321 +void glp_set_col_bnds(glp_prob *P, int j, int type, double lb,
 133.322 +      double ub);
 133.323 +/* set (change) column bounds */
 133.324 +
 133.325 +void glp_set_obj_coef(glp_prob *P, int j, double coef);
 133.326 +/* set (change) obj. coefficient or constant term */
 133.327 +
 133.328 +void glp_set_mat_row(glp_prob *P, int i, int len, const int ind[],
 133.329 +      const double val[]);
 133.330 +/* set (replace) row of the constraint matrix */
 133.331 +
 133.332 +void glp_set_mat_col(glp_prob *P, int j, int len, const int ind[],
 133.333 +      const double val[]);
 133.334 +/* set (replace) column of the constraint matrix */
 133.335 +
 133.336 +void glp_load_matrix(glp_prob *P, int ne, const int ia[],
 133.337 +      const int ja[], const double ar[]);
 133.338 +/* load (replace) the whole constraint matrix */
 133.339 +
 133.340 +int glp_check_dup(int m, int n, int ne, const int ia[], const int ja[]);
 133.341 +/* check for duplicate elements in sparse matrix */
 133.342 +
 133.343 +void glp_sort_matrix(glp_prob *P);
 133.344 +/* sort elements of the constraint matrix */
 133.345 +
 133.346 +void glp_del_rows(glp_prob *P, int nrs, const int num[]);
 133.347 +/* delete specified rows from problem object */
 133.348 +
 133.349 +void glp_del_cols(glp_prob *P, int ncs, const int num[]);
 133.350 +/* delete specified columns from problem object */
 133.351 +
 133.352 +void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names);
 133.353 +/* copy problem object content */
 133.354 +
 133.355 +void glp_erase_prob(glp_prob *P);
 133.356 +/* erase problem object content */
 133.357 +
 133.358 +void glp_delete_prob(glp_prob *P);
 133.359 +/* delete problem object */
 133.360 +
 133.361 +const char *glp_get_prob_name(glp_prob *P);
 133.362 +/* retrieve problem name */
 133.363 +
 133.364 +const char *glp_get_obj_name(glp_prob *P);
 133.365 +/* retrieve objective function name */
 133.366 +
 133.367 +int glp_get_obj_dir(glp_prob *P);
 133.368 +/* retrieve optimization direction flag */
 133.369 +
 133.370 +int glp_get_num_rows(glp_prob *P);
 133.371 +/* retrieve number of rows */
 133.372 +
 133.373 +int glp_get_num_cols(glp_prob *P);
 133.374 +/* retrieve number of columns */
 133.375 +
 133.376 +const char *glp_get_row_name(glp_prob *P, int i);
 133.377 +/* retrieve row name */
 133.378 +
 133.379 +const char *glp_get_col_name(glp_prob *P, int j);
 133.380 +/* retrieve column name */
 133.381 +
 133.382 +int glp_get_row_type(glp_prob *P, int i);
 133.383 +/* retrieve row type */
 133.384 +
 133.385 +double glp_get_row_lb(glp_prob *P, int i);
 133.386 +/* retrieve row lower bound */
 133.387 +
 133.388 +double glp_get_row_ub(glp_prob *P, int i);
 133.389 +/* retrieve row upper bound */
 133.390 +
 133.391 +int glp_get_col_type(glp_prob *P, int j);
 133.392 +/* retrieve column type */
 133.393 +
 133.394 +double glp_get_col_lb(glp_prob *P, int j);
 133.395 +/* retrieve column lower bound */
 133.396 +
 133.397 +double glp_get_col_ub(glp_prob *P, int j);
 133.398 +/* retrieve column upper bound */
 133.399 +
 133.400 +double glp_get_obj_coef(glp_prob *P, int j);
 133.401 +/* retrieve obj. coefficient or constant term */
 133.402 +
 133.403 +int glp_get_num_nz(glp_prob *P);
 133.404 +/* retrieve number of constraint coefficients */
 133.405 +
 133.406 +int glp_get_mat_row(glp_prob *P, int i, int ind[], double val[]);
 133.407 +/* retrieve row of the constraint matrix */
 133.408 +
 133.409 +int glp_get_mat_col(glp_prob *P, int j, int ind[], double val[]);
 133.410 +/* retrieve column of the constraint matrix */
 133.411 +
 133.412 +void glp_create_index(glp_prob *P);
 133.413 +/* create the name index */
 133.414 +
 133.415 +int glp_find_row(glp_prob *P, const char *name);
 133.416 +/* find row by its name */
 133.417 +
 133.418 +int glp_find_col(glp_prob *P, const char *name);
 133.419 +/* find column by its name */
 133.420 +
 133.421 +void glp_delete_index(glp_prob *P);
 133.422 +/* delete the name index */
 133.423 +
 133.424 +void glp_set_rii(glp_prob *P, int i, double rii);
 133.425 +/* set (change) row scale factor */
 133.426 +
 133.427 +void glp_set_sjj(glp_prob *P, int j, double sjj);
 133.428 +/* set (change) column scale factor */
 133.429 +
 133.430 +double glp_get_rii(glp_prob *P, int i);
 133.431 +/* retrieve row scale factor */
 133.432 +
 133.433 +double glp_get_sjj(glp_prob *P, int j);
 133.434 +/* retrieve column scale factor */
 133.435 +
 133.436 +void glp_scale_prob(glp_prob *P, int flags);
 133.437 +/* scale problem data */
 133.438 +
 133.439 +void glp_unscale_prob(glp_prob *P);
 133.440 +/* unscale problem data */
 133.441 +
 133.442 +void glp_set_row_stat(glp_prob *P, int i, int stat);
 133.443 +/* set (change) row status */
 133.444 +
 133.445 +void glp_set_col_stat(glp_prob *P, int j, int stat);
 133.446 +/* set (change) column status */
 133.447 +
 133.448 +void glp_std_basis(glp_prob *P);
 133.449 +/* construct standard initial LP basis */
 133.450 +
 133.451 +void glp_adv_basis(glp_prob *P, int flags);
 133.452 +/* construct advanced initial LP basis */
 133.453 +
 133.454 +void glp_cpx_basis(glp_prob *P);
 133.455 +/* construct Bixby's initial LP basis */
 133.456 +
 133.457 +int glp_simplex(glp_prob *P, const glp_smcp *parm);
 133.458 +/* solve LP problem with the simplex method */
 133.459 +
 133.460 +int glp_exact(glp_prob *P, const glp_smcp *parm);
 133.461 +/* solve LP problem in exact arithmetic */
 133.462 +
 133.463 +void glp_init_smcp(glp_smcp *parm);
 133.464 +/* initialize simplex method control parameters */
 133.465 +
 133.466 +int glp_get_status(glp_prob *P);
 133.467 +/* retrieve generic status of basic solution */
 133.468 +
 133.469 +int glp_get_prim_stat(glp_prob *P);
 133.470 +/* retrieve status of primal basic solution */
 133.471 +
 133.472 +int glp_get_dual_stat(glp_prob *P);
 133.473 +/* retrieve status of dual basic solution */
 133.474 +
 133.475 +double glp_get_obj_val(glp_prob *P);
 133.476 +/* retrieve objective value (basic solution) */
 133.477 +
 133.478 +int glp_get_row_stat(glp_prob *P, int i);
 133.479 +/* retrieve row status */
 133.480 +
 133.481 +double glp_get_row_prim(glp_prob *P, int i);
 133.482 +/* retrieve row primal value (basic solution) */
 133.483 +
 133.484 +double glp_get_row_dual(glp_prob *P, int i);
 133.485 +/* retrieve row dual value (basic solution) */
 133.486 +
 133.487 +int glp_get_col_stat(glp_prob *P, int j);
 133.488 +/* retrieve column status */
 133.489 +
 133.490 +double glp_get_col_prim(glp_prob *P, int j);
 133.491 +/* retrieve column primal value (basic solution) */
 133.492 +
 133.493 +double glp_get_col_dual(glp_prob *P, int j);
 133.494 +/* retrieve column dual value (basic solution) */
 133.495 +
 133.496 +int glp_get_unbnd_ray(glp_prob *P);
 133.497 +/* determine variable causing unboundedness */
 133.498 +
 133.499 +int glp_interior(glp_prob *P, const glp_iptcp *parm);
 133.500 +/* solve LP problem with the interior-point method */
 133.501 +
 133.502 +void glp_init_iptcp(glp_iptcp *parm);
 133.503 +/* initialize interior-point solver control parameters */
 133.504 +
 133.505 +int glp_ipt_status(glp_prob *P);
 133.506 +/* retrieve status of interior-point solution */
 133.507 +
 133.508 +double glp_ipt_obj_val(glp_prob *P);
 133.509 +/* retrieve objective value (interior point) */
 133.510 +
 133.511 +double glp_ipt_row_prim(glp_prob *P, int i);
 133.512 +/* retrieve row primal value (interior point) */
 133.513 +
 133.514 +double glp_ipt_row_dual(glp_prob *P, int i);
 133.515 +/* retrieve row dual value (interior point) */
 133.516 +
 133.517 +double glp_ipt_col_prim(glp_prob *P, int j);
 133.518 +/* retrieve column primal value (interior point) */
 133.519 +
 133.520 +double glp_ipt_col_dual(glp_prob *P, int j);
 133.521 +/* retrieve column dual value (interior point) */
 133.522 +
 133.523 +void glp_set_col_kind(glp_prob *P, int j, int kind);
 133.524 +/* set (change) column kind */
 133.525 +
 133.526 +int glp_get_col_kind(glp_prob *P, int j);
 133.527 +/* retrieve column kind */
 133.528 +
 133.529 +int glp_get_num_int(glp_prob *P);
 133.530 +/* retrieve number of integer columns */
 133.531 +
 133.532 +int glp_get_num_bin(glp_prob *P);
 133.533 +/* retrieve number of binary columns */
 133.534 +
 133.535 +int glp_intopt(glp_prob *P, const glp_iocp *parm);
 133.536 +/* solve MIP problem with the branch-and-bound method */
 133.537 +
 133.538 +void glp_init_iocp(glp_iocp *parm);
 133.539 +/* initialize integer optimizer control parameters */
 133.540 +
 133.541 +int glp_mip_status(glp_prob *P);
 133.542 +/* retrieve status of MIP solution */
 133.543 +
 133.544 +double glp_mip_obj_val(glp_prob *P);
 133.545 +/* retrieve objective value (MIP solution) */
 133.546 +
 133.547 +double glp_mip_row_val(glp_prob *P, int i);
 133.548 +/* retrieve row value (MIP solution) */
 133.549 +
 133.550 +double glp_mip_col_val(glp_prob *P, int j);
 133.551 +/* retrieve column value (MIP solution) */
 133.552 +
 133.553 +int glp_print_sol(glp_prob *P, const char *fname);
 133.554 +/* write basic solution in printable format */
 133.555 +
 133.556 +int glp_read_sol(glp_prob *P, const char *fname);
 133.557 +/* read basic solution from text file */
 133.558 +
 133.559 +int glp_write_sol(glp_prob *P, const char *fname);
 133.560 +/* write basic solution to text file */
 133.561 +
 133.562 +int glp_print_ranges(glp_prob *P, int len, const int list[],
 133.563 +      int flags, const char *fname);
 133.564 +/* print sensitivity analysis report */
 133.565 +
 133.566 +int glp_print_ipt(glp_prob *P, const char *fname);
 133.567 +/* write interior-point solution in printable format */
 133.568 +
 133.569 +int glp_read_ipt(glp_prob *P, const char *fname);
 133.570 +/* read interior-point solution from text file */
 133.571 +
 133.572 +int glp_write_ipt(glp_prob *P, const char *fname);
 133.573 +/* write interior-point solution to text file */
 133.574 +
 133.575 +int glp_print_mip(glp_prob *P, const char *fname);
 133.576 +/* write MIP solution in printable format */
 133.577 +
 133.578 +int glp_read_mip(glp_prob *P, const char *fname);
 133.579 +/* read MIP solution from text file */
 133.580 +
 133.581 +int glp_write_mip(glp_prob *P, const char *fname);
 133.582 +/* write MIP solution to text file */
 133.583 +
 133.584 +int glp_bf_exists(glp_prob *P);
 133.585 +/* check if the basis factorization exists */
 133.586 +
 133.587 +int glp_factorize(glp_prob *P);
 133.588 +/* compute the basis factorization */
 133.589 +
 133.590 +int glp_bf_updated(glp_prob *P);
 133.591 +/* check if the basis factorization has been updated */
 133.592 +
 133.593 +void glp_get_bfcp(glp_prob *P, glp_bfcp *parm);
 133.594 +/* retrieve basis factorization control parameters */
 133.595 +
 133.596 +void glp_set_bfcp(glp_prob *P, const glp_bfcp *parm);
 133.597 +/* change basis factorization control parameters */
 133.598 +
 133.599 +int glp_get_bhead(glp_prob *P, int k);
 133.600 +/* retrieve the basis header information */
 133.601 +
 133.602 +int glp_get_row_bind(glp_prob *P, int i);
 133.603 +/* retrieve row index in the basis header */
 133.604 +
 133.605 +int glp_get_col_bind(glp_prob *P, int j);
 133.606 +/* retrieve column index in the basis header */
 133.607 +
 133.608 +void glp_ftran(glp_prob *P, double x[]);
 133.609 +/* perform forward transformation (solve system B*x = b) */
 133.610 +
 133.611 +void glp_btran(glp_prob *P, double x[]);
 133.612 +/* perform backward transformation (solve system B'*x = b) */
 133.613 +
 133.614 +int glp_warm_up(glp_prob *P);
 133.615 +/* "warm up" LP basis */
 133.616 +
 133.617 +int glp_eval_tab_row(glp_prob *P, int k, int ind[], double val[]);
 133.618 +/* compute row of the simplex tableau */
 133.619 +
 133.620 +int glp_eval_tab_col(glp_prob *P, int k, int ind[], double val[]);
 133.621 +/* compute column of the simplex tableau */
 133.622 +
 133.623 +int glp_transform_row(glp_prob *P, int len, int ind[], double val[]);
 133.624 +/* transform explicitly specified row */
 133.625 +
 133.626 +int glp_transform_col(glp_prob *P, int len, int ind[], double val[]);
 133.627 +/* transform explicitly specified column */
 133.628 +
 133.629 +int glp_prim_rtest(glp_prob *P, int len, const int ind[],
 133.630 +      const double val[], int dir, double eps);
 133.631 +/* perform primal ratio test */
 133.632 +
 133.633 +int glp_dual_rtest(glp_prob *P, int len, const int ind[],
 133.634 +      const double val[], int dir, double eps);
 133.635 +/* perform dual ratio test */
 133.636 +
 133.637 +void glp_analyze_bound(glp_prob *P, int k, double *value1, int *var1,
 133.638 +      double *value2, int *var2);
 133.639 +/* analyze active bound of non-basic variable */
 133.640 +
 133.641 +void glp_analyze_coef(glp_prob *P, int k, double *coef1, int *var1,
 133.642 +      double *value1, double *coef2, int *var2, double *value2);
 133.643 +/* analyze objective coefficient at basic variable */
 133.644 +
 133.645 +int glp_ios_reason(glp_tree *T);
 133.646 +/* determine reason for calling the callback routine */
 133.647 +
 133.648 +glp_prob *glp_ios_get_prob(glp_tree *T);
 133.649 +/* access the problem object */
 133.650 +
 133.651 +void glp_ios_tree_size(glp_tree *T, int *a_cnt, int *n_cnt,
 133.652 +      int *t_cnt);
 133.653 +/* determine size of the branch-and-bound tree */
 133.654 +
 133.655 +int glp_ios_curr_node(glp_tree *T);
 133.656 +/* determine current active subproblem */
 133.657 +
 133.658 +int glp_ios_next_node(glp_tree *T, int p);
 133.659 +/* determine next active subproblem */
 133.660 +
 133.661 +int glp_ios_prev_node(glp_tree *T, int p);
 133.662 +/* determine previous active subproblem */
 133.663 +
 133.664 +int glp_ios_up_node(glp_tree *T, int p);
 133.665 +/* determine parent subproblem */
 133.666 +
 133.667 +int glp_ios_node_level(glp_tree *T, int p);
 133.668 +/* determine subproblem level */
 133.669 +
 133.670 +double glp_ios_node_bound(glp_tree *T, int p);
 133.671 +/* determine subproblem local bound */
 133.672 +
 133.673 +int glp_ios_best_node(glp_tree *T);
 133.674 +/* find active subproblem with best local bound */
 133.675 +
 133.676 +double glp_ios_mip_gap(glp_tree *T);
 133.677 +/* compute relative MIP gap */
 133.678 +
 133.679 +void *glp_ios_node_data(glp_tree *T, int p);
 133.680 +/* access subproblem application-specific data */
 133.681 +
 133.682 +void glp_ios_row_attr(glp_tree *T, int i, glp_attr *attr);
 133.683 +/* retrieve additional row attributes */
 133.684 +
 133.685 +int glp_ios_pool_size(glp_tree *T);
 133.686 +/* determine current size of the cut pool */
 133.687 +
 133.688 +int glp_ios_add_row(glp_tree *T,
 133.689 +      const char *name, int klass, int flags, int len, const int ind[],
 133.690 +      const double val[], int type, double rhs);
 133.691 +/* add row (constraint) to the cut pool */
 133.692 +
 133.693 +void glp_ios_del_row(glp_tree *T, int i);
 133.694 +/* remove row (constraint) from the cut pool */
 133.695 +
 133.696 +void glp_ios_clear_pool(glp_tree *T);
 133.697 +/* remove all rows (constraints) from the cut pool */
 133.698 +
 133.699 +int glp_ios_can_branch(glp_tree *T, int j);
 133.700 +/* check if can branch upon specified variable */
 133.701 +
 133.702 +void glp_ios_branch_upon(glp_tree *T, int j, int sel);
 133.703 +/* choose variable to branch upon */
 133.704 +
 133.705 +void glp_ios_select_node(glp_tree *T, int p);
 133.706 +/* select subproblem to continue the search */
 133.707 +
 133.708 +int glp_ios_heur_sol(glp_tree *T, const double x[]);
 133.709 +/* provide solution found by heuristic */
 133.710 +
 133.711 +void glp_ios_terminate(glp_tree *T);
 133.712 +/* terminate the solution process */
 133.713 +
 133.714 +void glp_init_mpscp(glp_mpscp *parm);
 133.715 +/* initialize MPS format control parameters */
 133.716 +
 133.717 +int glp_read_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
 133.718 +      const char *fname);
 133.719 +/* read problem data in MPS format */
 133.720 +
 133.721 +int glp_write_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
 133.722 +      const char *fname);
 133.723 +/* write problem data in MPS format */
 133.724 +
 133.725 +void glp_init_cpxcp(glp_cpxcp *parm);
 133.726 +/* initialize CPLEX LP format control parameters */
 133.727 +
 133.728 +int glp_read_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname);
 133.729 +/* read problem data in CPLEX LP format */
 133.730 +
 133.731 +int glp_write_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname);
 133.732 +/* write problem data in CPLEX LP format */
 133.733 +
 133.734 +int glp_read_prob(glp_prob *P, int flags, const char *fname);
 133.735 +/* read problem data in GLPK format */
 133.736 +
 133.737 +int glp_write_prob(glp_prob *P, int flags, const char *fname);
 133.738 +/* write problem data in GLPK format */
 133.739 +
 133.740 +glp_tran *glp_mpl_alloc_wksp(void);
 133.741 +/* allocate the MathProg translator workspace */
 133.742 +
 133.743 +int glp_mpl_read_model(glp_tran *tran, const char *fname, int skip);
 133.744 +/* read and translate model section */
 133.745 +
 133.746 +int glp_mpl_read_data(glp_tran *tran, const char *fname);
 133.747 +/* read and translate data section */
 133.748 +
 133.749 +int glp_mpl_generate(glp_tran *tran, const char *fname);
 133.750 +/* generate the model */
 133.751 +
 133.752 +void glp_mpl_build_prob(glp_tran *tran, glp_prob *prob);
 133.753 +/* build LP/MIP problem instance from the model */
 133.754 +
 133.755 +int glp_mpl_postsolve(glp_tran *tran, glp_prob *prob, int sol);
 133.756 +/* postsolve the model */
 133.757 +
 133.758 +void glp_mpl_free_wksp(glp_tran *tran);
 133.759 +/* free the MathProg translator workspace */
 133.760 +
 133.761 +int glp_main(int argc, const char *argv[]);
 133.762 +/* stand-alone LP/MIP solver */
 133.763 +
 133.764 +/**********************************************************************/
 133.765 +
 133.766 +#ifndef GLP_LONG_DEFINED
 133.767 +#define GLP_LONG_DEFINED
 133.768 +typedef struct { int lo, hi; } glp_long;
 133.769 +/* long integer data type */
 133.770 +#endif
 133.771 +
 133.772 +int glp_init_env(void);
 133.773 +/* initialize GLPK environment */
 133.774 +
 133.775 +const char *glp_version(void);
 133.776 +/* determine library version */
 133.777 +
 133.778 +int glp_free_env(void);
 133.779 +/* free GLPK environment */
 133.780 +
 133.781 +void glp_printf(const char *fmt, ...);
 133.782 +/* write formatted output to terminal */
 133.783 +
 133.784 +void glp_vprintf(const char *fmt, va_list arg);
 133.785 +/* write formatted output to terminal */
 133.786 +
 133.787 +int glp_term_out(int flag);
 133.788 +/* enable/disable terminal output */
 133.789 +
 133.790 +void glp_term_hook(int (*func)(void *info, const char *s), void *info);
 133.791 +/* install hook to intercept terminal output */
 133.792 +
 133.793 +int glp_open_tee(const char *fname);
 133.794 +/* start copying terminal output to text file */
 133.795 +
 133.796 +int glp_close_tee(void);
 133.797 +/* stop copying terminal output to text file */
 133.798 +
 133.799 +#ifndef GLP_ERROR_DEFINED
 133.800 +#define GLP_ERROR_DEFINED
 133.801 +typedef void (*_glp_error)(const char *fmt, ...);
 133.802 +#endif
 133.803 +
 133.804 +#define glp_error glp_error_(__FILE__, __LINE__)
 133.805 +_glp_error glp_error_(const char *file, int line);
 133.806 +/* display error message and terminate execution */
 133.807 +
 133.808 +#define glp_assert(expr) \
 133.809 +      ((void)((expr) || (glp_assert_(#expr, __FILE__, __LINE__), 1)))
 133.810 +void glp_assert_(const char *expr, const char *file, int line);
 133.811 +/* check for logical condition */
 133.812 +
 133.813 +void glp_error_hook(void (*func)(void *info), void *info);
 133.814 +/* install hook to intercept abnormal termination */
 133.815 +
 133.816 +void *glp_malloc(int size);
 133.817 +/* allocate memory block */
 133.818 +
 133.819 +void *glp_calloc(int n, int size);
 133.820 +/* allocate memory block */
 133.821 +
 133.822 +void glp_free(void *ptr);
 133.823 +/* free memory block */
 133.824 +
 133.825 +void glp_mem_limit(int limit);
 133.826 +/* set memory usage limit */
 133.827 +
 133.828 +void glp_mem_usage(int *count, int *cpeak, glp_long *total,
 133.829 +      glp_long *tpeak);
 133.830 +/* get memory usage information */
 133.831 +
 133.832 +glp_long glp_time(void);
 133.833 +/* determine current universal time */
 133.834 +
 133.835 +double glp_difftime(glp_long t1, glp_long t0);
 133.836 +/* compute difference between two time values */
 133.837 +
 133.838 +/**********************************************************************/
 133.839 +
 133.840 +#ifndef GLP_DATA_DEFINED
 133.841 +#define GLP_DATA_DEFINED
 133.842 +typedef struct { double _opaque_data[100]; } glp_data;
 133.843 +/* plain data file */
 133.844 +#endif
 133.845 +
 133.846 +glp_data *glp_sdf_open_file(const char *fname);
 133.847 +/* open plain data file */
 133.848 +
 133.849 +void glp_sdf_set_jump(glp_data *data, void *jump);
 133.850 +/* set up error handling */
 133.851 +
 133.852 +void glp_sdf_error(glp_data *data, const char *fmt, ...);
 133.853 +/* print error message */
 133.854 +
 133.855 +void glp_sdf_warning(glp_data *data, const char *fmt, ...);
 133.856 +/* print warning message */
 133.857 +
 133.858 +int glp_sdf_read_int(glp_data *data);
 133.859 +/* read integer number */
 133.860 +
 133.861 +double glp_sdf_read_num(glp_data *data);
 133.862 +/* read floating-point number */
 133.863 +
 133.864 +const char *glp_sdf_read_item(glp_data *data);
 133.865 +/* read data item */
 133.866 +
 133.867 +const char *glp_sdf_read_text(glp_data *data);
 133.868 +/* read text until end of line */
 133.869 +
 133.870 +int glp_sdf_line(glp_data *data);
 133.871 +/* determine current line number */
 133.872 +
 133.873 +void glp_sdf_close_file(glp_data *data);
 133.874 +/* close plain data file */
 133.875 +
 133.876 +/**********************************************************************/
 133.877 +
 133.878 +typedef struct _glp_graph glp_graph;
 133.879 +typedef struct _glp_vertex glp_vertex;
 133.880 +typedef struct _glp_arc glp_arc;
 133.881 +
 133.882 +struct _glp_graph
 133.883 +{     /* graph descriptor */
 133.884 +      void *pool; /* DMP *pool; */
 133.885 +      /* memory pool to store graph components */
 133.886 +      char *name;
 133.887 +      /* graph name (1 to 255 chars); NULL means no name is assigned
 133.888 +         to the graph */
 133.889 +      int nv_max;
 133.890 +      /* length of the vertex list (enlarged automatically) */
 133.891 +      int nv;
 133.892 +      /* number of vertices in the graph, 0 <= nv <= nv_max */
 133.893 +      int na;
 133.894 +      /* number of arcs in the graph, na >= 0 */
 133.895 +      glp_vertex **v; /* glp_vertex *v[1+nv_max]; */
 133.896 +      /* v[i], 1 <= i <= nv, is a pointer to i-th vertex */
 133.897 +      void *index; /* AVL *index; */
 133.898 +      /* vertex index to find vertices by their names; NULL means the
 133.899 +         index does not exist */
 133.900 +      int v_size;
 133.901 +      /* size of data associated with each vertex (0 to 256 bytes) */
 133.902 +      int a_size;
 133.903 +      /* size of data associated with each arc (0 to 256 bytes) */
 133.904 +};
 133.905 +
 133.906 +struct _glp_vertex
 133.907 +{     /* vertex descriptor */
 133.908 +      int i;
 133.909 +      /* vertex ordinal number, 1 <= i <= nv */
 133.910 +      char *name;
 133.911 +      /* vertex name (1 to 255 chars); NULL means no name is assigned
 133.912 +         to the vertex */
 133.913 +      void *entry; /* AVLNODE *entry; */
 133.914 +      /* pointer to corresponding entry in the vertex index; NULL means
 133.915 +         that either the index does not exist or the vertex has no name
 133.916 +         assigned */
 133.917 +      void *data;
 133.918 +      /* pointer to data associated with the vertex */
 133.919 +      void *temp;
 133.920 +      /* working pointer */
 133.921 +      glp_arc *in;
 133.922 +      /* pointer to the (unordered) list of incoming arcs */
 133.923 +      glp_arc *out;
 133.924 +      /* pointer to the (unordered) list of outgoing arcs */
 133.925 +};
 133.926 +
 133.927 +struct _glp_arc
 133.928 +{     /* arc descriptor */
 133.929 +      glp_vertex *tail;
 133.930 +      /* pointer to the tail endpoint */
 133.931 +      glp_vertex *head;
 133.932 +      /* pointer to the head endpoint */
 133.933 +      void *data;
 133.934 +      /* pointer to data associated with the arc */
 133.935 +      void *temp;
 133.936 +      /* working pointer */
 133.937 +      glp_arc *t_prev;
 133.938 +      /* pointer to previous arc having the same tail endpoint */
 133.939 +      glp_arc *t_next;
 133.940 +      /* pointer to next arc having the same tail endpoint */
 133.941 +      glp_arc *h_prev;
 133.942 +      /* pointer to previous arc having the same head endpoint */
 133.943 +      glp_arc *h_next;
 133.944 +      /* pointer to next arc having the same head endpoint */
 133.945 +};
 133.946 +
 133.947 +glp_graph *glp_create_graph(int v_size, int a_size);
 133.948 +/* create graph */
 133.949 +
 133.950 +void glp_set_graph_name(glp_graph *G, const char *name);
 133.951 +/* assign (change) graph name */
 133.952 +
 133.953 +int glp_add_vertices(glp_graph *G, int nadd);
 133.954 +/* add new vertices to graph */
 133.955 +
 133.956 +void glp_set_vertex_name(glp_graph *G, int i, const char *name);
 133.957 +/* assign (change) vertex name */
 133.958 +
 133.959 +glp_arc *glp_add_arc(glp_graph *G, int i, int j);
 133.960 +/* add new arc to graph */
 133.961 +
 133.962 +void glp_del_vertices(glp_graph *G, int ndel, const int num[]);
 133.963 +/* delete vertices from graph */
 133.964 +
 133.965 +void glp_del_arc(glp_graph *G, glp_arc *a);
 133.966 +/* delete arc from graph */
 133.967 +
 133.968 +void glp_erase_graph(glp_graph *G, int v_size, int a_size);
 133.969 +/* erase graph content */
 133.970 +
 133.971 +void glp_delete_graph(glp_graph *G);
 133.972 +/* delete graph */
 133.973 +
 133.974 +void glp_create_v_index(glp_graph *G);
 133.975 +/* create vertex name index */
 133.976 +
 133.977 +int glp_find_vertex(glp_graph *G, const char *name);
 133.978 +/* find vertex by its name */
 133.979 +
 133.980 +void glp_delete_v_index(glp_graph *G);
 133.981 +/* delete vertex name index */
 133.982 +
 133.983 +int glp_read_graph(glp_graph *G, const char *fname);
 133.984 +/* read graph from plain text file */
 133.985 +
 133.986 +int glp_write_graph(glp_graph *G, const char *fname);
 133.987 +/* write graph to plain text file */
 133.988 +
 133.989 +void glp_mincost_lp(glp_prob *P, glp_graph *G, int names, int v_rhs,
 133.990 +      int a_low, int a_cap, int a_cost);
 133.991 +/* convert minimum cost flow problem to LP */
 133.992 +
 133.993 +int glp_mincost_okalg(glp_graph *G, int v_rhs, int a_low, int a_cap,
 133.994 +      int a_cost, double *sol, int a_x, int v_pi);
 133.995 +/* find minimum-cost flow with out-of-kilter algorithm */
 133.996 +
 133.997 +void glp_maxflow_lp(glp_prob *P, glp_graph *G, int names, int s,
 133.998 +      int t, int a_cap);
 133.999 +/* convert maximum flow problem to LP */
133.1000 +
133.1001 +int glp_maxflow_ffalg(glp_graph *G, int s, int t, int a_cap,
133.1002 +      double *sol, int a_x, int v_cut);
133.1003 +/* find maximal flow with Ford-Fulkerson algorithm */
133.1004 +
133.1005 +int glp_check_asnprob(glp_graph *G, int v_set);
133.1006 +/* check correctness of assignment problem data */
133.1007 +
133.1008 +/* assignment problem formulation: */
133.1009 +#define GLP_ASN_MIN        1  /* perfect matching (minimization) */
133.1010 +#define GLP_ASN_MAX        2  /* perfect matching (maximization) */
133.1011 +#define GLP_ASN_MMP        3  /* maximum matching */
133.1012 +
133.1013 +int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G, int names,
133.1014 +      int v_set, int a_cost);
133.1015 +/* convert assignment problem to LP */
133.1016 +
133.1017 +int glp_asnprob_okalg(int form, glp_graph *G, int v_set, int a_cost,
133.1018 +      double *sol, int a_x);
133.1019 +/* solve assignment problem with out-of-kilter algorithm */
133.1020 +
133.1021 +int glp_asnprob_hall(glp_graph *G, int v_set, int a_x);
133.1022 +/* find bipartite matching of maximum cardinality */
133.1023 +
133.1024 +double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls);
133.1025 +/* solve critical path problem */
133.1026 +
133.1027 +int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
133.1028 +      int a_cost, const char *fname);
133.1029 +/* read min-cost flow problem data in DIMACS format */
133.1030 +
133.1031 +int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
133.1032 +      int a_cost, const char *fname);
133.1033 +/* write min-cost flow problem data in DIMACS format */
133.1034 +
133.1035 +int glp_read_maxflow(glp_graph *G, int *s, int *t, int a_cap,
133.1036 +      const char *fname);
133.1037 +/* read maximum flow problem data in DIMACS format */
133.1038 +
133.1039 +int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap,
133.1040 +      const char *fname);
133.1041 +/* write maximum flow problem data in DIMACS format */
133.1042 +
133.1043 +int glp_read_asnprob(glp_graph *G, int v_set, int a_cost, const char
133.1044 +      *fname);
133.1045 +/* read assignment problem data in DIMACS format */
133.1046 +
133.1047 +int glp_write_asnprob(glp_graph *G, int v_set, int a_cost, const char
133.1048 +      *fname);
133.1049 +/* write assignment problem data in DIMACS format */
133.1050 +
133.1051 +int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname);
133.1052 +/* read graph in DIMACS clique/coloring format */
133.1053 +
133.1054 +int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname);
133.1055 +/* write graph in DIMACS clique/coloring format */
133.1056 +
133.1057 +int glp_netgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
133.1058 +      const int parm[1+15]);
133.1059 +/* Klingman's network problem generator */
133.1060 +
133.1061 +int glp_gridgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
133.1062 +      const int parm[1+14]);
133.1063 +/* grid-like network problem generator */
133.1064 +
133.1065 +int glp_rmfgen(glp_graph *G, int *s, int *t, int a_cap,
133.1066 +      const int parm[1+5]);
133.1067 +/* Goldfarb's maximum flow problem generator */
133.1068 +
133.1069 +int glp_weak_comp(glp_graph *G, int v_num);
133.1070 +/* find all weakly connected components of graph */
133.1071 +
133.1072 +int glp_strong_comp(glp_graph *G, int v_num);
133.1073 +/* find all strongly connected components of graph */
133.1074 +
133.1075 +int glp_top_sort(glp_graph *G, int v_num);
133.1076 +/* topological sorting of acyclic digraph */
133.1077 +
133.1078 +int glp_wclique_exact(glp_graph *G, int v_wgt, double *sol, int v_set);
133.1079 +/* find maximum weight clique with exact algorithm */
133.1080 +
133.1081 +/***********************************************************************
133.1082 +*  NOTE: All symbols defined below are obsolete and kept here only for
133.1083 +*        backward compatibility.
133.1084 +***********************************************************************/
133.1085 +
133.1086 +#define LPX glp_prob
133.1087 +
133.1088 +/* problem class: */
133.1089 +#define LPX_LP          100   /* linear programming (LP) */
133.1090 +#define LPX_MIP         101   /* mixed integer programming (MIP) */
133.1091 +
133.1092 +/* type of auxiliary/structural variable: */
133.1093 +#define LPX_FR          110   /* free variable */
133.1094 +#define LPX_LO          111   /* variable with lower bound */
133.1095 +#define LPX_UP          112   /* variable with upper bound */
133.1096 +#define LPX_DB          113   /* double-bounded variable */
133.1097 +#define LPX_FX          114   /* fixed variable */
133.1098 +
133.1099 +/* optimization direction flag: */
133.1100 +#define LPX_MIN         120   /* minimization */
133.1101 +#define LPX_MAX         121   /* maximization */
133.1102 +
133.1103 +/* status of primal basic solution: */
133.1104 +#define LPX_P_UNDEF     132   /* primal solution is undefined */
133.1105 +#define LPX_P_FEAS      133   /* solution is primal feasible */
133.1106 +#define LPX_P_INFEAS    134   /* solution is primal infeasible */
133.1107 +#define LPX_P_NOFEAS    135   /* no primal feasible solution exists */
133.1108 +
133.1109 +/* status of dual basic solution: */
133.1110 +#define LPX_D_UNDEF     136   /* dual solution is undefined */
133.1111 +#define LPX_D_FEAS      137   /* solution is dual feasible */
133.1112 +#define LPX_D_INFEAS    138   /* solution is dual infeasible */
133.1113 +#define LPX_D_NOFEAS    139   /* no dual feasible solution exists */
133.1114 +
133.1115 +/* status of auxiliary/structural variable: */
133.1116 +#define LPX_BS          140   /* basic variable */
133.1117 +#define LPX_NL          141   /* non-basic variable on lower bound */
133.1118 +#define LPX_NU          142   /* non-basic variable on upper bound */
133.1119 +#define LPX_NF          143   /* non-basic free variable */
133.1120 +#define LPX_NS          144   /* non-basic fixed variable */
133.1121 +
133.1122 +/* status of interior-point solution: */
133.1123 +#define LPX_T_UNDEF     150   /* interior solution is undefined */
133.1124 +#define LPX_T_OPT       151   /* interior solution is optimal */
133.1125 +
133.1126 +/* kind of structural variable: */
133.1127 +#define LPX_CV          160   /* continuous variable */
133.1128 +#define LPX_IV          161   /* integer variable */
133.1129 +
133.1130 +/* status of integer solution: */
133.1131 +#define LPX_I_UNDEF     170   /* integer solution is undefined */
133.1132 +#define LPX_I_OPT       171   /* integer solution is optimal */
133.1133 +#define LPX_I_FEAS      172   /* integer solution is feasible */
133.1134 +#define LPX_I_NOFEAS    173   /* no integer solution exists */
133.1135 +
133.1136 +/* status codes reported by the routine lpx_get_status: */
133.1137 +#define LPX_OPT         180   /* optimal */
133.1138 +#define LPX_FEAS        181   /* feasible */
133.1139 +#define LPX_INFEAS      182   /* infeasible */
133.1140 +#define LPX_NOFEAS      183   /* no feasible */
133.1141 +#define LPX_UNBND       184   /* unbounded */
133.1142 +#define LPX_UNDEF       185   /* undefined */
133.1143 +
133.1144 +/* exit codes returned by solver routines: */
133.1145 +#define LPX_E_OK        200   /* success */
133.1146 +#define LPX_E_EMPTY     201   /* empty problem */
133.1147 +#define LPX_E_BADB      202   /* invalid initial basis */
133.1148 +#define LPX_E_INFEAS    203   /* infeasible initial solution */
133.1149 +#define LPX_E_FAULT     204   /* unable to start the search */
133.1150 +#define LPX_E_OBJLL     205   /* objective lower limit reached */
133.1151 +#define LPX_E_OBJUL     206   /* objective upper limit reached */
133.1152 +#define LPX_E_ITLIM     207   /* iterations limit exhausted */
133.1153 +#define LPX_E_TMLIM     208   /* time limit exhausted */
133.1154 +#define LPX_E_NOFEAS    209   /* no feasible solution */
133.1155 +#define LPX_E_INSTAB    210   /* numerical instability */
133.1156 +#define LPX_E_SING      211   /* problems with basis matrix */
133.1157 +#define LPX_E_NOCONV    212   /* no convergence (interior) */
133.1158 +#define LPX_E_NOPFS     213   /* no primal feas. sol. (LP presolver) */
133.1159 +#define LPX_E_NODFS     214   /* no dual feas. sol. (LP presolver) */
133.1160 +#define LPX_E_MIPGAP    215   /* relative mip gap tolerance reached */
133.1161 +
133.1162 +/* control parameter identifiers: */
133.1163 +#define LPX_K_MSGLEV    300   /* lp->msg_lev */
133.1164 +#define LPX_K_SCALE     301   /* lp->scale */
133.1165 +#define LPX_K_DUAL      302   /* lp->dual */
133.1166 +#define LPX_K_PRICE     303   /* lp->price */
133.1167 +#define LPX_K_RELAX     304   /* lp->relax */
133.1168 +#define LPX_K_TOLBND    305   /* lp->tol_bnd */
133.1169 +#define LPX_K_TOLDJ     306   /* lp->tol_dj */
133.1170 +#define LPX_K_TOLPIV    307   /* lp->tol_piv */
133.1171 +#define LPX_K_ROUND     308   /* lp->round */
133.1172 +#define LPX_K_OBJLL     309   /* lp->obj_ll */
133.1173 +#define LPX_K_OBJUL     310   /* lp->obj_ul */
133.1174 +#define LPX_K_ITLIM     311   /* lp->it_lim */
133.1175 +#define LPX_K_ITCNT     312   /* lp->it_cnt */
133.1176 +#define LPX_K_TMLIM     313   /* lp->tm_lim */
133.1177 +#define LPX_K_OUTFRQ    314   /* lp->out_frq */
133.1178 +#define LPX_K_OUTDLY    315   /* lp->out_dly */
133.1179 +#define LPX_K_BRANCH    316   /* lp->branch */
133.1180 +#define LPX_K_BTRACK    317   /* lp->btrack */
133.1181 +#define LPX_K_TOLINT    318   /* lp->tol_int */
133.1182 +#define LPX_K_TOLOBJ    319   /* lp->tol_obj */
133.1183 +#define LPX_K_MPSINFO   320   /* lp->mps_info */
133.1184 +#define LPX_K_MPSOBJ    321   /* lp->mps_obj */
133.1185 +#define LPX_K_MPSORIG   322   /* lp->mps_orig */
133.1186 +#define LPX_K_MPSWIDE   323   /* lp->mps_wide */
133.1187 +#define LPX_K_MPSFREE   324   /* lp->mps_free */
133.1188 +#define LPX_K_MPSSKIP   325   /* lp->mps_skip */
133.1189 +#define LPX_K_LPTORIG   326   /* lp->lpt_orig */
133.1190 +#define LPX_K_PRESOL    327   /* lp->presol */
133.1191 +#define LPX_K_BINARIZE  328   /* lp->binarize */
133.1192 +#define LPX_K_USECUTS   329   /* lp->use_cuts */
133.1193 +#define LPX_K_BFTYPE    330   /* lp->bfcp->type */
133.1194 +#define LPX_K_MIPGAP    331   /* lp->mip_gap */
133.1195 +
133.1196 +#define LPX_C_COVER     0x01  /* mixed cover cuts */
133.1197 +#define LPX_C_CLIQUE    0x02  /* clique cuts */
133.1198 +#define LPX_C_GOMORY    0x04  /* Gomory's mixed integer cuts */
133.1199 +#define LPX_C_MIR       0x08  /* mixed integer rounding cuts */
133.1200 +#define LPX_C_ALL       0xFF  /* all cuts */
133.1201 +
133.1202 +typedef struct
133.1203 +{     /* this structure contains results reported by the routines which
133.1204 +         checks Karush-Kuhn-Tucker conditions (for details see comments
133.1205 +         to those routines) */
133.1206 +      /*--------------------------------------------------------------*/
133.1207 +      /* xR - A * xS = 0 (KKT.PE) */
133.1208 +      double pe_ae_max;
133.1209 +      /* largest absolute error */
133.1210 +      int    pe_ae_row;
133.1211 +      /* number of row with largest absolute error */
133.1212 +      double pe_re_max;
133.1213 +      /* largest relative error */
133.1214 +      int    pe_re_row;
133.1215 +      /* number of row with largest relative error */
133.1216 +      int    pe_quality;
133.1217 +      /* quality of primal solution:
133.1218 +         'H' - high
133.1219 +         'M' - medium
133.1220 +         'L' - low
133.1221 +         '?' - primal solution is wrong */
133.1222 +      /*--------------------------------------------------------------*/
133.1223 +      /* l[k] <= x[k] <= u[k] (KKT.PB) */
133.1224 +      double pb_ae_max;
133.1225 +      /* largest absolute error */
133.1226 +      int    pb_ae_ind;
133.1227 +      /* number of variable with largest absolute error */
133.1228 +      double pb_re_max;
133.1229 +      /* largest relative error */
133.1230 +      int    pb_re_ind;
133.1231 +      /* number of variable with largest relative error */
133.1232 +      int    pb_quality;
133.1233 +      /* quality of primal feasibility:
133.1234 +         'H' - high
133.1235 +         'M' - medium
133.1236 +         'L' - low
133.1237 +         '?' - primal solution is infeasible */
133.1238 +      /*--------------------------------------------------------------*/
133.1239 +      /* A' * (dR - cR) + (dS - cS) = 0 (KKT.DE) */
133.1240 +      double de_ae_max;
133.1241 +      /* largest absolute error */
133.1242 +      int    de_ae_col;
133.1243 +      /* number of column with largest absolute error */
133.1244 +      double de_re_max;
133.1245 +      /* largest relative error */
133.1246 +      int    de_re_col;
133.1247 +      /* number of column with largest relative error */
133.1248 +      int    de_quality;
133.1249 +      /* quality of dual solution:
133.1250 +         'H' - high
133.1251 +         'M' - medium
133.1252 +         'L' - low
133.1253 +         '?' - dual solution is wrong */
133.1254 +      /*--------------------------------------------------------------*/
133.1255 +      /* d[k] >= 0 or d[k] <= 0 (KKT.DB) */
133.1256 +      double db_ae_max;
133.1257 +      /* largest absolute error */
133.1258 +      int    db_ae_ind;
133.1259 +      /* number of variable with largest absolute error */
133.1260 +      double db_re_max;
133.1261 +      /* largest relative error */
133.1262 +      int    db_re_ind;
133.1263 +      /* number of variable with largest relative error */
133.1264 +      int    db_quality;
133.1265 +      /* quality of dual feasibility:
133.1266 +         'H' - high
133.1267 +         'M' - medium
133.1268 +         'L' - low
133.1269 +         '?' - dual solution is infeasible */
133.1270 +      /*--------------------------------------------------------------*/
133.1271 +      /* (x[k] - bound of x[k]) * d[k] = 0 (KKT.CS) */
133.1272 +      double cs_ae_max;
133.1273 +      /* largest absolute error */
133.1274 +      int    cs_ae_ind;
133.1275 +      /* number of variable with largest absolute error */
133.1276 +      double cs_re_max;
133.1277 +      /* largest relative error */
133.1278 +      int    cs_re_ind;
133.1279 +      /* number of variable with largest relative error */
133.1280 +      int    cs_quality;
133.1281 +      /* quality of complementary slackness:
133.1282 +         'H' - high
133.1283 +         'M' - medium
133.1284 +         'L' - low
133.1285 +         '?' - primal and dual solutions are not complementary */
133.1286 +} LPXKKT;
133.1287 +
133.1288 +#define lpx_create_prob _glp_lpx_create_prob
133.1289 +LPX *lpx_create_prob(void);
133.1290 +/* create problem object */
133.1291 +
133.1292 +#define lpx_set_prob_name _glp_lpx_set_prob_name
133.1293 +void lpx_set_prob_name(LPX *lp, const char *name);
133.1294 +/* assign (change) problem name */
133.1295 +
133.1296 +#define lpx_set_obj_name _glp_lpx_set_obj_name
133.1297 +void lpx_set_obj_name(LPX *lp, const char *name);
133.1298 +/* assign (change) objective function name */
133.1299 +
133.1300 +#define lpx_set_obj_dir _glp_lpx_set_obj_dir
133.1301 +void lpx_set_obj_dir(LPX *lp, int dir);
133.1302 +/* set (change) optimization direction flag */
133.1303 +
133.1304 +#define lpx_add_rows _glp_lpx_add_rows
133.1305 +int lpx_add_rows(LPX *lp, int nrs);
133.1306 +/* add new rows to problem object */
133.1307 +
133.1308 +#define lpx_add_cols _glp_lpx_add_cols
133.1309 +int lpx_add_cols(LPX *lp, int ncs);
133.1310 +/* add new columns to problem object */
133.1311 +
133.1312 +#define lpx_set_row_name _glp_lpx_set_row_name
133.1313 +void lpx_set_row_name(LPX *lp, int i, const char *name);
133.1314 +/* assign (change) row name */
133.1315 +
133.1316 +#define lpx_set_col_name _glp_lpx_set_col_name
133.1317 +void lpx_set_col_name(LPX *lp, int j, const char *name);
133.1318 +/* assign (change) column name */
133.1319 +
133.1320 +#define lpx_set_row_bnds _glp_lpx_set_row_bnds
133.1321 +void lpx_set_row_bnds(LPX *lp, int i, int type, double lb, double ub);
133.1322 +/* set (change) row bounds */
133.1323 +
133.1324 +#define lpx_set_col_bnds _glp_lpx_set_col_bnds
133.1325 +void lpx_set_col_bnds(LPX *lp, int j, int type, double lb, double ub);
133.1326 +/* set (change) column bounds */
133.1327 +
133.1328 +#define lpx_set_obj_coef _glp_lpx_set_obj_coef
133.1329 +void lpx_set_obj_coef(glp_prob *lp, int j, double coef);
133.1330 +/* set (change) obj. coefficient or constant term */
133.1331 +
133.1332 +#define lpx_set_mat_row _glp_lpx_set_mat_row
133.1333 +void lpx_set_mat_row(LPX *lp, int i, int len, const int ind[],
133.1334 +      const double val[]);
133.1335 +/* set (replace) row of the constraint matrix */
133.1336 +
133.1337 +#define lpx_set_mat_col _glp_lpx_set_mat_col
133.1338 +void lpx_set_mat_col(LPX *lp, int j, int len, const int ind[],
133.1339 +      const double val[]);
133.1340 +/* set (replace) column of the constraint matrix */
133.1341 +
133.1342 +#define lpx_load_matrix _glp_lpx_load_matrix
133.1343 +void lpx_load_matrix(LPX *lp, int ne, const int ia[], const int ja[],
133.1344 +      const double ar[]);
133.1345 +/* load (replace) the whole constraint matrix */
133.1346 +
133.1347 +#define lpx_del_rows _glp_lpx_del_rows
133.1348 +void lpx_del_rows(LPX *lp, int nrs, const int num[]);
133.1349 +/* delete specified rows from problem object */
133.1350 +
133.1351 +#define lpx_del_cols _glp_lpx_del_cols
133.1352 +void lpx_del_cols(LPX *lp, int ncs, const int num[]);
133.1353 +/* delete specified columns from problem object */
133.1354 +
133.1355 +#define lpx_delete_prob _glp_lpx_delete_prob
133.1356 +void lpx_delete_prob(LPX *lp);
133.1357 +/* delete problem object */
133.1358 +
133.1359 +#define lpx_get_prob_name _glp_lpx_get_prob_name
133.1360 +const char *lpx_get_prob_name(LPX *lp);
133.1361 +/* retrieve problem name */
133.1362 +
133.1363 +#define lpx_get_obj_name _glp_lpx_get_obj_name
133.1364 +const char *lpx_get_obj_name(LPX *lp);
133.1365 +/* retrieve objective function name */
133.1366 +
133.1367 +#define lpx_get_obj_dir _glp_lpx_get_obj_dir
133.1368 +int lpx_get_obj_dir(LPX *lp);
133.1369 +/* retrieve optimization direction flag */
133.1370 +
133.1371 +#define lpx_get_num_rows _glp_lpx_get_num_rows
133.1372 +int lpx_get_num_rows(LPX *lp);
133.1373 +/* retrieve number of rows */
133.1374 +
133.1375 +#define lpx_get_num_cols _glp_lpx_get_num_cols
133.1376 +int lpx_get_num_cols(LPX *lp);
133.1377 +/* retrieve number of columns */
133.1378 +
133.1379 +#define lpx_get_row_name _glp_lpx_get_row_name
133.1380 +const char *lpx_get_row_name(LPX *lp, int i);
133.1381 +/* retrieve row name */
133.1382 +
133.1383 +#define lpx_get_col_name _glp_lpx_get_col_name
133.1384 +const char *lpx_get_col_name(LPX *lp, int j);
133.1385 +/* retrieve column name */
133.1386 +
133.1387 +#define lpx_get_row_type _glp_lpx_get_row_type
133.1388 +int lpx_get_row_type(LPX *lp, int i);
133.1389 +/* retrieve row type */
133.1390 +
133.1391 +#define lpx_get_row_lb _glp_lpx_get_row_lb
133.1392 +double lpx_get_row_lb(LPX *lp, int i);
133.1393 +/* retrieve row lower bound */
133.1394 +
133.1395 +#define lpx_get_row_ub _glp_lpx_get_row_ub
133.1396 +double lpx_get_row_ub(LPX *lp, int i);
133.1397 +/* retrieve row upper bound */
133.1398 +
133.1399 +#define lpx_get_row_bnds _glp_lpx_get_row_bnds
133.1400 +void lpx_get_row_bnds(LPX *lp, int i, int *typx, double *lb,
133.1401 +      double *ub);
133.1402 +/* retrieve row bounds */
133.1403 +
133.1404 +#define lpx_get_col_type _glp_lpx_get_col_type
133.1405 +int lpx_get_col_type(LPX *lp, int j);
133.1406 +/* retrieve column type */
133.1407 +
133.1408 +#define lpx_get_col_lb _glp_lpx_get_col_lb
133.1409 +double lpx_get_col_lb(LPX *lp, int j);
133.1410 +/* retrieve column lower bound */
133.1411 +
133.1412 +#define lpx_get_col_ub _glp_lpx_get_col_ub
133.1413 +double lpx_get_col_ub(LPX *lp, int j);
133.1414 +/* retrieve column upper bound */
133.1415 +
133.1416 +#define lpx_get_col_bnds _glp_lpx_get_col_bnds
133.1417 +void lpx_get_col_bnds(LPX *lp, int j, int *typx, double *lb,
133.1418 +      double *ub);
133.1419 +/* retrieve column bounds */
133.1420 +
133.1421 +#define lpx_get_obj_coef _glp_lpx_get_obj_coef
133.1422 +double lpx_get_obj_coef(LPX *lp, int j);
133.1423 +/* retrieve obj. coefficient or constant term */
133.1424 +
133.1425 +#define lpx_get_num_nz _glp_lpx_get_num_nz
133.1426 +int lpx_get_num_nz(LPX *lp);
133.1427 +/* retrieve number of constraint coefficients */
133.1428 +
133.1429 +#define lpx_get_mat_row _glp_lpx_get_mat_row
133.1430 +int lpx_get_mat_row(LPX *lp, int i, int ind[], double val[]);
133.1431 +/* retrieve row of the constraint matrix */
133.1432 +
133.1433 +#define lpx_get_mat_col _glp_lpx_get_mat_col
133.1434 +int lpx_get_mat_col(LPX *lp, int j, int ind[], double val[]);
133.1435 +/* retrieve column of the constraint matrix */
133.1436 +
133.1437 +#define lpx_create_index _glp_lpx_create_index
133.1438 +void lpx_create_index(LPX *lp);
133.1439 +/* create the name index */
133.1440 +
133.1441 +#define lpx_find_row _glp_lpx_find_row
133.1442 +int lpx_find_row(LPX *lp, const char *name);
133.1443 +/* find row by its name */
133.1444 +
133.1445 +#define lpx_find_col _glp_lpx_find_col
133.1446 +int lpx_find_col(LPX *lp, const char *name);
133.1447 +/* find column by its name */
133.1448 +
133.1449 +#define lpx_delete_index _glp_lpx_delete_index
133.1450 +void lpx_delete_index(LPX *lp);
133.1451 +/* delete the name index */
133.1452 +
133.1453 +#define lpx_scale_prob _glp_lpx_scale_prob
133.1454 +void lpx_scale_prob(LPX *lp);
133.1455 +/* scale problem data */
133.1456 +
133.1457 +#define lpx_unscale_prob _glp_lpx_unscale_prob
133.1458 +void lpx_unscale_prob(LPX *lp);
133.1459 +/* unscale problem data */
133.1460 +
133.1461 +#define lpx_set_row_stat _glp_lpx_set_row_stat
133.1462 +void lpx_set_row_stat(LPX *lp, int i, int stat);
133.1463 +/* set (change) row status */
133.1464 +
133.1465 +#define lpx_set_col_stat _glp_lpx_set_col_stat
133.1466 +void lpx_set_col_stat(LPX *lp, int j, int stat);
133.1467 +/* set (change) column status */
133.1468 +
133.1469 +#define lpx_std_basis _glp_lpx_std_basis
133.1470 +void lpx_std_basis(LPX *lp);
133.1471 +/* construct standard initial LP basis */
133.1472 +
133.1473 +#define lpx_adv_basis _glp_lpx_adv_basis
133.1474 +void lpx_adv_basis(LPX *lp);
133.1475 +/* construct advanced initial LP basis */
133.1476 +
133.1477 +#define lpx_cpx_basis _glp_lpx_cpx_basis
133.1478 +void lpx_cpx_basis(LPX *lp);
133.1479 +/* construct Bixby's initial LP basis */
133.1480 +
133.1481 +#define lpx_simplex _glp_lpx_simplex
133.1482 +int lpx_simplex(LPX *lp);
133.1483 +/* easy-to-use driver to the simplex method */
133.1484 +
133.1485 +#define lpx_exact _glp_lpx_exact
133.1486 +int lpx_exact(LPX *lp);
133.1487 +/* easy-to-use driver to the exact simplex method */
133.1488 +
133.1489 +#define lpx_get_status _glp_lpx_get_status
133.1490 +int lpx_get_status(LPX *lp);
133.1491 +/* retrieve generic status of basic solution */
133.1492 +
133.1493 +#define lpx_get_prim_stat _glp_lpx_get_prim_stat
133.1494 +int lpx_get_prim_stat(LPX *lp);
133.1495 +/* retrieve primal status of basic solution */
133.1496 +
133.1497 +#define lpx_get_dual_stat _glp_lpx_get_dual_stat
133.1498 +int lpx_get_dual_stat(LPX *lp);
133.1499 +/* retrieve dual status of basic solution */
133.1500 +
133.1501 +#define lpx_get_obj_val _glp_lpx_get_obj_val
133.1502 +double lpx_get_obj_val(LPX *lp);
133.1503 +/* retrieve objective value (basic solution) */
133.1504 +
133.1505 +#define lpx_get_row_stat _glp_lpx_get_row_stat
133.1506 +int lpx_get_row_stat(LPX *lp, int i);
133.1507 +/* retrieve row status (basic solution) */
133.1508 +
133.1509 +#define lpx_get_row_prim _glp_lpx_get_row_prim
133.1510 +double lpx_get_row_prim(LPX *lp, int i);
133.1511 +/* retrieve row primal value (basic solution) */
133.1512 +
133.1513 +#define lpx_get_row_dual _glp_lpx_get_row_dual
133.1514 +double lpx_get_row_dual(LPX *lp, int i);
133.1515 +/* retrieve row dual value (basic solution) */
133.1516 +
133.1517 +#define lpx_get_row_info _glp_lpx_get_row_info
133.1518 +void lpx_get_row_info(LPX *lp, int i, int *tagx, double *vx,
133.1519 +      double *dx);
133.1520 +/* obtain row solution information */
133.1521 +
133.1522 +#define lpx_get_col_stat _glp_lpx_get_col_stat
133.1523 +int lpx_get_col_stat(LPX *lp, int j);
133.1524 +/* retrieve column status (basic solution) */
133.1525 +
133.1526 +#define lpx_get_col_prim _glp_lpx_get_col_prim
133.1527 +double lpx_get_col_prim(LPX *lp, int j);
133.1528 +/* retrieve column primal value (basic solution) */
133.1529 +
133.1530 +#define lpx_get_col_dual _glp_lpx_get_col_dual
133.1531 +double lpx_get_col_dual(glp_prob *lp, int j);
133.1532 +/* retrieve column dual value (basic solution) */
133.1533 +
133.1534 +#define lpx_get_col_info _glp_lpx_get_col_info
133.1535 +void lpx_get_col_info(LPX *lp, int j, int *tagx, double *vx,
133.1536 +      double *dx);
133.1537 +/* obtain column solution information (obsolete) */
133.1538 +
133.1539 +#define lpx_get_ray_info _glp_lpx_get_ray_info
133.1540 +int lpx_get_ray_info(LPX *lp);
133.1541 +/* determine what causes primal unboundness */
133.1542 +
133.1543 +#define lpx_check_kkt _glp_lpx_check_kkt
133.1544 +void lpx_check_kkt(LPX *lp, int scaled, LPXKKT *kkt);
133.1545 +/* check Karush-Kuhn-Tucker conditions */
133.1546 +
133.1547 +#define lpx_warm_up _glp_lpx_warm_up
133.1548 +int lpx_warm_up(LPX *lp);
133.1549 +/* "warm up" LP basis */
133.1550 +
133.1551 +#define lpx_eval_tab_row _glp_lpx_eval_tab_row
133.1552 +int lpx_eval_tab_row(LPX *lp, int k, int ind[], double val[]);
133.1553 +/* compute row of the simplex table */
133.1554 +
133.1555 +#define lpx_eval_tab_col _glp_lpx_eval_tab_col
133.1556 +int lpx_eval_tab_col(LPX *lp, int k, int ind[], double val[]);
133.1557 +/* compute column of the simplex table */
133.1558 +
133.1559 +#define lpx_transform_row _glp_lpx_transform_row
133.1560 +int lpx_transform_row(LPX *lp, int len, int ind[], double val[]);
133.1561 +/* transform explicitly specified row */
133.1562 +
133.1563 +#define lpx_transform_col _glp_lpx_transform_col
133.1564 +int lpx_transform_col(LPX *lp, int len, int ind[], double val[]);
133.1565 +/* transform explicitly specified column */
133.1566 +
133.1567 +#define lpx_prim_ratio_test _glp_lpx_prim_ratio_test
133.1568 +int lpx_prim_ratio_test(LPX *lp, int len, const int ind[],
133.1569 +      const double val[], int how, double tol);
133.1570 +/* perform primal ratio test */
133.1571 +
133.1572 +#define lpx_dual_ratio_test _glp_lpx_dual_ratio_test
133.1573 +int lpx_dual_ratio_test(LPX *lp, int len, const int ind[],
133.1574 +      const double val[], int how, double tol);
133.1575 +/* perform dual ratio test */
133.1576 +
133.1577 +#define lpx_interior _glp_lpx_interior
133.1578 +int lpx_interior(LPX *lp);
133.1579 +/* easy-to-use driver to the interior point method */
133.1580 +
133.1581 +#define lpx_ipt_status _glp_lpx_ipt_status
133.1582 +int lpx_ipt_status(LPX *lp);
133.1583 +/* retrieve status of interior-point solution */
133.1584 +
133.1585 +#define lpx_ipt_obj_val _glp_lpx_ipt_obj_val
133.1586 +double lpx_ipt_obj_val(LPX *lp);
133.1587 +/* retrieve objective value (interior point) */
133.1588 +
133.1589 +#define lpx_ipt_row_prim _glp_lpx_ipt_row_prim
133.1590 +double lpx_ipt_row_prim(LPX *lp, int i);
133.1591 +/* retrieve row primal value (interior point) */
133.1592 +
133.1593 +#define lpx_ipt_row_dual _glp_lpx_ipt_row_dual
133.1594 +double lpx_ipt_row_dual(LPX *lp, int i);
133.1595 +/* retrieve row dual value (interior point) */
133.1596 +
133.1597 +#define lpx_ipt_col_prim _glp_lpx_ipt_col_prim
133.1598 +double lpx_ipt_col_prim(LPX *lp, int j);
133.1599 +/* retrieve column primal value (interior point) */
133.1600 +
133.1601 +#define lpx_ipt_col_dual _glp_lpx_ipt_col_dual
133.1602 +double lpx_ipt_col_dual(LPX *lp, int j);
133.1603 +/* retrieve column dual value (interior point) */
133.1604 +
133.1605 +#define lpx_set_class _glp_lpx_set_class
133.1606 +void lpx_set_class(LPX *lp, int klass);
133.1607 +/* set problem class */
133.1608 +
133.1609 +#define lpx_get_class _glp_lpx_get_class
133.1610 +int lpx_get_class(LPX *lp);
133.1611 +/* determine problem klass */
133.1612 +
133.1613 +#define lpx_set_col_kind _glp_lpx_set_col_kind
133.1614 +void lpx_set_col_kind(LPX *lp, int j, int kind);
133.1615 +/* set (change) column kind */
133.1616 +
133.1617 +#define lpx_get_col_kind _glp_lpx_get_col_kind
133.1618 +int lpx_get_col_kind(LPX *lp, int j);
133.1619 +/* retrieve column kind */
133.1620 +
133.1621 +#define lpx_get_num_int _glp_lpx_get_num_int
133.1622 +int lpx_get_num_int(LPX *lp);
133.1623 +/* retrieve number of integer columns */
133.1624 +
133.1625 +#define lpx_get_num_bin _glp_lpx_get_num_bin
133.1626 +int lpx_get_num_bin(LPX *lp);
133.1627 +/* retrieve number of binary columns */
133.1628 +
133.1629 +#define lpx_integer _glp_lpx_integer
133.1630 +int lpx_integer(LPX *lp);
133.1631 +/* easy-to-use driver to the branch-and-bound method */
133.1632 +
133.1633 +#define lpx_intopt _glp_lpx_intopt
133.1634 +int lpx_intopt(LPX *lp);
133.1635 +/* easy-to-use driver to the branch-and-bound method */
133.1636 +
133.1637 +#define lpx_mip_status _glp_lpx_mip_status
133.1638 +int lpx_mip_status(LPX *lp);
133.1639 +/* retrieve status of MIP solution */
133.1640 +
133.1641 +#define lpx_mip_obj_val _glp_lpx_mip_obj_val
133.1642 +double lpx_mip_obj_val(LPX *lp);
133.1643 +/* retrieve objective value (MIP solution) */
133.1644 +
133.1645 +#define lpx_mip_row_val _glp_lpx_mip_row_val
133.1646 +double lpx_mip_row_val(LPX *lp, int i);
133.1647 +/* retrieve row value (MIP solution) */
133.1648 +
133.1649 +#define lpx_mip_col_val _glp_lpx_mip_col_val
133.1650 +double lpx_mip_col_val(LPX *lp, int j);
133.1651 +/* retrieve column value (MIP solution) */
133.1652 +
133.1653 +#define lpx_check_int _glp_lpx_check_int
133.1654 +void lpx_check_int(LPX *lp, LPXKKT *kkt);
133.1655 +/* check integer feasibility conditions */
133.1656 +
133.1657 +#define lpx_reset_parms _glp_lpx_reset_parms
133.1658 +void lpx_reset_parms(LPX *lp);
133.1659 +/* reset control parameters to default values */
133.1660 +
133.1661 +#define lpx_set_int_parm _glp_lpx_set_int_parm
133.1662 +void lpx_set_int_parm(LPX *lp, int parm, int val);
133.1663 +/* set (change) integer control parameter */
133.1664 +
133.1665 +#define lpx_get_int_parm _glp_lpx_get_int_parm
133.1666 +int lpx_get_int_parm(LPX *lp, int parm);
133.1667 +/* query integer control parameter */
133.1668 +
133.1669 +#define lpx_set_real_parm _glp_lpx_set_real_parm
133.1670 +void lpx_set_real_parm(LPX *lp, int parm, double val);
133.1671 +/* set (change) real control parameter */
133.1672 +
133.1673 +#define lpx_get_real_parm _glp_lpx_get_real_parm
133.1674 +double lpx_get_real_parm(LPX *lp, int parm);
133.1675 +/* query real control parameter */
133.1676 +
133.1677 +#define lpx_read_mps _glp_lpx_read_mps
133.1678 +LPX *lpx_read_mps(const char *fname);
133.1679 +/* read problem data in fixed MPS format */
133.1680 +
133.1681 +#define lpx_write_mps _glp_lpx_write_mps
133.1682 +int lpx_write_mps(LPX *lp, const char *fname);
133.1683 +/* write problem data in fixed MPS format */
133.1684 +
133.1685 +#define lpx_read_bas _glp_lpx_read_bas
133.1686 +int lpx_read_bas(LPX *lp, const char *fname);
133.1687 +/* read LP basis in fixed MPS format */
133.1688 +
133.1689 +#define lpx_write_bas _glp_lpx_write_bas
133.1690 +int lpx_write_bas(LPX *lp, const char *fname);
133.1691 +/* write LP basis in fixed MPS format */
133.1692 +
133.1693 +#define lpx_read_freemps _glp_lpx_read_freemps
133.1694 +LPX *lpx_read_freemps(const char *fname);
133.1695 +/* read problem data in free MPS format */
133.1696 +
133.1697 +#define lpx_write_freemps _glp_lpx_write_freemps
133.1698 +int lpx_write_freemps(LPX *lp, const char *fname);
133.1699 +/* write problem data in free MPS format */
133.1700 +
133.1701 +#define lpx_read_cpxlp _glp_lpx_read_cpxlp
133.1702 +LPX *lpx_read_cpxlp(const char *fname);
133.1703 +/* read problem data in CPLEX LP format */
133.1704 +
133.1705 +#define lpx_write_cpxlp _glp_lpx_write_cpxlp
133.1706 +int lpx_write_cpxlp(LPX *lp, const char *fname);
133.1707 +/* write problem data in CPLEX LP format */
133.1708 +
133.1709 +#define lpx_read_model _glp_lpx_read_model
133.1710 +LPX *lpx_read_model(const char *model, const char *data,
133.1711 +      const char *output);
133.1712 +/* read LP/MIP model written in GNU MathProg language */
133.1713 +
133.1714 +#define lpx_print_prob _glp_lpx_print_prob
133.1715 +int lpx_print_prob(LPX *lp, const char *fname);
133.1716 +/* write problem data in plain text format */
133.1717 +
133.1718 +#define lpx_print_sol _glp_lpx_print_sol
133.1719 +int lpx_print_sol(LPX *lp, const char *fname);
133.1720 +/* write LP problem solution in printable format */
133.1721 +
133.1722 +#define lpx_print_sens_bnds _glp_lpx_print_sens_bnds
133.1723 +int lpx_print_sens_bnds(LPX *lp, const char *fname);
133.1724 +/* write bounds sensitivity information */
133.1725 +
133.1726 +#define lpx_print_ips _glp_lpx_print_ips
133.1727 +int lpx_print_ips(LPX *lp, const char *fname);
133.1728 +/* write interior point solution in printable format */
133.1729 +
133.1730 +#define lpx_print_mip _glp_lpx_print_mip
133.1731 +int lpx_print_mip(LPX *lp, const char *fname);
133.1732 +/* write MIP problem solution in printable format */
133.1733 +
133.1734 +#define lpx_is_b_avail _glp_lpx_is_b_avail
133.1735 +int lpx_is_b_avail(LPX *lp);
133.1736 +/* check if LP basis is available */
133.1737 +
133.1738 +#define lpx_write_pb _glp_lpx_write_pb
133.1739 +int lpx_write_pb(LPX *lp, const char *fname, int normalized,
133.1740 +      int binarize);
133.1741 +/* write problem data in (normalized) OPB format */
133.1742 +
133.1743 +#define lpx_main _glp_lpx_main
133.1744 +int lpx_main(int argc, const char *argv[]);
133.1745 +/* stand-alone LP/MIP solver */
133.1746 +
133.1747 +#ifdef __cplusplus
133.1748 +}
133.1749 +#endif
133.1750 +
133.1751 +#endif
133.1752 +
133.1753 +/* eof */
   134.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   134.2 +++ b/src/Makefile.am	Mon Dec 06 13:09:21 2010 +0100
   134.3 @@ -0,0 +1,121 @@
   134.4 +## Process this file with automake to produce Makefile.in ##
   134.5 +
   134.6 +INCLUDES = -I$(srcdir)/../include
   134.7 +
   134.8 +lib_LTLIBRARIES = libglpk.la
   134.9 +
  134.10 +libglpk_la_LDFLAGS = -version-info 30:0:30 \
  134.11 +-export-symbols-regex '^(glp_|_glp_lpx_).*'
  134.12 +
  134.13 +libglpk_la_SOURCES = \
  134.14 +glpapi01.c \
  134.15 +glpapi02.c \
  134.16 +glpapi03.c \
  134.17 +glpapi04.c \
  134.18 +glpapi05.c \
  134.19 +glpapi06.c \
  134.20 +glpapi07.c \
  134.21 +glpapi08.c \
  134.22 +glpapi09.c \
  134.23 +glpapi10.c \
  134.24 +glpapi11.c \
  134.25 +glpapi12.c \
  134.26 +glpapi13.c \
  134.27 +glpapi14.c \
  134.28 +glpapi15.c \
  134.29 +glpapi16.c \
  134.30 +glpapi17.c \
  134.31 +glpapi18.c \
  134.32 +glpapi19.c \
  134.33 +glpavl.c \
  134.34 +glpbfd.c \
  134.35 +glpbfx.c \
  134.36 +glpcpx.c \
  134.37 +glpdmp.c \
  134.38 +glpdmx.c \
  134.39 +glpenv01.c \
  134.40 +glpenv02.c \
  134.41 +glpenv03.c \
  134.42 +glpenv04.c \
  134.43 +glpenv05.c \
  134.44 +glpenv06.c \
  134.45 +glpenv07.c \
  134.46 +glpenv08.c \
  134.47 +glpfhv.c \
  134.48 +glpgmp.c \
  134.49 +glphbm.c \
  134.50 +glpini01.c \
  134.51 +glpini02.c \
  134.52 +glpios01.c \
  134.53 +glpios02.c \
  134.54 +glpios03.c \
  134.55 +glpios04.c \
  134.56 +glpios05.c \
  134.57 +glpios06.c \
  134.58 +glpios07.c \
  134.59 +glpios08.c \
  134.60 +glpios09.c \
  134.61 +glpios10.c \
  134.62 +glpios11.c \
  134.63 +glpios12.c \
  134.64 +glpipm.c \
  134.65 +glplib01.c \
  134.66 +glplib02.c \
  134.67 +glplib03.c \
  134.68 +glplpf.c \
  134.69 +glplpx01.c \
  134.70 +glplpx02.c \
  134.71 +glplpx03.c \
  134.72 +glpluf.c \
  134.73 +glplux.c \
  134.74 +glpmat.c \
  134.75 +glpmpl01.c \
  134.76 +glpmpl02.c \
  134.77 +glpmpl03.c \
  134.78 +glpmpl04.c \
  134.79 +glpmpl05.c \
  134.80 +glpmpl06.c \
  134.81 +glpmps.c \
  134.82 +glpnet01.c \
  134.83 +glpnet02.c \
  134.84 +glpnet03.c \
  134.85 +glpnet04.c \
  134.86 +glpnet05.c \
  134.87 +glpnet06.c \
  134.88 +glpnet07.c \
  134.89 +glpnet08.c \
  134.90 +glpnet09.c \
  134.91 +glpnpp01.c \
  134.92 +glpnpp02.c \
  134.93 +glpnpp03.c \
  134.94 +glpnpp04.c \
  134.95 +glpnpp05.c \
  134.96 +glpqmd.c \
  134.97 +glprgr.c \
  134.98 +glprng01.c \
  134.99 +glprng02.c \
 134.100 +glpscf.c \
 134.101 +glpscl.c \
 134.102 +glpsdf.c \
 134.103 +glpspm.c \
 134.104 +glpspx01.c \
 134.105 +glpspx02.c \
 134.106 +glpsql.c \
 134.107 +glpssx01.c \
 134.108 +glpssx02.c \
 134.109 +glptsp.c \
 134.110 +amd/amd_1.c \
 134.111 +amd/amd_2.c \
 134.112 +amd/amd_aat.c \
 134.113 +amd/amd_control.c \
 134.114 +amd/amd_defaults.c \
 134.115 +amd/amd_dump.c \
 134.116 +amd/amd_info.c \
 134.117 +amd/amd_order.c \
 134.118 +amd/amd_post_tree.c \
 134.119 +amd/amd_postorder.c \
 134.120 +amd/amd_preprocess.c \
 134.121 +amd/amd_valid.c \
 134.122 +colamd/colamd.c
 134.123 +
 134.124 +## eof ##
   135.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   135.2 +++ b/src/amd/COPYING	Mon Dec 06 13:09:21 2010 +0100
   135.3 @@ -0,0 +1,502 @@
   135.4 +                  GNU LESSER GENERAL PUBLIC LICENSE
   135.5 +                       Version 2.1, February 1999
   135.6 +
   135.7 + Copyright (C) 1991, 1999 Free Software Foundation, Inc.
   135.8 +     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   135.9 + Everyone is permitted to copy and distribute verbatim copies
  135.10 + of this license document, but changing it is not allowed.
  135.11 +
  135.12 +[This is the first released version of the Lesser GPL.  It also counts
  135.13 + as the successor of the GNU Library Public License, version 2, hence
  135.14 + the version number 2.1.]
  135.15 +
  135.16 +                            Preamble
  135.17 +
  135.18 +  The licenses for most software are designed to take away your
  135.19 +freedom to share and change it.  By contrast, the GNU General Public
  135.20 +Licenses are intended to guarantee your freedom to share and change
  135.21 +free software--to make sure the software is free for all its users.
  135.22 +
  135.23 +  This license, the Lesser General Public License, applies to some
  135.24 +specially designated software packages--typically libraries--of the
  135.25 +Free Software Foundation and other authors who decide to use it.  You
  135.26 +can use it too, but we suggest you first think carefully about whether
  135.27 +this license or the ordinary General Public License is the better
  135.28 +strategy to use in any particular case, based on the explanations below.
  135.29 +
  135.30 +  When we speak of free software, we are referring to freedom of use,
  135.31 +not price.  Our General Public Licenses are designed to make sure that
  135.32 +you have the freedom to distribute copies of free software (and charge
  135.33 +for this service if you wish); that you receive source code or can get
  135.34 +it if you want it; that you can change the software and use pieces of
  135.35 +it in new free programs; and that you are informed that you can do
  135.36 +these things.
  135.37 +
  135.38 +  To protect your rights, we need to make restrictions that forbid
  135.39 +distributors to deny you these rights or to ask you to surrender these
  135.40 +rights.  These restrictions translate to certain responsibilities for
  135.41 +you if you distribute copies of the library or if you modify it.
  135.42 +
  135.43 +  For example, if you distribute copies of the library, whether gratis
  135.44 +or for a fee, you must give the recipients all the rights that we gave
  135.45 +you.  You must make sure that they, too, receive or can get the source
  135.46 +code.  If you link other code with the library, you must provide
  135.47 +complete object files to the recipients, so that they can relink them
  135.48 +with the library after making changes to the library and recompiling
  135.49 +it.  And you must show them these terms so they know their rights.
  135.50 +
  135.51 +  We protect your rights with a two-step method: (1) we copyright the
  135.52 +library, and (2) we offer you this license, which gives you legal
  135.53 +permission to copy, distribute and/or modify the library.
  135.54 +
  135.55 +  To protect each distributor, we want to make it very clear that
  135.56 +there is no warranty for the free library.  Also, if the library is
  135.57 +modified by someone else and passed on, the recipients should know
  135.58 +that what they have is not the original version, so that the original
  135.59 +author's reputation will not be affected by problems that might be
  135.60 +introduced by others.
  135.61 +
  135.62 +  Finally, software patents pose a constant threat to the existence of
  135.63 +any free program.  We wish to make sure that a company cannot
  135.64 +effectively restrict the users of a free program by obtaining a
  135.65 +restrictive license from a patent holder.  Therefore, we insist that
  135.66 +any patent license obtained for a version of the library must be
  135.67 +consistent with the full freedom of use specified in this license.
  135.68 +
  135.69 +  Most GNU software, including some libraries, is covered by the
  135.70 +ordinary GNU General Public License.  This license, the GNU Lesser
  135.71 +General Public License, applies to certain designated libraries, and
  135.72 +is quite different from the ordinary General Public License.  We use
  135.73 +this license for certain libraries in order to permit linking those
  135.74 +libraries into non-free programs.
  135.75 +
  135.76 +  When a program is linked with a library, whether statically or using
  135.77 +a shared library, the combination of the two is legally speaking a
  135.78 +combined work, a derivative of the original library.  The ordinary
  135.79 +General Public License therefore permits such linking only if the
  135.80 +entire combination fits its criteria of freedom.  The Lesser General
  135.81 +Public License permits more lax criteria for linking other code with
  135.82 +the library.
  135.83 +
  135.84 +  We call this license the "Lesser" General Public License because it
  135.85 +does Less to protect the user's freedom than the ordinary General
  135.86 +Public License.  It also provides other free software developers Less
  135.87 +of an advantage over competing non-free programs.  These disadvantages
  135.88 +are the reason we use the ordinary General Public License for many
  135.89 +libraries.  However, the Lesser license provides advantages in certain
  135.90 +special circumstances.
  135.91 +
  135.92 +  For example, on rare occasions, there may be a special need to
  135.93 +encourage the widest possible use of a certain library, so that it becomes
  135.94 +a de-facto standard.  To achieve this, non-free programs must be
  135.95 +allowed to use the library.  A more frequent case is that a free
  135.96 +library does the same job as widely used non-free libraries.  In this
  135.97 +case, there is little to gain by limiting the free library to free
  135.98 +software only, so we use the Lesser General Public License.
  135.99 +
 135.100 +  In other cases, permission to use a particular library in non-free
 135.101 +programs enables a greater number of people to use a large body of
 135.102 +free software.  For example, permission to use the GNU C Library in
 135.103 +non-free programs enables many more people to use the whole GNU
 135.104 +operating system, as well as its variant, the GNU/Linux operating
 135.105 +system.
 135.106 +
 135.107 +  Although the Lesser General Public License is Less protective of the
 135.108 +users' freedom, it does ensure that the user of a program that is
 135.109 +linked with the Library has the freedom and the wherewithal to run
 135.110 +that program using a modified version of the Library.
 135.111 +
 135.112 +  The precise terms and conditions for copying, distribution and
 135.113 +modification follow.  Pay close attention to the difference between a
 135.114 +"work based on the library" and a "work that uses the library".  The
 135.115 +former contains code derived from the library, whereas the latter must
 135.116 +be combined with the library in order to run.
 135.117 +
 135.118 +                  GNU LESSER GENERAL PUBLIC LICENSE
 135.119 +   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 135.120 +
 135.121 +  0. This License Agreement applies to any software library or other
 135.122 +program which contains a notice placed by the copyright holder or
 135.123 +other authorized party saying it may be distributed under the terms of
 135.124 +this Lesser General Public License (also called "this License").
 135.125 +Each licensee is addressed as "you".
 135.126 +
 135.127 +  A "library" means a collection of software functions and/or data
 135.128 +prepared so as to be conveniently linked with application programs
 135.129 +(which use some of those functions and data) to form executables.
 135.130 +
 135.131 +  The "Library", below, refers to any such software library or work
 135.132 +which has been distributed under these terms.  A "work based on the
 135.133 +Library" means either the Library or any derivative work under
 135.134 +copyright law: that is to say, a work containing the Library or a
 135.135 +portion of it, either verbatim or with modifications and/or translated
 135.136 +straightforwardly into another language.  (Hereinafter, translation is
 135.137 +included without limitation in the term "modification".)
 135.138 +
 135.139 +  "Source code" for a work means the preferred form of the work for
 135.140 +making modifications to it.  For a library, complete source code means
 135.141 +all the source code for all modules it contains, plus any associated
 135.142 +interface definition files, plus the scripts used to control compilation
 135.143 +and installation of the library.
 135.144 +
 135.145 +  Activities other than copying, distribution and modification are not
 135.146 +covered by this License; they are outside its scope.  The act of
 135.147 +running a program using the Library is not restricted, and output from
 135.148 +such a program is covered only if its contents constitute a work based
 135.149 +on the Library (independent of the use of the Library in a tool for
 135.150 +writing it).  Whether that is true depends on what the Library does
 135.151 +and what the program that uses the Library does.
 135.152 +
 135.153 +  1. You may copy and distribute verbatim copies of the Library's
 135.154 +complete source code as you receive it, in any medium, provided that
 135.155 +you conspicuously and appropriately publish on each copy an
 135.156 +appropriate copyright notice and disclaimer of warranty; keep intact
 135.157 +all the notices that refer to this License and to the absence of any
 135.158 +warranty; and distribute a copy of this License along with the
 135.159 +Library.
 135.160 +
 135.161 +  You may charge a fee for the physical act of transferring a copy,
 135.162 +and you may at your option offer warranty protection in exchange for a
 135.163 +fee.
 135.164 +
 135.165 +  2. You may modify your copy or copies of the Library or any portion
 135.166 +of it, thus forming a work based on the Library, and copy and
 135.167 +distribute such modifications or work under the terms of Section 1
 135.168 +above, provided that you also meet all of these conditions:
 135.169 +
 135.170 +    a) The modified work must itself be a software library.
 135.171 +
 135.172 +    b) You must cause the files modified to carry prominent notices
 135.173 +    stating that you changed the files and the date of any change.
 135.174 +
 135.175 +    c) You must cause the whole of the work to be licensed at no
 135.176 +    charge to all third parties under the terms of this License.
 135.177 +
 135.178 +    d) If a facility in the modified Library refers to a function or a
 135.179 +    table of data to be supplied by an application program that uses
 135.180 +    the facility, other than as an argument passed when the facility
 135.181 +    is invoked, then you must make a good faith effort to ensure that,
 135.182 +    in the event an application does not supply such function or
 135.183 +    table, the facility still operates, and performs whatever part of
 135.184 +    its purpose remains meaningful.
 135.185 +
 135.186 +    (For example, a function in a library to compute square roots has
 135.187 +    a purpose that is entirely well-defined independent of the
 135.188 +    application.  Therefore, Subsection 2d requires that any
 135.189 +    application-supplied function or table used by this function must
 135.190 +    be optional: if the application does not supply it, the square
 135.191 +    root function must still compute square roots.)
 135.192 +
 135.193 +These requirements apply to the modified work as a whole.  If
 135.194 +identifiable sections of that work are not derived from the Library,
 135.195 +and can be reasonably considered independent and separate works in
 135.196 +themselves, then this License, and its terms, do not apply to those
 135.197 +sections when you distribute them as separate works.  But when you
 135.198 +distribute the same sections as part of a whole which is a work based
 135.199 +on the Library, the distribution of the whole must be on the terms of
 135.200 +this License, whose permissions for other licensees extend to the
 135.201 +entire whole, and thus to each and every part regardless of who wrote
 135.202 +it.
 135.203 +
 135.204 +Thus, it is not the intent of this section to claim rights or contest
 135.205 +your rights to work written entirely by you; rather, the intent is to
 135.206 +exercise the right to control the distribution of derivative or
 135.207 +collective works based on the Library.
 135.208 +
 135.209 +In addition, mere aggregation of another work not based on the Library
 135.210 +with the Library (or with a work based on the Library) on a volume of
 135.211 +a storage or distribution medium does not bring the other work under
 135.212 +the scope of this License.
 135.213 +
 135.214 +  3. You may opt to apply the terms of the ordinary GNU General Public
 135.215 +License instead of this License to a given copy of the Library.  To do
 135.216 +this, you must alter all the notices that refer to this License, so
 135.217 +that they refer to the ordinary GNU General Public License, version 2,
 135.218 +instead of to this License.  (If a newer version than version 2 of the
 135.219 +ordinary GNU General Public License has appeared, then you can specify
 135.220 +that version instead if you wish.)  Do not make any other change in
 135.221 +these notices.
 135.222 +
 135.223 +  Once this change is made in a given copy, it is irreversible for
 135.224 +that copy, so the ordinary GNU General Public License applies to all
 135.225 +subsequent copies and derivative works made from that copy.
 135.226 +
 135.227 +  This option is useful when you wish to copy part of the code of
 135.228 +the Library into a program that is not a library.
 135.229 +
 135.230 +  4. You may copy and distribute the Library (or a portion or
 135.231 +derivative of it, under Section 2) in object code or executable form
 135.232 +under the terms of Sections 1 and 2 above provided that you accompany
 135.233 +it with the complete corresponding machine-readable source code, which
 135.234 +must be distributed under the terms of Sections 1 and 2 above on a
 135.235 +medium customarily used for software interchange.
 135.236 +
 135.237 +  If distribution of object code is made by offering access to copy
 135.238 +from a designated place, then offering equivalent access to copy the
 135.239 +source code from the same place satisfies the requirement to
 135.240 +distribute the source code, even though third parties are not
 135.241 +compelled to copy the source along with the object code.
 135.242 +
 135.243 +  5. A program that contains no derivative of any portion of the
 135.244 +Library, but is designed to work with the Library by being compiled or
 135.245 +linked with it, is called a "work that uses the Library".  Such a
 135.246 +work, in isolation, is not a derivative work of the Library, and
 135.247 +therefore falls outside the scope of this License.
 135.248 +
 135.249 +  However, linking a "work that uses the Library" with the Library
 135.250 +creates an executable that is a derivative of the Library (because it
 135.251 +contains portions of the Library), rather than a "work that uses the
 135.252 +library".  The executable is therefore covered by this License.
 135.253 +Section 6 states terms for distribution of such executables.
 135.254 +
 135.255 +  When a "work that uses the Library" uses material from a header file
 135.256 +that is part of the Library, the object code for the work may be a
 135.257 +derivative work of the Library even though the source code is not.
 135.258 +Whether this is true is especially significant if the work can be
 135.259 +linked without the Library, or if the work is itself a library.  The
 135.260 +threshold for this to be true is not precisely defined by law.
 135.261 +
 135.262 +  If such an object file uses only numerical parameters, data
 135.263 +structure layouts and accessors, and small macros and small inline
 135.264 +functions (ten lines or less in length), then the use of the object
 135.265 +file is unrestricted, regardless of whether it is legally a derivative
 135.266 +work.  (Executables containing this object code plus portions of the
 135.267 +Library will still fall under Section 6.)
 135.268 +
 135.269 +  Otherwise, if the work is a derivative of the Library, you may
 135.270 +distribute the object code for the work under the terms of Section 6.
 135.271 +Any executables containing that work also fall under Section 6,
 135.272 +whether or not they are linked directly with the Library itself.
 135.273 +
 135.274 +  6. As an exception to the Sections above, you may also combine or
 135.275 +link a "work that uses the Library" with the Library to produce a
 135.276 +work containing portions of the Library, and distribute that work
 135.277 +under terms of your choice, provided that the terms permit
 135.278 +modification of the work for the customer's own use and reverse
 135.279 +engineering for debugging such modifications.
 135.280 +
 135.281 +  You must give prominent notice with each copy of the work that the
 135.282 +Library is used in it and that the Library and its use are covered by
 135.283 +this License.  You must supply a copy of this License.  If the work
 135.284 +during execution displays copyright notices, you must include the
 135.285 +copyright notice for the Library among them, as well as a reference
 135.286 +directing the user to the copy of this License.  Also, you must do one
 135.287 +of these things:
 135.288 +
 135.289 +    a) Accompany the work with the complete corresponding
 135.290 +    machine-readable source code for the Library including whatever
 135.291 +    changes were used in the work (which must be distributed under
 135.292 +    Sections 1 and 2 above); and, if the work is an executable linked
 135.293 +    with the Library, with the complete machine-readable "work that
 135.294 +    uses the Library", as object code and/or source code, so that the
 135.295 +    user can modify the Library and then relink to produce a modified
 135.296 +    executable containing the modified Library.  (It is understood
 135.297 +    that the user who changes the contents of definitions files in the
 135.298 +    Library will not necessarily be able to recompile the application
 135.299 +    to use the modified definitions.)
 135.300 +
 135.301 +    b) Use a suitable shared library mechanism for linking with the
 135.302 +    Library.  A suitable mechanism is one that (1) uses at run time a
 135.303 +    copy of the library already present on the user's computer system,
 135.304 +    rather than copying library functions into the executable, and (2)
 135.305 +    will operate properly with a modified version of the library, if
 135.306 +    the user installs one, as long as the modified version is
 135.307 +    interface-compatible with the version that the work was made with.
 135.308 +
 135.309 +    c) Accompany the work with a written offer, valid for at
 135.310 +    least three years, to give the same user the materials
 135.311 +    specified in Subsection 6a, above, for a charge no more
 135.312 +    than the cost of performing this distribution.
 135.313 +
 135.314 +    d) If distribution of the work is made by offering access to copy
 135.315 +    from a designated place, offer equivalent access to copy the above
 135.316 +    specified materials from the same place.
 135.317 +
 135.318 +    e) Verify that the user has already received a copy of these
 135.319 +    materials or that you have already sent this user a copy.
 135.320 +
 135.321 +  For an executable, the required form of the "work that uses the
 135.322 +Library" must include any data and utility programs needed for
 135.323 +reproducing the executable from it.  However, as a special exception,
 135.324 +the materials to be distributed need not include anything that is
 135.325 +normally distributed (in either source or binary form) with the major
 135.326 +components (compiler, kernel, and so on) of the operating system on
 135.327 +which the executable runs, unless that component itself accompanies
 135.328 +the executable.
 135.329 +
 135.330 +  It may happen that this requirement contradicts the license
 135.331 +restrictions of other proprietary libraries that do not normally
 135.332 +accompany the operating system.  Such a contradiction means you cannot
 135.333 +use both them and the Library together in an executable that you
 135.334 +distribute.
 135.335 +
 135.336 +  7. You may place library facilities that are a work based on the
 135.337 +Library side-by-side in a single library together with other library
 135.338 +facilities not covered by this License, and distribute such a combined
 135.339 +library, provided that the separate distribution of the work based on
 135.340 +the Library and of the other library facilities is otherwise
 135.341 +permitted, and provided that you do these two things:
 135.342 +
 135.343 +    a) Accompany the combined library with a copy of the same work
 135.344 +    based on the Library, uncombined with any other library
 135.345 +    facilities.  This must be distributed under the terms of the
 135.346 +    Sections above.
 135.347 +
 135.348 +    b) Give prominent notice with the combined library of the fact
 135.349 +    that part of it is a work based on the Library, and explaining
 135.350 +    where to find the accompanying uncombined form of the same work.
 135.351 +
 135.352 +  8. You may not copy, modify, sublicense, link with, or distribute
 135.353 +the Library except as expressly provided under this License.  Any
 135.354 +attempt otherwise to copy, modify, sublicense, link with, or
 135.355 +distribute the Library is void, and will automatically terminate your
 135.356 +rights under this License.  However, parties who have received copies,
 135.357 +or rights, from you under this License will not have their licenses
 135.358 +terminated so long as such parties remain in full compliance.
 135.359 +
 135.360 +  9. You are not required to accept this License, since you have not
 135.361 +signed it.  However, nothing else grants you permission to modify or
 135.362 +distribute the Library or its derivative works.  These actions are
 135.363 +prohibited by law if you do not accept this License.  Therefore, by
 135.364 +modifying or distributing the Library (or any work based on the
 135.365 +Library), you indicate your acceptance of this License to do so, and
 135.366 +all its terms and conditions for copying, distributing or modifying
 135.367 +the Library or works based on it.
 135.368 +
 135.369 +  10. Each time you redistribute the Library (or any work based on the
 135.370 +Library), the recipient automatically receives a license from the
 135.371 +original licensor to copy, distribute, link with or modify the Library
 135.372 +subject to these terms and conditions.  You may not impose any further
 135.373 +restrictions on the recipients' exercise of the rights granted herein.
 135.374 +You are not responsible for enforcing compliance by third parties with
 135.375 +this License.
 135.376 +
 135.377 +  11. If, as a consequence of a court judgment or allegation of patent
 135.378 +infringement or for any other reason (not limited to patent issues),
 135.379 +conditions are imposed on you (whether by court order, agreement or
 135.380 +otherwise) that contradict the conditions of this License, they do not
 135.381 +excuse you from the conditions of this License.  If you cannot
 135.382 +distribute so as to satisfy simultaneously your obligations under this
 135.383 +License and any other pertinent obligations, then as a consequence you
 135.384 +may not distribute the Library at all.  For example, if a patent
 135.385 +license would not permit royalty-free redistribution of the Library by
 135.386 +all those who receive copies directly or indirectly through you, then
 135.387 +the only way you could satisfy both it and this License would be to
 135.388 +refrain entirely from distribution of the Library.
 135.389 +
 135.390 +If any portion of this section is held invalid or unenforceable under any
 135.391 +particular circumstance, the balance of the section is intended to apply,
 135.392 +and the section as a whole is intended to apply in other circumstances.
 135.393 +
 135.394 +It is not the purpose of this section to induce you to infringe any
 135.395 +patents or other property right claims or to contest validity of any
 135.396 +such claims; this section has the sole purpose of protecting the
 135.397 +integrity of the free software distribution system which is
 135.398 +implemented by public license practices.  Many people have made
 135.399 +generous contributions to the wide range of software distributed
 135.400 +through that system in reliance on consistent application of that
 135.401 +system; it is up to the author/donor to decide if he or she is willing
 135.402 +to distribute software through any other system and a licensee cannot
 135.403 +impose that choice.
 135.404 +
 135.405 +This section is intended to make thoroughly clear what is believed to
 135.406 +be a consequence of the rest of this License.
 135.407 +
 135.408 +  12. If the distribution and/or use of the Library is restricted in
 135.409 +certain countries either by patents or by copyrighted interfaces, the
 135.410 +original copyright holder who places the Library under this License may add
 135.411 +an explicit geographical distribution limitation excluding those countries,
 135.412 +so that distribution is permitted only in or among countries not thus
 135.413 +excluded.  In such case, this License incorporates the limitation as if
 135.414 +written in the body of this License.
 135.415 +
 135.416 +  13. The Free Software Foundation may publish revised and/or new
 135.417 +versions of the Lesser General Public License from time to time.
 135.418 +Such new versions will be similar in spirit to the present version,
 135.419 +but may differ in detail to address new problems or concerns.
 135.420 +
 135.421 +Each version is given a distinguishing version number.  If the Library
 135.422 +specifies a version number of this License which applies to it and
 135.423 +"any later version", you have the option of following the terms and
 135.424 +conditions either of that version or of any later version published by
 135.425 +the Free Software Foundation.  If the Library does not specify a
 135.426 +license version number, you may choose any version ever published by
 135.427 +the Free Software Foundation.
 135.428 +
 135.429 +  14. If you wish to incorporate parts of the Library into other free
 135.430 +programs whose distribution conditions are incompatible with these,
 135.431 +write to the author to ask for permission.  For software which is
 135.432 +copyrighted by the Free Software Foundation, write to the Free
 135.433 +Software Foundation; we sometimes make exceptions for this.  Our
 135.434 +decision will be guided by the two goals of preserving the free status
 135.435 +of all derivatives of our free software and of promoting the sharing
 135.436 +and reuse of software generally.
 135.437 +
 135.438 +                            NO WARRANTY
 135.439 +
 135.440 +  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
 135.441 +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
 135.442 +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
 135.443 +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
 135.444 +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
 135.445 +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 135.446 +PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
 135.447 +LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
 135.448 +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
 135.449 +
 135.450 +  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
 135.451 +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
 135.452 +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
 135.453 +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
 135.454 +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
 135.455 +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
 135.456 +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
 135.457 +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
 135.458 +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
 135.459 +DAMAGES.
 135.460 +
 135.461 +                     END OF TERMS AND CONDITIONS
 135.462 +
 135.463 +           How to Apply These Terms to Your New Libraries
 135.464 +
 135.465 +  If you develop a new library, and you want it to be of the greatest
 135.466 +possible use to the public, we recommend making it free software that
 135.467 +everyone can redistribute and change.  You can do so by permitting
 135.468 +redistribution under these terms (or, alternatively, under the terms of the
 135.469 +ordinary General Public License).
 135.470 +
 135.471 +  To apply these terms, attach the following notices to the library.  It is
 135.472 +safest to attach them to the start of each source file to most effectively
 135.473 +convey the exclusion of warranty; and each file should have at least the
 135.474 +"copyright" line and a pointer to where the full notice is found.
 135.475 +
 135.476 +    <one line to give the library's name and a brief idea of what it does.>
 135.477 +    Copyright (C) <year>  <name of author>
 135.478 +
 135.479 +    This library is free software; you can redistribute it and/or
 135.480 +    modify it under the terms of the GNU Lesser General Public
 135.481 +    License as published by the Free Software Foundation; either
 135.482 +    version 2.1 of the License, or (at your option) any later version.
 135.483 +
 135.484 +    This library is distributed in the hope that it will be useful,
 135.485 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
 135.486 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 135.487 +    Lesser General Public License for more details.
 135.488 +
 135.489 +    You should have received a copy of the GNU Lesser General Public
 135.490 +    License along with this library; if not, write to the Free Software
 135.491 +    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 135.492 +
 135.493 +Also add information on how to contact you by electronic and paper mail.
 135.494 +
 135.495 +You should also get your employer (if you work as a programmer) or your
 135.496 +school, if any, to sign a "copyright disclaimer" for the library, if
 135.497 +necessary.  Here is a sample; alter the names:
 135.498 +
 135.499 +  Yoyodyne, Inc., hereby disclaims all copyright interest in the
 135.500 +  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
 135.501 +
 135.502 +  <signature of Ty Coon>, 1 April 1990
 135.503 +  Ty Coon, President of Vice
 135.504 +
 135.505 +That's all there is to it!
   136.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   136.2 +++ b/src/amd/README	Mon Dec 06 13:09:21 2010 +0100
   136.3 @@ -0,0 +1,58 @@
   136.4 +NOTE: Files in this subdirectory are NOT part of the GLPK package, but
   136.5 +      are used with GLPK.
   136.6 +
   136.7 +      The original code was modified according to GLPK requirements by
   136.8 +      Andrew Makhorin <mao@gnu.org>.
   136.9 +************************************************************************
  136.10 +AMD Version 2.2, Copyright (C) 2007 by Timothy A. Davis,
  136.11 +Patrick R. Amestoy, and Iain S. Duff.  All Rights Reserved.
  136.12 +
  136.13 +Description:
  136.14 +
  136.15 +   AMD is a set of routines for pre-ordering sparse matrices prior to
  136.16 +   Cholesky or LU factorization, using the approximate minimum degree
  136.17 +   ordering algorithm.  Written in ANSI/ISO C with a MATLAB interface,
  136.18 +   and in Fortran 77.
  136.19 +
  136.20 +Authors:
  136.21 +
  136.22 +   Timothy A. Davis (davis at cise.ufl.edu), University of Florida.
  136.23 +   Patrick R. Amestoy, ENSEEIHT, Toulouse, France.
  136.24 +   Iain S. Duff, Rutherford Appleton Laboratory, UK.
  136.25 +
  136.26 +AMD License:
  136.27 +
  136.28 +   Your use or distribution of AMD or any modified version of AMD
  136.29 +   implies that you agree to this License.
  136.30 +
  136.31 +   This library is free software; you can redistribute it and/or
  136.32 +   modify it under the terms of the GNU Lesser General Public License
  136.33 +   as published by the Free Software Foundation; either version 2.1 of
  136.34 +   the License, or (at your option) any later version.
  136.35 +
  136.36 +   This library is distributed in the hope that it will be useful,
  136.37 +   but WITHOUT ANY WARRANTY; without even the implied warranty of
  136.38 +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  136.39 +   Lesser General Public License for more details.
  136.40 +
  136.41 +   You should have received a copy of the GNU Lesser General Public
  136.42 +   License along with this library; if not, write to the Free Software
  136.43 +   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
  136.44 +   USA.
  136.45 +
  136.46 +   Permission is hereby granted to use or copy this program under the
  136.47 +   terms of the GNU LGPL, provided that the Copyright, this License,
  136.48 +   and the Availability of the original version is retained on all
  136.49 +   copies.  User documentation of any code that uses this code or any
  136.50 +   modified version of this code must cite the Copyright, this License,
  136.51 +   the Availability note, and "Used by permission."  Permission to
  136.52 +   modify the code and to distribute modified code is granted, provided
  136.53 +   the Copyright, this License, and the Availability note are retained,
  136.54 +   and a notice that the code was modified is included.
  136.55 +
  136.56 +   AMD is available under alternate licences; contact T. Davis for
  136.57 +   details.
  136.58 +
  136.59 +Availability:
  136.60 +
  136.61 +    http://www.cise.ufl.edu/research/sparse/amd
   137.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   137.2 +++ b/src/amd/amd.h	Mon Dec 06 13:09:21 2010 +0100
   137.3 @@ -0,0 +1,67 @@
   137.4 +/* amd.h */
   137.5 +
   137.6 +/* Written by Andrew Makhorin <mao@gnu.org>. */
   137.7 +
   137.8 +#ifndef GLPAMD_H
   137.9 +#define GLPAMD_H
  137.10 +
  137.11 +#define AMD_DATE "May 31, 2007"
  137.12 +#define AMD_VERSION_CODE(main, sub) ((main) * 1000 + (sub))
  137.13 +#define AMD_MAIN_VERSION 2
  137.14 +#define AMD_SUB_VERSION 2
  137.15 +#define AMD_SUBSUB_VERSION 0
  137.16 +#define AMD_VERSION AMD_VERSION_CODE(AMD_MAIN_VERSION, AMD_SUB_VERSION)
  137.17 +
  137.18 +#define AMD_CONTROL 5
  137.19 +#define AMD_INFO 20
  137.20 +
  137.21 +#define AMD_DENSE 0
  137.22 +#define AMD_AGGRESSIVE 1
  137.23 +
  137.24 +#define AMD_DEFAULT_DENSE 10.0
  137.25 +#define AMD_DEFAULT_AGGRESSIVE 1
  137.26 +
  137.27 +#define AMD_STATUS         0
  137.28 +#define AMD_N              1
  137.29 +#define AMD_NZ             2
  137.30 +#define AMD_SYMMETRY       3
  137.31 +#define AMD_NZDIAG         4
  137.32 +#define AMD_NZ_A_PLUS_AT   5
  137.33 +#define AMD_NDENSE         6
  137.34 +#define AMD_MEMORY         7
  137.35 +#define AMD_NCMPA          8
  137.36 +#define AMD_LNZ            9
  137.37 +#define AMD_NDIV           10
  137.38 +#define AMD_NMULTSUBS_LDL  11
  137.39 +#define AMD_NMULTSUBS_LU   12
  137.40 +#define AMD_DMAX           13
  137.41 +
  137.42 +#define AMD_OK             0
  137.43 +#define AMD_OUT_OF_MEMORY  (-1)
  137.44 +#define AMD_INVALID        (-2)
  137.45 +#define AMD_OK_BUT_JUMBLED 1
  137.46 +
  137.47 +#define amd_order _glp_amd_order
  137.48 +int amd_order(int n, const int Ap[], const int Ai[], int P[],
  137.49 +      double Control[], double Info[]);
  137.50 +
  137.51 +#define amd_2 _glp_amd_2
  137.52 +void amd_2(int n, int Pe[], int Iw[], int Len[], int iwlen, int pfree,
  137.53 +      int Nv[], int Next[], int Last[], int Head[], int Elen[],
  137.54 +      int Degree[], int W[], double Control[], double Info[]);
  137.55 +
  137.56 +#define amd_valid _glp_amd_valid
  137.57 +int amd_valid(int n_row, int n_col, const int Ap[], const int Ai[]);
  137.58 +
  137.59 +#define amd_defaults _glp_amd_defaults
  137.60 +void amd_defaults(double Control[]);
  137.61 +
  137.62 +#define amd_control _glp_amd_control
  137.63 +void amd_control(double Control[]);
  137.64 +
  137.65 +#define amd_info _glp_amd_info
  137.66 +void amd_info(double Info[]);
  137.67 +
  137.68 +#endif
  137.69 +
  137.70 +/* eof */
   138.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   138.2 +++ b/src/amd/amd_1.c	Mon Dec 06 13:09:21 2010 +0100
   138.3 @@ -0,0 +1,181 @@
   138.4 +/* ========================================================================= */
   138.5 +/* === AMD_1 =============================================================== */
   138.6 +/* ========================================================================= */
   138.7 +
   138.8 +/* ------------------------------------------------------------------------- */
   138.9 +/* AMD, Copyright (c) Timothy A. Davis,                                      */
  138.10 +/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
  138.11 +/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
  138.12 +/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
  138.13 +/* ------------------------------------------------------------------------- */
  138.14 +
  138.15 +/* AMD_1: Construct A+A' for a sparse matrix A and perform the AMD ordering.
  138.16 + *
  138.17 + * The n-by-n sparse matrix A can be unsymmetric.  It is stored in MATLAB-style
  138.18 + * compressed-column form, with sorted row indices in each column, and no
  138.19 + * duplicate entries.  Diagonal entries may be present, but they are ignored.
  138.20 + * Row indices of column j of A are stored in Ai [Ap [j] ... Ap [j+1]-1].
  138.21 + * Ap [0] must be zero, and nz = Ap [n] is the number of entries in A.  The
  138.22 + * size of the matrix, n, must be greater than or equal to zero.
  138.23 + *
  138.24 + * This routine must be preceded by a call to AMD_aat, which computes the
  138.25 + * number of entries in each row/column in A+A', excluding the diagonal.
  138.26 + * Len [j], on input, is the number of entries in row/column j of A+A'.  This
  138.27 + * routine constructs the matrix A+A' and then calls AMD_2.  No error checking
  138.28 + * is performed (this was done in AMD_valid).
  138.29 + */
  138.30 +
  138.31 +#include "amd_internal.h"
  138.32 +
  138.33 +GLOBAL void AMD_1
  138.34 +(
  138.35 +    Int n,              /* n > 0 */
  138.36 +    const Int Ap [ ],   /* input of size n+1, not modified */
  138.37 +    const Int Ai [ ],   /* input of size nz = Ap [n], not modified */
  138.38 +    Int P [ ],          /* size n output permutation */
  138.39 +    Int Pinv [ ],       /* size n output inverse permutation */
  138.40 +    Int Len [ ],        /* size n input, undefined on output */
  138.41 +    Int slen,           /* slen >= sum (Len [0..n-1]) + 7n,
  138.42 +                         * ideally slen = 1.2 * sum (Len) + 8n */
  138.43 +    Int S [ ],          /* size slen workspace */
  138.44 +    double Control [ ], /* input array of size AMD_CONTROL */
  138.45 +    double Info [ ]     /* output array of size AMD_INFO */
  138.46 +)
  138.47 +{
  138.48 +    Int i, j, k, p, pfree, iwlen, pj, p1, p2, pj2, *Iw, *Pe, *Nv, *Head,
  138.49 +        *Elen, *Degree, *s, *W, *Sp, *Tp ;
  138.50 +
  138.51 +    /* --------------------------------------------------------------------- */
  138.52 +    /* construct the matrix for AMD_2 */
  138.53 +    /* --------------------------------------------------------------------- */
  138.54 +
  138.55 +    ASSERT (n > 0) ;
  138.56 +
  138.57 +    iwlen = slen - 6*n ;
  138.58 +    s = S ;
  138.59 +    Pe = s ;        s += n ;
  138.60 +    Nv = s ;        s += n ;
  138.61 +    Head = s ;      s += n ;
  138.62 +    Elen = s ;      s += n ;
  138.63 +    Degree = s ;    s += n ;
  138.64 +    W = s ;         s += n ;
  138.65 +    Iw = s ;        s += iwlen ;
  138.66 +
  138.67 +    ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ;
  138.68 +
  138.69 +    /* construct the pointers for A+A' */
  138.70 +    Sp = Nv ;                   /* use Nv and W as workspace for Sp and Tp [ */
  138.71 +    Tp = W ;
  138.72 +    pfree = 0 ;
  138.73 +    for (j = 0 ; j < n ; j++)
  138.74 +    {
  138.75 +        Pe [j] = pfree ;
  138.76 +        Sp [j] = pfree ;
  138.77 +        pfree += Len [j] ;
  138.78 +    }
  138.79 +
  138.80 +    /* Note that this restriction on iwlen is slightly more restrictive than
  138.81 +     * what is strictly required in AMD_2.  AMD_2 can operate with no elbow
  138.82 +     * room at all, but it will be very slow.  For better performance, at
  138.83 +     * least size-n elbow room is enforced. */
  138.84 +    ASSERT (iwlen >= pfree + n) ;
  138.85 +
  138.86 +#ifndef NDEBUG
  138.87 +    for (p = 0 ; p < iwlen ; p++) Iw [p] = EMPTY ;
  138.88 +#endif
  138.89 +
  138.90 +    for (k = 0 ; k < n ; k++)
  138.91 +    {
  138.92 +        AMD_DEBUG1 (("Construct row/column k= "ID" of A+A'\n", k))  ;
  138.93 +        p1 = Ap [k] ;
  138.94 +        p2 = Ap [k+1] ;
  138.95 +
  138.96 +        /* construct A+A' */
  138.97 +        for (p = p1 ; p < p2 ; )
  138.98 +        {
  138.99 +            /* scan the upper triangular part of A */
 138.100 +            j = Ai [p] ;
 138.101 +            ASSERT (j >= 0 && j < n) ;
 138.102 +            if (j < k)
 138.103 +            {
 138.104 +                /* entry A (j,k) in the strictly upper triangular part */
 138.105 +                ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
 138.106 +                ASSERT (Sp [k] < (k == n-1 ? pfree : Pe [k+1])) ;
 138.107 +                Iw [Sp [j]++] = k ;
 138.108 +                Iw [Sp [k]++] = j ;
 138.109 +                p++ ;
 138.110 +            }
 138.111 +            else if (j == k)
 138.112 +            {
 138.113 +                /* skip the diagonal */
 138.114 +                p++ ;
 138.115 +                break ;
 138.116 +            }
 138.117 +            else /* j > k */
 138.118 +            {
 138.119 +                /* first entry below the diagonal */
 138.120 +                break ;
 138.121 +            }
 138.122 +            /* scan lower triangular part of A, in column j until reaching
 138.123 +             * row k.  Start where last scan left off. */
 138.124 +            ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ;
 138.125 +            pj2 = Ap [j+1] ;
 138.126 +            for (pj = Tp [j] ; pj < pj2 ; )
 138.127 +            {
 138.128 +                i = Ai [pj] ;
 138.129 +                ASSERT (i >= 0 && i < n) ;
 138.130 +                if (i < k)
 138.131 +                {
 138.132 +                    /* A (i,j) is only in the lower part, not in upper */
 138.133 +                    ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;
 138.134 +                    ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
 138.135 +                    Iw [Sp [i]++] = j ;
 138.136 +                    Iw [Sp [j]++] = i ;
 138.137 +                    pj++ ;
 138.138 +                }
 138.139 +                else if (i == k)
 138.140 +                {
 138.141 +                    /* entry A (k,j) in lower part and A (j,k) in upper */
 138.142 +                    pj++ ;
 138.143 +                    break ;
 138.144 +                }
 138.145 +                else /* i > k */
 138.146 +                {
 138.147 +                    /* consider this entry later, when k advances to i */
 138.148 +                    break ;
 138.149 +                }
 138.150 +            }
 138.151 +            Tp [j] = pj ;
 138.152 +        }
 138.153 +        Tp [k] = p ;
 138.154 +    }
 138.155 +
 138.156 +    /* clean up, for remaining mismatched entries */
 138.157 +    for (j = 0 ; j < n ; j++)
 138.158 +    {
 138.159 +        for (pj = Tp [j] ; pj < Ap [j+1] ; pj++)
 138.160 +        {
 138.161 +            i = Ai [pj] ;
 138.162 +            ASSERT (i >= 0 && i < n) ;
 138.163 +            /* A (i,j) is only in the lower part, not in upper */
 138.164 +            ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;
 138.165 +            ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
 138.166 +            Iw [Sp [i]++] = j ;
 138.167 +            Iw [Sp [j]++] = i ;
 138.168 +        }
 138.169 +    }
 138.170 +
 138.171 +#ifndef NDEBUG
 138.172 +    for (j = 0 ; j < n-1 ; j++) ASSERT (Sp [j] == Pe [j+1]) ;
 138.173 +    ASSERT (Sp [n-1] == pfree) ;
 138.174 +#endif
 138.175 +
 138.176 +    /* Tp and Sp no longer needed ] */
 138.177 +
 138.178 +    /* --------------------------------------------------------------------- */
 138.179 +    /* order the matrix */
 138.180 +    /* --------------------------------------------------------------------- */
 138.181 +
 138.182 +    AMD_2 (n, Pe, Iw, Len, iwlen, pfree,
 138.183 +        Nv, Pinv, P, Head, Elen, Degree, W, Control, Info) ;
 138.184 +}
   139.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   139.2 +++ b/src/amd/amd_2.c	Mon Dec 06 13:09:21 2010 +0100
   139.3 @@ -0,0 +1,1842 @@
   139.4 +/* ========================================================================= */
   139.5 +/* === AMD_2 =============================================================== */
   139.6 +/* ========================================================================= */
   139.7 +
   139.8 +/* ------------------------------------------------------------------------- */
   139.9 +/* AMD, Copyright (c) Timothy A. Davis,                                      */
  139.10 +/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
  139.11 +/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
  139.12 +/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
  139.13 +/* ------------------------------------------------------------------------- */
  139.14 +
  139.15 +/* AMD_2:  performs the AMD ordering on a symmetric sparse matrix A, followed
  139.16 + * by a postordering (via depth-first search) of the assembly tree using the
  139.17 + * AMD_postorder routine.
  139.18 + */
  139.19 +
  139.20 +#include "amd_internal.h"
  139.21 +
  139.22 +/* ========================================================================= */
  139.23 +/* === clear_flag ========================================================== */
  139.24 +/* ========================================================================= */
  139.25 +
  139.26 +static Int clear_flag (Int wflg, Int wbig, Int W [ ], Int n)
  139.27 +{
  139.28 +    Int x ;
  139.29 +    if (wflg < 2 || wflg >= wbig)
  139.30 +    {
  139.31 +        for (x = 0 ; x < n ; x++)
  139.32 +        {
  139.33 +            if (W [x] != 0) W [x] = 1 ;
  139.34 +        }
  139.35 +        wflg = 2 ;
  139.36 +    }
  139.37 +    /*  at this point, W [0..n-1] < wflg holds */
  139.38 +    return (wflg) ;
  139.39 +}
  139.40 +
  139.41 +
  139.42 +/* ========================================================================= */
  139.43 +/* === AMD_2 =============================================================== */
  139.44 +/* ========================================================================= */
  139.45 +
  139.46 +GLOBAL void AMD_2
  139.47 +(
  139.48 +    Int n,              /* A is n-by-n, where n > 0 */
  139.49 +    Int Pe [ ],         /* Pe [0..n-1]: index in Iw of row i on input */
  139.50 +    Int Iw [ ],         /* workspace of size iwlen. Iw [0..pfree-1]
  139.51 +                         * holds the matrix on input */
  139.52 +    Int Len [ ],        /* Len [0..n-1]: length for row/column i on input */
  139.53 +    Int iwlen,          /* length of Iw. iwlen >= pfree + n */
  139.54 +    Int pfree,          /* Iw [pfree ... iwlen-1] is empty on input */
  139.55 +
  139.56 +    /* 7 size-n workspaces, not defined on input: */
  139.57 +    Int Nv [ ],         /* the size of each supernode on output */
  139.58 +    Int Next [ ],       /* the output inverse permutation */
  139.59 +    Int Last [ ],       /* the output permutation */
  139.60 +    Int Head [ ],
  139.61 +    Int Elen [ ],       /* the size columns of L for each supernode */
  139.62 +    Int Degree [ ],
  139.63 +    Int W [ ],
  139.64 +
  139.65 +    /* control parameters and output statistics */
  139.66 +    double Control [ ], /* array of size AMD_CONTROL */
  139.67 +    double Info [ ]     /* array of size AMD_INFO */
  139.68 +)
  139.69 +{
  139.70 +
  139.71 +/*
  139.72 + * Given a representation of the nonzero pattern of a symmetric matrix, A,
  139.73 + * (excluding the diagonal) perform an approximate minimum (UMFPACK/MA38-style)
  139.74 + * degree ordering to compute a pivot order such that the introduction of
  139.75 + * nonzeros (fill-in) in the Cholesky factors A = LL' is kept low.  At each
  139.76 + * step, the pivot selected is the one with the minimum UMFAPACK/MA38-style
  139.77 + * upper-bound on the external degree.  This routine can optionally perform
  139.78 + * aggresive absorption (as done by MC47B in the Harwell Subroutine
  139.79 + * Library).
  139.80 + *
  139.81 + * The approximate degree algorithm implemented here is the symmetric analog of
  139.82 + * the degree update algorithm in MA38 and UMFPACK (the Unsymmetric-pattern
  139.83 + * MultiFrontal PACKage, both by Davis and Duff).  The routine is based on the
  139.84 + * MA27 minimum degree ordering algorithm by Iain Duff and John Reid.
  139.85 + *
  139.86 + * This routine is a translation of the original AMDBAR and MC47B routines,
  139.87 + * in Fortran, with the following modifications:
  139.88 + *
  139.89 + * (1) dense rows/columns are removed prior to ordering the matrix, and placed
  139.90 + *      last in the output order.  The presence of a dense row/column can
  139.91 + *      increase the ordering time by up to O(n^2), unless they are removed
  139.92 + *      prior to ordering.
  139.93 + *
  139.94 + * (2) the minimum degree ordering is followed by a postordering (depth-first
  139.95 + *      search) of the assembly tree.  Note that mass elimination (discussed
  139.96 + *      below) combined with the approximate degree update can lead to the mass
  139.97 + *      elimination of nodes with lower exact degree than the current pivot
  139.98 + *      element.  No additional fill-in is caused in the representation of the
  139.99 + *      Schur complement.  The mass-eliminated nodes merge with the current
 139.100 + *      pivot element.  They are ordered prior to the current pivot element.
 139.101 + *      Because they can have lower exact degree than the current element, the
 139.102 + *      merger of two or more of these nodes in the current pivot element can
 139.103 + *      lead to a single element that is not a "fundamental supernode".  The
 139.104 + *      diagonal block can have zeros in it.  Thus, the assembly tree used here
 139.105 + *      is not guaranteed to be the precise supernodal elemination tree (with
 139.106 + *      "funadmental" supernodes), and the postordering performed by this
 139.107 + *      routine is not guaranteed to be a precise postordering of the
 139.108 + *      elimination tree.
 139.109 + *
 139.110 + * (3) input parameters are added, to control aggressive absorption and the
 139.111 + *      detection of "dense" rows/columns of A.
 139.112 + *
 139.113 + * (4) additional statistical information is returned, such as the number of
 139.114 + *      nonzeros in L, and the flop counts for subsequent LDL' and LU
 139.115 + *      factorizations.  These are slight upper bounds, because of the mass
 139.116 + *      elimination issue discussed above.
 139.117 + *
 139.118 + * (5) additional routines are added to interface this routine to MATLAB
 139.119 + *      to provide a simple C-callable user-interface, to check inputs for
 139.120 + *      errors, compute the symmetry of the pattern of A and the number of
 139.121 + *      nonzeros in each row/column of A+A', to compute the pattern of A+A',
 139.122 + *      to perform the assembly tree postordering, and to provide debugging
 139.123 + *      ouput.  Many of these functions are also provided by the Fortran
 139.124 + *      Harwell Subroutine Library routine MC47A.
 139.125 + *
 139.126 + * (6) both int and UF_long versions are provided.  In the descriptions below
 139.127 + *      and integer is and int or UF_long depending on which version is
 139.128 + *      being used.
 139.129 +
 139.130 + **********************************************************************
 139.131 + ***** CAUTION:  ARGUMENTS ARE NOT CHECKED FOR ERRORS ON INPUT.  ******
 139.132 + **********************************************************************
 139.133 + ** If you want error checking, a more versatile input format, and a **
 139.134 + ** simpler user interface, use amd_order or amd_l_order instead.    **
 139.135 + ** This routine is not meant to be user-callable.                   **
 139.136 + **********************************************************************
 139.137 +
 139.138 + * ----------------------------------------------------------------------------
 139.139 + * References:
 139.140 + * ----------------------------------------------------------------------------
 139.141 + *
 139.142 + *  [1] Timothy A. Davis and Iain Duff, "An unsymmetric-pattern multifrontal
 139.143 + *      method for sparse LU factorization", SIAM J. Matrix Analysis and
 139.144 + *      Applications, vol. 18, no. 1, pp. 140-158.  Discusses UMFPACK / MA38,
 139.145 + *      which first introduced the approximate minimum degree used by this
 139.146 + *      routine.
 139.147 + *
 139.148 + *  [2] Patrick Amestoy, Timothy A. Davis, and Iain S. Duff, "An approximate
 139.149 + *      minimum degree ordering algorithm," SIAM J. Matrix Analysis and
 139.150 + *      Applications, vol. 17, no. 4, pp. 886-905, 1996.  Discusses AMDBAR and
 139.151 + *      MC47B, which are the Fortran versions of this routine.
 139.152 + *
 139.153 + *  [3] Alan George and Joseph Liu, "The evolution of the minimum degree
 139.154 + *      ordering algorithm," SIAM Review, vol. 31, no. 1, pp. 1-19, 1989.
 139.155 + *      We list below the features mentioned in that paper that this code
 139.156 + *      includes:
 139.157 + *
 139.158 + *      mass elimination:
 139.159 + *          Yes.  MA27 relied on supervariable detection for mass elimination.
 139.160 + *
 139.161 + *      indistinguishable nodes:
 139.162 + *          Yes (we call these "supervariables").  This was also in the MA27
 139.163 + *          code - although we modified the method of detecting them (the
 139.164 + *          previous hash was the true degree, which we no longer keep track
 139.165 + *          of).  A supervariable is a set of rows with identical nonzero
 139.166 + *          pattern.  All variables in a supervariable are eliminated together.
 139.167 + *          Each supervariable has as its numerical name that of one of its
 139.168 + *          variables (its principal variable).
 139.169 + *
 139.170 + *      quotient graph representation:
 139.171 + *          Yes.  We use the term "element" for the cliques formed during
 139.172 + *          elimination.  This was also in the MA27 code.  The algorithm can
 139.173 + *          operate in place, but it will work more efficiently if given some
 139.174 + *          "elbow room."
 139.175 + *
 139.176 + *      element absorption:
 139.177 + *          Yes.  This was also in the MA27 code.
 139.178 + *
 139.179 + *      external degree:
 139.180 + *          Yes.  The MA27 code was based on the true degree.
 139.181 + *
 139.182 + *      incomplete degree update and multiple elimination:
 139.183 + *          No.  This was not in MA27, either.  Our method of degree update
 139.184 + *          within MC47B is element-based, not variable-based.  It is thus
 139.185 + *          not well-suited for use with incomplete degree update or multiple
 139.186 + *          elimination.
 139.187 + *
 139.188 + * Authors, and Copyright (C) 2004 by:
 139.189 + * Timothy A. Davis, Patrick Amestoy, Iain S. Duff, John K. Reid.
 139.190 + *
 139.191 + * Acknowledgements: This work (and the UMFPACK package) was supported by the
 139.192 + * National Science Foundation (ASC-9111263, DMS-9223088, and CCR-0203270).
 139.193 + * The UMFPACK/MA38 approximate degree update algorithm, the unsymmetric analog
 139.194 + * which forms the basis of AMD, was developed while Tim Davis was supported by
 139.195 + * CERFACS (Toulouse, France) in a post-doctoral position.  This C version, and
 139.196 + * the etree postorder, were written while Tim Davis was on sabbatical at
 139.197 + * Stanford University and Lawrence Berkeley National Laboratory.
 139.198 +
 139.199 + * ----------------------------------------------------------------------------
 139.200 + * INPUT ARGUMENTS (unaltered):
 139.201 + * ----------------------------------------------------------------------------
 139.202 +
 139.203 + * n:  The matrix order.  Restriction:  n >= 1.
 139.204 + *
 139.205 + * iwlen:  The size of the Iw array.  On input, the matrix is stored in
 139.206 + *      Iw [0..pfree-1].  However, Iw [0..iwlen-1] should be slightly larger
 139.207 + *      than what is required to hold the matrix, at least iwlen >= pfree + n.
 139.208 + *      Otherwise, excessive compressions will take place.  The recommended
 139.209 + *      value of iwlen is 1.2 * pfree + n, which is the value used in the
 139.210 + *      user-callable interface to this routine (amd_order.c).  The algorithm
 139.211 + *      will not run at all if iwlen < pfree.  Restriction: iwlen >= pfree + n.
 139.212 + *      Note that this is slightly more restrictive than the actual minimum
 139.213 + *      (iwlen >= pfree), but AMD_2 will be very slow with no elbow room.
 139.214 + *      Thus, this routine enforces a bare minimum elbow room of size n.
 139.215 + *
 139.216 + * pfree: On input the tail end of the array, Iw [pfree..iwlen-1], is empty,
 139.217 + *      and the matrix is stored in Iw [0..pfree-1].  During execution,
 139.218 + *      additional data is placed in Iw, and pfree is modified so that
 139.219 + *      Iw [pfree..iwlen-1] is always the unused part of Iw.
 139.220 + *
 139.221 + * Control:  A double array of size AMD_CONTROL containing input parameters
 139.222 + *      that affect how the ordering is computed.  If NULL, then default
 139.223 + *      settings are used.
 139.224 + *
 139.225 + *      Control [AMD_DENSE] is used to determine whether or not a given input
 139.226 + *      row is "dense".  A row is "dense" if the number of entries in the row
 139.227 + *      exceeds Control [AMD_DENSE] times sqrt (n), except that rows with 16 or
 139.228 + *      fewer entries are never considered "dense".  To turn off the detection
 139.229 + *      of dense rows, set Control [AMD_DENSE] to a negative number, or to a
 139.230 + *      number larger than sqrt (n).  The default value of Control [AMD_DENSE]
 139.231 + *      is AMD_DEFAULT_DENSE, which is defined in amd.h as 10.
 139.232 + *
 139.233 + *      Control [AMD_AGGRESSIVE] is used to determine whether or not aggressive
 139.234 + *      absorption is to be performed.  If nonzero, then aggressive absorption
 139.235 + *      is performed (this is the default).
 139.236 +
 139.237 + * ----------------------------------------------------------------------------
 139.238 + * INPUT/OUPUT ARGUMENTS:
 139.239 + * ----------------------------------------------------------------------------
 139.240 + *
 139.241 + * Pe:  An integer array of size n.  On input, Pe [i] is the index in Iw of
 139.242 + *      the start of row i.  Pe [i] is ignored if row i has no off-diagonal
 139.243 + *      entries.  Thus Pe [i] must be in the range 0 to pfree-1 for non-empty
 139.244 + *      rows.
 139.245 + *
 139.246 + *      During execution, it is used for both supervariables and elements:
 139.247 + *
 139.248 + *      Principal supervariable i:  index into Iw of the description of
 139.249 + *          supervariable i.  A supervariable represents one or more rows of
 139.250 + *          the matrix with identical nonzero pattern.  In this case,
 139.251 + *          Pe [i] >= 0.
 139.252 + *
 139.253 + *      Non-principal supervariable i:  if i has been absorbed into another
 139.254 + *          supervariable j, then Pe [i] = FLIP (j), where FLIP (j) is defined
 139.255 + *          as (-(j)-2).  Row j has the same pattern as row i.  Note that j
 139.256 + *          might later be absorbed into another supervariable j2, in which
 139.257 + *          case Pe [i] is still FLIP (j), and Pe [j] = FLIP (j2) which is
 139.258 + *          < EMPTY, where EMPTY is defined as (-1) in amd_internal.h.
 139.259 + *
 139.260 + *      Unabsorbed element e:  the index into Iw of the description of element
 139.261 + *          e, if e has not yet been absorbed by a subsequent element.  Element
 139.262 + *          e is created when the supervariable of the same name is selected as
 139.263 + *          the pivot.  In this case, Pe [i] >= 0.
 139.264 + *
 139.265 + *      Absorbed element e:  if element e is absorbed into element e2, then
 139.266 + *          Pe [e] = FLIP (e2).  This occurs when the pattern of e (which we
 139.267 + *          refer to as Le) is found to be a subset of the pattern of e2 (that
 139.268 + *          is, Le2).  In this case, Pe [i] < EMPTY.  If element e is "null"
 139.269 + *          (it has no nonzeros outside its pivot block), then Pe [e] = EMPTY,
 139.270 + *          and e is the root of an assembly subtree (or the whole tree if
 139.271 + *          there is just one such root).
 139.272 + *
 139.273 + *      Dense variable i:  if i is "dense", then Pe [i] = EMPTY.
 139.274 + *
 139.275 + *      On output, Pe holds the assembly tree/forest, which implicitly
 139.276 + *      represents a pivot order with identical fill-in as the actual order
 139.277 + *      (via a depth-first search of the tree), as follows.  If Nv [i] > 0,
 139.278 + *      then i represents a node in the assembly tree, and the parent of i is
 139.279 + *      Pe [i], or EMPTY if i is a root.  If Nv [i] = 0, then (i, Pe [i])
 139.280 + *      represents an edge in a subtree, the root of which is a node in the
 139.281 + *      assembly tree.  Note that i refers to a row/column in the original
 139.282 + *      matrix, not the permuted matrix.
 139.283 + *
 139.284 + * Info:  A double array of size AMD_INFO.  If present, (that is, not NULL),
 139.285 + *      then statistics about the ordering are returned in the Info array.
 139.286 + *      See amd.h for a description.
 139.287 +
 139.288 + * ----------------------------------------------------------------------------
 139.289 + * INPUT/MODIFIED (undefined on output):
 139.290 + * ----------------------------------------------------------------------------
 139.291 + *
 139.292 + * Len:  An integer array of size n.  On input, Len [i] holds the number of
 139.293 + *      entries in row i of the matrix, excluding the diagonal.  The contents
 139.294 + *      of Len are undefined on output.
 139.295 + *
 139.296 + * Iw:  An integer array of size iwlen.  On input, Iw [0..pfree-1] holds the
 139.297 + *      description of each row i in the matrix.  The matrix must be symmetric,
 139.298 + *      and both upper and lower triangular parts must be present.  The
 139.299 + *      diagonal must not be present.  Row i is held as follows:
 139.300 + *
 139.301 + *          Len [i]:  the length of the row i data structure in the Iw array.
 139.302 + *          Iw [Pe [i] ... Pe [i] + Len [i] - 1]:
 139.303 + *              the list of column indices for nonzeros in row i (simple
 139.304 + *              supervariables), excluding the diagonal.  All supervariables
 139.305 + *              start with one row/column each (supervariable i is just row i).
 139.306 + *              If Len [i] is zero on input, then Pe [i] is ignored on input.
 139.307 + *
 139.308 + *          Note that the rows need not be in any particular order, and there
 139.309 + *          may be empty space between the rows.
 139.310 + *
 139.311 + *      During execution, the supervariable i experiences fill-in.  This is
 139.312 + *      represented by placing in i a list of the elements that cause fill-in
 139.313 + *      in supervariable i:
 139.314 + *
 139.315 + *          Len [i]:  the length of supervariable i in the Iw array.
 139.316 + *          Iw [Pe [i] ... Pe [i] + Elen [i] - 1]:
 139.317 + *              the list of elements that contain i.  This list is kept short
 139.318 + *              by removing absorbed elements.
 139.319 + *          Iw [Pe [i] + Elen [i] ... Pe [i] + Len [i] - 1]:
 139.320 + *              the list of supervariables in i.  This list is kept short by
 139.321 + *              removing nonprincipal variables, and any entry j that is also
 139.322 + *              contained in at least one of the elements (j in Le) in the list
 139.323 + *              for i (e in row i).
 139.324 + *
 139.325 + *      When supervariable i is selected as pivot, we create an element e of
 139.326 + *      the same name (e=i):
 139.327 + *
 139.328 + *          Len [e]:  the length of element e in the Iw array.
 139.329 + *          Iw [Pe [e] ... Pe [e] + Len [e] - 1]:
 139.330 + *              the list of supervariables in element e.
 139.331 + *
 139.332 + *      An element represents the fill-in that occurs when supervariable i is
 139.333 + *      selected as pivot (which represents the selection of row i and all
 139.334 + *      non-principal variables whose principal variable is i).  We use the
 139.335 + *      term Le to denote the set of all supervariables in element e.  Absorbed
 139.336 + *      supervariables and elements are pruned from these lists when
 139.337 + *      computationally convenient.
 139.338 + *
 139.339 + *  CAUTION:  THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION.
 139.340 + *  The contents of Iw are undefined on output.
 139.341 +
 139.342 + * ----------------------------------------------------------------------------
 139.343 + * OUTPUT (need not be set on input):
 139.344 + * ----------------------------------------------------------------------------
 139.345 + *
 139.346 + * Nv:  An integer array of size n.  During execution, ABS (Nv [i]) is equal to
 139.347 + *      the number of rows that are represented by the principal supervariable
 139.348 + *      i.  If i is a nonprincipal or dense variable, then Nv [i] = 0.
 139.349 + *      Initially, Nv [i] = 1 for all i.  Nv [i] < 0 signifies that i is a
 139.350 + *      principal variable in the pattern Lme of the current pivot element me.
 139.351 + *      After element me is constructed, Nv [i] is set back to a positive
 139.352 + *      value.
 139.353 + *
 139.354 + *      On output, Nv [i] holds the number of pivots represented by super
 139.355 + *      row/column i of the original matrix, or Nv [i] = 0 for non-principal
 139.356 + *      rows/columns.  Note that i refers to a row/column in the original
 139.357 + *      matrix, not the permuted matrix.
 139.358 + *
 139.359 + * Elen:  An integer array of size n.  See the description of Iw above.  At the
 139.360 + *      start of execution, Elen [i] is set to zero for all rows i.  During
 139.361 + *      execution, Elen [i] is the number of elements in the list for
 139.362 + *      supervariable i.  When e becomes an element, Elen [e] = FLIP (esize) is
 139.363 + *      set, where esize is the size of the element (the number of pivots, plus
 139.364 + *      the number of nonpivotal entries).  Thus Elen [e] < EMPTY.
 139.365 + *      Elen (i) = EMPTY set when variable i becomes nonprincipal.
 139.366 + *
 139.367 + *      For variables, Elen (i) >= EMPTY holds until just before the
 139.368 + *      postordering and permutation vectors are computed.  For elements,
 139.369 + *      Elen [e] < EMPTY holds.
 139.370 + *
 139.371 + *      On output, Elen [i] is the degree of the row/column in the Cholesky
 139.372 + *      factorization of the permuted matrix, corresponding to the original row
 139.373 + *      i, if i is a super row/column.  It is equal to EMPTY if i is
 139.374 + *      non-principal.  Note that i refers to a row/column in the original
 139.375 + *      matrix, not the permuted matrix.
 139.376 + *
 139.377 + *      Note that the contents of Elen on output differ from the Fortran
 139.378 + *      version (Elen holds the inverse permutation in the Fortran version,
 139.379 + *      which is instead returned in the Next array in this C version,
 139.380 + *      described below).
 139.381 + *
 139.382 + * Last: In a degree list, Last [i] is the supervariable preceding i, or EMPTY
 139.383 + *      if i is the head of the list.  In a hash bucket, Last [i] is the hash
 139.384 + *      key for i.
 139.385 + *
 139.386 + *      Last [Head [hash]] is also used as the head of a hash bucket if
 139.387 + *      Head [hash] contains a degree list (see the description of Head,
 139.388 + *      below).
 139.389 + *
 139.390 + *      On output, Last [0..n-1] holds the permutation.  That is, if
 139.391 + *      i = Last [k], then row i is the kth pivot row (where k ranges from 0 to
 139.392 + *      n-1).  Row Last [k] of A is the kth row in the permuted matrix, PAP'.
 139.393 + *
 139.394 + * Next: Next [i] is the supervariable following i in a link list, or EMPTY if
 139.395 + *      i is the last in the list.  Used for two kinds of lists:  degree lists
 139.396 + *      and hash buckets (a supervariable can be in only one kind of list at a
 139.397 + *      time).
 139.398 + *
 139.399 + *      On output Next [0..n-1] holds the inverse permutation.  That is, if
 139.400 + *      k = Next [i], then row i is the kth pivot row. Row i of A appears as
 139.401 + *      the (Next[i])-th row in the permuted matrix, PAP'.
 139.402 + *
 139.403 + *      Note that the contents of Next on output differ from the Fortran
 139.404 + *      version (Next is undefined on output in the Fortran version).
 139.405 +
 139.406 + * ----------------------------------------------------------------------------
 139.407 + * LOCAL WORKSPACE (not input or output - used only during execution):
 139.408 + * ----------------------------------------------------------------------------
 139.409 + *
 139.410 + * Degree:  An integer array of size n.  If i is a supervariable, then
 139.411 + *      Degree [i] holds the current approximation of the external degree of
 139.412 + *      row i (an upper bound).  The external degree is the number of nonzeros
 139.413 + *      in row i, minus ABS (Nv [i]), the diagonal part.  The bound is equal to
 139.414 + *      the exact external degree if Elen [i] is less than or equal to two.
 139.415 + *
 139.416 + *      We also use the term "external degree" for elements e to refer to
 139.417 + *      |Le \ Lme|.  If e is an element, then Degree [e] is |Le|, which is the
 139.418 + *      degree of the off-diagonal part of the element e (not including the
 139.419 + *      diagonal part).
 139.420 + *
 139.421 + * Head:   An integer array of size n.  Head is used for degree lists.
 139.422 + *      Head [deg] is the first supervariable in a degree list.  All
 139.423 + *      supervariables i in a degree list Head [deg] have the same approximate
 139.424 + *      degree, namely, deg = Degree [i].  If the list Head [deg] is empty then
 139.425 + *      Head [deg] = EMPTY.
 139.426 + *
 139.427 + *      During supervariable detection Head [hash] also serves as a pointer to
 139.428 + *      a hash bucket.  If Head [hash] >= 0, there is a degree list of degree
 139.429 + *      hash.  The hash bucket head pointer is Last [Head [hash]].  If
 139.430 + *      Head [hash] = EMPTY, then the degree list and hash bucket are both
 139.431 + *      empty.  If Head [hash] < EMPTY, then the degree list is empty, and
 139.432 + *      FLIP (Head [hash]) is the head of the hash bucket.  After supervariable
 139.433 + *      detection is complete, all hash buckets are empty, and the
 139.434 + *      (Last [Head [hash]] = EMPTY) condition is restored for the non-empty
 139.435 + *      degree lists.
 139.436 + *
 139.437 + * W:  An integer array of size n.  The flag array W determines the status of
 139.438 + *      elements and variables, and the external degree of elements.
 139.439 + *
 139.440 + *      for elements:
 139.441 + *          if W [e] = 0, then the element e is absorbed.
 139.442 + *          if W [e] >= wflg, then W [e] - wflg is the size of the set
 139.443 + *              |Le \ Lme|, in terms of nonzeros (the sum of ABS (Nv [i]) for
 139.444 + *              each principal variable i that is both in the pattern of
 139.445 + *              element e and NOT in the pattern of the current pivot element,
 139.446 + *              me).
 139.447 + *          if wflg > W [e] > 0, then e is not absorbed and has not yet been
 139.448 + *              seen in the scan of the element lists in the computation of
 139.449 + *              |Le\Lme| in Scan 1 below.
 139.450 + *
 139.451 + *      for variables:
 139.452 + *          during supervariable detection, if W [j] != wflg then j is
 139.453 + *          not in the pattern of variable i.
 139.454 + *
 139.455 + *      The W array is initialized by setting W [i] = 1 for all i, and by
 139.456 + *      setting wflg = 2.  It is reinitialized if wflg becomes too large (to
 139.457 + *      ensure that wflg+n does not cause integer overflow).
 139.458 +
 139.459 + * ----------------------------------------------------------------------------
 139.460 + * LOCAL INTEGERS:
 139.461 + * ----------------------------------------------------------------------------
 139.462 + */
 139.463 +
 139.464 +    Int deg, degme, dext, lemax, e, elenme, eln, i, ilast, inext, j,
 139.465 +        jlast, jnext, k, knt1, knt2, knt3, lenj, ln, me, mindeg, nel, nleft,
 139.466 +        nvi, nvj, nvpiv, slenme, wbig, we, wflg, wnvi, ok, ndense, ncmpa,
 139.467 +        dense, aggressive ;
 139.468 +
 139.469 +    unsigned Int hash ;     /* unsigned, so that hash % n is well defined.*/
 139.470 +
 139.471 +/*
 139.472 + * deg:         the degree of a variable or element
 139.473 + * degme:       size, |Lme|, of the current element, me (= Degree [me])
 139.474 + * dext:        external degree, |Le \ Lme|, of some element e
 139.475 + * lemax:       largest |Le| seen so far (called dmax in Fortran version)
 139.476 + * e:           an element
 139.477 + * elenme:      the length, Elen [me], of element list of pivotal variable
 139.478 + * eln:         the length, Elen [...], of an element list
 139.479 + * hash:        the computed value of the hash function
 139.480 + * i:           a supervariable
 139.481 + * ilast:       the entry in a link list preceding i
 139.482 + * inext:       the entry in a link list following i
 139.483 + * j:           a supervariable
 139.484 + * jlast:       the entry in a link list preceding j
 139.485 + * jnext:       the entry in a link list, or path, following j
 139.486 + * k:           the pivot order of an element or variable
 139.487 + * knt1:        loop counter used during element construction
 139.488 + * knt2:        loop counter used during element construction
 139.489 + * knt3:        loop counter used during compression
 139.490 + * lenj:        Len [j]
 139.491 + * ln:          length of a supervariable list
 139.492 + * me:          current supervariable being eliminated, and the current
 139.493 + *                  element created by eliminating that supervariable
 139.494 + * mindeg:      current minimum degree
 139.495 + * nel:         number of pivots selected so far
 139.496 + * nleft:       n - nel, the number of nonpivotal rows/columns remaining
 139.497 + * nvi:         the number of variables in a supervariable i (= Nv [i])
 139.498 + * nvj:         the number of variables in a supervariable j (= Nv [j])
 139.499 + * nvpiv:       number of pivots in current element
 139.500 + * slenme:      number of variables in variable list of pivotal variable
 139.501 + * wbig:        = INT_MAX - n for the int version, UF_long_max - n for the
 139.502 + *                  UF_long version.  wflg is not allowed to be >= wbig.
 139.503 + * we:          W [e]
 139.504 + * wflg:        used for flagging the W array.  See description of Iw.
 139.505 + * wnvi:        wflg - Nv [i]
 139.506 + * x:           either a supervariable or an element
 139.507 + *
 139.508 + * ok:          true if supervariable j can be absorbed into i
 139.509 + * ndense:      number of "dense" rows/columns
 139.510 + * dense:       rows/columns with initial degree > dense are considered "dense"
 139.511 + * aggressive:  true if aggressive absorption is being performed
 139.512 + * ncmpa:       number of garbage collections
 139.513 +
 139.514 + * ----------------------------------------------------------------------------
 139.515 + * LOCAL DOUBLES, used for statistical output only (except for alpha):
 139.516 + * ----------------------------------------------------------------------------
 139.517 + */
 139.518 +
 139.519 +    double f, r, ndiv, s, nms_lu, nms_ldl, dmax, alpha, lnz, lnzme ;
 139.520 +
 139.521 +/*
 139.522 + * f:           nvpiv
 139.523 + * r:           degme + nvpiv
 139.524 + * ndiv:        number of divisions for LU or LDL' factorizations
 139.525 + * s:           number of multiply-subtract pairs for LU factorization, for the
 139.526 + *                  current element me
 139.527 + * nms_lu       number of multiply-subtract pairs for LU factorization
 139.528 + * nms_ldl      number of multiply-subtract pairs for LDL' factorization
 139.529 + * dmax:        the largest number of entries in any column of L, including the
 139.530 + *                  diagonal
 139.531 + * alpha:       "dense" degree ratio
 139.532 + * lnz:         the number of nonzeros in L (excluding the diagonal)
 139.533 + * lnzme:       the number of nonzeros in L (excl. the diagonal) for the
 139.534 + *                  current element me
 139.535 +
 139.536 + * ----------------------------------------------------------------------------
 139.537 + * LOCAL "POINTERS" (indices into the Iw array)
 139.538 + * ----------------------------------------------------------------------------
 139.539 +*/
 139.540 +
 139.541 +    Int p, p1, p2, p3, p4, pdst, pend, pj, pme, pme1, pme2, pn, psrc ;
 139.542 +
 139.543 +/*
 139.544 + * Any parameter (Pe [...] or pfree) or local variable starting with "p" (for
 139.545 + * Pointer) is an index into Iw, and all indices into Iw use variables starting
 139.546 + * with "p."  The only exception to this rule is the iwlen input argument.
 139.547 + *
 139.548 + * p:           pointer into lots of things
 139.549 + * p1:          Pe [i] for some variable i (start of element list)
 139.550 + * p2:          Pe [i] + Elen [i] -  1 for some variable i
 139.551 + * p3:          index of first supervariable in clean list
 139.552 + * p4:          
 139.553 + * pdst:        destination pointer, for compression
 139.554 + * pend:        end of memory to compress
 139.555 + * pj:          pointer into an element or variable
 139.556 + * pme:         pointer into the current element (pme1...pme2)
 139.557 + * pme1:        the current element, me, is stored in Iw [pme1...pme2]
 139.558 + * pme2:        the end of the current element
 139.559 + * pn:          pointer into a "clean" variable, also used to compress
 139.560 + * psrc:        source pointer, for compression
 139.561 +*/
 139.562 +
 139.563 +/* ========================================================================= */
 139.564 +/*  INITIALIZATIONS */
 139.565 +/* ========================================================================= */
 139.566 +
 139.567 +    /* Note that this restriction on iwlen is slightly more restrictive than
 139.568 +     * what is actually required in AMD_2.  AMD_2 can operate with no elbow
 139.569 +     * room at all, but it will be slow.  For better performance, at least
 139.570 +     * size-n elbow room is enforced. */
 139.571 +    ASSERT (iwlen >= pfree + n) ;
 139.572 +    ASSERT (n > 0) ;
 139.573 +
 139.574 +    /* initialize output statistics */
 139.575 +    lnz = 0 ;
 139.576 +    ndiv = 0 ;
 139.577 +    nms_lu = 0 ;
 139.578 +    nms_ldl = 0 ;
 139.579 +    dmax = 1 ;
 139.580 +    me = EMPTY ;
 139.581 +
 139.582 +    mindeg = 0 ;
 139.583 +    ncmpa = 0 ;
 139.584 +    nel = 0 ;
 139.585 +    lemax = 0 ;
 139.586 +
 139.587 +    /* get control parameters */
 139.588 +    if (Control != (double *) NULL)
 139.589 +    {
 139.590 +        alpha = Control [AMD_DENSE] ;
 139.591 +        aggressive = (Control [AMD_AGGRESSIVE] != 0) ;
 139.592 +    }
 139.593 +    else
 139.594 +    {
 139.595 +        alpha = AMD_DEFAULT_DENSE ;
 139.596 +        aggressive = AMD_DEFAULT_AGGRESSIVE ;
 139.597 +    }
 139.598 +    /* Note: if alpha is NaN, this is undefined: */
 139.599 +    if (alpha < 0)
 139.600 +    {
 139.601 +        /* only remove completely dense rows/columns */
 139.602 +        dense = n-2 ;
 139.603 +    }
 139.604 +    else
 139.605 +    {
 139.606 +        dense = alpha * sqrt ((double) n) ;
 139.607 +    }
 139.608 +    dense = MAX (16, dense) ;
 139.609 +    dense = MIN (n,  dense) ;
 139.610 +    AMD_DEBUG1 (("\n\nAMD (debug), alpha %g, aggr. "ID"\n",
 139.611 +        alpha, aggressive)) ;
 139.612 +
 139.613 +    for (i = 0 ; i < n ; i++)
 139.614 +    {
 139.615 +        Last [i] = EMPTY ;
 139.616 +        Head [i] = EMPTY ;
 139.617 +        Next [i] = EMPTY ;
 139.618 +        /* if separate Hhead array is used for hash buckets: *
 139.619 +        Hhead [i] = EMPTY ;
 139.620 +        */
 139.621 +        Nv [i] = 1 ;
 139.622 +        W [i] = 1 ;
 139.623 +        Elen [i] = 0 ;
 139.624 +        Degree [i] = Len [i] ;
 139.625 +    }
 139.626 +
 139.627 +#ifndef NDEBUG
 139.628 +    AMD_DEBUG1 (("\n======Nel "ID" initial\n", nel)) ;
 139.629 +    AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next, Last,
 139.630 +                Head, Elen, Degree, W, -1) ;
 139.631 +#endif
 139.632 +
 139.633 +    /* initialize wflg */
 139.634 +    wbig = Int_MAX - n ;
 139.635 +    wflg = clear_flag (0, wbig, W, n) ;
 139.636 +
 139.637 +    /* --------------------------------------------------------------------- */
 139.638 +    /* initialize degree lists and eliminate dense and empty rows */
 139.639 +    /* --------------------------------------------------------------------- */
 139.640 +
 139.641 +    ndense = 0 ;
 139.642 +
 139.643 +    for (i = 0 ; i < n ; i++)
 139.644 +    {
 139.645 +        deg = Degree [i] ;
 139.646 +        ASSERT (deg >= 0 && deg < n) ;
 139.647 +        if (deg == 0)
 139.648 +        {
 139.649 +
 139.650 +            /* -------------------------------------------------------------
 139.651 +             * we have a variable that can be eliminated at once because
 139.652 +             * there is no off-diagonal non-zero in its row.  Note that
 139.653 +             * Nv [i] = 1 for an empty variable i.  It is treated just
 139.654 +             * the same as an eliminated element i.
 139.655 +             * ------------------------------------------------------------- */
 139.656 +
 139.657 +            Elen [i] = FLIP (1) ;
 139.658 +            nel++ ;
 139.659 +            Pe [i] = EMPTY ;
 139.660 +            W [i] = 0 ;
 139.661 +
 139.662 +        }
 139.663 +        else if (deg > dense)
 139.664 +        {
 139.665 +
 139.666 +            /* -------------------------------------------------------------
 139.667 +             * Dense variables are not treated as elements, but as unordered,
 139.668 +             * non-principal variables that have no parent.  They do not take
 139.669 +             * part in the postorder, since Nv [i] = 0.  Note that the Fortran
 139.670 +             * version does not have this option.
 139.671 +             * ------------------------------------------------------------- */
 139.672 +
 139.673 +            AMD_DEBUG1 (("Dense node "ID" degree "ID"\n", i, deg)) ;
 139.674 +            ndense++ ;
 139.675 +            Nv [i] = 0 ;                /* do not postorder this node */
 139.676 +            Elen [i] = EMPTY ;
 139.677 +            nel++ ;
 139.678 +            Pe [i] = EMPTY ;
 139.679 +
 139.680 +        }
 139.681 +        else
 139.682 +        {
 139.683 +
 139.684 +            /* -------------------------------------------------------------
 139.685 +             * place i in the degree list corresponding to its degree
 139.686 +             * ------------------------------------------------------------- */
 139.687 +
 139.688 +            inext = Head [deg] ;
 139.689 +            ASSERT (inext >= EMPTY && inext < n) ;
 139.690 +            if (inext != EMPTY) Last [inext] = i ;
 139.691 +            Next [i] = inext ;
 139.692 +            Head [deg] = i ;
 139.693 +
 139.694 +        }
 139.695 +    }
 139.696 +
 139.697 +/* ========================================================================= */
 139.698 +/* WHILE (selecting pivots) DO */
 139.699 +/* ========================================================================= */
 139.700 +
 139.701 +    while (nel < n)
 139.702 +    {
 139.703 +
 139.704 +#ifndef NDEBUG
 139.705 +        AMD_DEBUG1 (("\n======Nel "ID"\n", nel)) ;
 139.706 +        if (AMD_debug >= 2)
 139.707 +        {
 139.708 +            AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next,
 139.709 +                    Last, Head, Elen, Degree, W, nel) ;
 139.710 +        }
 139.711 +#endif
 139.712 +
 139.713 +/* ========================================================================= */
 139.714 +/* GET PIVOT OF MINIMUM DEGREE */
 139.715 +/* ========================================================================= */
 139.716 +
 139.717 +        /* ----------------------------------------------------------------- */
 139.718 +        /* find next supervariable for elimination */
 139.719 +        /* ----------------------------------------------------------------- */
 139.720 +
 139.721 +        ASSERT (mindeg >= 0 && mindeg < n) ;
 139.722 +        for (deg = mindeg ; deg < n ; deg++)
 139.723 +        {
 139.724 +            me = Head [deg] ;
 139.725 +            if (me != EMPTY) break ;
 139.726 +        }
 139.727 +        mindeg = deg ;
 139.728 +        ASSERT (me >= 0 && me < n) ;
 139.729 +        AMD_DEBUG1 (("=================me: "ID"\n", me)) ;
 139.730 +
 139.731 +        /* ----------------------------------------------------------------- */
 139.732 +        /* remove chosen variable from link list */
 139.733 +        /* ----------------------------------------------------------------- */
 139.734 +
 139.735 +        inext = Next [me] ;
 139.736 +        ASSERT (inext >= EMPTY && inext < n) ;
 139.737 +        if (inext != EMPTY) Last [inext] = EMPTY ;
 139.738 +        Head [deg] = inext ;
 139.739 +
 139.740 +        /* ----------------------------------------------------------------- */
 139.741 +        /* me represents the elimination of pivots nel to nel+Nv[me]-1. */
 139.742 +        /* place me itself as the first in this set. */
 139.743 +        /* ----------------------------------------------------------------- */
 139.744 +
 139.745 +        elenme = Elen [me] ;
 139.746 +        nvpiv = Nv [me] ;
 139.747 +        ASSERT (nvpiv > 0) ;
 139.748 +        nel += nvpiv ;
 139.749 +
 139.750 +/* ========================================================================= */
 139.751 +/* CONSTRUCT NEW ELEMENT */
 139.752 +/* ========================================================================= */
 139.753 +
 139.754 +        /* -----------------------------------------------------------------
 139.755 +         * At this point, me is the pivotal supervariable.  It will be
 139.756 +         * converted into the current element.  Scan list of the pivotal
 139.757 +         * supervariable, me, setting tree pointers and constructing new list
 139.758 +         * of supervariables for the new element, me.  p is a pointer to the
 139.759 +         * current position in the old list.
 139.760 +         * ----------------------------------------------------------------- */
 139.761 +
 139.762 +        /* flag the variable "me" as being in Lme by negating Nv [me] */
 139.763 +        Nv [me] = -nvpiv ;
 139.764 +        degme = 0 ;
 139.765 +        ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ;
 139.766 +
 139.767 +        if (elenme == 0)
 139.768 +        {
 139.769 +
 139.770 +            /* ------------------------------------------------------------- */
 139.771 +            /* construct the new element in place */
 139.772 +            /* ------------------------------------------------------------- */
 139.773 +
 139.774 +            pme1 = Pe [me] ;
 139.775 +            pme2 = pme1 - 1 ;
 139.776 +
 139.777 +            for (p = pme1 ; p <= pme1 + Len [me] - 1 ; p++)
 139.778 +            {
 139.779 +                i = Iw [p] ;
 139.780 +                ASSERT (i >= 0 && i < n && Nv [i] >= 0) ;
 139.781 +                nvi = Nv [i] ;
 139.782 +                if (nvi > 0)
 139.783 +                {
 139.784 +
 139.785 +                    /* ----------------------------------------------------- */
 139.786 +                    /* i is a principal variable not yet placed in Lme. */
 139.787 +                    /* store i in new list */
 139.788 +                    /* ----------------------------------------------------- */
 139.789 +
 139.790 +                    /* flag i as being in Lme by negating Nv [i] */
 139.791 +                    degme += nvi ;
 139.792 +                    Nv [i] = -nvi ;
 139.793 +                    Iw [++pme2] = i ;
 139.794 +
 139.795 +                    /* ----------------------------------------------------- */
 139.796 +                    /* remove variable i from degree list. */
 139.797 +                    /* ----------------------------------------------------- */
 139.798 +
 139.799 +                    ilast = Last [i] ;
 139.800 +                    inext = Next [i] ;
 139.801 +                    ASSERT (ilast >= EMPTY && ilast < n) ;
 139.802 +                    ASSERT (inext >= EMPTY && inext < n) ;
 139.803 +                    if (inext != EMPTY) Last [inext] = ilast ;
 139.804 +                    if (ilast != EMPTY)
 139.805 +                    {
 139.806 +                        Next [ilast] = inext ;
 139.807 +                    }
 139.808 +                    else
 139.809 +                    {
 139.810 +                        /* i is at the head of the degree list */
 139.811 +                        ASSERT (Degree [i] >= 0 && Degree [i] < n) ;
 139.812 +                        Head [Degree [i]] = inext ;
 139.813 +                    }
 139.814 +                }
 139.815 +            }
 139.816 +        }
 139.817 +        else
 139.818 +        {
 139.819 +
 139.820 +            /* ------------------------------------------------------------- */
 139.821 +            /* construct the new element in empty space, Iw [pfree ...] */
 139.822 +            /* ------------------------------------------------------------- */
 139.823 +
 139.824 +            p = Pe [me] ;
 139.825 +            pme1 = pfree ;
 139.826 +            slenme = Len [me] - elenme ;
 139.827 +
 139.828 +            for (knt1 = 1 ; knt1 <= elenme + 1 ; knt1++)
 139.829 +            {
 139.830 +
 139.831 +                if (knt1 > elenme)
 139.832 +                {
 139.833 +                    /* search the supervariables in me. */
 139.834 +                    e = me ;
 139.835 +                    pj = p ;
 139.836 +                    ln = slenme ;
 139.837 +                    AMD_DEBUG2 (("Search sv: "ID" "ID" "ID"\n", me,pj,ln)) ;
 139.838 +                }
 139.839 +                else
 139.840 +                {
 139.841 +                    /* search the elements in me. */
 139.842 +                    e = Iw [p++] ;
 139.843 +                    ASSERT (e >= 0 && e < n) ;
 139.844 +                    pj = Pe [e] ;
 139.845 +                    ln = Len [e] ;
 139.846 +                    AMD_DEBUG2 (("Search element e "ID" in me "ID"\n", e,me)) ;
 139.847 +                    ASSERT (Elen [e] < EMPTY && W [e] > 0 && pj >= 0) ;
 139.848 +                }
 139.849 +                ASSERT (ln >= 0 && (ln == 0 || (pj >= 0 && pj < iwlen))) ;
 139.850 +
 139.851 +                /* ---------------------------------------------------------
 139.852 +                 * search for different supervariables and add them to the
 139.853 +                 * new list, compressing when necessary. this loop is
 139.854 +                 * executed once for each element in the list and once for
 139.855 +                 * all the supervariables in the list.
 139.856 +                 * --------------------------------------------------------- */
 139.857 +
 139.858 +                for (knt2 = 1 ; knt2 <= ln ; knt2++)
 139.859 +                {
 139.860 +                    i = Iw [pj++] ;
 139.861 +                    ASSERT (i >= 0 && i < n && (i == me || Elen [i] >= EMPTY));
 139.862 +                    nvi = Nv [i] ;
 139.863 +                    AMD_DEBUG2 ((": "ID" "ID" "ID" "ID"\n",
 139.864 +                                i, Elen [i], Nv [i], wflg)) ;
 139.865 +
 139.866 +                    if (nvi > 0)
 139.867 +                    {
 139.868 +
 139.869 +                        /* ------------------------------------------------- */
 139.870 +                        /* compress Iw, if necessary */
 139.871 +                        /* ------------------------------------------------- */
 139.872 +
 139.873 +                        if (pfree >= iwlen)
 139.874 +                        {
 139.875 +
 139.876 +                            AMD_DEBUG1 (("GARBAGE COLLECTION\n")) ;
 139.877 +
 139.878 +                            /* prepare for compressing Iw by adjusting pointers
 139.879 +                             * and lengths so that the lists being searched in
 139.880 +                             * the inner and outer loops contain only the
 139.881 +                             * remaining entries. */
 139.882 +
 139.883 +                            Pe [me] = p ;
 139.884 +                            Len [me] -= knt1 ;
 139.885 +                            /* check if nothing left of supervariable me */
 139.886 +                            if (Len [me] == 0) Pe [me] = EMPTY ;
 139.887 +                            Pe [e] = pj ;
 139.888 +                            Len [e] = ln - knt2 ;
 139.889 +                            /* nothing left of element e */
 139.890 +                            if (Len [e] == 0) Pe [e] = EMPTY ;
 139.891 +
 139.892 +                            ncmpa++ ;   /* one more garbage collection */
 139.893 +
 139.894 +                            /* store first entry of each object in Pe */
 139.895 +                            /* FLIP the first entry in each object */
 139.896 +                            for (j = 0 ; j < n ; j++)
 139.897 +                            {
 139.898 +                                pn = Pe [j] ;
 139.899 +                                if (pn >= 0)
 139.900 +                                {
 139.901 +                                    ASSERT (pn >= 0 && pn < iwlen) ;
 139.902 +                                    Pe [j] = Iw [pn] ;
 139.903 +                                    Iw [pn] = FLIP (j) ;
 139.904 +                                }
 139.905 +                            }
 139.906 +
 139.907 +                            /* psrc/pdst point to source/destination */
 139.908 +                            psrc = 0 ;
 139.909 +                            pdst = 0 ;
 139.910 +                            pend = pme1 - 1 ;
 139.911 +
 139.912 +                            while (psrc <= pend)
 139.913 +                            {
 139.914 +                                /* search for next FLIP'd entry */
 139.915 +                                j = FLIP (Iw [psrc++]) ;
 139.916 +                                if (j >= 0)
 139.917 +                                {
 139.918 +                                    AMD_DEBUG2 (("Got object j: "ID"\n", j)) ;
 139.919 +                                    Iw [pdst] = Pe [j] ;
 139.920 +                                    Pe [j] = pdst++ ;
 139.921 +                                    lenj = Len [j] ;
 139.922 +                                    /* copy from source to destination */
 139.923 +                                    for (knt3 = 0 ; knt3 <= lenj - 2 ; knt3++)
 139.924 +                                    {
 139.925 +                                        Iw [pdst++] = Iw [psrc++] ;
 139.926 +                                    }
 139.927 +                                }
 139.928 +                            }
 139.929 +
 139.930 +                            /* move the new partially-constructed element */
 139.931 +                            p1 = pdst ;
 139.932 +                            for (psrc = pme1 ; psrc <= pfree-1 ; psrc++)
 139.933 +                            {
 139.934 +                                Iw [pdst++] = Iw [psrc] ;
 139.935 +                            }
 139.936 +                            pme1 = p1 ;
 139.937 +                            pfree = pdst ;
 139.938 +                            pj = Pe [e] ;
 139.939 +                            p = Pe [me] ;
 139.940 +
 139.941 +                        }
 139.942 +
 139.943 +                        /* ------------------------------------------------- */
 139.944 +                        /* i is a principal variable not yet placed in Lme */
 139.945 +                        /* store i in new list */
 139.946 +                        /* ------------------------------------------------- */
 139.947 +
 139.948 +                        /* flag i as being in Lme by negating Nv [i] */
 139.949 +                        degme += nvi ;
 139.950 +                        Nv [i] = -nvi ;
 139.951 +                        Iw [pfree++] = i ;
 139.952 +                        AMD_DEBUG2 (("     s: "ID"     nv "ID"\n", i, Nv [i]));
 139.953 +
 139.954 +                        /* ------------------------------------------------- */
 139.955 +                        /* remove variable i from degree link list */
 139.956 +                        /* ------------------------------------------------- */
 139.957 +
 139.958 +                        ilast = Last [i] ;
 139.959 +                        inext = Next [i] ;
 139.960 +                        ASSERT (ilast >= EMPTY && ilast < n) ;
 139.961 +                        ASSERT (inext >= EMPTY && inext < n) ;
 139.962 +                        if (inext != EMPTY) Last [inext] = ilast ;
 139.963 +                        if (ilast != EMPTY)
 139.964 +                        {
 139.965 +                            Next [ilast] = inext ;
 139.966 +                        }
 139.967 +                        else
 139.968 +                        {
 139.969 +                            /* i is at the head of the degree list */
 139.970 +                            ASSERT (Degree [i] >= 0 && Degree [i] < n) ;
 139.971 +                            Head [Degree [i]] = inext ;
 139.972 +                        }
 139.973 +                    }
 139.974 +                }
 139.975 +
 139.976 +                if (e != me)
 139.977 +                {
 139.978 +                    /* set tree pointer and flag to indicate element e is
 139.979 +                     * absorbed into new element me (the parent of e is me) */
 139.980 +                    AMD_DEBUG1 ((" Element "ID" => "ID"\n", e, me)) ;
 139.981 +                    Pe [e] = FLIP (me) ;
 139.982 +                    W [e] = 0 ;
 139.983 +                }
 139.984 +            }
 139.985 +
 139.986 +            pme2 = pfree - 1 ;
 139.987 +        }
 139.988 +
 139.989 +        /* ----------------------------------------------------------------- */
 139.990 +        /* me has now been converted into an element in Iw [pme1..pme2] */
 139.991 +        /* ----------------------------------------------------------------- */
 139.992 +
 139.993 +        /* degme holds the external degree of new element */
 139.994 +        Degree [me] = degme ;
 139.995 +        Pe [me] = pme1 ;
 139.996 +        Len [me] = pme2 - pme1 + 1 ;
 139.997 +        ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ;
 139.998 +
 139.999 +        Elen [me] = FLIP (nvpiv + degme) ;
139.1000 +        /* FLIP (Elen (me)) is now the degree of pivot (including
139.1001 +         * diagonal part). */
139.1002 +
139.1003 +#ifndef NDEBUG
139.1004 +        AMD_DEBUG2 (("New element structure: length= "ID"\n", pme2-pme1+1)) ;
139.1005 +        for (pme = pme1 ; pme <= pme2 ; pme++) AMD_DEBUG3 ((" "ID"", Iw[pme]));
139.1006 +        AMD_DEBUG3 (("\n")) ;
139.1007 +#endif
139.1008 +
139.1009 +        /* ----------------------------------------------------------------- */
139.1010 +        /* make sure that wflg is not too large. */
139.1011 +        /* ----------------------------------------------------------------- */
139.1012 +
139.1013 +        /* With the current value of wflg, wflg+n must not cause integer
139.1014 +         * overflow */
139.1015 +
139.1016 +        wflg = clear_flag (wflg, wbig, W, n) ;
139.1017 +
139.1018 +/* ========================================================================= */
139.1019 +/* COMPUTE (W [e] - wflg) = |Le\Lme| FOR ALL ELEMENTS */
139.1020 +/* ========================================================================= */
139.1021 +
139.1022 +        /* -----------------------------------------------------------------
139.1023 +         * Scan 1:  compute the external degrees of previous elements with
139.1024 +         * respect to the current element.  That is:
139.1025 +         *       (W [e] - wflg) = |Le \ Lme|
139.1026 +         * for each element e that appears in any supervariable in Lme.  The
139.1027 +         * notation Le refers to the pattern (list of supervariables) of a
139.1028 +         * previous element e, where e is not yet absorbed, stored in
139.1029 +         * Iw [Pe [e] + 1 ... Pe [e] + Len [e]].  The notation Lme
139.1030 +         * refers to the pattern of the current element (stored in
139.1031 +         * Iw [pme1..pme2]).   If aggressive absorption is enabled, and
139.1032 +         * (W [e] - wflg) becomes zero, then the element e will be absorbed
139.1033 +         * in Scan 2.
139.1034 +         * ----------------------------------------------------------------- */
139.1035 +
139.1036 +        AMD_DEBUG2 (("me: ")) ;
139.1037 +        for (pme = pme1 ; pme <= pme2 ; pme++)
139.1038 +        {
139.1039 +            i = Iw [pme] ;
139.1040 +            ASSERT (i >= 0 && i < n) ;
139.1041 +            eln = Elen [i] ;
139.1042 +            AMD_DEBUG3 ((""ID" Elen "ID": \n", i, eln)) ;
139.1043 +            if (eln > 0)
139.1044 +            {
139.1045 +                /* note that Nv [i] has been negated to denote i in Lme: */
139.1046 +                nvi = -Nv [i] ;
139.1047 +                ASSERT (nvi > 0 && Pe [i] >= 0 && Pe [i] < iwlen) ;
139.1048 +                wnvi = wflg - nvi ;
139.1049 +                for (p = Pe [i] ; p <= Pe [i] + eln - 1 ; p++)
139.1050 +                {
139.1051 +                    e = Iw [p] ;
139.1052 +                    ASSERT (e >= 0 && e < n) ;
139.1053 +                    we = W [e] ;
139.1054 +                    AMD_DEBUG4 (("    e "ID" we "ID" ", e, we)) ;
139.1055 +                    if (we >= wflg)
139.1056 +                    {
139.1057 +                        /* unabsorbed element e has been seen in this loop */
139.1058 +                        AMD_DEBUG4 (("    unabsorbed, first time seen")) ;
139.1059 +                        we -= nvi ;
139.1060 +                    }
139.1061 +                    else if (we != 0)
139.1062 +                    {
139.1063 +                        /* e is an unabsorbed element */
139.1064 +                        /* this is the first we have seen e in all of Scan 1 */
139.1065 +                        AMD_DEBUG4 (("    unabsorbed")) ;
139.1066 +                        we = Degree [e] + wnvi ;
139.1067 +                    }
139.1068 +                    AMD_DEBUG4 (("\n")) ;
139.1069 +                    W [e] = we ;
139.1070 +                }
139.1071 +            }
139.1072 +        }
139.1073 +        AMD_DEBUG2 (("\n")) ;
139.1074 +
139.1075 +/* ========================================================================= */
139.1076 +/* DEGREE UPDATE AND ELEMENT ABSORPTION */
139.1077 +/* ========================================================================= */
139.1078 +
139.1079 +        /* -----------------------------------------------------------------
139.1080 +         * Scan 2:  for each i in Lme, sum up the degree of Lme (which is
139.1081 +         * degme), plus the sum of the external degrees of each Le for the
139.1082 +         * elements e appearing within i, plus the supervariables in i.
139.1083 +         * Place i in hash list.
139.1084 +         * ----------------------------------------------------------------- */
139.1085 +
139.1086 +        for (pme = pme1 ; pme <= pme2 ; pme++)
139.1087 +        {
139.1088 +            i = Iw [pme] ;
139.1089 +            ASSERT (i >= 0 && i < n && Nv [i] < 0 && Elen [i] >= 0) ;
139.1090 +            AMD_DEBUG2 (("Updating: i "ID" "ID" "ID"\n", i, Elen[i], Len [i]));
139.1091 +            p1 = Pe [i] ;
139.1092 +            p2 = p1 + Elen [i] - 1 ;
139.1093 +            pn = p1 ;
139.1094 +            hash = 0 ;
139.1095 +            deg = 0 ;
139.1096 +            ASSERT (p1 >= 0 && p1 < iwlen && p2 >= -1 && p2 < iwlen) ;
139.1097 +
139.1098 +            /* ------------------------------------------------------------- */
139.1099 +            /* scan the element list associated with supervariable i */
139.1100 +            /* ------------------------------------------------------------- */
139.1101 +
139.1102 +            /* UMFPACK/MA38-style approximate degree: */
139.1103 +            if (aggressive)
139.1104 +            {
139.1105 +                for (p = p1 ; p <= p2 ; p++)
139.1106 +                {
139.1107 +                    e = Iw [p] ;
139.1108 +                    ASSERT (e >= 0 && e < n) ;
139.1109 +                    we = W [e] ;
139.1110 +                    if (we != 0)
139.1111 +                    {
139.1112 +                        /* e is an unabsorbed element */
139.1113 +                        /* dext = | Le \ Lme | */
139.1114 +                        dext = we - wflg ;
139.1115 +                        if (dext > 0)
139.1116 +                        {
139.1117 +                            deg += dext ;
139.1118 +                            Iw [pn++] = e ;
139.1119 +                            hash += e ;
139.1120 +                            AMD_DEBUG4 ((" e: "ID" hash = "ID"\n",e,hash)) ;
139.1121 +                        }
139.1122 +                        else
139.1123 +                        {
139.1124 +                            /* external degree of e is zero, absorb e into me*/
139.1125 +                            AMD_DEBUG1 ((" Element "ID" =>"ID" (aggressive)\n",
139.1126 +                                e, me)) ;
139.1127 +                            ASSERT (dext == 0) ;
139.1128 +                            Pe [e] = FLIP (me) ;
139.1129 +                            W [e] = 0 ;
139.1130 +                        }
139.1131 +                    }
139.1132 +                }
139.1133 +            }
139.1134 +            else
139.1135 +            {
139.1136 +                for (p = p1 ; p <= p2 ; p++)
139.1137 +                {
139.1138 +                    e = Iw [p] ;
139.1139 +                    ASSERT (e >= 0 && e < n) ;
139.1140 +                    we = W [e] ;
139.1141 +                    if (we != 0)
139.1142 +                    {
139.1143 +                        /* e is an unabsorbed element */
139.1144 +                        dext = we - wflg ;
139.1145 +                        ASSERT (dext >= 0) ;
139.1146 +                        deg += dext ;
139.1147 +                        Iw [pn++] = e ;
139.1148 +                        hash += e ;
139.1149 +                        AMD_DEBUG4 (("  e: "ID" hash = "ID"\n",e,hash)) ;
139.1150 +                    }
139.1151 +                }
139.1152 +            }
139.1153 +
139.1154 +            /* count the number of elements in i (including me): */
139.1155 +            Elen [i] = pn - p1 + 1 ;
139.1156 +
139.1157 +            /* ------------------------------------------------------------- */
139.1158 +            /* scan the supervariables in the list associated with i */
139.1159 +            /* ------------------------------------------------------------- */
139.1160 +
139.1161 +            /* The bulk of the AMD run time is typically spent in this loop,
139.1162 +             * particularly if the matrix has many dense rows that are not
139.1163 +             * removed prior to ordering. */
139.1164 +            p3 = pn ;
139.1165 +            p4 = p1 + Len [i] ;
139.1166 +            for (p = p2 + 1 ; p < p4 ; p++)
139.1167 +            {
139.1168 +                j = Iw [p] ;
139.1169 +                ASSERT (j >= 0 && j < n) ;
139.1170 +                nvj = Nv [j] ;
139.1171 +                if (nvj > 0)
139.1172 +                {
139.1173 +                    /* j is unabsorbed, and not in Lme. */
139.1174 +                    /* add to degree and add to new list */
139.1175 +                    deg += nvj ;
139.1176 +                    Iw [pn++] = j ;
139.1177 +                    hash += j ;
139.1178 +                    AMD_DEBUG4 (("  s: "ID" hash "ID" Nv[j]= "ID"\n",
139.1179 +                                j, hash, nvj)) ;
139.1180 +                }
139.1181 +            }
139.1182 +
139.1183 +            /* ------------------------------------------------------------- */
139.1184 +            /* update the degree and check for mass elimination */
139.1185 +            /* ------------------------------------------------------------- */
139.1186 +
139.1187 +            /* with aggressive absorption, deg==0 is identical to the
139.1188 +             * Elen [i] == 1 && p3 == pn test, below. */
139.1189 +            ASSERT (IMPLIES (aggressive, (deg==0) == (Elen[i]==1 && p3==pn))) ;
139.1190 +
139.1191 +            if (Elen [i] == 1 && p3 == pn)
139.1192 +            {
139.1193 +
139.1194 +                /* --------------------------------------------------------- */
139.1195 +                /* mass elimination */
139.1196 +                /* --------------------------------------------------------- */
139.1197 +
139.1198 +                /* There is nothing left of this node except for an edge to
139.1199 +                 * the current pivot element.  Elen [i] is 1, and there are
139.1200 +                 * no variables adjacent to node i.  Absorb i into the
139.1201 +                 * current pivot element, me.  Note that if there are two or
139.1202 +                 * more mass eliminations, fillin due to mass elimination is
139.1203 +                 * possible within the nvpiv-by-nvpiv pivot block.  It is this
139.1204 +                 * step that causes AMD's analysis to be an upper bound.
139.1205 +                 *
139.1206 +                 * The reason is that the selected pivot has a lower
139.1207 +                 * approximate degree than the true degree of the two mass
139.1208 +                 * eliminated nodes.  There is no edge between the two mass
139.1209 +                 * eliminated nodes.  They are merged with the current pivot
139.1210 +                 * anyway.
139.1211 +                 *
139.1212 +                 * No fillin occurs in the Schur complement, in any case,
139.1213 +                 * and this effect does not decrease the quality of the
139.1214 +                 * ordering itself, just the quality of the nonzero and
139.1215 +                 * flop count analysis.  It also means that the post-ordering
139.1216 +                 * is not an exact elimination tree post-ordering. */
139.1217 +
139.1218 +                AMD_DEBUG1 (("  MASS i "ID" => parent e "ID"\n", i, me)) ;
139.1219 +                Pe [i] = FLIP (me) ;
139.1220 +                nvi = -Nv [i] ;
139.1221 +                degme -= nvi ;
139.1222 +                nvpiv += nvi ;
139.1223 +                nel += nvi ;
139.1224 +                Nv [i] = 0 ;
139.1225 +                Elen [i] = EMPTY ;
139.1226 +
139.1227 +            }
139.1228 +            else
139.1229 +            {
139.1230 +
139.1231 +                /* --------------------------------------------------------- */
139.1232 +                /* update the upper-bound degree of i */
139.1233 +                /* --------------------------------------------------------- */
139.1234 +
139.1235 +                /* the following degree does not yet include the size
139.1236 +                 * of the current element, which is added later: */
139.1237 +
139.1238 +                Degree [i] = MIN (Degree [i], deg) ;
139.1239 +
139.1240 +                /* --------------------------------------------------------- */
139.1241 +                /* add me to the list for i */
139.1242 +                /* --------------------------------------------------------- */
139.1243 +
139.1244 +                /* move first supervariable to end of list */
139.1245 +                Iw [pn] = Iw [p3] ;
139.1246 +                /* move first element to end of element part of list */
139.1247 +                Iw [p3] = Iw [p1] ;
139.1248 +                /* add new element, me, to front of list. */
139.1249 +                Iw [p1] = me ;
139.1250 +                /* store the new length of the list in Len [i] */
139.1251 +                Len [i] = pn - p1 + 1 ;
139.1252 +
139.1253 +                /* --------------------------------------------------------- */
139.1254 +                /* place in hash bucket.  Save hash key of i in Last [i]. */
139.1255 +                /* --------------------------------------------------------- */
139.1256 +
139.1257 +                /* NOTE: this can fail if hash is negative, because the ANSI C
139.1258 +                 * standard does not define a % b when a and/or b are negative.
139.1259 +                 * That's why hash is defined as an unsigned Int, to avoid this
139.1260 +                 * problem. */
139.1261 +                hash = hash % n ;
139.1262 +                ASSERT (((Int) hash) >= 0 && ((Int) hash) < n) ;
139.1263 +
139.1264 +                /* if the Hhead array is not used: */
139.1265 +                j = Head [hash] ;
139.1266 +                if (j <= EMPTY)
139.1267 +                {
139.1268 +                    /* degree list is empty, hash head is FLIP (j) */
139.1269 +                    Next [i] = FLIP (j) ;
139.1270 +                    Head [hash] = FLIP (i) ;
139.1271 +                }
139.1272 +                else
139.1273 +                {
139.1274 +                    /* degree list is not empty, use Last [Head [hash]] as
139.1275 +                     * hash head. */
139.1276 +                    Next [i] = Last [j] ;
139.1277 +                    Last [j] = i ;
139.1278 +                }
139.1279 +
139.1280 +                /* if a separate Hhead array is used: *
139.1281 +                Next [i] = Hhead [hash] ;
139.1282 +                Hhead [hash] = i ;
139.1283 +                */
139.1284 +
139.1285 +                Last [i] = hash ;
139.1286 +            }
139.1287 +        }
139.1288 +
139.1289 +        Degree [me] = degme ;
139.1290 +
139.1291 +        /* ----------------------------------------------------------------- */
139.1292 +        /* Clear the counter array, W [...], by incrementing wflg. */
139.1293 +        /* ----------------------------------------------------------------- */
139.1294 +
139.1295 +        /* make sure that wflg+n does not cause integer overflow */
139.1296 +        lemax =  MAX (lemax, degme) ;
139.1297 +        wflg += lemax ;
139.1298 +        wflg = clear_flag (wflg, wbig, W, n) ;
139.1299 +        /*  at this point, W [0..n-1] < wflg holds */
139.1300 +
139.1301 +/* ========================================================================= */
139.1302 +/* SUPERVARIABLE DETECTION */
139.1303 +/* ========================================================================= */
139.1304 +
139.1305 +        AMD_DEBUG1 (("Detecting supervariables:\n")) ;
139.1306 +        for (pme = pme1 ; pme <= pme2 ; pme++)
139.1307 +        {
139.1308 +            i = Iw [pme] ;
139.1309 +            ASSERT (i >= 0 && i < n) ;
139.1310 +            AMD_DEBUG2 (("Consider i "ID" nv "ID"\n", i, Nv [i])) ;
139.1311 +            if (Nv [i] < 0)
139.1312 +            {
139.1313 +                /* i is a principal variable in Lme */
139.1314 +
139.1315 +                /* ---------------------------------------------------------
139.1316 +                 * examine all hash buckets with 2 or more variables.  We do
139.1317 +                 * this by examing all unique hash keys for supervariables in
139.1318 +                 * the pattern Lme of the current element, me
139.1319 +                 * --------------------------------------------------------- */
139.1320 +
139.1321 +                /* let i = head of hash bucket, and empty the hash bucket */
139.1322 +                ASSERT (Last [i] >= 0 && Last [i] < n) ;
139.1323 +                hash = Last [i] ;
139.1324 +
139.1325 +                /* if Hhead array is not used: */
139.1326 +                j = Head [hash] ;
139.1327 +                if (j == EMPTY)
139.1328 +                {
139.1329 +                    /* hash bucket and degree list are both empty */
139.1330 +                    i = EMPTY ;
139.1331 +                }
139.1332 +                else if (j < EMPTY)
139.1333 +                {
139.1334 +                    /* degree list is empty */
139.1335 +                    i = FLIP (j) ;
139.1336 +                    Head [hash] = EMPTY ;
139.1337 +                }
139.1338 +                else
139.1339 +                {
139.1340 +                    /* degree list is not empty, restore Last [j] of head j */
139.1341 +                    i = Last [j] ;
139.1342 +                    Last [j] = EMPTY ;
139.1343 +                }
139.1344 +
139.1345 +                /* if separate Hhead array is used: *
139.1346 +                i = Hhead [hash] ;
139.1347 +                Hhead [hash] = EMPTY ;
139.1348 +                */
139.1349 +
139.1350 +                ASSERT (i >= EMPTY && i < n) ;
139.1351 +                AMD_DEBUG2 (("----i "ID" hash "ID"\n", i, hash)) ;
139.1352 +
139.1353 +                while (i != EMPTY && Next [i] != EMPTY)
139.1354 +                {
139.1355 +
139.1356 +                    /* -----------------------------------------------------
139.1357 +                     * this bucket has one or more variables following i.
139.1358 +                     * scan all of them to see if i can absorb any entries
139.1359 +                     * that follow i in hash bucket.  Scatter i into w.
139.1360 +                     * ----------------------------------------------------- */
139.1361 +
139.1362 +                    ln = Len [i] ;
139.1363 +                    eln = Elen [i] ;
139.1364 +                    ASSERT (ln >= 0 && eln >= 0) ;
139.1365 +                    ASSERT (Pe [i] >= 0 && Pe [i] < iwlen) ;
139.1366 +                    /* do not flag the first element in the list (me) */
139.1367 +                    for (p = Pe [i] + 1 ; p <= Pe [i] + ln - 1 ; p++)
139.1368 +                    {
139.1369 +                        ASSERT (Iw [p] >= 0 && Iw [p] < n) ;
139.1370 +                        W [Iw [p]] = wflg ;
139.1371 +                    }
139.1372 +
139.1373 +                    /* ----------------------------------------------------- */
139.1374 +                    /* scan every other entry j following i in bucket */
139.1375 +                    /* ----------------------------------------------------- */
139.1376 +
139.1377 +                    jlast = i ;
139.1378 +                    j = Next [i] ;
139.1379 +                    ASSERT (j >= EMPTY && j < n) ;
139.1380 +
139.1381 +                    while (j != EMPTY)
139.1382 +                    {
139.1383 +                        /* ------------------------------------------------- */
139.1384 +                        /* check if j and i have identical nonzero pattern */
139.1385 +                        /* ------------------------------------------------- */
139.1386 +
139.1387 +                        AMD_DEBUG3 (("compare i "ID" and j "ID"\n", i,j)) ;
139.1388 +
139.1389 +                        /* check if i and j have the same Len and Elen */
139.1390 +                        ASSERT (Len [j] >= 0 && Elen [j] >= 0) ;
139.1391 +                        ASSERT (Pe [j] >= 0 && Pe [j] < iwlen) ;
139.1392 +                        ok = (Len [j] == ln) && (Elen [j] == eln) ;
139.1393 +                        /* skip the first element in the list (me) */
139.1394 +                        for (p = Pe [j] + 1 ; ok && p <= Pe [j] + ln - 1 ; p++)
139.1395 +                        {
139.1396 +                            ASSERT (Iw [p] >= 0 && Iw [p] < n) ;
139.1397 +                            if (W [Iw [p]] != wflg) ok = 0 ;
139.1398 +                        }
139.1399 +                        if (ok)
139.1400 +                        {
139.1401 +                            /* --------------------------------------------- */
139.1402 +                            /* found it!  j can be absorbed into i */
139.1403 +                            /* --------------------------------------------- */
139.1404 +
139.1405 +                            AMD_DEBUG1 (("found it! j "ID" => i "ID"\n", j,i));
139.1406 +                            Pe [j] = FLIP (i) ;
139.1407 +                            /* both Nv [i] and Nv [j] are negated since they */
139.1408 +                            /* are in Lme, and the absolute values of each */
139.1409 +                            /* are the number of variables in i and j: */
139.1410 +                            Nv [i] += Nv [j] ;
139.1411 +                            Nv [j] = 0 ;
139.1412 +                            Elen [j] = EMPTY ;
139.1413 +                            /* delete j from hash bucket */
139.1414 +                            ASSERT (j != Next [j]) ;
139.1415 +                            j = Next [j] ;
139.1416 +                            Next [jlast] = j ;
139.1417 +
139.1418 +                        }
139.1419 +                        else
139.1420 +                        {
139.1421 +                            /* j cannot be absorbed into i */
139.1422 +                            jlast = j ;
139.1423 +                            ASSERT (j != Next [j]) ;
139.1424 +                            j = Next [j] ;
139.1425 +                        }
139.1426 +                        ASSERT (j >= EMPTY && j < n) ;
139.1427 +                    }
139.1428 +
139.1429 +                    /* -----------------------------------------------------
139.1430 +                     * no more variables can be absorbed into i
139.1431 +                     * go to next i in bucket and clear flag array
139.1432 +                     * ----------------------------------------------------- */
139.1433 +
139.1434 +                    wflg++ ;
139.1435 +                    i = Next [i] ;
139.1436 +                    ASSERT (i >= EMPTY && i < n) ;
139.1437 +
139.1438 +                }
139.1439 +            }
139.1440 +        }
139.1441 +        AMD_DEBUG2 (("detect done\n")) ;
139.1442 +
139.1443 +/* ========================================================================= */
139.1444 +/* RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVARIABLES FROM ELEMENT */
139.1445 +/* ========================================================================= */
139.1446 +
139.1447 +        p = pme1 ;
139.1448 +        nleft = n - nel ;
139.1449 +        for (pme = pme1 ; pme <= pme2 ; pme++)
139.1450 +        {
139.1451 +            i = Iw [pme] ;
139.1452 +            ASSERT (i >= 0 && i < n) ;
139.1453 +            nvi = -Nv [i] ;
139.1454 +            AMD_DEBUG3 (("Restore i "ID" "ID"\n", i, nvi)) ;
139.1455 +            if (nvi > 0)
139.1456 +            {
139.1457 +                /* i is a principal variable in Lme */
139.1458 +                /* restore Nv [i] to signify that i is principal */
139.1459 +                Nv [i] = nvi ;
139.1460 +
139.1461 +                /* --------------------------------------------------------- */
139.1462 +                /* compute the external degree (add size of current element) */
139.1463 +                /* --------------------------------------------------------- */
139.1464 +
139.1465 +                deg = Degree [i] + degme - nvi ;
139.1466 +                deg = MIN (deg, nleft - nvi) ;
139.1467 +                ASSERT (IMPLIES (aggressive, deg > 0) && deg >= 0 && deg < n) ;
139.1468 +
139.1469 +                /* --------------------------------------------------------- */
139.1470 +                /* place the supervariable at the head of the degree list */
139.1471 +                /* --------------------------------------------------------- */
139.1472 +
139.1473 +                inext = Head [deg] ;
139.1474 +                ASSERT (inext >= EMPTY && inext < n) ;
139.1475 +                if (inext != EMPTY) Last [inext] = i ;
139.1476 +                Next [i] = inext ;
139.1477 +                Last [i] = EMPTY ;
139.1478 +                Head [deg] = i ;
139.1479 +
139.1480 +                /* --------------------------------------------------------- */
139.1481 +                /* save the new degree, and find the minimum degree */
139.1482 +                /* --------------------------------------------------------- */
139.1483 +
139.1484 +                mindeg = MIN (mindeg, deg) ;
139.1485 +                Degree [i] = deg ;
139.1486 +
139.1487 +                /* --------------------------------------------------------- */
139.1488 +                /* place the supervariable in the element pattern */
139.1489 +                /* --------------------------------------------------------- */
139.1490 +
139.1491 +                Iw [p++] = i ;
139.1492 +
139.1493 +            }
139.1494 +        }
139.1495 +        AMD_DEBUG2 (("restore done\n")) ;
139.1496 +
139.1497 +/* ========================================================================= */
139.1498 +/* FINALIZE THE NEW ELEMENT */
139.1499 +/* ========================================================================= */
139.1500 +
139.1501 +        AMD_DEBUG2 (("ME = "ID" DONE\n", me)) ;
139.1502 +        Nv [me] = nvpiv ;
139.1503 +        /* save the length of the list for the new element me */
139.1504 +        Len [me] = p - pme1 ;
139.1505 +        if (Len [me] == 0)
139.1506 +        {
139.1507 +            /* there is nothing left of the current pivot element */
139.1508 +            /* it is a root of the assembly tree */
139.1509 +            Pe [me] = EMPTY ;
139.1510 +            W [me] = 0 ;
139.1511 +        }
139.1512 +        if (elenme != 0)
139.1513 +        {
139.1514 +            /* element was not constructed in place: deallocate part of */
139.1515 +            /* it since newly nonprincipal variables may have been removed */
139.1516 +            pfree = p ;
139.1517 +        }
139.1518 +
139.1519 +        /* The new element has nvpiv pivots and the size of the contribution
139.1520 +         * block for a multifrontal method is degme-by-degme, not including
139.1521 +         * the "dense" rows/columns.  If the "dense" rows/columns are included,
139.1522 +         * the frontal matrix is no larger than
139.1523 +         * (degme+ndense)-by-(degme+ndense).
139.1524 +         */
139.1525 +
139.1526 +        if (Info != (double *) NULL)
139.1527 +        {
139.1528 +            f = nvpiv ;
139.1529 +            r = degme + ndense ;
139.1530 +            dmax = MAX (dmax, f + r) ;
139.1531 +
139.1532 +            /* number of nonzeros in L (excluding the diagonal) */
139.1533 +            lnzme = f*r + (f-1)*f/2 ;
139.1534 +            lnz += lnzme ;
139.1535 +
139.1536 +            /* number of divide operations for LDL' and for LU */
139.1537 +            ndiv += lnzme ;
139.1538 +
139.1539 +            /* number of multiply-subtract pairs for LU */
139.1540 +            s = f*r*r + r*(f-1)*f + (f-1)*f*(2*f-1)/6 ;
139.1541 +            nms_lu += s ;
139.1542 +
139.1543 +            /* number of multiply-subtract pairs for LDL' */
139.1544 +            nms_ldl += (s + lnzme)/2 ;
139.1545 +        }
139.1546 +
139.1547 +#ifndef NDEBUG
139.1548 +        AMD_DEBUG2 (("finalize done nel "ID" n "ID"\n   ::::\n", nel, n)) ;
139.1549 +        for (pme = Pe [me] ; pme <= Pe [me] + Len [me] - 1 ; pme++)
139.1550 +        {
139.1551 +              AMD_DEBUG3 ((" "ID"", Iw [pme])) ;
139.1552 +        }
139.1553 +        AMD_DEBUG3 (("\n")) ;
139.1554 +#endif
139.1555 +
139.1556 +    }
139.1557 +
139.1558 +/* ========================================================================= */
139.1559 +/* DONE SELECTING PIVOTS */
139.1560 +/* ========================================================================= */
139.1561 +
139.1562 +    if (Info != (double *) NULL)
139.1563 +    {
139.1564 +
139.1565 +        /* count the work to factorize the ndense-by-ndense submatrix */
139.1566 +        f = ndense ;
139.1567 +        dmax = MAX (dmax, (double) ndense) ;
139.1568 +
139.1569 +        /* number of nonzeros in L (excluding the diagonal) */
139.1570 +        lnzme = (f-1)*f/2 ;
139.1571 +        lnz += lnzme ;
139.1572 +
139.1573 +        /* number of divide operations for LDL' and for LU */
139.1574 +        ndiv += lnzme ;
139.1575 +
139.1576 +        /* number of multiply-subtract pairs for LU */
139.1577 +        s = (f-1)*f*(2*f-1)/6 ;
139.1578 +        nms_lu += s ;
139.1579 +
139.1580 +        /* number of multiply-subtract pairs for LDL' */
139.1581 +        nms_ldl += (s + lnzme)/2 ;
139.1582 +
139.1583 +        /* number of nz's in L (excl. diagonal) */
139.1584 +        Info [AMD_LNZ] = lnz ;
139.1585 +
139.1586 +        /* number of divide ops for LU and LDL' */
139.1587 +        Info [AMD_NDIV] = ndiv ;
139.1588 +
139.1589 +        /* number of multiply-subtract pairs for LDL' */
139.1590 +        Info [AMD_NMULTSUBS_LDL] = nms_ldl ;
139.1591 +
139.1592 +        /* number of multiply-subtract pairs for LU */
139.1593 +        Info [AMD_NMULTSUBS_LU] = nms_lu ;
139.1594 +
139.1595 +        /* number of "dense" rows/columns */
139.1596 +        Info [AMD_NDENSE] = ndense ;
139.1597 +
139.1598 +        /* largest front is dmax-by-dmax */
139.1599 +        Info [AMD_DMAX] = dmax ;
139.1600 +
139.1601 +        /* number of garbage collections in AMD */
139.1602 +        Info [AMD_NCMPA] = ncmpa ;
139.1603 +
139.1604 +        /* successful ordering */
139.1605 +        Info [AMD_STATUS] = AMD_OK ;
139.1606 +    }
139.1607 +
139.1608 +/* ========================================================================= */
139.1609 +/* POST-ORDERING */
139.1610 +/* ========================================================================= */
139.1611 +
139.1612 +/* -------------------------------------------------------------------------
139.1613 + * Variables at this point:
139.1614 + *
139.1615 + * Pe: holds the elimination tree.  The parent of j is FLIP (Pe [j]),
139.1616 + *      or EMPTY if j is a root.  The tree holds both elements and
139.1617 + *      non-principal (unordered) variables absorbed into them.
139.1618 + *      Dense variables are non-principal and unordered.
139.1619 + *
139.1620 + * Elen: holds the size of each element, including the diagonal part.
139.1621 + *      FLIP (Elen [e]) > 0 if e is an element.  For unordered
139.1622 + *      variables i, Elen [i] is EMPTY.
139.1623 + *
139.1624 + * Nv: Nv [e] > 0 is the number of pivots represented by the element e.
139.1625 + *      For unordered variables i, Nv [i] is zero.
139.1626 + *
139.1627 + * Contents no longer needed:
139.1628 + *      W, Iw, Len, Degree, Head, Next, Last.
139.1629 + *
139.1630 + * The matrix itself has been destroyed.
139.1631 + *
139.1632 + * n: the size of the matrix.
139.1633 + * No other scalars needed (pfree, iwlen, etc.)
139.1634 + * ------------------------------------------------------------------------- */
139.1635 +
139.1636 +    /* restore Pe */
139.1637 +    for (i = 0 ; i < n ; i++)
139.1638 +    {
139.1639 +        Pe [i] = FLIP (Pe [i]) ;
139.1640 +    }
139.1641 +
139.1642 +    /* restore Elen, for output information, and for postordering */
139.1643 +    for (i = 0 ; i < n ; i++)
139.1644 +    {
139.1645 +        Elen [i] = FLIP (Elen [i]) ;
139.1646 +    }
139.1647 +
139.1648 +/* Now the parent of j is Pe [j], or EMPTY if j is a root.  Elen [e] > 0
139.1649 + * is the size of element e.  Elen [i] is EMPTY for unordered variable i. */
139.1650 +
139.1651 +#ifndef NDEBUG
139.1652 +    AMD_DEBUG2 (("\nTree:\n")) ;
139.1653 +    for (i = 0 ; i < n ; i++)
139.1654 +    {
139.1655 +        AMD_DEBUG2 ((" "ID" parent: "ID"   ", i, Pe [i])) ;
139.1656 +        ASSERT (Pe [i] >= EMPTY && Pe [i] < n) ;
139.1657 +        if (Nv [i] > 0)
139.1658 +        {
139.1659 +            /* this is an element */
139.1660 +            e = i ;
139.1661 +            AMD_DEBUG2 ((" element, size is "ID"\n", Elen [i])) ;
139.1662 +            ASSERT (Elen [e] > 0) ;
139.1663 +        }
139.1664 +        AMD_DEBUG2 (("\n")) ;
139.1665 +    }
139.1666 +    AMD_DEBUG2 (("\nelements:\n")) ;
139.1667 +    for (e = 0 ; e < n ; e++)
139.1668 +    {
139.1669 +        if (Nv [e] > 0)
139.1670 +        {
139.1671 +            AMD_DEBUG3 (("Element e= "ID" size "ID" nv "ID" \n", e,
139.1672 +                Elen [e], Nv [e])) ;
139.1673 +        }
139.1674 +    }
139.1675 +    AMD_DEBUG2 (("\nvariables:\n")) ;
139.1676 +    for (i = 0 ; i < n ; i++)
139.1677 +    {
139.1678 +        Int cnt ;
139.1679 +        if (Nv [i] == 0)
139.1680 +        {
139.1681 +            AMD_DEBUG3 (("i unordered: "ID"\n", i)) ;
139.1682 +            j = Pe [i] ;
139.1683 +            cnt = 0 ;
139.1684 +            AMD_DEBUG3 (("  j: "ID"\n", j)) ;
139.1685 +            if (j == EMPTY)
139.1686 +            {
139.1687 +                AMD_DEBUG3 (("  i is a dense variable\n")) ;
139.1688 +            }
139.1689 +            else
139.1690 +            {
139.1691 +                ASSERT (j >= 0 && j < n) ;
139.1692 +                while (Nv [j] == 0)
139.1693 +                {
139.1694 +                    AMD_DEBUG3 (("      j : "ID"\n", j)) ;
139.1695 +                    j = Pe [j] ;
139.1696 +                    AMD_DEBUG3 (("      j:: "ID"\n", j)) ;
139.1697 +                    cnt++ ;
139.1698 +                    if (cnt > n) break ;
139.1699 +                }
139.1700 +                e = j ;
139.1701 +                AMD_DEBUG3 (("  got to e: "ID"\n", e)) ;
139.1702 +            }
139.1703 +        }
139.1704 +    }
139.1705 +#endif
139.1706 +
139.1707 +/* ========================================================================= */
139.1708 +/* compress the paths of the variables */
139.1709 +/* ========================================================================= */
139.1710 +
139.1711 +    for (i = 0 ; i < n ; i++)
139.1712 +    {
139.1713 +        if (Nv [i] == 0)
139.1714 +        {
139.1715 +
139.1716 +            /* -------------------------------------------------------------
139.1717 +             * i is an un-ordered row.  Traverse the tree from i until
139.1718 +             * reaching an element, e.  The element, e, was the principal
139.1719 +             * supervariable of i and all nodes in the path from i to when e
139.1720 +             * was selected as pivot.
139.1721 +             * ------------------------------------------------------------- */
139.1722 +
139.1723 +            AMD_DEBUG1 (("Path compression, i unordered: "ID"\n", i)) ;
139.1724 +            j = Pe [i] ;
139.1725 +            ASSERT (j >= EMPTY && j < n) ;
139.1726 +            AMD_DEBUG3 (("      j: "ID"\n", j)) ;
139.1727 +            if (j == EMPTY)
139.1728 +            {
139.1729 +                /* Skip a dense variable.  It has no parent. */
139.1730 +                AMD_DEBUG3 (("      i is a dense variable\n")) ;
139.1731 +                continue ;
139.1732 +            }
139.1733 +
139.1734 +            /* while (j is a variable) */
139.1735 +            while (Nv [j] == 0)
139.1736 +            {
139.1737 +                AMD_DEBUG3 (("          j : "ID"\n", j)) ;
139.1738 +                j = Pe [j] ;
139.1739 +                AMD_DEBUG3 (("          j:: "ID"\n", j)) ;
139.1740 +                ASSERT (j >= 0 && j < n) ;
139.1741 +            }
139.1742 +            /* got to an element e */
139.1743 +            e = j ;
139.1744 +            AMD_DEBUG3 (("got to e: "ID"\n", e)) ;
139.1745 +
139.1746 +            /* -------------------------------------------------------------
139.1747 +             * traverse the path again from i to e, and compress the path
139.1748 +             * (all nodes point to e).  Path compression allows this code to
139.1749 +             * compute in O(n) time.
139.1750 +             * ------------------------------------------------------------- */
139.1751 +
139.1752 +            j = i ;
139.1753 +            /* while (j is a variable) */
139.1754 +            while (Nv [j] == 0)
139.1755 +            {
139.1756 +                jnext = Pe [j] ;
139.1757 +                AMD_DEBUG3 (("j "ID" jnext "ID"\n", j, jnext)) ;
139.1758 +                Pe [j] = e ;
139.1759 +                j = jnext ;
139.1760 +                ASSERT (j >= 0 && j < n) ;
139.1761 +            }
139.1762 +        }
139.1763 +    }
139.1764 +
139.1765 +/* ========================================================================= */
139.1766 +/* postorder the assembly tree */
139.1767 +/* ========================================================================= */
139.1768 +
139.1769 +    AMD_postorder (n, Pe, Nv, Elen,
139.1770 +        W,                      /* output order */
139.1771 +        Head, Next, Last) ;     /* workspace */
139.1772 +
139.1773 +/* ========================================================================= */
139.1774 +/* compute output permutation and inverse permutation */
139.1775 +/* ========================================================================= */
139.1776 +
139.1777 +    /* W [e] = k means that element e is the kth element in the new
139.1778 +     * order.  e is in the range 0 to n-1, and k is in the range 0 to
139.1779 +     * the number of elements.  Use Head for inverse order. */
139.1780 +
139.1781 +    for (k = 0 ; k < n ; k++)
139.1782 +    {
139.1783 +        Head [k] = EMPTY ;
139.1784 +        Next [k] = EMPTY ;
139.1785 +    }
139.1786 +    for (e = 0 ; e < n ; e++)
139.1787 +    {
139.1788 +        k = W [e] ;
139.1789 +        ASSERT ((k == EMPTY) == (Nv [e] == 0)) ;
139.1790 +        if (k != EMPTY)
139.1791 +        {
139.1792 +            ASSERT (k >= 0 && k < n) ;
139.1793 +            Head [k] = e ;
139.1794 +        }
139.1795 +    }
139.1796 +
139.1797 +    /* construct output inverse permutation in Next,
139.1798 +     * and permutation in Last */
139.1799 +    nel = 0 ;
139.1800 +    for (k = 0 ; k < n ; k++)
139.1801 +    {
139.1802 +        e = Head [k] ;
139.1803 +        if (e == EMPTY) break ;
139.1804 +        ASSERT (e >= 0 && e < n && Nv [e] > 0) ;
139.1805 +        Next [e] = nel ;
139.1806 +        nel += Nv [e] ;
139.1807 +    }
139.1808 +    ASSERT (nel == n - ndense) ;
139.1809 +
139.1810 +    /* order non-principal variables (dense, & those merged into supervar's) */
139.1811 +    for (i = 0 ; i < n ; i++)
139.1812 +    {
139.1813 +        if (Nv [i] == 0)
139.1814 +        {
139.1815 +            e = Pe [i] ;
139.1816 +            ASSERT (e >= EMPTY && e < n) ;
139.1817 +            if (e != EMPTY)
139.1818 +            {
139.1819 +                /* This is an unordered variable that was merged
139.1820 +                 * into element e via supernode detection or mass
139.1821 +                 * elimination of i when e became the pivot element.
139.1822 +                 * Place i in order just before e. */
139.1823 +                ASSERT (Next [i] == EMPTY && Nv [e] > 0) ;
139.1824 +                Next [i] = Next [e] ;
139.1825 +                Next [e]++ ;
139.1826 +            }
139.1827 +            else
139.1828 +            {
139.1829 +                /* This is a dense unordered variable, with no parent.
139.1830 +                 * Place it last in the output order. */
139.1831 +                Next [i] = nel++ ;
139.1832 +            }
139.1833 +        }
139.1834 +    }
139.1835 +    ASSERT (nel == n) ;
139.1836 +
139.1837 +    AMD_DEBUG2 (("\n\nPerm:\n")) ;
139.1838 +    for (i = 0 ; i < n ; i++)
139.1839 +    {
139.1840 +        k = Next [i] ;
139.1841 +        ASSERT (k >= 0 && k < n) ;
139.1842 +        Last [k] = i ;
139.1843 +        AMD_DEBUG2 (("   perm ["ID"] = "ID"\n", k, i)) ;
139.1844 +    }
139.1845 +}
   140.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   140.2 +++ b/src/amd/amd_aat.c	Mon Dec 06 13:09:21 2010 +0100
   140.3 @@ -0,0 +1,185 @@
   140.4 +/* ========================================================================= */
   140.5 +/* === AMD_aat ============================================================= */
   140.6 +/* ========================================================================= */
   140.7 +
   140.8 +/* ------------------------------------------------------------------------- */
   140.9 +/* AMD, Copyright (c) Timothy A. Davis,                                      */
  140.10 +/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
  140.11 +/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
  140.12 +/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
  140.13 +/* ------------------------------------------------------------------------- */
  140.14 +
  140.15 +/* AMD_aat:  compute the symmetry of the pattern of A, and count the number of
  140.16 + * nonzeros each column of A+A' (excluding the diagonal).  Assumes the input
  140.17 + * matrix has no errors, with sorted columns and no duplicates
  140.18 + * (AMD_valid (n, n, Ap, Ai) must be AMD_OK, but this condition is not
  140.19 + * checked).
  140.20 + */
  140.21 +
  140.22 +#include "amd_internal.h"
  140.23 +
  140.24 +GLOBAL size_t AMD_aat   /* returns nz in A+A' */
  140.25 +(
  140.26 +    Int n,
  140.27 +    const Int Ap [ ],
  140.28 +    const Int Ai [ ],
  140.29 +    Int Len [ ],        /* Len [j]: length of column j of A+A', excl diagonal*/
  140.30 +    Int Tp [ ],         /* workspace of size n */
  140.31 +    double Info [ ]
  140.32 +)
  140.33 +{
  140.34 +    Int p1, p2, p, i, j, pj, pj2, k, nzdiag, nzboth, nz ;
  140.35 +    double sym ;
  140.36 +    size_t nzaat ;
  140.37 +
  140.38 +#ifndef NDEBUG
  140.39 +    AMD_debug_init ("AMD AAT") ;
  140.40 +    for (k = 0 ; k < n ; k++) Tp [k] = EMPTY ;
  140.41 +    ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ;
  140.42 +#endif
  140.43 +
  140.44 +    if (Info != (double *) NULL)
  140.45 +    {
  140.46 +        /* clear the Info array, if it exists */
  140.47 +        for (i = 0 ; i < AMD_INFO ; i++)
  140.48 +        {
  140.49 +            Info [i] = EMPTY ;
  140.50 +        }
  140.51 +        Info [AMD_STATUS] = AMD_OK ;
  140.52 +    }
  140.53 +
  140.54 +    for (k = 0 ; k < n ; k++)
  140.55 +    {
  140.56 +        Len [k] = 0 ;
  140.57 +    }
  140.58 +
  140.59 +    nzdiag = 0 ;
  140.60 +    nzboth = 0 ;
  140.61 +    nz = Ap [n] ;
  140.62 +
  140.63 +    for (k = 0 ; k < n ; k++)
  140.64 +    {
  140.65 +        p1 = Ap [k] ;
  140.66 +        p2 = Ap [k+1] ;
  140.67 +        AMD_DEBUG2 (("\nAAT Column: "ID" p1: "ID" p2: "ID"\n", k, p1, p2)) ;
  140.68 +
  140.69 +        /* construct A+A' */
  140.70 +        for (p = p1 ; p < p2 ; )
  140.71 +        {
  140.72 +            /* scan the upper triangular part of A */
  140.73 +            j = Ai [p] ;
  140.74 +            if (j < k)
  140.75 +            {
  140.76 +                /* entry A (j,k) is in the strictly upper triangular part,
  140.77 +                 * add both A (j,k) and A (k,j) to the matrix A+A' */
  140.78 +                Len [j]++ ;
  140.79 +                Len [k]++ ;
  140.80 +                AMD_DEBUG3 (("    upper ("ID","ID") ("ID","ID")\n", j,k, k,j));
  140.81 +                p++ ;
  140.82 +            }
  140.83 +            else if (j == k)
  140.84 +            {
  140.85 +                /* skip the diagonal */
  140.86 +                p++ ;
  140.87 +                nzdiag++ ;
  140.88 +                break ;
  140.89 +            }
  140.90 +            else /* j > k */
  140.91 +            {
  140.92 +                /* first entry below the diagonal */
  140.93 +                break ;
  140.94 +            }
  140.95 +            /* scan lower triangular part of A, in column j until reaching
  140.96 +             * row k.  Start where last scan left off. */
  140.97 +            ASSERT (Tp [j] != EMPTY) ;
  140.98 +            ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ;
  140.99 +            pj2 = Ap [j+1] ;
 140.100 +            for (pj = Tp [j] ; pj < pj2 ; )
 140.101 +            {
 140.102 +                i = Ai [pj] ;
 140.103 +                if (i < k)
 140.104 +                {
 140.105 +                    /* A (i,j) is only in the lower part, not in upper.
 140.106 +                     * add both A (i,j) and A (j,i) to the matrix A+A' */
 140.107 +                    Len [i]++ ;
 140.108 +                    Len [j]++ ;
 140.109 +                    AMD_DEBUG3 (("    lower ("ID","ID") ("ID","ID")\n",
 140.110 +                        i,j, j,i)) ;
 140.111 +                    pj++ ;
 140.112 +                }
 140.113 +                else if (i == k)
 140.114 +                {
 140.115 +                    /* entry A (k,j) in lower part and A (j,k) in upper */
 140.116 +                    pj++ ;
 140.117 +                    nzboth++ ;
 140.118 +                    break ;
 140.119 +                }
 140.120 +                else /* i > k */
 140.121 +                {
 140.122 +                    /* consider this entry later, when k advances to i */
 140.123 +                    break ;
 140.124 +                }
 140.125 +            }
 140.126 +            Tp [j] = pj ;
 140.127 +        }
 140.128 +        /* Tp [k] points to the entry just below the diagonal in column k */
 140.129 +        Tp [k] = p ;
 140.130 +    }
 140.131 +
 140.132 +    /* clean up, for remaining mismatched entries */
 140.133 +    for (j = 0 ; j < n ; j++)
 140.134 +    {
 140.135 +        for (pj = Tp [j] ; pj < Ap [j+1] ; pj++)
 140.136 +        {
 140.137 +            i = Ai [pj] ;
 140.138 +            /* A (i,j) is only in the lower part, not in upper.
 140.139 +             * add both A (i,j) and A (j,i) to the matrix A+A' */
 140.140 +            Len [i]++ ;
 140.141 +            Len [j]++ ;
 140.142 +            AMD_DEBUG3 (("    lower cleanup ("ID","ID") ("ID","ID")\n",
 140.143 +                i,j, j,i)) ;
 140.144 +        }
 140.145 +    }
 140.146 +
 140.147 +    /* --------------------------------------------------------------------- */
 140.148 +    /* compute the symmetry of the nonzero pattern of A */
 140.149 +    /* --------------------------------------------------------------------- */
 140.150 +
 140.151 +    /* Given a matrix A, the symmetry of A is:
 140.152 +     *  B = tril (spones (A), -1) + triu (spones (A), 1) ;
 140.153 +     *  sym = nnz (B & B') / nnz (B) ;
 140.154 +     *  or 1 if nnz (B) is zero.
 140.155 +     */
 140.156 +
 140.157 +    if (nz == nzdiag)
 140.158 +    {
 140.159 +        sym = 1 ;
 140.160 +    }
 140.161 +    else
 140.162 +    {
 140.163 +        sym = (2 * (double) nzboth) / ((double) (nz - nzdiag)) ;
 140.164 +    }
 140.165 +
 140.166 +    nzaat = 0 ;
 140.167 +    for (k = 0 ; k < n ; k++)
 140.168 +    {
 140.169 +        nzaat += Len [k] ;
 140.170 +    }
 140.171 +
 140.172 +    AMD_DEBUG1 (("AMD nz in A+A', excluding diagonal (nzaat) = %g\n",
 140.173 +        (double) nzaat)) ;
 140.174 +    AMD_DEBUG1 (("   nzboth: "ID" nz: "ID" nzdiag: "ID" symmetry: %g\n",
 140.175 +                nzboth, nz, nzdiag, sym)) ;
 140.176 +
 140.177 +    if (Info != (double *) NULL)
 140.178 +    {
 140.179 +        Info [AMD_STATUS] = AMD_OK ;
 140.180 +        Info [AMD_N] = n ;
 140.181 +        Info [AMD_NZ] = nz ;
 140.182 +        Info [AMD_SYMMETRY] = sym ;         /* symmetry of pattern of A */
 140.183 +        Info [AMD_NZDIAG] = nzdiag ;        /* nonzeros on diagonal of A */
 140.184 +        Info [AMD_NZ_A_PLUS_AT] = nzaat ;   /* nonzeros in A+A' */
 140.185 +    }
 140.186 +
 140.187 +    return (nzaat) ;
 140.188 +}
   141.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   141.2 +++ b/src/amd/amd_control.c	Mon Dec 06 13:09:21 2010 +0100
   141.3 @@ -0,0 +1,64 @@
   141.4 +/* ========================================================================= */
   141.5 +/* === AMD_control ========================================================= */
   141.6 +/* ========================================================================= */
   141.7 +
   141.8 +/* ------------------------------------------------------------------------- */
   141.9 +/* AMD, Copyright (c) Timothy A. Davis,                                      */
  141.10 +/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
  141.11 +/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
  141.12 +/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
  141.13 +/* ------------------------------------------------------------------------- */
  141.14 +
  141.15 +/* User-callable.  Prints the control parameters for AMD.  See amd.h
  141.16 + * for details.  If the Control array is not present, the defaults are
  141.17 + * printed instead.
  141.18 + */
  141.19 +
  141.20 +#include "amd_internal.h"
  141.21 +
  141.22 +GLOBAL void AMD_control
  141.23 +(
  141.24 +    double Control [ ]
  141.25 +)
  141.26 +{
  141.27 +    double alpha ;
  141.28 +    Int aggressive ;
  141.29 +
  141.30 +    if (Control != (double *) NULL)
  141.31 +    {
  141.32 +        alpha = Control [AMD_DENSE] ;
  141.33 +        aggressive = Control [AMD_AGGRESSIVE] != 0 ;
  141.34 +    }
  141.35 +    else
  141.36 +    {
  141.37 +        alpha = AMD_DEFAULT_DENSE ;
  141.38 +        aggressive = AMD_DEFAULT_AGGRESSIVE ;
  141.39 +    }
  141.40 +
  141.41 +    PRINTF (("\nAMD version %d.%d.%d, %s: approximate minimum degree ordering\n"
  141.42 +        "    dense row parameter: %g\n", AMD_MAIN_VERSION, AMD_SUB_VERSION,
  141.43 +        AMD_SUBSUB_VERSION, AMD_DATE, alpha)) ;
  141.44 +
  141.45 +    if (alpha < 0)
  141.46 +    {
  141.47 +        PRINTF (("    no rows treated as dense\n")) ;
  141.48 +    }
  141.49 +    else
  141.50 +    {
  141.51 +        PRINTF ((
  141.52 +        "    (rows with more than max (%g * sqrt (n), 16) entries are\n"
  141.53 +        "    considered \"dense\", and placed last in output permutation)\n",
  141.54 +        alpha)) ;
  141.55 +    }
  141.56 +
  141.57 +    if (aggressive)
  141.58 +    {
  141.59 +        PRINTF (("    aggressive absorption:  yes\n")) ;
  141.60 +    }
  141.61 +    else
  141.62 +    {
  141.63 +        PRINTF (("    aggressive absorption:  no\n")) ;
  141.64 +    }
  141.65 +
  141.66 +    PRINTF (("    size of AMD integer: %d\n\n", sizeof (Int))) ;
  141.67 +}
   142.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   142.2 +++ b/src/amd/amd_defaults.c	Mon Dec 06 13:09:21 2010 +0100
   142.3 @@ -0,0 +1,38 @@
   142.4 +/* ========================================================================= */
   142.5 +/* === AMD_defaults ======================================================== */
   142.6 +/* ========================================================================= */
   142.7 +
   142.8 +/* ------------------------------------------------------------------------- */
   142.9 +/* AMD, Copyright (c) Timothy A. Davis,                                      */
  142.10 +/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
  142.11 +/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
  142.12 +/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
  142.13 +/* ------------------------------------------------------------------------- */
  142.14 +
  142.15 +/* User-callable.  Sets default control parameters for AMD.  See amd.h
  142.16 + * for details.
  142.17 + */
  142.18 +
  142.19 +#include "amd_internal.h"
  142.20 +
  142.21 +/* ========================================================================= */
  142.22 +/* === AMD defaults ======================================================== */
  142.23 +/* ========================================================================= */
  142.24 +
  142.25 +GLOBAL void AMD_defaults
  142.26 +(
  142.27 +    double Control [ ]
  142.28 +)
  142.29 +{
  142.30 +    Int i ;
  142.31 +
  142.32 +    if (Control != (double *) NULL)
  142.33 +    {
  142.34 +        for (i = 0 ; i < AMD_CONTROL ; i++)
  142.35 +        {
  142.36 +            Control [i] = 0 ;
  142.37 +        }
  142.38 +        Control [AMD_DENSE] = AMD_DEFAULT_DENSE ;
  142.39 +        Control [AMD_AGGRESSIVE] = AMD_DEFAULT_AGGRESSIVE ;
  142.40 +    }
  142.41 +}
   143.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   143.2 +++ b/src/amd/amd_dump.c	Mon Dec 06 13:09:21 2010 +0100
   143.3 @@ -0,0 +1,180 @@
   143.4 +/* ========================================================================= */
   143.5 +/* === AMD_dump ============================================================ */
   143.6 +/* ========================================================================= */
   143.7 +
   143.8 +/* ------------------------------------------------------------------------- */
   143.9 +/* AMD, Copyright (c) Timothy A. Davis,                                      */
  143.10 +/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
  143.11 +/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
  143.12 +/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
  143.13 +/* ------------------------------------------------------------------------- */
  143.14 +
  143.15 +/* Debugging routines for AMD.  Not used if NDEBUG is not defined at compile-
  143.16 + * time (the default).  See comments in amd_internal.h on how to enable
  143.17 + * debugging.  Not user-callable.
  143.18 + */
  143.19 +
  143.20 +#include "amd_internal.h"
  143.21 +
  143.22 +#ifndef NDEBUG
  143.23 +
  143.24 +/* This global variable is present only when debugging */
  143.25 +GLOBAL Int AMD_debug = -999 ;           /* default is no debug printing */
  143.26 +
  143.27 +/* ========================================================================= */
  143.28 +/* === AMD_debug_init ====================================================== */
  143.29 +/* ========================================================================= */
  143.30 +
  143.31 +/* Sets the debug print level, by reading the file debug.amd (if it exists) */
  143.32 +
  143.33 +GLOBAL void AMD_debug_init ( char *s )
  143.34 +{
  143.35 +    FILE *f ;
  143.36 +    f = fopen ("debug.amd", "r") ;
  143.37 +    if (f == (FILE *) NULL)
  143.38 +    {
  143.39 +        AMD_debug = -999 ;
  143.40 +    }
  143.41 +    else
  143.42 +    {
  143.43 +        fscanf (f, ID, &AMD_debug) ;
  143.44 +        fclose (f) ;
  143.45 +    }
  143.46 +    if (AMD_debug >= 0)
  143.47 +    {
  143.48 +        printf ("%s: AMD_debug_init, D= "ID"\n", s, AMD_debug) ;
  143.49 +    }
  143.50 +}
  143.51 +
  143.52 +/* ========================================================================= */
  143.53 +/* === AMD_dump ============================================================ */
  143.54 +/* ========================================================================= */
  143.55 +
  143.56 +/* Dump AMD's data structure, except for the hash buckets.  This routine
  143.57 + * cannot be called when the hash buckets are non-empty.
  143.58 + */
  143.59 +
  143.60 +GLOBAL void AMD_dump (
  143.61 +    Int n,          /* A is n-by-n */
  143.62 +    Int Pe [ ],     /* pe [0..n-1]: index in iw of start of row i */
  143.63 +    Int Iw [ ],     /* workspace of size iwlen, iwlen [0..pfree-1]
  143.64 +                     * holds the matrix on input */
  143.65 +    Int Len [ ],    /* len [0..n-1]: length for row i */
  143.66 +    Int iwlen,      /* length of iw */
  143.67 +    Int pfree,      /* iw [pfree ... iwlen-1] is empty on input */
  143.68 +    Int Nv [ ],     /* nv [0..n-1] */
  143.69 +    Int Next [ ],   /* next [0..n-1] */
  143.70 +    Int Last [ ],   /* last [0..n-1] */
  143.71 +    Int Head [ ],   /* head [0..n-1] */
  143.72 +    Int Elen [ ],   /* size n */
  143.73 +    Int Degree [ ], /* size n */
  143.74 +    Int W [ ],      /* size n */
  143.75 +    Int nel
  143.76 +)
  143.77 +{
  143.78 +    Int i, pe, elen, nv, len, e, p, k, j, deg, w, cnt, ilast ;
  143.79 +
  143.80 +    if (AMD_debug < 0) return ;
  143.81 +    ASSERT (pfree <= iwlen) ;
  143.82 +    AMD_DEBUG3 (("\nAMD dump, pfree: "ID"\n", pfree)) ;
  143.83 +    for (i = 0 ; i < n ; i++)
  143.84 +    {
  143.85 +        pe = Pe [i] ;
  143.86 +        elen = Elen [i] ;
  143.87 +        nv = Nv [i] ;
  143.88 +        len = Len [i] ;
  143.89 +        w = W [i] ;
  143.90 +
  143.91 +        if (elen >= EMPTY)
  143.92 +        {
  143.93 +            if (nv == 0)
  143.94 +            {
  143.95 +                AMD_DEBUG3 (("\nI "ID": nonprincipal:    ", i)) ;
  143.96 +                ASSERT (elen == EMPTY) ;
  143.97 +                if (pe == EMPTY)
  143.98 +                {
  143.99 +                    AMD_DEBUG3 ((" dense node\n")) ;
 143.100 +                    ASSERT (w == 1) ;
 143.101 +                }
 143.102 +                else
 143.103 +                {
 143.104 +                    ASSERT (pe < EMPTY) ;
 143.105 +                    AMD_DEBUG3 ((" i "ID" -> parent "ID"\n", i, FLIP (Pe[i])));
 143.106 +                }
 143.107 +            }
 143.108 +            else
 143.109 +            {
 143.110 +                AMD_DEBUG3 (("\nI "ID": active principal supervariable:\n",i));
 143.111 +                AMD_DEBUG3 (("   nv(i): "ID"  Flag: %d\n", nv, (nv < 0))) ;
 143.112 +                ASSERT (elen >= 0) ;
 143.113 +                ASSERT (nv > 0 && pe >= 0) ;
 143.114 +                p = pe ;
 143.115 +                AMD_DEBUG3 (("   e/s: ")) ;
 143.116 +                if (elen == 0) AMD_DEBUG3 ((" : ")) ;
 143.117 +                ASSERT (pe + len <= pfree) ;
 143.118 +                for (k = 0 ; k < len ; k++)
 143.119 +                {
 143.120 +                    j = Iw [p] ;
 143.121 +                    AMD_DEBUG3 (("  "ID"", j)) ;
 143.122 +                    ASSERT (j >= 0 && j < n) ;
 143.123 +                    if (k == elen-1) AMD_DEBUG3 ((" : ")) ;
 143.124 +                    p++ ;
 143.125 +                }
 143.126 +                AMD_DEBUG3 (("\n")) ;
 143.127 +            }
 143.128 +        }
 143.129 +        else
 143.130 +        {
 143.131 +            e = i ;
 143.132 +            if (w == 0)
 143.133 +            {
 143.134 +                AMD_DEBUG3 (("\nE "ID": absorbed element: w "ID"\n", e, w)) ;
 143.135 +                ASSERT (nv > 0 && pe < 0) ;
 143.136 +                AMD_DEBUG3 ((" e "ID" -> parent "ID"\n", e, FLIP (Pe [e]))) ;
 143.137 +            }
 143.138 +            else
 143.139 +            {
 143.140 +                AMD_DEBUG3 (("\nE "ID": unabsorbed element: w "ID"\n", e, w)) ;
 143.141 +                ASSERT (nv > 0 && pe >= 0) ;
 143.142 +                p = pe ;
 143.143 +                AMD_DEBUG3 ((" : ")) ;
 143.144 +                ASSERT (pe + len <= pfree) ;
 143.145 +                for (k = 0 ; k < len ; k++)
 143.146 +                {
 143.147 +                    j = Iw [p] ;
 143.148 +                    AMD_DEBUG3 (("  "ID"", j)) ;
 143.149 +                    ASSERT (j >= 0 && j < n) ;
 143.150 +                    p++ ;
 143.151 +                }
 143.152 +                AMD_DEBUG3 (("\n")) ;
 143.153 +            }
 143.154 +        }
 143.155 +    }
 143.156 +
 143.157 +    /* this routine cannot be called when the hash buckets are non-empty */
 143.158 +    AMD_DEBUG3 (("\nDegree lists:\n")) ;
 143.159 +    if (nel >= 0)
 143.160 +    {
 143.161 +        cnt = 0 ;
 143.162 +        for (deg = 0 ; deg < n ; deg++)
 143.163 +        {
 143.164 +            if (Head [deg] == EMPTY) continue ;
 143.165 +            ilast = EMPTY ;
 143.166 +            AMD_DEBUG3 ((ID": \n", deg)) ;
 143.167 +            for (i = Head [deg] ; i != EMPTY ; i = Next [i])
 143.168 +            {
 143.169 +                AMD_DEBUG3 (("   "ID" : next "ID" last "ID" deg "ID"\n",
 143.170 +                    i, Next [i], Last [i], Degree [i])) ;
 143.171 +                ASSERT (i >= 0 && i < n && ilast == Last [i] &&
 143.172 +                    deg == Degree [i]) ;
 143.173 +                cnt += Nv [i] ;
 143.174 +                ilast = i ;
 143.175 +            }
 143.176 +            AMD_DEBUG3 (("\n")) ;
 143.177 +        }
 143.178 +        ASSERT (cnt == n - nel) ;
 143.179 +    }
 143.180 +
 143.181 +}
 143.182 +
 143.183 +#endif
   144.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   144.2 +++ b/src/amd/amd_info.c	Mon Dec 06 13:09:21 2010 +0100
   144.3 @@ -0,0 +1,120 @@
   144.4 +/* ========================================================================= */
   144.5 +/* === AMD_info ============================================================ */
   144.6 +/* ========================================================================= */
   144.7 +
   144.8 +/* ------------------------------------------------------------------------- */
   144.9 +/* AMD, Copyright (c) Timothy A. Davis,                                      */
  144.10 +/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
  144.11 +/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
  144.12 +/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
  144.13 +/* ------------------------------------------------------------------------- */
  144.14 +
  144.15 +/* User-callable.  Prints the output statistics for AMD.  See amd.h
  144.16 + * for details.  If the Info array is not present, nothing is printed.
  144.17 + */
  144.18 +
  144.19 +#include "amd_internal.h"
  144.20 +
  144.21 +#define PRI(format,x) { if (x >= 0) { PRINTF ((format, x)) ; }}
  144.22 +
  144.23 +GLOBAL void AMD_info
  144.24 +(
  144.25 +    double Info [ ]
  144.26 +)
  144.27 +{
  144.28 +    double n, ndiv, nmultsubs_ldl, nmultsubs_lu, lnz, lnzd ;
  144.29 +
  144.30 +    PRINTF (("\nAMD version %d.%d.%d, %s, results:\n",
  144.31 +        AMD_MAIN_VERSION, AMD_SUB_VERSION, AMD_SUBSUB_VERSION, AMD_DATE)) ;
  144.32 +
  144.33 +    if (!Info)
  144.34 +    {
  144.35 +        return ;
  144.36 +    }
  144.37 +
  144.38 +    n = Info [AMD_N] ;
  144.39 +    ndiv = Info [AMD_NDIV] ;
  144.40 +    nmultsubs_ldl = Info [AMD_NMULTSUBS_LDL] ;
  144.41 +    nmultsubs_lu = Info [AMD_NMULTSUBS_LU] ;
  144.42 +    lnz = Info [AMD_LNZ] ;
  144.43 +    lnzd = (n >= 0 && lnz >= 0) ? (n + lnz) : (-1) ;
  144.44 +
  144.45 +    /* AMD return status */
  144.46 +    PRINTF (("    status: ")) ;
  144.47 +    if (Info [AMD_STATUS] == AMD_OK)
  144.48 +    {
  144.49 +        PRINTF (("OK\n")) ;
  144.50 +    }
  144.51 +    else if (Info [AMD_STATUS] == AMD_OUT_OF_MEMORY)
  144.52 +    {
  144.53 +        PRINTF (("out of memory\n")) ;
  144.54 +    }
  144.55 +    else if (Info [AMD_STATUS] == AMD_INVALID)
  144.56 +    {
  144.57 +        PRINTF (("invalid matrix\n")) ;
  144.58 +    }
  144.59 +    else if (Info [AMD_STATUS] == AMD_OK_BUT_JUMBLED)
  144.60 +    {
  144.61 +        PRINTF (("OK, but jumbled\n")) ;
  144.62 +    }
  144.63 +    else
  144.64 +    {
  144.65 +        PRINTF (("unknown\n")) ;
  144.66 +    }
  144.67 +
  144.68 +    /* statistics about the input matrix */
  144.69 +    PRI ("    n, dimension of A:                                  %.20g\n", n);
  144.70 +    PRI ("    nz, number of nonzeros in A:                        %.20g\n",
  144.71 +        Info [AMD_NZ]) ;
  144.72 +    PRI ("    symmetry of A:                                      %.4f\n",
  144.73 +        Info [AMD_SYMMETRY]) ;
  144.74 +    PRI ("    number of nonzeros on diagonal:                     %.20g\n",
  144.75 +        Info [AMD_NZDIAG]) ;
  144.76 +    PRI ("    nonzeros in pattern of A+A' (excl. diagonal):       %.20g\n",
  144.77 +        Info [AMD_NZ_A_PLUS_AT]) ;
  144.78 +    PRI ("    # dense rows/columns of A+A':                       %.20g\n",
  144.79 +        Info [AMD_NDENSE]) ;
  144.80 +
  144.81 +    /* statistics about AMD's behavior  */
  144.82 +    PRI ("    memory used, in bytes:                              %.20g\n",
  144.83 +        Info [AMD_MEMORY]) ;
  144.84 +    PRI ("    # of memory compactions:                            %.20g\n",
  144.85 +        Info [AMD_NCMPA]) ;
  144.86 +
  144.87 +    /* statistics about the ordering quality */
  144.88 +    PRINTF (("\n"
  144.89 +        "    The following approximate statistics are for a subsequent\n"
  144.90 +        "    factorization of A(P,P) + A(P,P)'.  They are slight upper\n"
  144.91 +        "    bounds if there are no dense rows/columns in A+A', and become\n"
  144.92 +        "    looser if dense rows/columns exist.\n\n")) ;
  144.93 +
  144.94 +    PRI ("    nonzeros in L (excluding diagonal):                 %.20g\n",
  144.95 +        lnz) ;
  144.96 +    PRI ("    nonzeros in L (including diagonal):                 %.20g\n",
  144.97 +        lnzd) ;
  144.98 +    PRI ("    # divide operations for LDL' or LU:                 %.20g\n",
  144.99 +        ndiv) ;
 144.100 +    PRI ("    # multiply-subtract operations for LDL':            %.20g\n",
 144.101 +        nmultsubs_ldl) ;
 144.102 +    PRI ("    # multiply-subtract operations for LU:              %.20g\n",
 144.103 +        nmultsubs_lu) ;
 144.104 +    PRI ("    max nz. in any column of L (incl. diagonal):        %.20g\n",
 144.105 +        Info [AMD_DMAX]) ;
 144.106 +
 144.107 +    /* total flop counts for various factorizations */
 144.108 +
 144.109 +    if (n >= 0 && ndiv >= 0 && nmultsubs_ldl >= 0 && nmultsubs_lu >= 0)
 144.110 +    {
 144.111 +        PRINTF (("\n"
 144.112 +        "    chol flop count for real A, sqrt counted as 1 flop: %.20g\n"
 144.113 +        "    LDL' flop count for real A:                         %.20g\n"
 144.114 +        "    LDL' flop count for complex A:                      %.20g\n"
 144.115 +        "    LU flop count for real A (with no pivoting):        %.20g\n"
 144.116 +        "    LU flop count for complex A (with no pivoting):     %.20g\n\n",
 144.117 +        n + ndiv + 2*nmultsubs_ldl,
 144.118 +            ndiv + 2*nmultsubs_ldl,
 144.119 +          9*ndiv + 8*nmultsubs_ldl,
 144.120 +            ndiv + 2*nmultsubs_lu,
 144.121 +          9*ndiv + 8*nmultsubs_lu)) ;
 144.122 +    }
 144.123 +}
   145.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   145.2 +++ b/src/amd/amd_internal.h	Mon Dec 06 13:09:21 2010 +0100
   145.3 @@ -0,0 +1,113 @@
   145.4 +/* amd_internal.h */
   145.5 +
   145.6 +/* Written by Andrew Makhorin <mao@gnu.org>. */
   145.7 +
   145.8 +#ifndef AMD_INTERNAL_H
   145.9 +#define AMD_INTERNAL_H
  145.10 +
  145.11 +/* AMD will be exceedingly slow when running in debug mode. */
  145.12 +#if 1
  145.13 +#define NDEBUG
  145.14 +#endif
  145.15 +
  145.16 +#include "amd.h"
  145.17 +#define _GLPSTD_STDIO
  145.18 +#include "glpenv.h"
  145.19 +
  145.20 +#define Int int
  145.21 +#define ID "%d"
  145.22 +#define Int_MAX INT_MAX
  145.23 +
  145.24 +#define SIZE_T_MAX ((size_t)(-1))
  145.25 +
  145.26 +#define EMPTY (-1)
  145.27 +#define FLIP(i) (-(i)-2)
  145.28 +#define UNFLIP(i) ((i < EMPTY) ? FLIP (i) : (i))
  145.29 +
  145.30 +#define MAX(a,b) (((a) > (b)) ? (a) : (b))
  145.31 +#define MIN(a,b) (((a) < (b)) ? (a) : (b))
  145.32 +
  145.33 +#define IMPLIES(p, q) (!(p) || (q))
  145.34 +
  145.35 +#define GLOBAL
  145.36 +
  145.37 +#define AMD_order amd_order
  145.38 +#define AMD_defaults amd_defaults
  145.39 +#define AMD_control amd_control
  145.40 +#define AMD_info amd_info
  145.41 +#define AMD_1 amd_1
  145.42 +#define AMD_2 amd_2
  145.43 +#define AMD_valid amd_valid
  145.44 +#define AMD_aat amd_aat
  145.45 +#define AMD_postorder amd_postorder
  145.46 +#define AMD_post_tree amd_post_tree
  145.47 +#define AMD_dump amd_dump
  145.48 +#define AMD_debug amd_debug
  145.49 +#define AMD_debug_init amd_debug_init
  145.50 +#define AMD_preprocess amd_preprocess
  145.51 +
  145.52 +#define amd_malloc xmalloc
  145.53 +#if 0 /* 24/V-2009 */
  145.54 +#define amd_free xfree
  145.55 +#else
  145.56 +#define amd_free(ptr) { if ((ptr) != NULL) xfree(ptr); } 
  145.57 +#endif
  145.58 +#define amd_printf xprintf
  145.59 +
  145.60 +#define PRINTF(params) { amd_printf params; }
  145.61 +
  145.62 +#ifndef NDEBUG
  145.63 +#define ASSERT(expr) xassert(expr)
  145.64 +#define AMD_DEBUG0(params) { PRINTF(params); }
  145.65 +#define AMD_DEBUG1(params) { if (AMD_debug >= 1) PRINTF(params); }
  145.66 +#define AMD_DEBUG2(params) { if (AMD_debug >= 2) PRINTF(params); }
  145.67 +#define AMD_DEBUG3(params) { if (AMD_debug >= 3) PRINTF(params); }
  145.68 +#define AMD_DEBUG4(params) { if (AMD_debug >= 4) PRINTF(params); }
  145.69 +#else
  145.70 +#define ASSERT(expression)
  145.71 +#define AMD_DEBUG0(params)
  145.72 +#define AMD_DEBUG1(params)
  145.73 +#define AMD_DEBUG2(params)
  145.74 +#define AMD_DEBUG3(params)
  145.75 +#define AMD_DEBUG4(params)
  145.76 +#endif
  145.77 +
  145.78 +#define amd_aat _glp_amd_aat
  145.79 +size_t AMD_aat(Int n, const Int Ap[], const Int Ai[], Int Len[],
  145.80 +      Int Tp[], double Info[]);
  145.81 +
  145.82 +#define amd_1 _glp_amd_1
  145.83 +void AMD_1(Int n, const Int Ap[], const Int Ai[], Int P[], Int Pinv[],
  145.84 +      Int Len[], Int slen, Int S[], double Control[], double Info[]);
  145.85 +
  145.86 +#define amd_postorder _glp_amd_postorder
  145.87 +void AMD_postorder(Int nn, Int Parent[], Int Npiv[], Int Fsize[],
  145.88 +      Int Order[], Int Child[], Int Sibling[], Int Stack[]);
  145.89 +
  145.90 +#define amd_post_tree _glp_amd_post_tree
  145.91 +#ifndef NDEBUG
  145.92 +Int AMD_post_tree(Int root, Int k, Int Child[], const Int Sibling[],
  145.93 +      Int Order[], Int Stack[], Int nn);
  145.94 +#else
  145.95 +Int AMD_post_tree(Int root, Int k, Int Child[], const Int Sibling[],
  145.96 +      Int Order[], Int Stack[]);
  145.97 +#endif
  145.98 +
  145.99 +#define amd_preprocess _glp_amd_preprocess
 145.100 +void AMD_preprocess(Int n, const Int Ap[], const Int Ai[], Int Rp[],
 145.101 +      Int Ri[], Int W[], Int Flag[]);
 145.102 +
 145.103 +#define amd_debug _glp_amd_debug
 145.104 +extern Int AMD_debug;
 145.105 +
 145.106 +#define amd_debug_init _glp_amd_debug_init
 145.107 +void AMD_debug_init(char *s);
 145.108 +
 145.109 +#define amd_dump _glp_amd_dump
 145.110 +void AMD_dump(Int n, Int Pe[], Int Iw[], Int Len[], Int iwlen,
 145.111 +      Int pfree, Int Nv[], Int Next[], Int Last[], Int Head[],
 145.112 +      Int Elen[], Int Degree[], Int W[], Int nel);
 145.113 +
 145.114 +#endif
 145.115 +
 145.116 +/* eof */
   146.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   146.2 +++ b/src/amd/amd_order.c	Mon Dec 06 13:09:21 2010 +0100
   146.3 @@ -0,0 +1,200 @@
   146.4 +/* ========================================================================= */
   146.5 +/* === AMD_order =========================================================== */
   146.6 +/* ========================================================================= */
   146.7 +
   146.8 +/* ------------------------------------------------------------------------- */
   146.9 +/* AMD, Copyright (c) Timothy A. Davis,                                      */
  146.10 +/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
  146.11 +/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
  146.12 +/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
  146.13 +/* ------------------------------------------------------------------------- */
  146.14 +
  146.15 +/* User-callable AMD minimum degree ordering routine.  See amd.h for
  146.16 + * documentation.
  146.17 + */
  146.18 +
  146.19 +#include "amd_internal.h"
  146.20 +
  146.21 +/* ========================================================================= */
  146.22 +/* === AMD_order =========================================================== */
  146.23 +/* ========================================================================= */
  146.24 +
  146.25 +GLOBAL Int AMD_order
  146.26 +(
  146.27 +    Int n,
  146.28 +    const Int Ap [ ],
  146.29 +    const Int Ai [ ],
  146.30 +    Int P [ ],
  146.31 +    double Control [ ],
  146.32 +    double Info [ ]
  146.33 +)
  146.34 +{
  146.35 +    Int *Len, *S, nz, i, *Pinv, info, status, *Rp, *Ri, *Cp, *Ci, ok ;
  146.36 +    size_t nzaat, slen ;
  146.37 +    double mem = 0 ;
  146.38 +
  146.39 +#ifndef NDEBUG
  146.40 +    AMD_debug_init ("amd") ;
  146.41 +#endif
  146.42 +
  146.43 +    /* clear the Info array, if it exists */
  146.44 +    info = Info != (double *) NULL ;
  146.45 +    if (info)
  146.46 +    {
  146.47 +        for (i = 0 ; i < AMD_INFO ; i++)
  146.48 +        {
  146.49 +            Info [i] = EMPTY ;
  146.50 +        }
  146.51 +        Info [AMD_N] = n ;
  146.52 +        Info [AMD_STATUS] = AMD_OK ;
  146.53 +    }
  146.54 +
  146.55 +    /* make sure inputs exist and n is >= 0 */
  146.56 +    if (Ai == (Int *) NULL || Ap == (Int *) NULL || P == (Int *) NULL || n < 0)
  146.57 +    {
  146.58 +        if (info) Info [AMD_STATUS] = AMD_INVALID ;
  146.59 +        return (AMD_INVALID) ;      /* arguments are invalid */
  146.60 +    }
  146.61 +
  146.62 +    if (n == 0)
  146.63 +    {
  146.64 +        return (AMD_OK) ;           /* n is 0 so there's nothing to do */
  146.65 +    }
  146.66 +
  146.67 +    nz = Ap [n] ;
  146.68 +    if (info)
  146.69 +    {
  146.70 +        Info [AMD_NZ] = nz ;
  146.71 +    }
  146.72 +    if (nz < 0)
  146.73 +    {
  146.74 +        if (info) Info [AMD_STATUS] = AMD_INVALID ;
  146.75 +        return (AMD_INVALID) ;
  146.76 +    }
  146.77 +
  146.78 +    /* check if n or nz will cause size_t overflow */
  146.79 +    if (((size_t) n) >= SIZE_T_MAX / sizeof (Int)
  146.80 +     || ((size_t) nz) >= SIZE_T_MAX / sizeof (Int))
  146.81 +    {
  146.82 +        if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
  146.83 +        return (AMD_OUT_OF_MEMORY) ;        /* problem too large */
  146.84 +    }
  146.85 +
  146.86 +    /* check the input matrix:  AMD_OK, AMD_INVALID, or AMD_OK_BUT_JUMBLED */
  146.87 +    status = AMD_valid (n, n, Ap, Ai) ;
  146.88 +
  146.89 +    if (status == AMD_INVALID)
  146.90 +    {
  146.91 +        if (info) Info [AMD_STATUS] = AMD_INVALID ;
  146.92 +        return (AMD_INVALID) ;      /* matrix is invalid */
  146.93 +    }
  146.94 +
  146.95 +    /* allocate two size-n integer workspaces */
  146.96 +    Len = amd_malloc (n * sizeof (Int)) ;
  146.97 +    Pinv = amd_malloc (n * sizeof (Int)) ;
  146.98 +    mem += n ;
  146.99 +    mem += n ;
 146.100 +    if (!Len || !Pinv)
 146.101 +    {
 146.102 +        /* :: out of memory :: */
 146.103 +        amd_free (Len) ;
 146.104 +        amd_free (Pinv) ;
 146.105 +        if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
 146.106 +        return (AMD_OUT_OF_MEMORY) ;
 146.107 +    }
 146.108 +
 146.109 +    if (status == AMD_OK_BUT_JUMBLED)
 146.110 +    {
 146.111 +        /* sort the input matrix and remove duplicate entries */
 146.112 +        AMD_DEBUG1 (("Matrix is jumbled\n")) ;
 146.113 +        Rp = amd_malloc ((n+1) * sizeof (Int)) ;
 146.114 +        Ri = amd_malloc (MAX (nz,1) * sizeof (Int)) ;
 146.115 +        mem += (n+1) ;
 146.116 +        mem += MAX (nz,1) ;
 146.117 +        if (!Rp || !Ri)
 146.118 +        {
 146.119 +            /* :: out of memory :: */
 146.120 +            amd_free (Rp) ;
 146.121 +            amd_free (Ri) ;
 146.122 +            amd_free (Len) ;
 146.123 +            amd_free (Pinv) ;
 146.124 +            if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
 146.125 +            return (AMD_OUT_OF_MEMORY) ;
 146.126 +        }
 146.127 +        /* use Len and Pinv as workspace to create R = A' */
 146.128 +        AMD_preprocess (n, Ap, Ai, Rp, Ri, Len, Pinv) ;
 146.129 +        Cp = Rp ;
 146.130 +        Ci = Ri ;
 146.131 +    }
 146.132 +    else
 146.133 +    {
 146.134 +        /* order the input matrix as-is.  No need to compute R = A' first */
 146.135 +        Rp = NULL ;
 146.136 +        Ri = NULL ;
 146.137 +        Cp = (Int *) Ap ;
 146.138 +        Ci = (Int *) Ai ;
 146.139 +    }
 146.140 +
 146.141 +    /* --------------------------------------------------------------------- */
 146.142 +    /* determine the symmetry and count off-diagonal nonzeros in A+A' */
 146.143 +    /* --------------------------------------------------------------------- */
 146.144 +
 146.145 +    nzaat = AMD_aat (n, Cp, Ci, Len, P, Info) ;
 146.146 +    AMD_DEBUG1 (("nzaat: %g\n", (double) nzaat)) ;
 146.147 +    ASSERT ((MAX (nz-n, 0) <= nzaat) && (nzaat <= 2 * (size_t) nz)) ;
 146.148 +
 146.149 +    /* --------------------------------------------------------------------- */
 146.150 +    /* allocate workspace for matrix, elbow room, and 6 size-n vectors */
 146.151 +    /* --------------------------------------------------------------------- */
 146.152 +
 146.153 +    S = NULL ;
 146.154 +    slen = nzaat ;                      /* space for matrix */
 146.155 +    ok = ((slen + nzaat/5) >= slen) ;   /* check for size_t overflow */
 146.156 +    slen += nzaat/5 ;                   /* add elbow room */
 146.157 +    for (i = 0 ; ok && i < 7 ; i++)
 146.158 +    {
 146.159 +        ok = ((slen + n) > slen) ;      /* check for size_t overflow */
 146.160 +        slen += n ;                     /* size-n elbow room, 6 size-n work */
 146.161 +    }
 146.162 +    mem += slen ;
 146.163 +    ok = ok && (slen < SIZE_T_MAX / sizeof (Int)) ; /* check for overflow */
 146.164 +    ok = ok && (slen < Int_MAX) ;       /* S[i] for Int i must be OK */
 146.165 +    if (ok)
 146.166 +    {
 146.167 +        S = amd_malloc (slen * sizeof (Int)) ;
 146.168 +    }
 146.169 +    AMD_DEBUG1 (("slen %g\n", (double) slen)) ;
 146.170 +    if (!S)
 146.171 +    {
 146.172 +        /* :: out of memory :: (or problem too large) */
 146.173 +        amd_free (Rp) ;
 146.174 +        amd_free (Ri) ;
 146.175 +        amd_free (Len) ;
 146.176 +        amd_free (Pinv) ;
 146.177 +        if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
 146.178 +        return (AMD_OUT_OF_MEMORY) ;
 146.179 +    }
 146.180 +    if (info)
 146.181 +    {
 146.182 +        /* memory usage, in bytes. */
 146.183 +        Info [AMD_MEMORY] = mem * sizeof (Int) ;
 146.184 +    }
 146.185 +
 146.186 +    /* --------------------------------------------------------------------- */
 146.187 +    /* order the matrix */
 146.188 +    /* --------------------------------------------------------------------- */
 146.189 +
 146.190 +    AMD_1 (n, Cp, Ci, P, Pinv, Len, slen, S, Control, Info) ;
 146.191 +
 146.192 +    /* --------------------------------------------------------------------- */
 146.193 +    /* free the workspace */
 146.194 +    /* --------------------------------------------------------------------- */
 146.195 +
 146.196 +    amd_free (Rp) ;
 146.197 +    amd_free (Ri) ;
 146.198 +    amd_free (Len) ;
 146.199 +    amd_free (Pinv) ;
 146.200 +    amd_free (S) ;
 146.201 +    if (info) Info [AMD_STATUS] = status ;
 146.202 +    return (status) ;       /* successful ordering */
 146.203 +}
   147.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   147.2 +++ b/src/amd/amd_post_tree.c	Mon Dec 06 13:09:21 2010 +0100
   147.3 @@ -0,0 +1,121 @@
   147.4 +/* ========================================================================= */
   147.5 +/* === AMD_post_tree ======================================================= */
   147.6 +/* ========================================================================= */
   147.7 +
   147.8 +/* ------------------------------------------------------------------------- */
   147.9 +/* AMD, Copyright (c) Timothy A. Davis,                                      */
  147.10 +/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
  147.11 +/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
  147.12 +/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
  147.13 +/* ------------------------------------------------------------------------- */
  147.14 +
  147.15 +/* Post-ordering of a supernodal elimination tree.  */
  147.16 +
  147.17 +#include "amd_internal.h"
  147.18 +
  147.19 +GLOBAL Int AMD_post_tree
  147.20 +(
  147.21 +    Int root,                   /* root of the tree */
  147.22 +    Int k,                      /* start numbering at k */
  147.23 +    Int Child [ ],              /* input argument of size nn, undefined on
  147.24 +                                 * output.  Child [i] is the head of a link
  147.25 +                                 * list of all nodes that are children of node
  147.26 +                                 * i in the tree. */
  147.27 +    const Int Sibling [ ],      /* input argument of size nn, not modified.
  147.28 +                                 * If f is a node in the link list of the
  147.29 +                                 * children of node i, then Sibling [f] is the
  147.30 +                                 * next child of node i.
  147.31 +                                 */
  147.32 +    Int Order [ ],              /* output order, of size nn.  Order [i] = k
  147.33 +                                 * if node i is the kth node of the reordered
  147.34 +                                 * tree. */
  147.35 +    Int Stack [ ]               /* workspace of size nn */
  147.36 +#ifndef NDEBUG
  147.37 +    , Int nn                    /* nodes are in the range 0..nn-1. */
  147.38 +#endif
  147.39 +)
  147.40 +{
  147.41 +    Int f, head, h, i ;
  147.42 +
  147.43 +#if 0
  147.44 +    /* --------------------------------------------------------------------- */
  147.45 +    /* recursive version (Stack [ ] is not used): */
  147.46 +    /* --------------------------------------------------------------------- */
  147.47 +
  147.48 +    /* this is simple, but can caouse stack overflow if nn is large */
  147.49 +    i = root ;
  147.50 +    for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
  147.51 +    {
  147.52 +        k = AMD_post_tree (f, k, Child, Sibling, Order, Stack, nn) ;
  147.53 +    }
  147.54 +    Order [i] = k++ ;
  147.55 +    return (k) ;
  147.56 +#endif
  147.57 +
  147.58 +    /* --------------------------------------------------------------------- */
  147.59 +    /* non-recursive version, using an explicit stack */
  147.60 +    /* --------------------------------------------------------------------- */
  147.61 +
  147.62 +    /* push root on the stack */
  147.63 +    head = 0 ;
  147.64 +    Stack [0] = root ;
  147.65 +
  147.66 +    while (head >= 0)
  147.67 +    {
  147.68 +        /* get head of stack */
  147.69 +        ASSERT (head < nn) ;
  147.70 +        i = Stack [head] ;
  147.71 +        AMD_DEBUG1 (("head of stack "ID" \n", i)) ;
  147.72 +        ASSERT (i >= 0 && i < nn) ;
  147.73 +
  147.74 +        if (Child [i] != EMPTY)
  147.75 +        {
  147.76 +            /* the children of i are not yet ordered */
  147.77 +            /* push each child onto the stack in reverse order */
  147.78 +            /* so that small ones at the head of the list get popped first */
  147.79 +            /* and the biggest one at the end of the list gets popped last */
  147.80 +            for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
  147.81 +            {
  147.82 +                head++ ;
  147.83 +                ASSERT (head < nn) ;
  147.84 +                ASSERT (f >= 0 && f < nn) ;
  147.85 +            }
  147.86 +            h = head ;
  147.87 +            ASSERT (head < nn) ;
  147.88 +            for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
  147.89 +            {
  147.90 +                ASSERT (h > 0) ;
  147.91 +                Stack [h--] = f ;
  147.92 +                AMD_DEBUG1 (("push "ID" on stack\n", f)) ;
  147.93 +                ASSERT (f >= 0 && f < nn) ;
  147.94 +            }
  147.95 +            ASSERT (Stack [h] == i) ;
  147.96 +
  147.97 +            /* delete child list so that i gets ordered next time we see it */
  147.98 +            Child [i] = EMPTY ;
  147.99 +        }
 147.100 +        else
 147.101 +        {
 147.102 +            /* the children of i (if there were any) are already ordered */
 147.103 +            /* remove i from the stack and order it.  Front i is kth front */
 147.104 +            head-- ;
 147.105 +            AMD_DEBUG1 (("pop "ID" order "ID"\n", i, k)) ;
 147.106 +            Order [i] = k++ ;
 147.107 +            ASSERT (k <= nn) ;
 147.108 +        }
 147.109 +
 147.110 +#ifndef NDEBUG
 147.111 +        AMD_DEBUG1 (("\nStack:")) ;
 147.112 +        for (h = head ; h >= 0 ; h--)
 147.113 +        {
 147.114 +            Int j = Stack [h] ;
 147.115 +            AMD_DEBUG1 ((" "ID, j)) ;
 147.116 +            ASSERT (j >= 0 && j < nn) ;
 147.117 +        }
 147.118 +        AMD_DEBUG1 (("\n\n")) ;
 147.119 +        ASSERT (head < nn) ;
 147.120 +#endif
 147.121 +
 147.122 +    }
 147.123 +    return (k) ;
 147.124 +}
   148.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   148.2 +++ b/src/amd/amd_postorder.c	Mon Dec 06 13:09:21 2010 +0100
   148.3 @@ -0,0 +1,207 @@
   148.4 +/* ========================================================================= */
   148.5 +/* === AMD_postorder ======================================================= */
   148.6 +/* ========================================================================= */
   148.7 +
   148.8 +/* ------------------------------------------------------------------------- */
   148.9 +/* AMD, Copyright (c) Timothy A. Davis,                                      */
  148.10 +/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
  148.11 +/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
  148.12 +/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
  148.13 +/* ------------------------------------------------------------------------- */
  148.14 +
  148.15 +/* Perform a postordering (via depth-first search) of an assembly tree. */
  148.16 +
  148.17 +#include "amd_internal.h"
  148.18 +
  148.19 +GLOBAL void AMD_postorder
  148.20 +(
  148.21 +    /* inputs, not modified on output: */
  148.22 +    Int nn,             /* nodes are in the range 0..nn-1 */
  148.23 +    Int Parent [ ],     /* Parent [j] is the parent of j, or EMPTY if root */
  148.24 +    Int Nv [ ],         /* Nv [j] > 0 number of pivots represented by node j,
  148.25 +                         * or zero if j is not a node. */
  148.26 +    Int Fsize [ ],      /* Fsize [j]: size of node j */
  148.27 +
  148.28 +    /* output, not defined on input: */
  148.29 +    Int Order [ ],      /* output post-order */
  148.30 +
  148.31 +    /* workspaces of size nn: */
  148.32 +    Int Child [ ],
  148.33 +    Int Sibling [ ],
  148.34 +    Int Stack [ ]
  148.35 +)
  148.36 +{
  148.37 +    Int i, j, k, parent, frsize, f, fprev, maxfrsize, bigfprev, bigf, fnext ;
  148.38 +
  148.39 +    for (j = 0 ; j < nn ; j++)
  148.40 +    {
  148.41 +        Child [j] = EMPTY ;
  148.42 +        Sibling [j] = EMPTY ;
  148.43 +    }
  148.44 +
  148.45 +    /* --------------------------------------------------------------------- */
  148.46 +    /* place the children in link lists - bigger elements tend to be last */
  148.47 +    /* --------------------------------------------------------------------- */
  148.48 +
  148.49 +    for (j = nn-1 ; j >= 0 ; j--)
  148.50 +    {
  148.51 +        if (Nv [j] > 0)
  148.52 +        {
  148.53 +            /* this is an element */
  148.54 +            parent = Parent [j] ;
  148.55 +            if (parent != EMPTY)
  148.56 +            {
  148.57 +                /* place the element in link list of the children its parent */
  148.58 +                /* bigger elements will tend to be at the end of the list */
  148.59 +                Sibling [j] = Child [parent] ;
  148.60 +                Child [parent] = j ;
  148.61 +            }
  148.62 +        }
  148.63 +    }
  148.64 +
  148.65 +#ifndef NDEBUG
  148.66 +    {
  148.67 +        Int nels, ff, nchild ;
  148.68 +        AMD_DEBUG1 (("\n\n================================ AMD_postorder:\n"));
  148.69 +        nels = 0 ;
  148.70 +        for (j = 0 ; j < nn ; j++)
  148.71 +        {
  148.72 +            if (Nv [j] > 0)
  148.73 +            {
  148.74 +                AMD_DEBUG1 (( ""ID" :  nels "ID" npiv "ID" size "ID
  148.75 +                    " parent "ID" maxfr "ID"\n", j, nels,
  148.76 +                    Nv [j], Fsize [j], Parent [j], Fsize [j])) ;
  148.77 +                /* this is an element */
  148.78 +                /* dump the link list of children */
  148.79 +                nchild = 0 ;
  148.80 +                AMD_DEBUG1 (("    Children: ")) ;
  148.81 +                for (ff = Child [j] ; ff != EMPTY ; ff = Sibling [ff])
  148.82 +                {
  148.83 +                    AMD_DEBUG1 ((ID" ", ff)) ;
  148.84 +                    ASSERT (Parent [ff] == j) ;
  148.85 +                    nchild++ ;
  148.86 +                    ASSERT (nchild < nn) ;
  148.87 +                }
  148.88 +                AMD_DEBUG1 (("\n")) ;
  148.89 +                parent = Parent [j] ;
  148.90 +                if (parent != EMPTY)
  148.91 +                {
  148.92 +                    ASSERT (Nv [parent] > 0) ;
  148.93 +                }
  148.94 +                nels++ ;
  148.95 +            }
  148.96 +        }
  148.97 +    }
  148.98 +    AMD_DEBUG1 (("\n\nGo through the children of each node, and put\n"
  148.99 +                 "the biggest child last in each list:\n")) ;
 148.100 +#endif
 148.101 +
 148.102 +    /* --------------------------------------------------------------------- */
 148.103 +    /* place the largest child last in the list of children for each node */
 148.104 +    /* --------------------------------------------------------------------- */
 148.105 +
 148.106 +    for (i = 0 ; i < nn ; i++)
 148.107 +    {
 148.108 +        if (Nv [i] > 0 && Child [i] != EMPTY)
 148.109 +        {
 148.110 +
 148.111 +#ifndef NDEBUG
 148.112 +            Int nchild ;
 148.113 +            AMD_DEBUG1 (("Before partial sort, element "ID"\n", i)) ;
 148.114 +            nchild = 0 ;
 148.115 +            for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
 148.116 +            {
 148.117 +                ASSERT (f >= 0 && f < nn) ;
 148.118 +                AMD_DEBUG1 (("      f: "ID"  size: "ID"\n", f, Fsize [f])) ;
 148.119 +                nchild++ ;
 148.120 +                ASSERT (nchild <= nn) ;
 148.121 +            }
 148.122 +#endif
 148.123 +
 148.124 +            /* find the biggest element in the child list */
 148.125 +            fprev = EMPTY ;
 148.126 +            maxfrsize = EMPTY ;
 148.127 +            bigfprev = EMPTY ;
 148.128 +            bigf = EMPTY ;
 148.129 +            for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
 148.130 +            {
 148.131 +                ASSERT (f >= 0 && f < nn) ;
 148.132 +                frsize = Fsize [f] ;
 148.133 +                if (frsize >= maxfrsize)
 148.134 +                {
 148.135 +                    /* this is the biggest seen so far */
 148.136 +                    maxfrsize = frsize ;
 148.137 +                    bigfprev = fprev ;
 148.138 +                    bigf = f ;
 148.139 +                }
 148.140 +                fprev = f ;
 148.141 +            }
 148.142 +            ASSERT (bigf != EMPTY) ;
 148.143 +
 148.144 +            fnext = Sibling [bigf] ;
 148.145 +
 148.146 +            AMD_DEBUG1 (("bigf "ID" maxfrsize "ID" bigfprev "ID" fnext "ID
 148.147 +                " fprev " ID"\n", bigf, maxfrsize, bigfprev, fnext, fprev)) ;
 148.148 +
 148.149 +            if (fnext != EMPTY)
 148.150 +            {
 148.151 +                /* if fnext is EMPTY then bigf is already at the end of list */
 148.152 +
 148.153 +                if (bigfprev == EMPTY)
 148.154 +                {
 148.155 +                    /* delete bigf from the element of the list */
 148.156 +                    Child [i] = fnext ;
 148.157 +                }
 148.158 +                else
 148.159 +                {
 148.160 +                    /* delete bigf from the middle of the list */
 148.161 +                    Sibling [bigfprev] = fnext ;
 148.162 +                }
 148.163 +
 148.164 +                /* put bigf at the end of the list */
 148.165 +                Sibling [bigf] = EMPTY ;
 148.166 +                ASSERT (Child [i] != EMPTY) ;
 148.167 +                ASSERT (fprev != bigf) ;
 148.168 +                ASSERT (fprev != EMPTY) ;
 148.169 +                Sibling [fprev] = bigf ;
 148.170 +            }
 148.171 +
 148.172 +#ifndef NDEBUG
 148.173 +            AMD_DEBUG1 (("After partial sort, element "ID"\n", i)) ;
 148.174 +            for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
 148.175 +            {
 148.176 +                ASSERT (f >= 0 && f < nn) ;
 148.177 +                AMD_DEBUG1 (("        "ID"  "ID"\n", f, Fsize [f])) ;
 148.178 +                ASSERT (Nv [f] > 0) ;
 148.179 +                nchild-- ;
 148.180 +            }
 148.181 +            ASSERT (nchild == 0) ;
 148.182 +#endif
 148.183 +
 148.184 +        }
 148.185 +    }
 148.186 +
 148.187 +    /* --------------------------------------------------------------------- */
 148.188 +    /* postorder the assembly tree */
 148.189 +    /* --------------------------------------------------------------------- */
 148.190 +
 148.191 +    for (i = 0 ; i < nn ; i++)
 148.192 +    {
 148.193 +        Order [i] = EMPTY ;
 148.194 +    }
 148.195 +
 148.196 +    k = 0 ;
 148.197 +
 148.198 +    for (i = 0 ; i < nn ; i++)
 148.199 +    {
 148.200 +        if (Parent [i] == EMPTY && Nv [i] > 0)
 148.201 +        {
 148.202 +            AMD_DEBUG1 (("Root of assembly tree "ID"\n", i)) ;
 148.203 +            k = AMD_post_tree (i, k, Child, Sibling, Order, Stack
 148.204 +#ifndef NDEBUG
 148.205 +                , nn
 148.206 +#endif
 148.207 +                ) ;
 148.208 +        }
 148.209 +    }
 148.210 +}
   149.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   149.2 +++ b/src/amd/amd_preprocess.c	Mon Dec 06 13:09:21 2010 +0100
   149.3 @@ -0,0 +1,119 @@
   149.4 +/* ========================================================================= */
   149.5 +/* === AMD_preprocess ====================================================== */
   149.6 +/* ========================================================================= */
   149.7 +
   149.8 +/* ------------------------------------------------------------------------- */
   149.9 +/* AMD, Copyright (c) Timothy A. Davis,                                      */
  149.10 +/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
  149.11 +/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
  149.12 +/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
  149.13 +/* ------------------------------------------------------------------------- */
  149.14 +
  149.15 +/* Sorts, removes duplicate entries, and transposes from the nonzero pattern of
  149.16 + * a column-form matrix A, to obtain the matrix R.  The input matrix can have
  149.17 + * duplicate entries and/or unsorted columns (AMD_valid (n,Ap,Ai) must not be
  149.18 + * AMD_INVALID).
  149.19 + *
  149.20 + * This input condition is NOT checked.  This routine is not user-callable.
  149.21 + */
  149.22 +
  149.23 +#include "amd_internal.h"
  149.24 +
  149.25 +/* ========================================================================= */
  149.26 +/* === AMD_preprocess ====================================================== */
  149.27 +/* ========================================================================= */
  149.28 +
  149.29 +/* AMD_preprocess does not check its input for errors or allocate workspace.
  149.30 + * On input, the condition (AMD_valid (n,n,Ap,Ai) != AMD_INVALID) must hold.
  149.31 + */
  149.32 +
  149.33 +GLOBAL void AMD_preprocess
  149.34 +(
  149.35 +    Int n,              /* input matrix: A is n-by-n */
  149.36 +    const Int Ap [ ],   /* size n+1 */
  149.37 +    const Int Ai [ ],   /* size nz = Ap [n] */
  149.38 +
  149.39 +    /* output matrix R: */
  149.40 +    Int Rp [ ],         /* size n+1 */
  149.41 +    Int Ri [ ],         /* size nz (or less, if duplicates present) */
  149.42 +
  149.43 +    Int W [ ],          /* workspace of size n */
  149.44 +    Int Flag [ ]        /* workspace of size n */
  149.45 +)
  149.46 +{
  149.47 +
  149.48 +    /* --------------------------------------------------------------------- */
  149.49 +    /* local variables */
  149.50 +    /* --------------------------------------------------------------------- */
  149.51 +
  149.52 +    Int i, j, p, p2 ;
  149.53 +
  149.54 +    ASSERT (AMD_valid (n, n, Ap, Ai) != AMD_INVALID) ;
  149.55 +
  149.56 +    /* --------------------------------------------------------------------- */
  149.57 +    /* count the entries in each row of A (excluding duplicates) */
  149.58 +    /* --------------------------------------------------------------------- */
  149.59 +
  149.60 +    for (i = 0 ; i < n ; i++)
  149.61 +    {
  149.62 +        W [i] = 0 ;             /* # of nonzeros in row i (excl duplicates) */
  149.63 +        Flag [i] = EMPTY ;      /* Flag [i] = j if i appears in column j */
  149.64 +    }
  149.65 +    for (j = 0 ; j < n ; j++)
  149.66 +    {
  149.67 +        p2 = Ap [j+1] ;
  149.68 +        for (p = Ap [j] ; p < p2 ; p++)
  149.69 +        {
  149.70 +            i = Ai [p] ;
  149.71 +            if (Flag [i] != j)
  149.72 +            {
  149.73 +                /* row index i has not yet appeared in column j */
  149.74 +                W [i]++ ;           /* one more entry in row i */
  149.75 +                Flag [i] = j ;      /* flag row index i as appearing in col j*/
  149.76 +            }
  149.77 +        }
  149.78 +    }
  149.79 +
  149.80 +    /* --------------------------------------------------------------------- */
  149.81 +    /* compute the row pointers for R */
  149.82 +    /* --------------------------------------------------------------------- */
  149.83 +
  149.84 +    Rp [0] = 0 ;
  149.85 +    for (i = 0 ; i < n ; i++)
  149.86 +    {
  149.87 +        Rp [i+1] = Rp [i] + W [i] ;
  149.88 +    }
  149.89 +    for (i = 0 ; i < n ; i++)
  149.90 +    {
  149.91 +        W [i] = Rp [i] ;
  149.92 +        Flag [i] = EMPTY ;
  149.93 +    }
  149.94 +
  149.95 +    /* --------------------------------------------------------------------- */
  149.96 +    /* construct the row form matrix R */
  149.97 +    /* --------------------------------------------------------------------- */
  149.98 +
  149.99 +    /* R = row form of pattern of A */
 149.100 +    for (j = 0 ; j < n ; j++)
 149.101 +    {
 149.102 +        p2 = Ap [j+1] ;
 149.103 +        for (p = Ap [j] ; p < p2 ; p++)
 149.104 +        {
 149.105 +            i = Ai [p] ;
 149.106 +            if (Flag [i] != j)
 149.107 +            {
 149.108 +                /* row index i has not yet appeared in column j */
 149.109 +                Ri [W [i]++] = j ;  /* put col j in row i */
 149.110 +                Flag [i] = j ;      /* flag row index i as appearing in col j*/
 149.111 +            }
 149.112 +        }
 149.113 +    }
 149.114 +
 149.115 +#ifndef NDEBUG
 149.116 +    ASSERT (AMD_valid (n, n, Rp, Ri) == AMD_OK) ;
 149.117 +    for (j = 0 ; j < n ; j++)
 149.118 +    {
 149.119 +        ASSERT (W [j] == Rp [j+1]) ;
 149.120 +    }
 149.121 +#endif
 149.122 +}
   150.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   150.2 +++ b/src/amd/amd_valid.c	Mon Dec 06 13:09:21 2010 +0100
   150.3 @@ -0,0 +1,93 @@
   150.4 +/* ========================================================================= */
   150.5 +/* === AMD_valid =========================================================== */
   150.6 +/* ========================================================================= */
   150.7 +
   150.8 +/* ------------------------------------------------------------------------- */
   150.9 +/* AMD, Copyright (c) Timothy A. Davis,                                      */
  150.10 +/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
  150.11 +/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
  150.12 +/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
  150.13 +/* ------------------------------------------------------------------------- */
  150.14 +
  150.15 +/* Check if a column-form matrix is valid or not.  The matrix A is
  150.16 + * n_row-by-n_col.  The row indices of entries in column j are in
  150.17 + * Ai [Ap [j] ... Ap [j+1]-1].  Required conditions are:
  150.18 + *
  150.19 + *      n_row >= 0
  150.20 + *      n_col >= 0
  150.21 + *      nz = Ap [n_col] >= 0        number of entries in the matrix
  150.22 + *      Ap [0] == 0
  150.23 + *      Ap [j] <= Ap [j+1] for all j in the range 0 to n_col.
  150.24 + *      Ai [0 ... nz-1] must be in the range 0 to n_row-1.
  150.25 + *
  150.26 + * If any of the above conditions hold, AMD_INVALID is returned.  If the
  150.27 + * following condition holds, AMD_OK_BUT_JUMBLED is returned (a warning,
  150.28 + * not an error):
  150.29 + *
  150.30 + *      row indices in Ai [Ap [j] ... Ap [j+1]-1] are not sorted in ascending
  150.31 + *          order, and/or duplicate entries exist.
  150.32 + *
  150.33 + * Otherwise, AMD_OK is returned.
  150.34 + *
  150.35 + * In v1.2 and earlier, this function returned TRUE if the matrix was valid
  150.36 + * (now returns AMD_OK), or FALSE otherwise (now returns AMD_INVALID or
  150.37 + * AMD_OK_BUT_JUMBLED).
  150.38 + */
  150.39 +
  150.40 +#include "amd_internal.h"
  150.41 +
  150.42 +GLOBAL Int AMD_valid
  150.43 +(
  150.44 +    /* inputs, not modified on output: */
  150.45 +    Int n_row,          /* A is n_row-by-n_col */
  150.46 +    Int n_col,
  150.47 +    const Int Ap [ ],   /* column pointers of A, of size n_col+1 */
  150.48 +    const Int Ai [ ]    /* row indices of A, of size nz = Ap [n_col] */
  150.49 +)
  150.50 +{
  150.51 +    Int nz, j, p1, p2, ilast, i, p, result = AMD_OK ;
  150.52 +
  150.53 +    if (n_row < 0 || n_col < 0 || Ap == NULL || Ai == NULL)
  150.54 +    {
  150.55 +        return (AMD_INVALID) ;
  150.56 +    }
  150.57 +    nz = Ap [n_col] ;
  150.58 +    if (Ap [0] != 0 || nz < 0)
  150.59 +    {
  150.60 +        /* column pointers must start at Ap [0] = 0, and Ap [n] must be >= 0 */
  150.61 +        AMD_DEBUG0 (("column 0 pointer bad or nz < 0\n")) ;
  150.62 +        return (AMD_INVALID) ;
  150.63 +    }
  150.64 +    for (j = 0 ; j < n_col ; j++)
  150.65 +    {
  150.66 +        p1 = Ap [j] ;
  150.67 +        p2 = Ap [j+1] ;
  150.68 +        AMD_DEBUG2 (("\nColumn: "ID" p1: "ID" p2: "ID"\n", j, p1, p2)) ;
  150.69 +        if (p1 > p2)
  150.70 +        {
  150.71 +            /* column pointers must be ascending */
  150.72 +            AMD_DEBUG0 (("column "ID" pointer bad\n", j)) ;
  150.73 +            return (AMD_INVALID) ;
  150.74 +        }
  150.75 +        ilast = EMPTY ;
  150.76 +        for (p = p1 ; p < p2 ; p++)
  150.77 +        {
  150.78 +            i = Ai [p] ;
  150.79 +            AMD_DEBUG3 (("row: "ID"\n", i)) ;
  150.80 +            if (i < 0 || i >= n_row)
  150.81 +            {
  150.82 +                /* row index out of range */
  150.83 +                AMD_DEBUG0 (("index out of range, col "ID" row "ID"\n", j, i));
  150.84 +                return (AMD_INVALID) ;
  150.85 +            }
  150.86 +            if (i <= ilast)
  150.87 +            {
  150.88 +                /* row index unsorted, or duplicate entry present */
  150.89 +                AMD_DEBUG1 (("index unsorted/dupl col "ID" row "ID"\n", j, i));
  150.90 +                result = AMD_OK_BUT_JUMBLED ;
  150.91 +            }
  150.92 +            ilast = i ;
  150.93 +        }
  150.94 +    }
  150.95 +    return (result) ;
  150.96 +}
   151.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   151.2 +++ b/src/colamd/COPYING	Mon Dec 06 13:09:21 2010 +0100
   151.3 @@ -0,0 +1,502 @@
   151.4 +                  GNU LESSER GENERAL PUBLIC LICENSE
   151.5 +                       Version 2.1, February 1999
   151.6 +
   151.7 + Copyright (C) 1991, 1999 Free Software Foundation, Inc.
   151.8 +     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   151.9 + Everyone is permitted to copy and distribute verbatim copies
  151.10 + of this license document, but changing it is not allowed.
  151.11 +
  151.12 +[This is the first released version of the Lesser GPL.  It also counts
  151.13 + as the successor of the GNU Library Public License, version 2, hence
  151.14 + the version number 2.1.]
  151.15 +
  151.16 +                            Preamble
  151.17 +
  151.18 +  The licenses for most software are designed to take away your
  151.19 +freedom to share and change it.  By contrast, the GNU General Public
  151.20 +Licenses are intended to guarantee your freedom to share and change
  151.21 +free software--to make sure the software is free for all its users.
  151.22 +
  151.23 +  This license, the Lesser General Public License, applies to some
  151.24 +specially designated software packages--typically libraries--of the
  151.25 +Free Software Foundation and other authors who decide to use it.  You
  151.26 +can use it too, but we suggest you first think carefully about whether
  151.27 +this license or the ordinary General Public License is the better
  151.28 +strategy to use in any particular case, based on the explanations below.
  151.29 +
  151.30 +  When we speak of free software, we are referring to freedom of use,
  151.31 +not price.  Our General Public Licenses are designed to make sure that
  151.32 +you have the freedom to distribute copies of free software (and charge
  151.33 +for this service if you wish); that you receive source code or can get
  151.34 +it if you want it; that you can change the software and use pieces of
  151.35 +it in new free programs; and that you are informed that you can do
  151.36 +these things.
  151.37 +
  151.38 +  To protect your rights, we need to make restrictions that forbid
  151.39 +distributors to deny you these rights or to ask you to surrender these
  151.40 +rights.  These restrictions translate to certain responsibilities for
  151.41 +you if you distribute copies of the library or if you modify it.
  151.42 +
  151.43 +  For example, if you distribute copies of the library, whether gratis
  151.44 +or for a fee, you must give the recipients all the rights that we gave
  151.45 +you.  You must make sure that they, too, receive or can get the source
  151.46 +code.  If you link other code with the library, you must provide
  151.47 +complete object files to the recipients, so that they can relink them
  151.48 +with the library after making changes to the library and recompiling
  151.49 +it.  And you must show them these terms so they know their rights.
  151.50 +
  151.51 +  We protect your rights with a two-step method: (1) we copyright the
  151.52 +library, and (2) we offer you this license, which gives you legal
  151.53 +permission to copy, distribute and/or modify the library.
  151.54 +
  151.55 +  To protect each distributor, we want to make it very clear that
  151.56 +there is no warranty for the free library.  Also, if the library is
  151.57 +modified by someone else and passed on, the recipients should know
  151.58 +that what they have is not the original version, so that the original
  151.59 +author's reputation will not be affected by problems that might be
  151.60 +introduced by others.
  151.61 +
  151.62 +  Finally, software patents pose a constant threat to the existence of
  151.63 +any free program.  We wish to make sure that a company cannot
  151.64 +effectively restrict the users of a free program by obtaining a
  151.65 +restrictive license from a patent holder.  Therefore, we insist that
  151.66 +any patent license obtained for a version of the library must be
  151.67 +consistent with the full freedom of use specified in this license.
  151.68 +
  151.69 +  Most GNU software, including some libraries, is covered by the
  151.70 +ordinary GNU General Public License.  This license, the GNU Lesser
  151.71 +General Public License, applies to certain designated libraries, and
  151.72 +is quite different from the ordinary General Public License.  We use
  151.73 +this license for certain libraries in order to permit linking those
  151.74 +libraries into non-free programs.
  151.75 +
  151.76 +  When a program is linked with a library, whether statically or using
  151.77 +a shared library, the combination of the two is legally speaking a
  151.78 +combined work, a derivative of the original library.  The ordinary
  151.79 +General Public License therefore permits such linking only if the
  151.80 +entire combination fits its criteria of freedom.  The Lesser General
  151.81 +Public License permits more lax criteria for linking other code with
  151.82 +the library.
  151.83 +
  151.84 +  We call this license the "Lesser" General Public License because it
  151.85 +does Less to protect the user's freedom than the ordinary General
  151.86 +Public License.  It also provides other free software developers Less
  151.87 +of an advantage over competing non-free programs.  These disadvantages
  151.88 +are the reason we use the ordinary General Public License for many
  151.89 +libraries.  However, the Lesser license provides advantages in certain
  151.90 +special circumstances.
  151.91 +
  151.92 +  For example, on rare occasions, there may be a special need to
  151.93 +encourage the widest possible use of a certain library, so that it becomes
  151.94 +a de-facto standard.  To achieve this, non-free programs must be
  151.95 +allowed to use the library.  A more frequent case is that a free
  151.96 +library does the same job as widely used non-free libraries.  In this
  151.97 +case, there is little to gain by limiting the free library to free
  151.98 +software only, so we use the Lesser General Public License.
  151.99 +
 151.100 +  In other cases, permission to use a particular library in non-free
 151.101 +programs enables a greater number of people to use a large body of
 151.102 +free software.  For example, permission to use the GNU C Library in
 151.103 +non-free programs enables many more people to use the whole GNU
 151.104 +operating system, as well as its variant, the GNU/Linux operating
 151.105 +system.
 151.106 +
 151.107 +  Although the Lesser General Public License is Less protective of the
 151.108 +users' freedom, it does ensure that the user of a program that is
 151.109 +linked with the Library has the freedom and the wherewithal to run
 151.110 +that program using a modified version of the Library.
 151.111 +
 151.112 +  The precise terms and conditions for copying, distribution and
 151.113 +modification follow.  Pay close attention to the difference between a
 151.114 +"work based on the library" and a "work that uses the library".  The
 151.115 +former contains code derived from the library, whereas the latter must
 151.116 +be combined with the library in order to run.
 151.117 +
 151.118 +                  GNU LESSER GENERAL PUBLIC LICENSE
 151.119 +   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 151.120 +
 151.121 +  0. This License Agreement applies to any software library or other
 151.122 +program which contains a notice placed by the copyright holder or
 151.123 +other authorized party saying it may be distributed under the terms of
 151.124 +this Lesser General Public License (also called "this License").
 151.125 +Each licensee is addressed as "you".
 151.126 +
 151.127 +  A "library" means a collection of software functions and/or data
 151.128 +prepared so as to be conveniently linked with application programs
 151.129 +(which use some of those functions and data) to form executables.
 151.130 +
 151.131 +  The "Library", below, refers to any such software library or work
 151.132 +which has been distributed under these terms.  A "work based on the
 151.133 +Library" means either the Library or any derivative work under
 151.134 +copyright law: that is to say, a work containing the Library or a
 151.135 +portion of it, either verbatim or with modifications and/or translated
 151.136 +straightforwardly into another language.  (Hereinafter, translation is
 151.137 +included without limitation in the term "modification".)
 151.138 +
 151.139 +  "Source code" for a work means the preferred form of the work for
 151.140 +making modifications to it.  For a library, complete source code means
 151.141 +all the source code for all modules it contains, plus any associated
 151.142 +interface definition files, plus the scripts used to control compilation
 151.143 +and installation of the library.
 151.144 +
 151.145 +  Activities other than copying, distribution and modification are not
 151.146 +covered by this License; they are outside its scope.  The act of
 151.147 +running a program using the Library is not restricted, and output from
 151.148 +such a program is covered only if its contents constitute a work based
 151.149 +on the Library (independent of the use of the Library in a tool for
 151.150 +writing it).  Whether that is true depends on what the Library does
 151.151 +and what the program that uses the Library does.
 151.152 +
 151.153 +  1. You may copy and distribute verbatim copies of the Library's
 151.154 +complete source code as you receive it, in any medium, provided that
 151.155 +you conspicuously and appropriately publish on each copy an
 151.156 +appropriate copyright notice and disclaimer of warranty; keep intact
 151.157 +all the notices that refer to this License and to the absence of any
 151.158 +warranty; and distribute a copy of this License along with the
 151.159 +Library.
 151.160 +
 151.161 +  You may charge a fee for the physical act of transferring a copy,
 151.162 +and you may at your option offer warranty protection in exchange for a
 151.163 +fee.
 151.164 +
 151.165 +  2. You may modify your copy or copies of the Library or any portion
 151.166 +of it, thus forming a work based on the Library, and copy and
 151.167 +distribute such modifications or work under the terms of Section 1
 151.168 +above, provided that you also meet all of these conditions:
 151.169 +
 151.170 +    a) The modified work must itself be a software library.
 151.171 +
 151.172 +    b) You must cause the files modified to carry prominent notices
 151.173 +    stating that you changed the files and the date of any change.
 151.174 +
 151.175 +    c) You must cause the whole of the work to be licensed at no
 151.176 +    charge to all third parties under the terms of this License.
 151.177 +
 151.178 +    d) If a facility in the modified Library refers to a function or a
 151.179 +    table of data to be supplied by an application program that uses
 151.180 +    the facility, other than as an argument passed when the facility
 151.181 +    is invoked, then you must make a good faith effort to ensure that,
 151.182 +    in the event an application does not supply such function or
 151.183 +    table, the facility still operates, and performs whatever part of
 151.184 +    its purpose remains meaningful.
 151.185 +
 151.186 +    (For example, a function in a library to compute square roots has
 151.187 +    a purpose that is entirely well-defined independent of the
 151.188 +    application.  Therefore, Subsection 2d requires that any
 151.189 +    application-supplied function or table used by this function must
 151.190 +    be optional: if the application does not supply it, the square
 151.191 +    root function must still compute square roots.)
 151.192 +
 151.193 +These requirements apply to the modified work as a whole.  If
 151.194 +identifiable sections of that work are not derived from the Library,
 151.195 +and can be reasonably considered independent and separate works in
 151.196 +themselves, then this License, and its terms, do not apply to those
 151.197 +sections when you distribute them as separate works.  But when you
 151.198 +distribute the same sections as part of a whole which is a work based
 151.199 +on the Library, the distribution of the whole must be on the terms of
 151.200 +this License, whose permissions for other licensees extend to the
 151.201 +entire whole, and thus to each and every part regardless of who wrote
 151.202 +it.
 151.203 +
 151.204 +Thus, it is not the intent of this section to claim rights or contest
 151.205 +your rights to work written entirely by you; rather, the intent is to
 151.206 +exercise the right to control the distribution of derivative or
 151.207 +collective works based on the Library.
 151.208 +
 151.209 +In addition, mere aggregation of another work not based on the Library
 151.210 +with the Library (or with a work based on the Library) on a volume of
 151.211 +a storage or distribution medium does not bring the other work under
 151.212 +the scope of this License.
 151.213 +
 151.214 +  3. You may opt to apply the terms of the ordinary GNU General Public
 151.215 +License instead of this License to a given copy of the Library.  To do
 151.216 +this, you must alter all the notices that refer to this License, so
 151.217 +that they refer to the ordinary GNU General Public License, version 2,
 151.218 +instead of to this License.  (If a newer version than version 2 of the
 151.219 +ordinary GNU General Public License has appeared, then you can specify
 151.220 +that version instead if you wish.)  Do not make any other change in
 151.221 +these notices.
 151.222 +
 151.223 +  Once this change is made in a given copy, it is irreversible for
 151.224 +that copy, so the ordinary GNU General Public License applies to all
 151.225 +subsequent copies and derivative works made from that copy.
 151.226 +
 151.227 +  This option is useful when you wish to copy part of the code of
 151.228 +the Library into a program that is not a library.
 151.229 +
 151.230 +  4. You may copy and distribute the Library (or a portion or
 151.231 +derivative of it, under Section 2) in object code or executable form
 151.232 +under the terms of Sections 1 and 2 above provided that you accompany
 151.233 +it with the complete corresponding machine-readable source code, which
 151.234 +must be distributed under the terms of Sections 1 and 2 above on a
 151.235 +medium customarily used for software interchange.
 151.236 +
 151.237 +  If distribution of object code is made by offering access to copy
 151.238 +from a designated place, then offering equivalent access to copy the
 151.239 +source code from the same place satisfies the requirement to
 151.240 +distribute the source code, even though third parties are not
 151.241 +compelled to copy the source along with the object code.
 151.242 +
 151.243 +  5. A program that contains no derivative of any portion of the
 151.244 +Library, but is designed to work with the Library by being compiled or
 151.245 +linked with it, is called a "work that uses the Library".  Such a
 151.246 +work, in isolation, is not a derivative work of the Library, and
 151.247 +therefore falls outside the scope of this License.
 151.248 +
 151.249 +  However, linking a "work that uses the Library" with the Library
 151.250 +creates an executable that is a derivative of the Library (because it
 151.251 +contains portions of the Library), rather than a "work that uses the
 151.252 +library".  The executable is therefore covered by this License.
 151.253 +Section 6 states terms for distribution of such executables.
 151.254 +
 151.255 +  When a "work that uses the Library" uses material from a header file
 151.256 +that is part of the Library, the object code for the work may be a
 151.257 +derivative work of the Library even though the source code is not.
 151.258 +Whether this is true is especially significant if the work can be
 151.259 +linked without the Library, or if the work is itself a library.  The
 151.260 +threshold for this to be true is not precisely defined by law.
 151.261 +
 151.262 +  If such an object file uses only numerical parameters, data
 151.263 +structure layouts and accessors, and small macros and small inline
 151.264 +functions (ten lines or less in length), then the use of the object
 151.265 +file is unrestricted, regardless of whether it is legally a derivative
 151.266 +work.  (Executables containing this object code plus portions of the
 151.267 +Library will still fall under Section 6.)
 151.268 +
 151.269 +  Otherwise, if the work is a derivative of the Library, you may
 151.270 +distribute the object code for the work under the terms of Section 6.
 151.271 +Any executables containing that work also fall under Section 6,
 151.272 +whether or not they are linked directly with the Library itself.
 151.273 +
 151.274 +  6. As an exception to the Sections above, you may also combine or
 151.275 +link a "work that uses the Library" with the Library to produce a
 151.276 +work containing portions of the Library, and distribute that work
 151.277 +under terms of your choice, provided that the terms permit
 151.278 +modification of the work for the customer's own use and reverse
 151.279 +engineering for debugging such modifications.
 151.280 +
 151.281 +  You must give prominent notice with each copy of the work that the
 151.282 +Library is used in it and that the Library and its use are covered by
 151.283 +this License.  You must supply a copy of this License.  If the work
 151.284 +during execution displays copyright notices, you must include the
 151.285 +copyright notice for the Library among them, as well as a reference
 151.286 +directing the user to the copy of this License.  Also, you must do one
 151.287 +of these things:
 151.288 +
 151.289 +    a) Accompany the work with the complete corresponding
 151.290 +    machine-readable source code for the Library including whatever
 151.291 +    changes were used in the work (which must be distributed under
 151.292 +    Sections 1 and 2 above); and, if the work is an executable linked
 151.293 +    with the Library, with the complete machine-readable "work that
 151.294 +    uses the Library", as object code and/or source code, so that the
 151.295 +    user can modify the Library and then relink to produce a modified
 151.296 +    executable containing the modified Library.  (It is understood
 151.297 +    that the user who changes the contents of definitions files in the
 151.298 +    Library will not necessarily be able to recompile the application
 151.299 +    to use the modified definitions.)
 151.300 +
 151.301 +    b) Use a suitable shared library mechanism for linking with the
 151.302 +    Library.  A suitable mechanism is one that (1) uses at run time a
 151.303 +    copy of the library already present on the user's computer system,
 151.304 +    rather than copying library functions into the executable, and (2)
 151.305 +    will operate properly with a modified version of the library, if
 151.306 +    the user installs one, as long as the modified version is
 151.307 +    interface-compatible with the version that the work was made with.
 151.308 +
 151.309 +    c) Accompany the work with a written offer, valid for at
 151.310 +    least three years, to give the same user the materials
 151.311 +    specified in Subsection 6a, above, for a charge no more
 151.312 +    than the cost of performing this distribution.
 151.313 +
 151.314 +    d) If distribution of the work is made by offering access to copy
 151.315 +    from a designated place, offer equivalent access to copy the above
 151.316 +    specified materials from the same place.
 151.317 +
 151.318 +    e) Verify that the user has already received a copy of these
 151.319 +    materials or that you have already sent this user a copy.
 151.320 +
 151.321 +  For an executable, the required form of the "work that uses the
 151.322 +Library" must include any data and utility programs needed for
 151.323 +reproducing the executable from it.  However, as a special exception,
 151.324 +the materials to be distributed need not include anything that is
 151.325 +normally distributed (in either source or binary form) with the major
 151.326 +components (compiler, kernel, and so on) of the operating system on
 151.327 +which the executable runs, unless that component itself accompanies
 151.328 +the executable.
 151.329 +
 151.330 +  It may happen that this requirement contradicts the license
 151.331 +restrictions of other proprietary libraries that do not normally
 151.332 +accompany the operating system.  Such a contradiction means you cannot
 151.333 +use both them and the Library together in an executable that you
 151.334 +distribute.
 151.335 +
 151.336 +  7. You may place library facilities that are a work based on the
 151.337 +Library side-by-side in a single library together with other library
 151.338 +facilities not covered by this License, and distribute such a combined
 151.339 +library, provided that the separate distribution of the work based on
 151.340 +the Library and of the other library facilities is otherwise
 151.341 +permitted, and provided that you do these two things:
 151.342 +
 151.343 +    a) Accompany the combined library with a copy of the same work
 151.344 +    based on the Library, uncombined with any other library
 151.345 +    facilities.  This must be distributed under the terms of the
 151.346 +    Sections above.
 151.347 +
 151.348 +    b) Give prominent notice with the combined library of the fact
 151.349 +    that part of it is a work based on the Library, and explaining
 151.350 +    where to find the accompanying uncombined form of the same work.
 151.351 +
 151.352 +  8. You may not copy, modify, sublicense, link with, or distribute
 151.353 +the Library except as expressly provided under this License.  Any
 151.354 +attempt otherwise to copy, modify, sublicense, link with, or
 151.355 +distribute the Library is void, and will automatically terminate your
 151.356 +rights under this License.  However, parties who have received copies,
 151.357 +or rights, from you under this License will not have their licenses
 151.358 +terminated so long as such parties remain in full compliance.
 151.359 +
 151.360 +  9. You are not required to accept this License, since you have not
 151.361 +signed it.  However, nothing else grants you permission to modify or
 151.362 +distribute the Library or its derivative works.  These actions are
 151.363 +prohibited by law if you do not accept this License.  Therefore, by
 151.364 +modifying or distributing the Library (or any work based on the
 151.365 +Library), you indicate your acceptance of this License to do so, and
 151.366 +all its terms and conditions for copying, distributing or modifying
 151.367 +the Library or works based on it.
 151.368 +
 151.369 +  10. Each time you redistribute the Library (or any work based on the
 151.370 +Library), the recipient automatically receives a license from the
 151.371 +original licensor to copy, distribute, link with or modify the Library
 151.372 +subject to these terms and conditions.  You may not impose any further
 151.373 +restrictions on the recipients' exercise of the rights granted herein.
 151.374 +You are not responsible for enforcing compliance by third parties with
 151.375 +this License.
 151.376 +
 151.377 +  11. If, as a consequence of a court judgment or allegation of patent
 151.378 +infringement or for any other reason (not limited to patent issues),
 151.379 +conditions are imposed on you (whether by court order, agreement or
 151.380 +otherwise) that contradict the conditions of this License, they do not
 151.381 +excuse you from the conditions of this License.  If you cannot
 151.382 +distribute so as to satisfy simultaneously your obligations under this
 151.383 +License and any other pertinent obligations, then as a consequence you
 151.384 +may not distribute the Library at all.  For example, if a patent
 151.385 +license would not permit royalty-free redistribution of the Library by
 151.386 +all those who receive copies directly or indirectly through you, then
 151.387 +the only way you could satisfy both it and this License would be to
 151.388 +refrain entirely from distribution of the Library.
 151.389 +
 151.390 +If any portion of this section is held invalid or unenforceable under any
 151.391 +particular circumstance, the balance of the section is intended to apply,
 151.392 +and the section as a whole is intended to apply in other circumstances.
 151.393 +
 151.394 +It is not the purpose of this section to induce you to infringe any
 151.395 +patents or other property right claims or to contest validity of any
 151.396 +such claims; this section has the sole purpose of protecting the
 151.397 +integrity of the free software distribution system which is
 151.398 +implemented by public license practices.  Many people have made
 151.399 +generous contributions to the wide range of software distributed
 151.400 +through that system in reliance on consistent application of that
 151.401 +system; it is up to the author/donor to decide if he or she is willing
 151.402 +to distribute software through any other system and a licensee cannot
 151.403 +impose that choice.
 151.404 +
 151.405 +This section is intended to make thoroughly clear what is believed to
 151.406 +be a consequence of the rest of this License.
 151.407 +
 151.408 +  12. If the distribution and/or use of the Library is restricted in
 151.409 +certain countries either by patents or by copyrighted interfaces, the
 151.410 +original copyright holder who places the Library under this License may add
 151.411 +an explicit geographical distribution limitation excluding those countries,
 151.412 +so that distribution is permitted only in or among countries not thus
 151.413 +excluded.  In such case, this License incorporates the limitation as if
 151.414 +written in the body of this License.
 151.415 +
 151.416 +  13. The Free Software Foundation may publish revised and/or new
 151.417 +versions of the Lesser General Public License from time to time.
 151.418 +Such new versions will be similar in spirit to the present version,
 151.419 +but may differ in detail to address new problems or concerns.
 151.420 +
 151.421 +Each version is given a distinguishing version number.  If the Library
 151.422 +specifies a version number of this License which applies to it and
 151.423 +"any later version", you have the option of following the terms and
 151.424 +conditions either of that version or of any later version published by
 151.425 +the Free Software Foundation.  If the Library does not specify a
 151.426 +license version number, you may choose any version ever published by
 151.427 +the Free Software Foundation.
 151.428 +
 151.429 +  14. If you wish to incorporate parts of the Library into other free
 151.430 +programs whose distribution conditions are incompatible with these,
 151.431 +write to the author to ask for permission.  For software which is
 151.432 +copyrighted by the Free Software Foundation, write to the Free
 151.433 +Software Foundation; we sometimes make exceptions for this.  Our
 151.434 +decision will be guided by the two goals of preserving the free status
 151.435 +of all derivatives of our free software and of promoting the sharing
 151.436 +and reuse of software generally.
 151.437 +
 151.438 +                            NO WARRANTY
 151.439 +
 151.440 +  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
 151.441 +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
 151.442 +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
 151.443 +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
 151.444 +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
 151.445 +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 151.446 +PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
 151.447 +LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
 151.448 +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
 151.449 +
 151.450 +  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
 151.451 +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
 151.452 +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
 151.453 +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
 151.454 +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
 151.455 +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
 151.456 +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
 151.457 +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
 151.458 +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
 151.459 +DAMAGES.
 151.460 +
 151.461 +                     END OF TERMS AND CONDITIONS
 151.462 +
 151.463 +           How to Apply These Terms to Your New Libraries
 151.464 +
 151.465 +  If you develop a new library, and you want it to be of the greatest
 151.466 +possible use to the public, we recommend making it free software that
 151.467 +everyone can redistribute and change.  You can do so by permitting
 151.468 +redistribution under these terms (or, alternatively, under the terms of the
 151.469 +ordinary General Public License).
 151.470 +
 151.471 +  To apply these terms, attach the following notices to the library.  It is
 151.472 +safest to attach them to the start of each source file to most effectively
 151.473 +convey the exclusion of warranty; and each file should have at least the
 151.474 +"copyright" line and a pointer to where the full notice is found.
 151.475 +
 151.476 +    <one line to give the library's name and a brief idea of what it does.>
 151.477 +    Copyright (C) <year>  <name of author>
 151.478 +
 151.479 +    This library is free software; you can redistribute it and/or
 151.480 +    modify it under the terms of the GNU Lesser General Public
 151.481 +    License as published by the Free Software Foundation; either
 151.482 +    version 2.1 of the License, or (at your option) any later version.
 151.483 +
 151.484 +    This library is distributed in the hope that it will be useful,
 151.485 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
 151.486 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 151.487 +    Lesser General Public License for more details.
 151.488 +
 151.489 +    You should have received a copy of the GNU Lesser General Public
 151.490 +    License along with this library; if not, write to the Free Software
 151.491 +    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 151.492 +
 151.493 +Also add information on how to contact you by electronic and paper mail.
 151.494 +
 151.495 +You should also get your employer (if you work as a programmer) or your
 151.496 +school, if any, to sign a "copyright disclaimer" for the library, if
 151.497 +necessary.  Here is a sample; alter the names:
 151.498 +
 151.499 +  Yoyodyne, Inc., hereby disclaims all copyright interest in the
 151.500 +  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
 151.501 +
 151.502 +  <signature of Ty Coon>, 1 April 1990
 151.503 +  Ty Coon, President of Vice
 151.504 +
 151.505 +That's all there is to it!
   152.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   152.2 +++ b/src/colamd/README	Mon Dec 06 13:09:21 2010 +0100
   152.3 @@ -0,0 +1,98 @@
   152.4 +NOTE: Files in this subdirectory are NOT part of the GLPK package, but
   152.5 +      are used with GLPK.
   152.6 +
   152.7 +      The original code was modified according to GLPK requirements by
   152.8 +      Andrew Makhorin <mao@gnu.org>.
   152.9 +************************************************************************
  152.10 +COLAMD/SYMAMD Version 2.7, Copyright (C) 1998-2007, Timothy A. Davis,
  152.11 +All Rights Reserved.
  152.12 +
  152.13 +Description:
  152.14 +
  152.15 +   colamd:  an approximate minimum degree column ordering algorithm,
  152.16 +            for LU factorization of symmetric or unsymmetric matrices,
  152.17 +            QR factorization, least squares, interior point methods for
  152.18 +            linear programming problems, and other related problems.
  152.19 +
  152.20 +   symamd:  an approximate minimum degree ordering algorithm for
  152.21 +            Cholesky factorization of symmetric matrices.
  152.22 +
  152.23 +Purpose:
  152.24 +
  152.25 +   Colamd computes a permutation Q such that the Cholesky factorization
  152.26 +   of (AQ)'(AQ) has less fill-in and requires fewer floating point
  152.27 +   operations than A'A.  This also provides a good ordering for sparse
  152.28 +   partial pivoting methods, P(AQ) = LU, where Q is computed prior to
  152.29 +   numerical factorization, and P is computed during numerical
  152.30 +   factorization via conventional partial pivoting with row
  152.31 +   interchanges.  Colamd is the column ordering method used in SuperLU,
  152.32 +   part of the ScaLAPACK library.  It is also available as built-in
  152.33 +   function in MATLAB Version 6, available from MathWorks, Inc.
  152.34 +   (http://www.mathworks.com).  This routine can be used in place of
  152.35 +   colmmd in MATLAB.
  152.36 +
  152.37 +   Symamd computes a permutation P of a symmetric matrix A such that
  152.38 +   the Cholesky factorization of PAP' has less fill-in and requires
  152.39 +   fewer floating point operations than A.  Symamd constructs a matrix
  152.40 +   M such that M'M has the same nonzero pattern of A, and then orders
  152.41 +   the columns of M using colmmd.  The column ordering of M is then
  152.42 +   returned as the row and column ordering P of A.
  152.43 +
  152.44 +Authors:
  152.45 +
  152.46 +   The authors of the code itself are Stefan I. Larimore and Timothy A.
  152.47 +   Davis (davis at cise.ufl.edu), University of Florida.  The algorithm
  152.48 +   was developed in collaboration with John Gilbert, Xerox PARC, and
  152.49 +   Esmond Ng, Oak Ridge National Laboratory.
  152.50 +
  152.51 +Acknowledgements:
  152.52 +
  152.53 +   This work was supported by the National Science Foundation, under
  152.54 +   grants DMS-9504974 and DMS-9803599.
  152.55 +
  152.56 +License:
  152.57 +
  152.58 +   This library is free software; you can redistribute it and/or
  152.59 +   modify it under the terms of the GNU Lesser General Public License
  152.60 +   as published by the Free Software Foundation; either version 2.1 of
  152.61 +   the License, or (at your option) any later version.
  152.62 +
  152.63 +   This library is distributed in the hope that it will be useful,
  152.64 +   but WITHOUT ANY WARRANTY; without even the implied warranty of
  152.65 +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  152.66 +   Lesser General Public License for more details.
  152.67 +
  152.68 +   You should have received a copy of the GNU Lesser General Public
  152.69 +   License along with this library; if not, write to the Free Software
  152.70 +   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
  152.71 +   USA.
  152.72 +
  152.73 +   Permission is hereby granted to use or copy this program under the
  152.74 +   terms of the GNU LGPL, provided that the Copyright, this License,
  152.75 +   and the Availability of the original version is retained on all
  152.76 +   copies.  User documentation of any code that uses this code or any
  152.77 +   modified version of this code must cite the Copyright, this License,
  152.78 +   the Availability note, and "Used by permission."  Permission to
  152.79 +   modify the code and to distribute modified code is granted, provided
  152.80 +   the Copyright, this License, and the Availability note are retained,
  152.81 +   and a notice that the code was modified is included.
  152.82 +
  152.83 +   COLAMD is also available under alternate licenses, contact T. Davis
  152.84 +   for details.
  152.85 +
  152.86 +Availability:
  152.87 +
  152.88 +   The colamd/symamd library is available at:
  152.89 +
  152.90 +   http://www.cise.ufl.edu/research/sparse/colamd/
  152.91 +
  152.92 +References:
  152.93 +
  152.94 +   T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate
  152.95 +   column minimum degree ordering algorithm, ACM Transactions on
  152.96 +   Mathematical Software, vol. 30, no. 3., pp. 353-376, 2004.
  152.97 +
  152.98 +   T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836:
  152.99 +   COLAMD, an approximate column minimum degree ordering algorithm, ACM
 152.100 +   Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380,
 152.101 +   2004.
   153.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   153.2 +++ b/src/colamd/colamd.c	Mon Dec 06 13:09:21 2010 +0100
   153.3 @@ -0,0 +1,3622 @@
   153.4 +/* ========================================================================== */
   153.5 +/* === colamd/symamd - a sparse matrix column ordering algorithm ============ */
   153.6 +/* ========================================================================== */
   153.7 +
   153.8 +/* COLAMD / SYMAMD
   153.9 +
  153.10 +    colamd:  an approximate minimum degree column ordering algorithm,
  153.11 +        for LU factorization of symmetric or unsymmetric matrices,
  153.12 +        QR factorization, least squares, interior point methods for
  153.13 +        linear programming problems, and other related problems.
  153.14 +
  153.15 +    symamd:  an approximate minimum degree ordering algorithm for Cholesky
  153.16 +        factorization of symmetric matrices.
  153.17 +
  153.18 +    Purpose:
  153.19 +
  153.20 +        Colamd computes a permutation Q such that the Cholesky factorization of
  153.21 +        (AQ)'(AQ) has less fill-in and requires fewer floating point operations
  153.22 +        than A'A.  This also provides a good ordering for sparse partial
  153.23 +        pivoting methods, P(AQ) = LU, where Q is computed prior to numerical
  153.24 +        factorization, and P is computed during numerical factorization via
  153.25 +        conventional partial pivoting with row interchanges.  Colamd is the
  153.26 +        column ordering method used in SuperLU, part of the ScaLAPACK library.
  153.27 +        It is also available as built-in function in MATLAB Version 6,
  153.28 +        available from MathWorks, Inc. (http://www.mathworks.com).  This
  153.29 +        routine can be used in place of colmmd in MATLAB.
  153.30 +
  153.31 +        Symamd computes a permutation P of a symmetric matrix A such that the
  153.32 +        Cholesky factorization of PAP' has less fill-in and requires fewer
  153.33 +        floating point operations than A.  Symamd constructs a matrix M such
  153.34 +        that M'M has the same nonzero pattern of A, and then orders the columns
  153.35 +        of M using colmmd.  The column ordering of M is then returned as the
  153.36 +        row and column ordering P of A. 
  153.37 +
  153.38 +    Authors:
  153.39 +
  153.40 +        The authors of the code itself are Stefan I. Larimore and Timothy A.
  153.41 +        Davis (davis at cise.ufl.edu), University of Florida.  The algorithm was
  153.42 +        developed in collaboration with John Gilbert, Xerox PARC, and Esmond
  153.43 +        Ng, Oak Ridge National Laboratory.
  153.44 +
  153.45 +    Acknowledgements:
  153.46 +
  153.47 +        This work was supported by the National Science Foundation, under
  153.48 +        grants DMS-9504974 and DMS-9803599.
  153.49 +
  153.50 +    Copyright and License:
  153.51 +
  153.52 +        Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved.
  153.53 +        COLAMD is also available under alternate licenses, contact T. Davis
  153.54 +        for details.
  153.55 +
  153.56 +        This library is free software; you can redistribute it and/or
  153.57 +        modify it under the terms of the GNU Lesser General Public
  153.58 +        License as published by the Free Software Foundation; either
  153.59 +        version 2.1 of the License, or (at your option) any later version.
  153.60 +
  153.61 +        This library is distributed in the hope that it will be useful,
  153.62 +        but WITHOUT ANY WARRANTY; without even the implied warranty of
  153.63 +        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  153.64 +        Lesser General Public License for more details.
  153.65 +
  153.66 +        You should have received a copy of the GNU Lesser General Public
  153.67 +        License along with this library; if not, write to the Free Software
  153.68 +        Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
  153.69 +        USA
  153.70 +
  153.71 +        Permission is hereby granted to use or copy this program under the
  153.72 +        terms of the GNU LGPL, provided that the Copyright, this License,
  153.73 +        and the Availability of the original version is retained on all copies.
  153.74 +        User documentation of any code that uses this code or any modified
  153.75 +        version of this code must cite the Copyright, this License, the
  153.76 +        Availability note, and "Used by permission." Permission to modify
  153.77 +        the code and to distribute modified code is granted, provided the
  153.78 +        Copyright, this License, and the Availability note are retained,
  153.79 +        and a notice that the code was modified is included.
  153.80 +
  153.81 +    Availability:
  153.82 +
  153.83 +        The colamd/symamd library is available at
  153.84 +
  153.85 +            http://www.cise.ufl.edu/research/sparse/colamd/
  153.86 +
  153.87 +        This is the http://www.cise.ufl.edu/research/sparse/colamd/colamd.c
  153.88 +        file.  It requires the colamd.h file.  It is required by the colamdmex.c
  153.89 +        and symamdmex.c files, for the MATLAB interface to colamd and symamd.
  153.90 +        Appears as ACM Algorithm 836.
  153.91 +
  153.92 +    See the ChangeLog file for changes since Version 1.0.
  153.93 +
  153.94 +    References:
  153.95 +
  153.96 +        T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate column
  153.97 +        minimum degree ordering algorithm, ACM Transactions on Mathematical
  153.98 +        Software, vol. 30, no. 3., pp. 353-376, 2004.
  153.99 +
 153.100 +        T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836: COLAMD,
 153.101 +        an approximate column minimum degree ordering algorithm, ACM
 153.102 +        Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380,
 153.103 +        2004.
 153.104 +
 153.105 +*/
 153.106 +
 153.107 +/* ========================================================================== */
 153.108 +/* === Description of user-callable routines ================================ */
 153.109 +/* ========================================================================== */
 153.110 +
 153.111 +/* COLAMD includes both int and UF_long versions of all its routines.  The
 153.112 + * description below is for the int version.  For UF_long, all int arguments
 153.113 + * become UF_long.  UF_long is normally defined as long, except for WIN64.
 153.114 +
 153.115 +    ----------------------------------------------------------------------------
 153.116 +    colamd_recommended:
 153.117 +    ----------------------------------------------------------------------------
 153.118 +
 153.119 +        C syntax:
 153.120 +
 153.121 +            #include "colamd.h"
 153.122 +            size_t colamd_recommended (int nnz, int n_row, int n_col) ;
 153.123 +            size_t colamd_l_recommended (UF_long nnz, UF_long n_row,
 153.124 +                UF_long n_col) ;
 153.125 +
 153.126 +        Purpose:
 153.127 +
 153.128 +            Returns recommended value of Alen for use by colamd.  Returns 0
 153.129 +            if any input argument is negative.  The use of this routine
 153.130 +            is optional.  Not needed for symamd, which dynamically allocates
 153.131 +            its own memory.
 153.132 +
 153.133 +            Note that in v2.4 and earlier, these routines returned int or long.
 153.134 +            They now return a value of type size_t.
 153.135 +
 153.136 +        Arguments (all input arguments):
 153.137 +
 153.138 +            int nnz ;           Number of nonzeros in the matrix A.  This must
 153.139 +                                be the same value as p [n_col] in the call to
 153.140 +                                colamd - otherwise you will get a wrong value
 153.141 +                                of the recommended memory to use.
 153.142 +
 153.143 +            int n_row ;         Number of rows in the matrix A.
 153.144 +
 153.145 +            int n_col ;         Number of columns in the matrix A.
 153.146 +
 153.147 +    ----------------------------------------------------------------------------
 153.148 +    colamd_set_defaults:
 153.149 +    ----------------------------------------------------------------------------
 153.150 +
 153.151 +        C syntax:
 153.152 +
 153.153 +            #include "colamd.h"
 153.154 +            colamd_set_defaults (double knobs [COLAMD_KNOBS]) ;
 153.155 +            colamd_l_set_defaults (double knobs [COLAMD_KNOBS]) ;
 153.156 +
 153.157 +        Purpose:
 153.158 +
 153.159 +            Sets the default parameters.  The use of this routine is optional.
 153.160 +
 153.161 +        Arguments:
 153.162 +
 153.163 +            double knobs [COLAMD_KNOBS] ;       Output only.
 153.164 +
 153.165 +                NOTE: the meaning of the dense row/col knobs has changed in v2.4
 153.166 +
 153.167 +                knobs [0] and knobs [1] control dense row and col detection:
 153.168 +
 153.169 +                Colamd: rows with more than
 153.170 +                max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n_col))
 153.171 +                entries are removed prior to ordering.  Columns with more than
 153.172 +                max (16, knobs [COLAMD_DENSE_COL] * sqrt (MIN (n_row,n_col)))
 153.173 +                entries are removed prior to
 153.174 +                ordering, and placed last in the output column ordering. 
 153.175 +
 153.176 +                Symamd: uses only knobs [COLAMD_DENSE_ROW], which is knobs [0].
 153.177 +                Rows and columns with more than
 153.178 +                max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n))
 153.179 +                entries are removed prior to ordering, and placed last in the
 153.180 +                output ordering.
 153.181 +
 153.182 +                COLAMD_DENSE_ROW and COLAMD_DENSE_COL are defined as 0 and 1,
 153.183 +                respectively, in colamd.h.  Default values of these two knobs
 153.184 +                are both 10.  Currently, only knobs [0] and knobs [1] are
 153.185 +                used, but future versions may use more knobs.  If so, they will
 153.186 +                be properly set to their defaults by the future version of
 153.187 +                colamd_set_defaults, so that the code that calls colamd will
 153.188 +                not need to change, assuming that you either use
 153.189 +                colamd_set_defaults, or pass a (double *) NULL pointer as the
 153.190 +                knobs array to colamd or symamd.
 153.191 +
 153.192 +            knobs [2]: aggressive absorption
 153.193 +
 153.194 +                knobs [COLAMD_AGGRESSIVE] controls whether or not to do
 153.195 +                aggressive absorption during the ordering.  Default is TRUE.
 153.196 +
 153.197 +
 153.198 +    ----------------------------------------------------------------------------
 153.199 +    colamd:
 153.200 +    ----------------------------------------------------------------------------
 153.201 +
 153.202 +        C syntax:
 153.203 +
 153.204 +            #include "colamd.h"
 153.205 +            int colamd (int n_row, int n_col, int Alen, int *A, int *p,
 153.206 +                double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS]) ;
 153.207 +            UF_long colamd_l (UF_long n_row, UF_long n_col, UF_long Alen,
 153.208 +                UF_long *A, UF_long *p, double knobs [COLAMD_KNOBS],
 153.209 +                UF_long stats [COLAMD_STATS]) ;
 153.210 +
 153.211 +        Purpose:
 153.212 +
 153.213 +            Computes a column ordering (Q) of A such that P(AQ)=LU or
 153.214 +            (AQ)'AQ=LL' have less fill-in and require fewer floating point
 153.215 +            operations than factorizing the unpermuted matrix A or A'A,
 153.216 +            respectively.
 153.217 +            
 153.218 +        Returns:
 153.219 +
 153.220 +            TRUE (1) if successful, FALSE (0) otherwise.
 153.221 +
 153.222 +        Arguments:
 153.223 +
 153.224 +            int n_row ;         Input argument.
 153.225 +
 153.226 +                Number of rows in the matrix A.
 153.227 +                Restriction:  n_row >= 0.
 153.228 +                Colamd returns FALSE if n_row is negative.
 153.229 +
 153.230 +            int n_col ;         Input argument.
 153.231 +
 153.232 +                Number of columns in the matrix A.
 153.233 +                Restriction:  n_col >= 0.
 153.234 +                Colamd returns FALSE if n_col is negative.
 153.235 +
 153.236 +            int Alen ;          Input argument.
 153.237 +
 153.238 +                Restriction (see note):
 153.239 +                Alen >= 2*nnz + 6*(n_col+1) + 4*(n_row+1) + n_col
 153.240 +                Colamd returns FALSE if these conditions are not met.
 153.241 +
 153.242 +                Note:  this restriction makes an modest assumption regarding
 153.243 +                the size of the two typedef's structures in colamd.h.
 153.244 +                We do, however, guarantee that
 153.245 +
 153.246 +                        Alen >= colamd_recommended (nnz, n_row, n_col)
 153.247 +
 153.248 +                will be sufficient.  Note: the macro version does not check
 153.249 +                for integer overflow, and thus is not recommended.  Use
 153.250 +                the colamd_recommended routine instead.
 153.251 +
 153.252 +            int A [Alen] ;      Input argument, undefined on output.
 153.253 +
 153.254 +                A is an integer array of size Alen.  Alen must be at least as
 153.255 +                large as the bare minimum value given above, but this is very
 153.256 +                low, and can result in excessive run time.  For best
 153.257 +                performance, we recommend that Alen be greater than or equal to
 153.258 +                colamd_recommended (nnz, n_row, n_col), which adds
 153.259 +                nnz/5 to the bare minimum value given above.
 153.260 +
 153.261 +                On input, the row indices of the entries in column c of the
 153.262 +                matrix are held in A [(p [c]) ... (p [c+1]-1)].  The row indices
 153.263 +                in a given column c need not be in ascending order, and
 153.264 +                duplicate row indices may be be present.  However, colamd will
 153.265 +                work a little faster if both of these conditions are met
 153.266 +                (Colamd puts the matrix into this format, if it finds that the
 153.267 +                the conditions are not met).
 153.268 +
 153.269 +                The matrix is 0-based.  That is, rows are in the range 0 to
 153.270 +                n_row-1, and columns are in the range 0 to n_col-1.  Colamd
 153.271 +                returns FALSE if any row index is out of range.
 153.272 +
 153.273 +                The contents of A are modified during ordering, and are
 153.274 +                undefined on output.
 153.275 +
 153.276 +            int p [n_col+1] ;   Both input and output argument.
 153.277 +
 153.278 +                p is an integer array of size n_col+1.  On input, it holds the
 153.279 +                "pointers" for the column form of the matrix A.  Column c of
 153.280 +                the matrix A is held in A [(p [c]) ... (p [c+1]-1)].  The first
 153.281 +                entry, p [0], must be zero, and p [c] <= p [c+1] must hold
 153.282 +                for all c in the range 0 to n_col-1.  The value p [n_col] is
 153.283 +                thus the total number of entries in the pattern of the matrix A.
 153.284 +                Colamd returns FALSE if these conditions are not met.
 153.285 +
 153.286 +                On output, if colamd returns TRUE, the array p holds the column
 153.287 +                permutation (Q, for P(AQ)=LU or (AQ)'(AQ)=LL'), where p [0] is
 153.288 +                the first column index in the new ordering, and p [n_col-1] is
 153.289 +                the last.  That is, p [k] = j means that column j of A is the
 153.290 +                kth pivot column, in AQ, where k is in the range 0 to n_col-1
 153.291 +                (p [0] = j means that column j of A is the first column in AQ).
 153.292 +
 153.293 +                If colamd returns FALSE, then no permutation is returned, and
 153.294 +                p is undefined on output.
 153.295 +
 153.296 +            double knobs [COLAMD_KNOBS] ;       Input argument.
 153.297 +
 153.298 +                See colamd_set_defaults for a description.
 153.299 +
 153.300 +            int stats [COLAMD_STATS] ;          Output argument.
 153.301 +
 153.302 +                Statistics on the ordering, and error status.
 153.303 +                See colamd.h for related definitions.
 153.304 +                Colamd returns FALSE if stats is not present.
 153.305 +
 153.306 +                stats [0]:  number of dense or empty rows ignored.
 153.307 +
 153.308 +                stats [1]:  number of dense or empty columns ignored (and
 153.309 +                                ordered last in the output permutation p)
 153.310 +                                Note that a row can become "empty" if it
 153.311 +                                contains only "dense" and/or "empty" columns,
 153.312 +                                and similarly a column can become "empty" if it
 153.313 +                                only contains "dense" and/or "empty" rows.
 153.314 +
 153.315 +                stats [2]:  number of garbage collections performed.
 153.316 +                                This can be excessively high if Alen is close
 153.317 +                                to the minimum required value.
 153.318 +
 153.319 +                stats [3]:  status code.  < 0 is an error code.
 153.320 +                            > 1 is a warning or notice.
 153.321 +
 153.322 +                        0       OK.  Each column of the input matrix contained
 153.323 +                                row indices in increasing order, with no
 153.324 +                                duplicates.
 153.325 +
 153.326 +                        1       OK, but columns of input matrix were jumbled
 153.327 +                                (unsorted columns or duplicate entries).  Colamd
 153.328 +                                had to do some extra work to sort the matrix
 153.329 +                                first and remove duplicate entries, but it
 153.330 +                                still was able to return a valid permutation
 153.331 +                                (return value of colamd was TRUE).
 153.332 +
 153.333 +                                        stats [4]: highest numbered column that
 153.334 +                                                is unsorted or has duplicate
 153.335 +                                                entries.
 153.336 +                                        stats [5]: last seen duplicate or
 153.337 +                                                unsorted row index.
 153.338 +                                        stats [6]: number of duplicate or
 153.339 +                                                unsorted row indices.
 153.340 +
 153.341 +                        -1      A is a null pointer
 153.342 +
 153.343 +                        -2      p is a null pointer
 153.344 +
 153.345 +                        -3      n_row is negative
 153.346 +
 153.347 +                                        stats [4]: n_row
 153.348 +
 153.349 +                        -4      n_col is negative
 153.350 +
 153.351 +                                        stats [4]: n_col
 153.352 +
 153.353 +                        -5      number of nonzeros in matrix is negative
 153.354 +
 153.355 +                                        stats [4]: number of nonzeros, p [n_col]
 153.356 +
 153.357 +                        -6      p [0] is nonzero
 153.358 +
 153.359 +                                        stats [4]: p [0]
 153.360 +
 153.361 +                        -7      A is too small
 153.362 +
 153.363 +                                        stats [4]: required size
 153.364 +                                        stats [5]: actual size (Alen)
 153.365 +
 153.366 +                        -8      a column has a negative number of entries
 153.367 +
 153.368 +                                        stats [4]: column with < 0 entries
 153.369 +                                        stats [5]: number of entries in col
 153.370 +
 153.371 +                        -9      a row index is out of bounds
 153.372 +
 153.373 +                                        stats [4]: column with bad row index
 153.374 +                                        stats [5]: bad row index
 153.375 +                                        stats [6]: n_row, # of rows of matrx
 153.376 +
 153.377 +                        -10     (unused; see symamd.c)
 153.378 +
 153.379 +                        -999    (unused; see symamd.c)
 153.380 +
 153.381 +                Future versions may return more statistics in the stats array.
 153.382 +
 153.383 +        Example:
 153.384 +        
 153.385 +            See http://www.cise.ufl.edu/research/sparse/colamd/example.c
 153.386 +            for a complete example.
 153.387 +
 153.388 +            To order the columns of a 5-by-4 matrix with 11 nonzero entries in
 153.389 +            the following nonzero pattern
 153.390 +
 153.391 +                x 0 x 0
 153.392 +                x 0 x x
 153.393 +                0 x x 0
 153.394 +                0 0 x x
 153.395 +                x x 0 0
 153.396 +
 153.397 +            with default knobs and no output statistics, do the following:
 153.398 +
 153.399 +                #include "colamd.h"
 153.400 +                #define ALEN 100
 153.401 +                int A [ALEN] = {0, 1, 4, 2, 4, 0, 1, 2, 3, 1, 3} ;
 153.402 +                int p [ ] = {0, 3, 5, 9, 11} ;
 153.403 +                int stats [COLAMD_STATS] ;
 153.404 +                colamd (5, 4, ALEN, A, p, (double *) NULL, stats) ;
 153.405 +
 153.406 +            The permutation is returned in the array p, and A is destroyed.
 153.407 +
 153.408 +    ----------------------------------------------------------------------------
 153.409 +    symamd:
 153.410 +    ----------------------------------------------------------------------------
 153.411 +
 153.412 +        C syntax:
 153.413 +
 153.414 +            #include "colamd.h"
 153.415 +            int symamd (int n, int *A, int *p, int *perm,
 153.416 +                double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS],
 153.417 +                void (*allocate) (size_t, size_t), void (*release) (void *)) ;
 153.418 +            UF_long symamd_l (UF_long n, UF_long *A, UF_long *p, UF_long *perm,
 153.419 +                double knobs [COLAMD_KNOBS], UF_long stats [COLAMD_STATS],
 153.420 +                void (*allocate) (size_t, size_t), void (*release) (void *)) ;
 153.421 +
 153.422 +        Purpose:
 153.423 +
 153.424 +            The symamd routine computes an ordering P of a symmetric sparse
 153.425 +            matrix A such that the Cholesky factorization PAP' = LL' remains
 153.426 +            sparse.  It is based on a column ordering of a matrix M constructed
 153.427 +            so that the nonzero pattern of M'M is the same as A.  The matrix A
 153.428 +            is assumed to be symmetric; only the strictly lower triangular part
 153.429 +            is accessed.  You must pass your selected memory allocator (usually
 153.430 +            calloc/free or mxCalloc/mxFree) to symamd, for it to allocate
 153.431 +            memory for the temporary matrix M.
 153.432 +
 153.433 +        Returns:
 153.434 +
 153.435 +            TRUE (1) if successful, FALSE (0) otherwise.
 153.436 +
 153.437 +        Arguments:
 153.438 +
 153.439 +            int n ;             Input argument.
 153.440 +
 153.441 +                Number of rows and columns in the symmetrix matrix A.
 153.442 +                Restriction:  n >= 0.
 153.443 +                Symamd returns FALSE if n is negative.
 153.444 +
 153.445 +            int A [nnz] ;       Input argument.
 153.446 +
 153.447 +                A is an integer array of size nnz, where nnz = p [n].
 153.448 +                
 153.449 +                The row indices of the entries in column c of the matrix are
 153.450 +                held in A [(p [c]) ... (p [c+1]-1)].  The row indices in a
 153.451 +                given column c need not be in ascending order, and duplicate
 153.452 +                row indices may be present.  However, symamd will run faster
 153.453 +                if the columns are in sorted order with no duplicate entries. 
 153.454 +
 153.455 +                The matrix is 0-based.  That is, rows are in the range 0 to
 153.456 +                n-1, and columns are in the range 0 to n-1.  Symamd
 153.457 +                returns FALSE if any row index is out of range.
 153.458 +
 153.459 +                The contents of A are not modified.
 153.460 +
 153.461 +            int p [n+1] ;       Input argument.
 153.462 +
 153.463 +                p is an integer array of size n+1.  On input, it holds the
 153.464 +                "pointers" for the column form of the matrix A.  Column c of
 153.465 +                the matrix A is held in A [(p [c]) ... (p [c+1]-1)].  The first
 153.466 +                entry, p [0], must be zero, and p [c] <= p [c+1] must hold
 153.467 +                for all c in the range 0 to n-1.  The value p [n] is
 153.468 +                thus the total number of entries in the pattern of the matrix A.
 153.469 +                Symamd returns FALSE if these conditions are not met.
 153.470 +
 153.471 +                The contents of p are not modified.
 153.472 +
 153.473 +            int perm [n+1] ;    Output argument.
 153.474 +
 153.475 +                On output, if symamd returns TRUE, the array perm holds the
 153.476 +                permutation P, where perm [0] is the first index in the new
 153.477 +                ordering, and perm [n-1] is the last.  That is, perm [k] = j
 153.478 +                means that row and column j of A is the kth column in PAP',
 153.479 +                where k is in the range 0 to n-1 (perm [0] = j means
 153.480 +                that row and column j of A are the first row and column in
 153.481 +                PAP').  The array is used as a workspace during the ordering,
 153.482 +                which is why it must be of length n+1, not just n.
 153.483 +
 153.484 +            double knobs [COLAMD_KNOBS] ;       Input argument.
 153.485 +
 153.486 +                See colamd_set_defaults for a description.
 153.487 +
 153.488 +            int stats [COLAMD_STATS] ;          Output argument.
 153.489 +
 153.490 +                Statistics on the ordering, and error status.
 153.491 +                See colamd.h for related definitions.
 153.492 +                Symamd returns FALSE if stats is not present.
 153.493 +
 153.494 +                stats [0]:  number of dense or empty row and columns ignored
 153.495 +                                (and ordered last in the output permutation 
 153.496 +                                perm).  Note that a row/column can become
 153.497 +                                "empty" if it contains only "dense" and/or
 153.498 +                                "empty" columns/rows.
 153.499 +
 153.500 +                stats [1]:  (same as stats [0])
 153.501 +
 153.502 +                stats [2]:  number of garbage collections performed.
 153.503 +
 153.504 +                stats [3]:  status code.  < 0 is an error code.
 153.505 +                            > 1 is a warning or notice.
 153.506 +
 153.507 +                        0       OK.  Each column of the input matrix contained
 153.508 +                                row indices in increasing order, with no
 153.509 +                                duplicates.
 153.510 +
 153.511 +                        1       OK, but columns of input matrix were jumbled
 153.512 +                                (unsorted columns or duplicate entries).  Symamd
 153.513 +                                had to do some extra work to sort the matrix
 153.514 +                                first and remove duplicate entries, but it
 153.515 +                                still was able to return a valid permutation
 153.516 +                                (return value of symamd was TRUE).
 153.517 +
 153.518 +                                        stats [4]: highest numbered column that
 153.519 +                                                is unsorted or has duplicate
 153.520 +                                                entries.
 153.521 +                                        stats [5]: last seen duplicate or
 153.522 +                                                unsorted row index.
 153.523 +                                        stats [6]: number of duplicate or
 153.524 +                                                unsorted row indices.
 153.525 +
 153.526 +                        -1      A is a null pointer
 153.527 +
 153.528 +                        -2      p is a null pointer
 153.529 +
 153.530 +                        -3      (unused, see colamd.c)
 153.531 +
 153.532 +                        -4      n is negative
 153.533 +
 153.534 +                                        stats [4]: n
 153.535 +
 153.536 +                        -5      number of nonzeros in matrix is negative
 153.537 +
 153.538 +                                        stats [4]: # of nonzeros (p [n]).
 153.539 +
 153.540 +                        -6      p [0] is nonzero
 153.541 +
 153.542 +                                        stats [4]: p [0]
 153.543 +
 153.544 +                        -7      (unused)
 153.545 +
 153.546 +                        -8      a column has a negative number of entries
 153.547 +
 153.548 +                                        stats [4]: column with < 0 entries
 153.549 +                                        stats [5]: number of entries in col
 153.550 +
 153.551 +                        -9      a row index is out of bounds
 153.552 +
 153.553 +                                        stats [4]: column with bad row index
 153.554 +                                        stats [5]: bad row index
 153.555 +                                        stats [6]: n_row, # of rows of matrx
 153.556 +
 153.557 +                        -10     out of memory (unable to allocate temporary
 153.558 +                                workspace for M or count arrays using the
 153.559 +                                "allocate" routine passed into symamd).
 153.560 +
 153.561 +                Future versions may return more statistics in the stats array.
 153.562 +
 153.563 +            void * (*allocate) (size_t, size_t)
 153.564 +
 153.565 +                A pointer to a function providing memory allocation.  The
 153.566 +                allocated memory must be returned initialized to zero.  For a
 153.567 +                C application, this argument should normally be a pointer to
 153.568 +                calloc.  For a MATLAB mexFunction, the routine mxCalloc is
 153.569 +                passed instead.
 153.570 +
 153.571 +            void (*release) (size_t, size_t)
 153.572 +
 153.573 +                A pointer to a function that frees memory allocated by the
 153.574 +                memory allocation routine above.  For a C application, this
 153.575 +                argument should normally be a pointer to free.  For a MATLAB
 153.576 +                mexFunction, the routine mxFree is passed instead.
 153.577 +
 153.578 +
 153.579 +    ----------------------------------------------------------------------------
 153.580 +    colamd_report:
 153.581 +    ----------------------------------------------------------------------------
 153.582 +
 153.583 +        C syntax:
 153.584 +
 153.585 +            #include "colamd.h"
 153.586 +            colamd_report (int stats [COLAMD_STATS]) ;
 153.587 +            colamd_l_report (UF_long stats [COLAMD_STATS]) ;
 153.588 +
 153.589 +        Purpose:
 153.590 +
 153.591 +            Prints the error status and statistics recorded in the stats
 153.592 +            array on the standard error output (for a standard C routine)
 153.593 +            or on the MATLAB output (for a mexFunction).
 153.594 +
 153.595 +        Arguments:
 153.596 +
 153.597 +            int stats [COLAMD_STATS] ;  Input only.  Statistics from colamd.
 153.598 +
 153.599 +
 153.600 +    ----------------------------------------------------------------------------
 153.601 +    symamd_report:
 153.602 +    ----------------------------------------------------------------------------
 153.603 +
 153.604 +        C syntax:
 153.605 +
 153.606 +            #include "colamd.h"
 153.607 +            symamd_report (int stats [COLAMD_STATS]) ;
 153.608 +            symamd_l_report (UF_long stats [COLAMD_STATS]) ;
 153.609 +
 153.610 +        Purpose:
 153.611 +
 153.612 +            Prints the error status and statistics recorded in the stats
 153.613 +            array on the standard error output (for a standard C routine)
 153.614 +            or on the MATLAB output (for a mexFunction).
 153.615 +
 153.616 +        Arguments:
 153.617 +
 153.618 +            int stats [COLAMD_STATS] ;  Input only.  Statistics from symamd.
 153.619 +
 153.620 +
 153.621 +*/
 153.622 +
 153.623 +/* ========================================================================== */
 153.624 +/* === Scaffolding code definitions  ======================================== */
 153.625 +/* ========================================================================== */
 153.626 +
 153.627 +/* Ensure that debugging is turned off: */
 153.628 +#ifndef NDEBUG
 153.629 +#define NDEBUG
 153.630 +#endif
 153.631 +
 153.632 +/* turn on debugging by uncommenting the following line
 153.633 + #undef NDEBUG
 153.634 +*/
 153.635 +
 153.636 +/*
 153.637 +   Our "scaffolding code" philosophy:  In our opinion, well-written library
 153.638 +   code should keep its "debugging" code, and just normally have it turned off
 153.639 +   by the compiler so as not to interfere with performance.  This serves
 153.640 +   several purposes:
 153.641 +
 153.642 +   (1) assertions act as comments to the reader, telling you what the code
 153.643 +        expects at that point.  All assertions will always be true (unless
 153.644 +        there really is a bug, of course).
 153.645 +
 153.646 +   (2) leaving in the scaffolding code assists anyone who would like to modify
 153.647 +        the code, or understand the algorithm (by reading the debugging output,
 153.648 +        one can get a glimpse into what the code is doing).
 153.649 +
 153.650 +   (3) (gasp!) for actually finding bugs.  This code has been heavily tested
 153.651 +        and "should" be fully functional and bug-free ... but you never know...
 153.652 +
 153.653 +    The code will become outrageously slow when debugging is
 153.654 +    enabled.  To control the level of debugging output, set an environment
 153.655 +    variable D to 0 (little), 1 (some), 2, 3, or 4 (lots).  When debugging,
 153.656 +    you should see the following message on the standard output:
 153.657 +
 153.658 +        colamd: debug version, D = 1 (THIS WILL BE SLOW!)
 153.659 +
 153.660 +    or a similar message for symamd.  If you don't, then debugging has not
 153.661 +    been enabled.
 153.662 +
 153.663 +*/
 153.664 +
 153.665 +/* ========================================================================== */
 153.666 +/* === Include files ======================================================== */
 153.667 +/* ========================================================================== */
 153.668 +
 153.669 +#include "colamd.h"
 153.670 +
 153.671 +#if 0 /* by mao */
 153.672 +#include <limits.h>
 153.673 +#include <math.h>
 153.674 +
 153.675 +#ifdef MATLAB_MEX_FILE
 153.676 +#include "mex.h"
 153.677 +#include "matrix.h"
 153.678 +#endif /* MATLAB_MEX_FILE */
 153.679 +
 153.680 +#if !defined (NPRINT) || !defined (NDEBUG)
 153.681 +#include <stdio.h>
 153.682 +#endif
 153.683 +
 153.684 +#ifndef NULL
 153.685 +#define NULL ((void *) 0)
 153.686 +#endif
 153.687 +#endif
 153.688 +
 153.689 +/* ========================================================================== */
 153.690 +/* === int or UF_long ======================================================= */
 153.691 +/* ========================================================================== */
 153.692 +
 153.693 +#if 0 /* by mao */
 153.694 +/* define UF_long */
 153.695 +#include "UFconfig.h"
 153.696 +#endif
 153.697 +
 153.698 +#ifdef DLONG
 153.699 +
 153.700 +#define Int UF_long
 153.701 +#define ID  UF_long_id
 153.702 +#define Int_MAX UF_long_max
 153.703 +
 153.704 +#define COLAMD_recommended colamd_l_recommended
 153.705 +#define COLAMD_set_defaults colamd_l_set_defaults
 153.706 +#define COLAMD_MAIN colamd_l
 153.707 +#define SYMAMD_MAIN symamd_l
 153.708 +#define COLAMD_report colamd_l_report
 153.709 +#define SYMAMD_report symamd_l_report
 153.710 +
 153.711 +#else
 153.712 +
 153.713 +#define Int int
 153.714 +#define ID "%d"
 153.715 +#define Int_MAX INT_MAX
 153.716 +
 153.717 +#define COLAMD_recommended colamd_recommended
 153.718 +#define COLAMD_set_defaults colamd_set_defaults
 153.719 +#define COLAMD_MAIN colamd
 153.720 +#define SYMAMD_MAIN symamd
 153.721 +#define COLAMD_report colamd_report
 153.722 +#define SYMAMD_report symamd_report
 153.723 +
 153.724 +#endif
 153.725 +
 153.726 +/* ========================================================================== */
 153.727 +/* === Row and Column structures ============================================ */
 153.728 +/* ========================================================================== */
 153.729 +
 153.730 +/* User code that makes use of the colamd/symamd routines need not directly */
 153.731 +/* reference these structures.  They are used only for colamd_recommended. */
 153.732 +
 153.733 +typedef struct Colamd_Col_struct
 153.734 +{
 153.735 +    Int start ;         /* index for A of first row in this column, or DEAD */
 153.736 +                        /* if column is dead */
 153.737 +    Int length ;        /* number of rows in this column */
 153.738 +    union
 153.739 +    {
 153.740 +        Int thickness ; /* number of original columns represented by this */
 153.741 +                        /* col, if the column is alive */
 153.742 +        Int parent ;    /* parent in parent tree super-column structure, if */
 153.743 +                        /* the column is dead */
 153.744 +    } shared1 ;
 153.745 +    union
 153.746 +    {
 153.747 +        Int score ;     /* the score used to maintain heap, if col is alive */
 153.748 +        Int order ;     /* pivot ordering of this column, if col is dead */
 153.749 +    } shared2 ;
 153.750 +    union
 153.751 +    {
 153.752 +        Int headhash ;  /* head of a hash bucket, if col is at the head of */
 153.753 +                        /* a degree list */
 153.754 +        Int hash ;      /* hash value, if col is not in a degree list */
 153.755 +        Int prev ;      /* previous column in degree list, if col is in a */
 153.756 +                        /* degree list (but not at the head of a degree list) */
 153.757 +    } shared3 ;
 153.758 +    union
 153.759 +    {
 153.760 +        Int degree_next ;       /* next column, if col is in a degree list */
 153.761 +        Int hash_next ;         /* next column, if col is in a hash list */
 153.762 +    } shared4 ;
 153.763 +
 153.764 +} Colamd_Col ;
 153.765 +
 153.766 +typedef struct Colamd_Row_struct
 153.767 +{
 153.768 +    Int start ;         /* index for A of first col in this row */
 153.769 +    Int length ;        /* number of principal columns in this row */
 153.770 +    union
 153.771 +    {
 153.772 +        Int degree ;    /* number of principal & non-principal columns in row */
 153.773 +        Int p ;         /* used as a row pointer in init_rows_cols () */
 153.774 +    } shared1 ;
 153.775 +    union
 153.776 +    {
 153.777 +        Int mark ;      /* for computing set differences and marking dead rows*/
 153.778 +        Int first_column ;/* first column in row (used in garbage collection) */
 153.779 +    } shared2 ;
 153.780 +
 153.781 +} Colamd_Row ;
 153.782 +
 153.783 +/* ========================================================================== */
 153.784 +/* === Definitions ========================================================== */
 153.785 +/* ========================================================================== */
 153.786 +
 153.787 +/* Routines are either PUBLIC (user-callable) or PRIVATE (not user-callable) */
 153.788 +#define PUBLIC
 153.789 +#define PRIVATE static
 153.790 +
 153.791 +#define DENSE_DEGREE(alpha,n) \
 153.792 +    ((Int) MAX (16.0, (alpha) * sqrt ((double) (n))))
 153.793 +
 153.794 +#define MAX(a,b) (((a) > (b)) ? (a) : (b))
 153.795 +#define MIN(a,b) (((a) < (b)) ? (a) : (b))
 153.796 +
 153.797 +#define ONES_COMPLEMENT(r) (-(r)-1)
 153.798 +
 153.799 +/* -------------------------------------------------------------------------- */
 153.800 +/* Change for version 2.1:  define TRUE and FALSE only if not yet defined */  
 153.801 +/* -------------------------------------------------------------------------- */
 153.802 +
 153.803 +#ifndef TRUE
 153.804 +#define TRUE (1)
 153.805 +#endif
 153.806 +
 153.807 +#ifndef FALSE
 153.808 +#define FALSE (0)
 153.809 +#endif
 153.810 +
 153.811 +/* -------------------------------------------------------------------------- */
 153.812 +
 153.813 +#define EMPTY   (-1)
 153.814 +
 153.815 +/* Row and column status */
 153.816 +#define ALIVE   (0)
 153.817 +#define DEAD    (-1)
 153.818 +
 153.819 +/* Column status */
 153.820 +#define DEAD_PRINCIPAL          (-1)
 153.821 +#define DEAD_NON_PRINCIPAL      (-2)
 153.822 +
 153.823 +/* Macros for row and column status update and checking. */
 153.824 +#define ROW_IS_DEAD(r)                  ROW_IS_MARKED_DEAD (Row[r].shared2.mark)
 153.825 +#define ROW_IS_MARKED_DEAD(row_mark)    (row_mark < ALIVE)
 153.826 +#define ROW_IS_ALIVE(r)                 (Row [r].shared2.mark >= ALIVE)
 153.827 +#define COL_IS_DEAD(c)                  (Col [c].start < ALIVE)
 153.828 +#define COL_IS_ALIVE(c)                 (Col [c].start >= ALIVE)
 153.829 +#define COL_IS_DEAD_PRINCIPAL(c)        (Col [c].start == DEAD_PRINCIPAL)
 153.830 +#define KILL_ROW(r)                     { Row [r].shared2.mark = DEAD ; }
 153.831 +#define KILL_PRINCIPAL_COL(c)           { Col [c].start = DEAD_PRINCIPAL ; }
 153.832 +#define KILL_NON_PRINCIPAL_COL(c)       { Col [c].start = DEAD_NON_PRINCIPAL ; }
 153.833 +
 153.834 +/* ========================================================================== */
 153.835 +/* === Colamd reporting mechanism =========================================== */
 153.836 +/* ========================================================================== */
 153.837 +
 153.838 +#if defined (MATLAB_MEX_FILE) || defined (MATHWORKS)
 153.839 +/* In MATLAB, matrices are 1-based to the user, but 0-based internally */
 153.840 +#define INDEX(i) ((i)+1)
 153.841 +#else
 153.842 +/* In C, matrices are 0-based and indices are reported as such in *_report */
 153.843 +#define INDEX(i) (i)
 153.844 +#endif
 153.845 +
 153.846 +/* All output goes through the PRINTF macro.  */
 153.847 +#define PRINTF(params) { if (colamd_printf != NULL) (void) colamd_printf params ; }
 153.848 +
 153.849 +/* ========================================================================== */
 153.850 +/* === Prototypes of PRIVATE routines ======================================= */
 153.851 +/* ========================================================================== */
 153.852 +
 153.853 +PRIVATE Int init_rows_cols
 153.854 +(
 153.855 +    Int n_row,
 153.856 +    Int n_col,
 153.857 +    Colamd_Row Row [],
 153.858 +    Colamd_Col Col [],
 153.859 +    Int A [],
 153.860 +    Int p [],
 153.861 +    Int stats [COLAMD_STATS]
 153.862 +) ;
 153.863 +
 153.864 +PRIVATE void init_scoring
 153.865 +(
 153.866 +    Int n_row,
 153.867 +    Int n_col,
 153.868 +    Colamd_Row Row [],
 153.869 +    Colamd_Col Col [],
 153.870 +    Int A [],
 153.871 +    Int head [],
 153.872 +    double knobs [COLAMD_KNOBS],
 153.873 +    Int *p_n_row2,
 153.874 +    Int *p_n_col2,
 153.875 +    Int *p_max_deg
 153.876 +) ;
 153.877 +
 153.878 +PRIVATE Int find_ordering
 153.879 +(
 153.880 +    Int n_row,
 153.881 +    Int n_col,
 153.882 +    Int Alen,
 153.883 +    Colamd_Row Row [],
 153.884 +    Colamd_Col Col [],
 153.885 +    Int A [],
 153.886 +    Int head [],
 153.887 +    Int n_col2,
 153.888 +    Int max_deg,
 153.889 +    Int pfree,
 153.890 +    Int aggressive
 153.891 +) ;
 153.892 +
 153.893 +PRIVATE void order_children
 153.894 +(
 153.895 +    Int n_col,
 153.896 +    Colamd_Col Col [],
 153.897 +    Int p []
 153.898 +) ;
 153.899 +
 153.900 +PRIVATE void detect_super_cols
 153.901 +(
 153.902 +
 153.903 +#ifndef NDEBUG
 153.904 +    Int n_col,
 153.905 +    Colamd_Row Row [],
 153.906 +#endif /* NDEBUG */
 153.907 +
 153.908 +    Colamd_Col Col [],
 153.909 +    Int A [],
 153.910 +    Int head [],
 153.911 +    Int row_start,
 153.912 +    Int row_length
 153.913 +) ;
 153.914 +
 153.915 +PRIVATE Int garbage_collection
 153.916 +(
 153.917 +    Int n_row,
 153.918 +    Int n_col,
 153.919 +    Colamd_Row Row [],
 153.920 +    Colamd_Col Col [],
 153.921 +    Int A [],
 153.922 +    Int *pfree
 153.923 +) ;
 153.924 +
 153.925 +PRIVATE Int clear_mark
 153.926 +(
 153.927 +    Int tag_mark,
 153.928 +    Int max_mark,
 153.929 +    Int n_row,
 153.930 +    Colamd_Row Row []
 153.931 +) ;
 153.932 +
 153.933 +PRIVATE void print_report
 153.934 +(
 153.935 +    char *method,
 153.936 +    Int stats [COLAMD_STATS]
 153.937 +) ;
 153.938 +
 153.939 +/* ========================================================================== */
 153.940 +/* === Debugging prototypes and definitions ================================= */
 153.941 +/* ========================================================================== */
 153.942 +
 153.943 +#ifndef NDEBUG
 153.944 +
 153.945 +#if 0 /* by mao */
 153.946 +#include <assert.h>
 153.947 +#endif
 153.948 +
 153.949 +/* colamd_debug is the *ONLY* global variable, and is only */
 153.950 +/* present when debugging */
 153.951 +
 153.952 +PRIVATE Int colamd_debug = 0 ;  /* debug print level */
 153.953 +
 153.954 +#define DEBUG0(params) { PRINTF (params) ; }
 153.955 +#define DEBUG1(params) { if (colamd_debug >= 1) PRINTF (params) ; }
 153.956 +#define DEBUG2(params) { if (colamd_debug >= 2) PRINTF (params) ; }
 153.957 +#define DEBUG3(params) { if (colamd_debug >= 3) PRINTF (params) ; }
 153.958 +#define DEBUG4(params) { if (colamd_debug >= 4) PRINTF (params) ; }
 153.959 +
 153.960 +#if 0 /* by mao */
 153.961 +#ifdef MATLAB_MEX_FILE
 153.962 +#define ASSERT(expression) (mxAssert ((expression), ""))
 153.963 +#else
 153.964 +#define ASSERT(expression) (assert (expression))
 153.965 +#endif /* MATLAB_MEX_FILE */
 153.966 +#else
 153.967 +#define ASSERT xassert
 153.968 +#endif
 153.969 +
 153.970 +PRIVATE void colamd_get_debug   /* gets the debug print level from getenv */
 153.971 +(
 153.972 +    char *method
 153.973 +) ;
 153.974 +
 153.975 +PRIVATE void debug_deg_lists
 153.976 +(
 153.977 +    Int n_row,
 153.978 +    Int n_col,
 153.979 +    Colamd_Row Row [],
 153.980 +    Colamd_Col Col [],
 153.981 +    Int head [],
 153.982 +    Int min_score,
 153.983 +    Int should,
 153.984 +    Int max_deg
 153.985 +) ;
 153.986 +
 153.987 +PRIVATE void debug_mark
 153.988 +(
 153.989 +    Int n_row,
 153.990 +    Colamd_Row Row [],
 153.991 +    Int tag_mark,
 153.992 +    Int max_mark
 153.993 +) ;
 153.994 +
 153.995 +PRIVATE void debug_matrix
 153.996 +(
 153.997 +    Int n_row,
 153.998 +    Int n_col,
 153.999 +    Colamd_Row Row [],
153.1000 +    Colamd_Col Col [],
153.1001 +    Int A []
153.1002 +) ;
153.1003 +
153.1004 +PRIVATE void debug_structures
153.1005 +(
153.1006 +    Int n_row,
153.1007 +    Int n_col,
153.1008 +    Colamd_Row Row [],
153.1009 +    Colamd_Col Col [],
153.1010 +    Int A [],
153.1011 +    Int n_col2
153.1012 +) ;
153.1013 +
153.1014 +#else /* NDEBUG */
153.1015 +
153.1016 +/* === No debugging ========================================================= */
153.1017 +
153.1018 +#define DEBUG0(params) ;
153.1019 +#define DEBUG1(params) ;
153.1020 +#define DEBUG2(params) ;
153.1021 +#define DEBUG3(params) ;
153.1022 +#define DEBUG4(params) ;
153.1023 +
153.1024 +#define ASSERT(expression)
153.1025 +
153.1026 +#endif /* NDEBUG */
153.1027 +
153.1028 +/* ========================================================================== */
153.1029 +/* === USER-CALLABLE ROUTINES: ============================================== */
153.1030 +/* ========================================================================== */
153.1031 +
153.1032 +/* ========================================================================== */
153.1033 +/* === colamd_recommended =================================================== */
153.1034 +/* ========================================================================== */
153.1035 +
153.1036 +/*
153.1037 +    The colamd_recommended routine returns the suggested size for Alen.  This
153.1038 +    value has been determined to provide good balance between the number of
153.1039 +    garbage collections and the memory requirements for colamd.  If any
153.1040 +    argument is negative, or if integer overflow occurs, a 0 is returned as an
153.1041 +    error condition.  2*nnz space is required for the row and column
153.1042 +    indices of the matrix. COLAMD_C (n_col) + COLAMD_R (n_row) space is
153.1043 +    required for the Col and Row arrays, respectively, which are internal to
153.1044 +    colamd (roughly 6*n_col + 4*n_row).  An additional n_col space is the
153.1045 +    minimal amount of "elbow room", and nnz/5 more space is recommended for
153.1046 +    run time efficiency.
153.1047 +
153.1048 +    Alen is approximately 2.2*nnz + 7*n_col + 4*n_row + 10.
153.1049 +
153.1050 +    This function is not needed when using symamd.
153.1051 +*/
153.1052 +
153.1053 +/* add two values of type size_t, and check for integer overflow */
153.1054 +static size_t t_add (size_t a, size_t b, int *ok)
153.1055 +{
153.1056 +    (*ok) = (*ok) && ((a + b) >= MAX (a,b)) ;
153.1057 +    return ((*ok) ? (a + b) : 0) ;
153.1058 +}
153.1059 +
153.1060 +/* compute a*k where k is a small integer, and check for integer overflow */
153.1061 +static size_t t_mult (size_t a, size_t k, int *ok)
153.1062 +{
153.1063 +    size_t i, s = 0 ;
153.1064 +    for (i = 0 ; i < k ; i++)
153.1065 +    {
153.1066 +        s = t_add (s, a, ok) ;
153.1067 +    }
153.1068 +    return (s) ;
153.1069 +}
153.1070 +
153.1071 +/* size of the Col and Row structures */
153.1072 +#define COLAMD_C(n_col,ok) \
153.1073 +    ((t_mult (t_add (n_col, 1, ok), sizeof (Colamd_Col), ok) / sizeof (Int)))
153.1074 +
153.1075 +#define COLAMD_R(n_row,ok) \
153.1076 +    ((t_mult (t_add (n_row, 1, ok), sizeof (Colamd_Row), ok) / sizeof (Int)))
153.1077 +
153.1078 +
153.1079 +PUBLIC size_t COLAMD_recommended        /* returns recommended value of Alen. */
153.1080 +(
153.1081 +    /* === Parameters ======================================================= */
153.1082 +
153.1083 +    Int nnz,                    /* number of nonzeros in A */
153.1084 +    Int n_row,                  /* number of rows in A */
153.1085 +    Int n_col                   /* number of columns in A */
153.1086 +)
153.1087 +{
153.1088 +    size_t s, c, r ;
153.1089 +    int ok = TRUE ;
153.1090 +    if (nnz < 0 || n_row < 0 || n_col < 0)
153.1091 +    {
153.1092 +        return (0) ;
153.1093 +    }
153.1094 +    s = t_mult (nnz, 2, &ok) ;      /* 2*nnz */
153.1095 +    c = COLAMD_C (n_col, &ok) ;     /* size of column structures */
153.1096 +    r = COLAMD_R (n_row, &ok) ;     /* size of row structures */
153.1097 +    s = t_add (s, c, &ok) ;
153.1098 +    s = t_add (s, r, &ok) ;
153.1099 +    s = t_add (s, n_col, &ok) ;     /* elbow room */
153.1100 +    s = t_add (s, nnz/5, &ok) ;     /* elbow room */
153.1101 +    ok = ok && (s < Int_MAX) ;
153.1102 +    return (ok ? s : 0) ;
153.1103 +}
153.1104 +
153.1105 +
153.1106 +/* ========================================================================== */
153.1107 +/* === colamd_set_defaults ================================================== */
153.1108 +/* ========================================================================== */
153.1109 +
153.1110 +/*
153.1111 +    The colamd_set_defaults routine sets the default values of the user-
153.1112 +    controllable parameters for colamd and symamd:
153.1113 +
153.1114 +        Colamd: rows with more than max (16, knobs [0] * sqrt (n_col))
153.1115 +        entries are removed prior to ordering.  Columns with more than
153.1116 +        max (16, knobs [1] * sqrt (MIN (n_row,n_col))) entries are removed
153.1117 +        prior to ordering, and placed last in the output column ordering. 
153.1118 +
153.1119 +        Symamd: Rows and columns with more than max (16, knobs [0] * sqrt (n))
153.1120 +        entries are removed prior to ordering, and placed last in the
153.1121 +        output ordering.
153.1122 +
153.1123 +        knobs [0]       dense row control
153.1124 +
153.1125 +        knobs [1]       dense column control
153.1126 +
153.1127 +        knobs [2]       if nonzero, do aggresive absorption
153.1128 +
153.1129 +        knobs [3..19]   unused, but future versions might use this
153.1130 +
153.1131 +*/
153.1132 +
153.1133 +PUBLIC void COLAMD_set_defaults
153.1134 +(
153.1135 +    /* === Parameters ======================================================= */
153.1136 +
153.1137 +    double knobs [COLAMD_KNOBS]         /* knob array */
153.1138 +)
153.1139 +{
153.1140 +    /* === Local variables ================================================== */
153.1141 +
153.1142 +    Int i ;
153.1143 +
153.1144 +    if (!knobs)
153.1145 +    {
153.1146 +        return ;                        /* no knobs to initialize */
153.1147 +    }
153.1148 +    for (i = 0 ; i < COLAMD_KNOBS ; i++)
153.1149 +    {
153.1150 +        knobs [i] = 0 ;
153.1151 +    }
153.1152 +    knobs [COLAMD_DENSE_ROW] = 10 ;
153.1153 +    knobs [COLAMD_DENSE_COL] = 10 ;
153.1154 +    knobs [COLAMD_AGGRESSIVE] = TRUE ;  /* default: do aggressive absorption*/
153.1155 +}
153.1156 +
153.1157 +
153.1158 +/* ========================================================================== */
153.1159 +/* === symamd =============================================================== */
153.1160 +/* ========================================================================== */
153.1161 +
153.1162 +PUBLIC Int SYMAMD_MAIN                  /* return TRUE if OK, FALSE otherwise */
153.1163 +(
153.1164 +    /* === Parameters ======================================================= */
153.1165 +
153.1166 +    Int n,                              /* number of rows and columns of A */
153.1167 +    Int A [],                           /* row indices of A */
153.1168 +    Int p [],                           /* column pointers of A */
153.1169 +    Int perm [],                        /* output permutation, size n+1 */
153.1170 +    double knobs [COLAMD_KNOBS],        /* parameters (uses defaults if NULL) */
153.1171 +    Int stats [COLAMD_STATS],           /* output statistics and error codes */
153.1172 +    void * (*allocate) (size_t, size_t),
153.1173 +                                        /* pointer to calloc (ANSI C) or */
153.1174 +                                        /* mxCalloc (for MATLAB mexFunction) */
153.1175 +    void (*release) (void *)
153.1176 +                                        /* pointer to free (ANSI C) or */
153.1177 +                                        /* mxFree (for MATLAB mexFunction) */
153.1178 +)
153.1179 +{
153.1180 +    /* === Local variables ================================================== */
153.1181 +
153.1182 +    Int *count ;                /* length of each column of M, and col pointer*/
153.1183 +    Int *mark ;                 /* mark array for finding duplicate entries */
153.1184 +    Int *M ;                    /* row indices of matrix M */
153.1185 +    size_t Mlen ;               /* length of M */
153.1186 +    Int n_row ;                 /* number of rows in M */
153.1187 +    Int nnz ;                   /* number of entries in A */
153.1188 +    Int i ;                     /* row index of A */
153.1189 +    Int j ;                     /* column index of A */
153.1190 +    Int k ;                     /* row index of M */ 
153.1191 +    Int mnz ;                   /* number of nonzeros in M */
153.1192 +    Int pp ;                    /* index into a column of A */
153.1193 +    Int last_row ;              /* last row seen in the current column */
153.1194 +    Int length ;                /* number of nonzeros in a column */
153.1195 +
153.1196 +    double cknobs [COLAMD_KNOBS] ;              /* knobs for colamd */
153.1197 +    double default_knobs [COLAMD_KNOBS] ;       /* default knobs for colamd */
153.1198 +
153.1199 +#ifndef NDEBUG
153.1200 +    colamd_get_debug ("symamd") ;
153.1201 +#endif /* NDEBUG */
153.1202 +
153.1203 +    /* === Check the input arguments ======================================== */
153.1204 +
153.1205 +    if (!stats)
153.1206 +    {
153.1207 +        DEBUG0 (("symamd: stats not present\n")) ;
153.1208 +        return (FALSE) ;
153.1209 +    }
153.1210 +    for (i = 0 ; i < COLAMD_STATS ; i++)
153.1211 +    {
153.1212 +        stats [i] = 0 ;
153.1213 +    }
153.1214 +    stats [COLAMD_STATUS] = COLAMD_OK ;
153.1215 +    stats [COLAMD_INFO1] = -1 ;
153.1216 +    stats [COLAMD_INFO2] = -1 ;
153.1217 +
153.1218 +    if (!A)
153.1219 +    {
153.1220 +        stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ;
153.1221 +        DEBUG0 (("symamd: A not present\n")) ;
153.1222 +        return (FALSE) ;
153.1223 +    }
153.1224 +
153.1225 +    if (!p)             /* p is not present */
153.1226 +    {
153.1227 +        stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ;
153.1228 +        DEBUG0 (("symamd: p not present\n")) ;
153.1229 +        return (FALSE) ;
153.1230 +    }
153.1231 +
153.1232 +    if (n < 0)          /* n must be >= 0 */
153.1233 +    {
153.1234 +        stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ;
153.1235 +        stats [COLAMD_INFO1] = n ;
153.1236 +        DEBUG0 (("symamd: n negative %d\n", n)) ;
153.1237 +        return (FALSE) ;
153.1238 +    }
153.1239 +
153.1240 +    nnz = p [n] ;
153.1241 +    if (nnz < 0)        /* nnz must be >= 0 */
153.1242 +    {
153.1243 +        stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ;
153.1244 +        stats [COLAMD_INFO1] = nnz ;
153.1245 +        DEBUG0 (("symamd: number of entries negative %d\n", nnz)) ;
153.1246 +        return (FALSE) ;
153.1247 +    }
153.1248 +
153.1249 +    if (p [0] != 0)
153.1250 +    {
153.1251 +        stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ;
153.1252 +        stats [COLAMD_INFO1] = p [0] ;
153.1253 +        DEBUG0 (("symamd: p[0] not zero %d\n", p [0])) ;
153.1254 +        return (FALSE) ;
153.1255 +    }
153.1256 +
153.1257 +    /* === If no knobs, set default knobs =================================== */
153.1258 +
153.1259 +    if (!knobs)
153.1260 +    {
153.1261 +        COLAMD_set_defaults (default_knobs) ;
153.1262 +        knobs = default_knobs ;
153.1263 +    }
153.1264 +
153.1265 +    /* === Allocate count and mark ========================================== */
153.1266 +
153.1267 +    count = (Int *) ((*allocate) (n+1, sizeof (Int))) ;
153.1268 +    if (!count)
153.1269 +    {
153.1270 +        stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
153.1271 +        DEBUG0 (("symamd: allocate count (size %d) failed\n", n+1)) ;
153.1272 +        return (FALSE) ;
153.1273 +    }
153.1274 +
153.1275 +    mark = (Int *) ((*allocate) (n+1, sizeof (Int))) ;
153.1276 +    if (!mark)
153.1277 +    {
153.1278 +        stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
153.1279 +        (*release) ((void *) count) ;
153.1280 +        DEBUG0 (("symamd: allocate mark (size %d) failed\n", n+1)) ;
153.1281 +        return (FALSE) ;
153.1282 +    }
153.1283 +
153.1284 +    /* === Compute column counts of M, check if A is valid ================== */
153.1285 +
153.1286 +    stats [COLAMD_INFO3] = 0 ;  /* number of duplicate or unsorted row indices*/
153.1287 +
153.1288 +    for (i = 0 ; i < n ; i++)
153.1289 +    {
153.1290 +        mark [i] = -1 ;
153.1291 +    }
153.1292 +
153.1293 +    for (j = 0 ; j < n ; j++)
153.1294 +    {
153.1295 +        last_row = -1 ;
153.1296 +
153.1297 +        length = p [j+1] - p [j] ;
153.1298 +        if (length < 0)
153.1299 +        {
153.1300 +            /* column pointers must be non-decreasing */
153.1301 +            stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ;
153.1302 +            stats [COLAMD_INFO1] = j ;
153.1303 +            stats [COLAMD_INFO2] = length ;
153.1304 +            (*release) ((void *) count) ;
153.1305 +            (*release) ((void *) mark) ;
153.1306 +            DEBUG0 (("symamd: col %d negative length %d\n", j, length)) ;
153.1307 +            return (FALSE) ;
153.1308 +        }
153.1309 +
153.1310 +        for (pp = p [j] ; pp < p [j+1] ; pp++)
153.1311 +        {
153.1312 +            i = A [pp] ;
153.1313 +            if (i < 0 || i >= n)
153.1314 +            {
153.1315 +                /* row index i, in column j, is out of bounds */
153.1316 +                stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ;
153.1317 +                stats [COLAMD_INFO1] = j ;
153.1318 +                stats [COLAMD_INFO2] = i ;
153.1319 +                stats [COLAMD_INFO3] = n ;
153.1320 +                (*release) ((void *) count) ;
153.1321 +                (*release) ((void *) mark) ;
153.1322 +                DEBUG0 (("symamd: row %d col %d out of bounds\n", i, j)) ;
153.1323 +                return (FALSE) ;
153.1324 +            }
153.1325 +
153.1326 +            if (i <= last_row || mark [i] == j)
153.1327 +            {
153.1328 +                /* row index is unsorted or repeated (or both), thus col */
153.1329 +                /* is jumbled.  This is a notice, not an error condition. */
153.1330 +                stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ;
153.1331 +                stats [COLAMD_INFO1] = j ;
153.1332 +                stats [COLAMD_INFO2] = i ;
153.1333 +                (stats [COLAMD_INFO3]) ++ ;
153.1334 +                DEBUG1 (("symamd: row %d col %d unsorted/duplicate\n", i, j)) ;
153.1335 +            }
153.1336 +
153.1337 +            if (i > j && mark [i] != j)
153.1338 +            {
153.1339 +                /* row k of M will contain column indices i and j */
153.1340 +                count [i]++ ;
153.1341 +                count [j]++ ;
153.1342 +            }
153.1343 +
153.1344 +            /* mark the row as having been seen in this column */
153.1345 +            mark [i] = j ;
153.1346 +
153.1347 +            last_row = i ;
153.1348 +        }
153.1349 +    }
153.1350 +
153.1351 +    /* v2.4: removed free(mark) */
153.1352 +
153.1353 +    /* === Compute column pointers of M ===================================== */
153.1354 +
153.1355 +    /* use output permutation, perm, for column pointers of M */
153.1356 +    perm [0] = 0 ;
153.1357 +    for (j = 1 ; j <= n ; j++)
153.1358 +    {
153.1359 +        perm [j] = perm [j-1] + count [j-1] ;
153.1360 +    }
153.1361 +    for (j = 0 ; j < n ; j++)
153.1362 +    {
153.1363 +        count [j] = perm [j] ;
153.1364 +    }
153.1365 +
153.1366 +    /* === Construct M ====================================================== */
153.1367 +
153.1368 +    mnz = perm [n] ;
153.1369 +    n_row = mnz / 2 ;
153.1370 +    Mlen = COLAMD_recommended (mnz, n_row, n) ;
153.1371 +    M = (Int *) ((*allocate) (Mlen, sizeof (Int))) ;
153.1372 +    DEBUG0 (("symamd: M is %d-by-%d with %d entries, Mlen = %g\n",
153.1373 +        n_row, n, mnz, (double) Mlen)) ;
153.1374 +
153.1375 +    if (!M)
153.1376 +    {
153.1377 +        stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
153.1378 +        (*release) ((void *) count) ;
153.1379 +        (*release) ((void *) mark) ;
153.1380 +        DEBUG0 (("symamd: allocate M (size %g) failed\n", (double) Mlen)) ;
153.1381 +        return (FALSE) ;
153.1382 +    }
153.1383 +
153.1384 +    k = 0 ;
153.1385 +
153.1386 +    if (stats [COLAMD_STATUS] == COLAMD_OK)
153.1387 +    {
153.1388 +        /* Matrix is OK */
153.1389 +        for (j = 0 ; j < n ; j++)
153.1390 +        {
153.1391 +            ASSERT (p [j+1] - p [j] >= 0) ;
153.1392 +            for (pp = p [j] ; pp < p [j+1] ; pp++)
153.1393 +            {
153.1394 +                i = A [pp] ;
153.1395 +                ASSERT (i >= 0 && i < n) ;
153.1396 +                if (i > j)
153.1397 +                {
153.1398 +                    /* row k of M contains column indices i and j */
153.1399 +                    M [count [i]++] = k ;
153.1400 +                    M [count [j]++] = k ;
153.1401 +                    k++ ;
153.1402 +                }
153.1403 +            }
153.1404 +        }
153.1405 +    }
153.1406 +    else
153.1407 +    {
153.1408 +        /* Matrix is jumbled.  Do not add duplicates to M.  Unsorted cols OK. */
153.1409 +        DEBUG0 (("symamd: Duplicates in A.\n")) ;
153.1410 +        for (i = 0 ; i < n ; i++)
153.1411 +        {
153.1412 +            mark [i] = -1 ;
153.1413 +        }
153.1414 +        for (j = 0 ; j < n ; j++)
153.1415 +        {
153.1416 +            ASSERT (p [j+1] - p [j] >= 0) ;
153.1417 +            for (pp = p [j] ; pp < p [j+1] ; pp++)
153.1418 +            {
153.1419 +                i = A [pp] ;
153.1420 +                ASSERT (i >= 0 && i < n) ;
153.1421 +                if (i > j && mark [i] != j)
153.1422 +                {
153.1423 +                    /* row k of M contains column indices i and j */
153.1424 +                    M [count [i]++] = k ;
153.1425 +                    M [count [j]++] = k ;
153.1426 +                    k++ ;
153.1427 +                    mark [i] = j ;
153.1428 +                }
153.1429 +            }
153.1430 +        }
153.1431 +        /* v2.4: free(mark) moved below */
153.1432 +    }
153.1433 +
153.1434 +    /* count and mark no longer needed */
153.1435 +    (*release) ((void *) count) ;
153.1436 +    (*release) ((void *) mark) ;        /* v2.4: free (mark) moved here */
153.1437 +    ASSERT (k == n_row) ;
153.1438 +
153.1439 +    /* === Adjust the knobs for M =========================================== */
153.1440 +
153.1441 +    for (i = 0 ; i < COLAMD_KNOBS ; i++)
153.1442 +    {
153.1443 +        cknobs [i] = knobs [i] ;
153.1444 +    }
153.1445 +
153.1446 +    /* there are no dense rows in M */
153.1447 +    cknobs [COLAMD_DENSE_ROW] = -1 ;
153.1448 +    cknobs [COLAMD_DENSE_COL] = knobs [COLAMD_DENSE_ROW] ;
153.1449 +
153.1450 +    /* === Order the columns of M =========================================== */
153.1451 +
153.1452 +    /* v2.4: colamd cannot fail here, so the error check is removed */
153.1453 +    (void) COLAMD_MAIN (n_row, n, (Int) Mlen, M, perm, cknobs, stats) ;
153.1454 +
153.1455 +    /* Note that the output permutation is now in perm */
153.1456 +
153.1457 +    /* === get the statistics for symamd from colamd ======================== */
153.1458 +
153.1459 +    /* a dense column in colamd means a dense row and col in symamd */
153.1460 +    stats [COLAMD_DENSE_ROW] = stats [COLAMD_DENSE_COL] ;
153.1461 +
153.1462 +    /* === Free M =========================================================== */
153.1463 +
153.1464 +    (*release) ((void *) M) ;
153.1465 +    DEBUG0 (("symamd: done.\n")) ;
153.1466 +    return (TRUE) ;
153.1467 +
153.1468 +}
153.1469 +
153.1470 +/* ========================================================================== */
153.1471 +/* === colamd =============================================================== */
153.1472 +/* ========================================================================== */
153.1473 +
153.1474 +/*
153.1475 +    The colamd routine computes a column ordering Q of a sparse matrix
153.1476 +    A such that the LU factorization P(AQ) = LU remains sparse, where P is
153.1477 +    selected via partial pivoting.   The routine can also be viewed as
153.1478 +    providing a permutation Q such that the Cholesky factorization
153.1479 +    (AQ)'(AQ) = LL' remains sparse.
153.1480 +*/
153.1481 +
153.1482 +PUBLIC Int COLAMD_MAIN          /* returns TRUE if successful, FALSE otherwise*/
153.1483 +(
153.1484 +    /* === Parameters ======================================================= */
153.1485 +
153.1486 +    Int n_row,                  /* number of rows in A */
153.1487 +    Int n_col,                  /* number of columns in A */
153.1488 +    Int Alen,                   /* length of A */
153.1489 +    Int A [],                   /* row indices of A */
153.1490 +    Int p [],                   /* pointers to columns in A */
153.1491 +    double knobs [COLAMD_KNOBS],/* parameters (uses defaults if NULL) */
153.1492 +    Int stats [COLAMD_STATS]    /* output statistics and error codes */
153.1493 +)
153.1494 +{
153.1495 +    /* === Local variables ================================================== */
153.1496 +
153.1497 +    Int i ;                     /* loop index */
153.1498 +    Int nnz ;                   /* nonzeros in A */
153.1499 +    size_t Row_size ;           /* size of Row [], in integers */
153.1500 +    size_t Col_size ;           /* size of Col [], in integers */
153.1501 +    size_t need ;               /* minimum required length of A */
153.1502 +    Colamd_Row *Row ;           /* pointer into A of Row [0..n_row] array */
153.1503 +    Colamd_Col *Col ;           /* pointer into A of Col [0..n_col] array */
153.1504 +    Int n_col2 ;                /* number of non-dense, non-empty columns */
153.1505 +    Int n_row2 ;                /* number of non-dense, non-empty rows */
153.1506 +    Int ngarbage ;              /* number of garbage collections performed */
153.1507 +    Int max_deg ;               /* maximum row degree */
153.1508 +    double default_knobs [COLAMD_KNOBS] ;       /* default knobs array */
153.1509 +    Int aggressive ;            /* do aggressive absorption */
153.1510 +    int ok ;
153.1511 +
153.1512 +#ifndef NDEBUG
153.1513 +    colamd_get_debug ("colamd") ;
153.1514 +#endif /* NDEBUG */
153.1515 +
153.1516 +    /* === Check the input arguments ======================================== */
153.1517 +
153.1518 +    if (!stats)
153.1519 +    {
153.1520 +        DEBUG0 (("colamd: stats not present\n")) ;
153.1521 +        return (FALSE) ;
153.1522 +    }
153.1523 +    for (i = 0 ; i < COLAMD_STATS ; i++)
153.1524 +    {
153.1525 +        stats [i] = 0 ;
153.1526 +    }
153.1527 +    stats [COLAMD_STATUS] = COLAMD_OK ;
153.1528 +    stats [COLAMD_INFO1] = -1 ;
153.1529 +    stats [COLAMD_INFO2] = -1 ;
153.1530 +
153.1531 +    if (!A)             /* A is not present */
153.1532 +    {
153.1533 +        stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ;
153.1534 +        DEBUG0 (("colamd: A not present\n")) ;
153.1535 +        return (FALSE) ;
153.1536 +    }
153.1537 +
153.1538 +    if (!p)             /* p is not present */
153.1539 +    {
153.1540 +        stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ;
153.1541 +        DEBUG0 (("colamd: p not present\n")) ;
153.1542 +        return (FALSE) ;
153.1543 +    }
153.1544 +
153.1545 +    if (n_row < 0)      /* n_row must be >= 0 */
153.1546 +    {
153.1547 +        stats [COLAMD_STATUS] = COLAMD_ERROR_nrow_negative ;
153.1548 +        stats [COLAMD_INFO1] = n_row ;
153.1549 +        DEBUG0 (("colamd: nrow negative %d\n", n_row)) ;
153.1550 +        return (FALSE) ;
153.1551 +    }
153.1552 +
153.1553 +    if (n_col < 0)      /* n_col must be >= 0 */
153.1554 +    {
153.1555 +        stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ;
153.1556 +        stats [COLAMD_INFO1] = n_col ;
153.1557 +        DEBUG0 (("colamd: ncol negative %d\n", n_col)) ;
153.1558 +        return (FALSE) ;
153.1559 +    }
153.1560 +
153.1561 +    nnz = p [n_col] ;
153.1562 +    if (nnz < 0)        /* nnz must be >= 0 */
153.1563 +    {
153.1564 +        stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ;
153.1565 +        stats [COLAMD_INFO1] = nnz ;
153.1566 +        DEBUG0 (("colamd: number of entries negative %d\n", nnz)) ;
153.1567 +        return (FALSE) ;
153.1568 +    }
153.1569 +
153.1570 +    if (p [0] != 0)
153.1571 +    {
153.1572 +        stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ;
153.1573 +        stats [COLAMD_INFO1] = p [0] ;
153.1574 +        DEBUG0 (("colamd: p[0] not zero %d\n", p [0])) ;
153.1575 +        return (FALSE) ;
153.1576 +    }
153.1577 +
153.1578 +    /* === If no knobs, set default knobs =================================== */
153.1579 +
153.1580 +    if (!knobs)
153.1581 +    {
153.1582 +        COLAMD_set_defaults (default_knobs) ;
153.1583 +        knobs = default_knobs ;
153.1584 +    }
153.1585 +
153.1586 +    aggressive = (knobs [COLAMD_AGGRESSIVE] != FALSE) ;
153.1587 +
153.1588 +    /* === Allocate the Row and Col arrays from array A ===================== */
153.1589 +
153.1590 +    ok = TRUE ;
153.1591 +    Col_size = COLAMD_C (n_col, &ok) ;      /* size of Col array of structs */
153.1592 +    Row_size = COLAMD_R (n_row, &ok) ;      /* size of Row array of structs */
153.1593 +
153.1594 +    /* need = 2*nnz + n_col + Col_size + Row_size ; */
153.1595 +    need = t_mult (nnz, 2, &ok) ;
153.1596 +    need = t_add (need, n_col, &ok) ;
153.1597 +    need = t_add (need, Col_size, &ok) ;
153.1598 +    need = t_add (need, Row_size, &ok) ;
153.1599 +
153.1600 +    if (!ok || need > (size_t) Alen || need > Int_MAX)
153.1601 +    {
153.1602 +        /* not enough space in array A to perform the ordering */
153.1603 +        stats [COLAMD_STATUS] = COLAMD_ERROR_A_too_small ;
153.1604 +        stats [COLAMD_INFO1] = need ;
153.1605 +        stats [COLAMD_INFO2] = Alen ;
153.1606 +        DEBUG0 (("colamd: Need Alen >= %d, given only Alen = %d\n", need,Alen));
153.1607 +        return (FALSE) ;
153.1608 +    }
153.1609 +
153.1610 +    Alen -= Col_size + Row_size ;
153.1611 +    Col = (Colamd_Col *) &A [Alen] ;
153.1612 +    Row = (Colamd_Row *) &A [Alen + Col_size] ;
153.1613 +
153.1614 +    /* === Construct the row and column data structures ===================== */
153.1615 +
153.1616 +    if (!init_rows_cols (n_row, n_col, Row, Col, A, p, stats))
153.1617 +    {
153.1618 +        /* input matrix is invalid */
153.1619 +        DEBUG0 (("colamd: Matrix invalid\n")) ;
153.1620 +        return (FALSE) ;
153.1621 +    }
153.1622 +
153.1623 +    /* === Initialize scores, kill dense rows/columns ======================= */
153.1624 +
153.1625 +    init_scoring (n_row, n_col, Row, Col, A, p, knobs,
153.1626 +        &n_row2, &n_col2, &max_deg) ;
153.1627 +
153.1628 +    /* === Order the supercolumns =========================================== */
153.1629 +
153.1630 +    ngarbage = find_ordering (n_row, n_col, Alen, Row, Col, A, p,
153.1631 +        n_col2, max_deg, 2*nnz, aggressive) ;
153.1632 +
153.1633 +    /* === Order the non-principal columns ================================== */
153.1634 +
153.1635 +    order_children (n_col, Col, p) ;
153.1636 +
153.1637 +    /* === Return statistics in stats ======================================= */
153.1638 +
153.1639 +    stats [COLAMD_DENSE_ROW] = n_row - n_row2 ;
153.1640 +    stats [COLAMD_DENSE_COL] = n_col - n_col2 ;
153.1641 +    stats [COLAMD_DEFRAG_COUNT] = ngarbage ;
153.1642 +    DEBUG0 (("colamd: done.\n")) ; 
153.1643 +    return (TRUE) ;
153.1644 +}
153.1645 +
153.1646 +
153.1647 +/* ========================================================================== */
153.1648 +/* === colamd_report ======================================================== */
153.1649 +/* ========================================================================== */
153.1650 +
153.1651 +PUBLIC void COLAMD_report
153.1652 +(
153.1653 +    Int stats [COLAMD_STATS]
153.1654 +)
153.1655 +{
153.1656 +    print_report ("colamd", stats) ;
153.1657 +}
153.1658 +
153.1659 +
153.1660 +/* ========================================================================== */
153.1661 +/* === symamd_report ======================================================== */
153.1662 +/* ========================================================================== */
153.1663 +
153.1664 +PUBLIC void SYMAMD_report
153.1665 +(
153.1666 +    Int stats [COLAMD_STATS]
153.1667 +)
153.1668 +{
153.1669 +    print_report ("symamd", stats) ;
153.1670 +}
153.1671 +
153.1672 +
153.1673 +
153.1674 +/* ========================================================================== */
153.1675 +/* === NON-USER-CALLABLE ROUTINES: ========================================== */
153.1676 +/* ========================================================================== */
153.1677 +
153.1678 +/* There are no user-callable routines beyond this point in the file */
153.1679 +
153.1680 +
153.1681 +/* ========================================================================== */
153.1682 +/* === init_rows_cols ======================================================= */
153.1683 +/* ========================================================================== */
153.1684 +
153.1685 +/*
153.1686 +    Takes the column form of the matrix in A and creates the row form of the
153.1687 +    matrix.  Also, row and column attributes are stored in the Col and Row
153.1688 +    structs.  If the columns are un-sorted or contain duplicate row indices,
153.1689 +    this routine will also sort and remove duplicate row indices from the
153.1690 +    column form of the matrix.  Returns FALSE if the matrix is invalid,
153.1691 +    TRUE otherwise.  Not user-callable.
153.1692 +*/
153.1693 +
153.1694 +PRIVATE Int init_rows_cols      /* returns TRUE if OK, or FALSE otherwise */
153.1695 +(
153.1696 +    /* === Parameters ======================================================= */
153.1697 +
153.1698 +    Int n_row,                  /* number of rows of A */
153.1699 +    Int n_col,                  /* number of columns of A */
153.1700 +    Colamd_Row Row [],          /* of size n_row+1 */
153.1701 +    Colamd_Col Col [],          /* of size n_col+1 */
153.1702 +    Int A [],                   /* row indices of A, of size Alen */
153.1703 +    Int p [],                   /* pointers to columns in A, of size n_col+1 */
153.1704 +    Int stats [COLAMD_STATS]    /* colamd statistics */ 
153.1705 +)
153.1706 +{
153.1707 +    /* === Local variables ================================================== */
153.1708 +
153.1709 +    Int col ;                   /* a column index */
153.1710 +    Int row ;                   /* a row index */
153.1711 +    Int *cp ;                   /* a column pointer */
153.1712 +    Int *cp_end ;               /* a pointer to the end of a column */
153.1713 +    Int *rp ;                   /* a row pointer */
153.1714 +    Int *rp_end ;               /* a pointer to the end of a row */
153.1715 +    Int last_row ;              /* previous row */
153.1716 +
153.1717 +    /* === Initialize columns, and check column pointers ==================== */
153.1718 +
153.1719 +    for (col = 0 ; col < n_col ; col++)
153.1720 +    {
153.1721 +        Col [col].start = p [col] ;
153.1722 +        Col [col].length = p [col+1] - p [col] ;
153.1723 +
153.1724 +        if (Col [col].length < 0)
153.1725 +        {
153.1726 +            /* column pointers must be non-decreasing */
153.1727 +            stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ;
153.1728 +            stats [COLAMD_INFO1] = col ;
153.1729 +            stats [COLAMD_INFO2] = Col [col].length ;
153.1730 +            DEBUG0 (("colamd: col %d length %d < 0\n", col, Col [col].length)) ;
153.1731 +            return (FALSE) ;
153.1732 +        }
153.1733 +
153.1734 +        Col [col].shared1.thickness = 1 ;
153.1735 +        Col [col].shared2.score = 0 ;
153.1736 +        Col [col].shared3.prev = EMPTY ;
153.1737 +        Col [col].shared4.degree_next = EMPTY ;
153.1738 +    }
153.1739 +
153.1740 +    /* p [0..n_col] no longer needed, used as "head" in subsequent routines */
153.1741 +
153.1742 +    /* === Scan columns, compute row degrees, and check row indices ========= */
153.1743 +
153.1744 +    stats [COLAMD_INFO3] = 0 ;  /* number of duplicate or unsorted row indices*/
153.1745 +
153.1746 +    for (row = 0 ; row < n_row ; row++)
153.1747 +    {
153.1748 +        Row [row].length = 0 ;
153.1749 +        Row [row].shared2.mark = -1 ;
153.1750 +    }
153.1751 +
153.1752 +    for (col = 0 ; col < n_col ; col++)
153.1753 +    {
153.1754 +        last_row = -1 ;
153.1755 +
153.1756 +        cp = &A [p [col]] ;
153.1757 +        cp_end = &A [p [col+1]] ;
153.1758 +
153.1759 +        while (cp < cp_end)
153.1760 +        {
153.1761 +            row = *cp++ ;
153.1762 +
153.1763 +            /* make sure row indices within range */
153.1764 +            if (row < 0 || row >= n_row)
153.1765 +            {
153.1766 +                stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ;
153.1767 +                stats [COLAMD_INFO1] = col ;
153.1768 +                stats [COLAMD_INFO2] = row ;
153.1769 +                stats [COLAMD_INFO3] = n_row ;
153.1770 +                DEBUG0 (("colamd: row %d col %d out of bounds\n", row, col)) ;
153.1771 +                return (FALSE) ;
153.1772 +            }
153.1773 +
153.1774 +            if (row <= last_row || Row [row].shared2.mark == col)
153.1775 +            {
153.1776 +                /* row index are unsorted or repeated (or both), thus col */
153.1777 +                /* is jumbled.  This is a notice, not an error condition. */
153.1778 +                stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ;
153.1779 +                stats [COLAMD_INFO1] = col ;
153.1780 +                stats [COLAMD_INFO2] = row ;
153.1781 +                (stats [COLAMD_INFO3]) ++ ;
153.1782 +                DEBUG1 (("colamd: row %d col %d unsorted/duplicate\n",row,col));
153.1783 +            }
153.1784 +
153.1785 +            if (Row [row].shared2.mark != col)
153.1786 +            {
153.1787 +                Row [row].length++ ;
153.1788 +            }
153.1789 +            else
153.1790 +            {
153.1791 +                /* this is a repeated entry in the column, */
153.1792 +                /* it will be removed */
153.1793 +                Col [col].length-- ;
153.1794 +            }
153.1795 +
153.1796 +            /* mark the row as having been seen in this column */
153.1797 +            Row [row].shared2.mark = col ;
153.1798 +
153.1799 +            last_row = row ;
153.1800 +        }
153.1801 +    }
153.1802 +
153.1803 +    /* === Compute row pointers ============================================= */
153.1804 +
153.1805 +    /* row form of the matrix starts directly after the column */
153.1806 +    /* form of matrix in A */
153.1807 +    Row [0].start = p [n_col] ;
153.1808 +    Row [0].shared1.p = Row [0].start ;
153.1809 +    Row [0].shared2.mark = -1 ;
153.1810 +    for (row = 1 ; row < n_row ; row++)
153.1811 +    {
153.1812 +        Row [row].start = Row [row-1].start + Row [row-1].length ;
153.1813 +        Row [row].shared1.p = Row [row].start ;
153.1814 +        Row [row].shared2.mark = -1 ;
153.1815 +    }
153.1816 +
153.1817 +    /* === Create row form ================================================== */
153.1818 +
153.1819 +    if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED)
153.1820 +    {
153.1821 +        /* if cols jumbled, watch for repeated row indices */
153.1822 +        for (col = 0 ; col < n_col ; col++)
153.1823 +        {
153.1824 +            cp = &A [p [col]] ;
153.1825 +            cp_end = &A [p [col+1]] ;
153.1826 +            while (cp < cp_end)
153.1827 +            {
153.1828 +                row = *cp++ ;
153.1829 +                if (Row [row].shared2.mark != col)
153.1830 +                {
153.1831 +                    A [(Row [row].shared1.p)++] = col ;
153.1832 +                    Row [row].shared2.mark = col ;
153.1833 +                }
153.1834 +            }
153.1835 +        }
153.1836 +    }
153.1837 +    else
153.1838 +    {
153.1839 +        /* if cols not jumbled, we don't need the mark (this is faster) */
153.1840 +        for (col = 0 ; col < n_col ; col++)
153.1841 +        {
153.1842 +            cp = &A [p [col]] ;
153.1843 +            cp_end = &A [p [col+1]] ;
153.1844 +            while (cp < cp_end)
153.1845 +            {
153.1846 +                A [(Row [*cp++].shared1.p)++] = col ;
153.1847 +            }
153.1848 +        }
153.1849 +    }
153.1850 +
153.1851 +    /* === Clear the row marks and set row degrees ========================== */
153.1852 +
153.1853 +    for (row = 0 ; row < n_row ; row++)
153.1854 +    {
153.1855 +        Row [row].shared2.mark = 0 ;
153.1856 +        Row [row].shared1.degree = Row [row].length ;
153.1857 +    }
153.1858 +
153.1859 +    /* === See if we need to re-create columns ============================== */
153.1860 +
153.1861 +    if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED)
153.1862 +    {
153.1863 +        DEBUG0 (("colamd: reconstructing column form, matrix jumbled\n")) ;
153.1864 +
153.1865 +#ifndef NDEBUG
153.1866 +        /* make sure column lengths are correct */
153.1867 +        for (col = 0 ; col < n_col ; col++)
153.1868 +        {
153.1869 +            p [col] = Col [col].length ;
153.1870 +        }
153.1871 +        for (row = 0 ; row < n_row ; row++)
153.1872 +        {
153.1873 +            rp = &A [Row [row].start] ;
153.1874 +            rp_end = rp + Row [row].length ;
153.1875 +            while (rp < rp_end)
153.1876 +            {
153.1877 +                p [*rp++]-- ;
153.1878 +            }
153.1879 +        }
153.1880 +        for (col = 0 ; col < n_col ; col++)
153.1881 +        {
153.1882 +            ASSERT (p [col] == 0) ;
153.1883 +        }
153.1884 +        /* now p is all zero (different than when debugging is turned off) */
153.1885 +#endif /* NDEBUG */
153.1886 +
153.1887 +        /* === Compute col pointers ========================================= */
153.1888 +
153.1889 +        /* col form of the matrix starts at A [0]. */
153.1890 +        /* Note, we may have a gap between the col form and the row */
153.1891 +        /* form if there were duplicate entries, if so, it will be */
153.1892 +        /* removed upon the first garbage collection */
153.1893 +        Col [0].start = 0 ;
153.1894 +        p [0] = Col [0].start ;
153.1895 +        for (col = 1 ; col < n_col ; col++)
153.1896 +        {
153.1897 +            /* note that the lengths here are for pruned columns, i.e. */
153.1898 +            /* no duplicate row indices will exist for these columns */
153.1899 +            Col [col].start = Col [col-1].start + Col [col-1].length ;
153.1900 +            p [col] = Col [col].start ;
153.1901 +        }
153.1902 +
153.1903 +        /* === Re-create col form =========================================== */
153.1904 +
153.1905 +        for (row = 0 ; row < n_row ; row++)
153.1906 +        {
153.1907 +            rp = &A [Row [row].start] ;
153.1908 +            rp_end = rp + Row [row].length ;
153.1909 +            while (rp < rp_end)
153.1910 +            {
153.1911 +                A [(p [*rp++])++] = row ;
153.1912 +            }
153.1913 +        }
153.1914 +    }
153.1915 +
153.1916 +    /* === Done.  Matrix is not (or no longer) jumbled ====================== */
153.1917 +
153.1918 +    return (TRUE) ;
153.1919 +}
153.1920 +
153.1921 +
153.1922 +/* ========================================================================== */
153.1923 +/* === init_scoring ========================================================= */
153.1924 +/* ========================================================================== */
153.1925 +
153.1926 +/*
153.1927 +    Kills dense or empty columns and rows, calculates an initial score for
153.1928 +    each column, and places all columns in the degree lists.  Not user-callable.
153.1929 +*/
153.1930 +
153.1931 +PRIVATE void init_scoring
153.1932 +(
153.1933 +    /* === Parameters ======================================================= */
153.1934 +
153.1935 +    Int n_row,                  /* number of rows of A */
153.1936 +    Int n_col,                  /* number of columns of A */
153.1937 +    Colamd_Row Row [],          /* of size n_row+1 */
153.1938 +    Colamd_Col Col [],          /* of size n_col+1 */
153.1939 +    Int A [],                   /* column form and row form of A */
153.1940 +    Int head [],                /* of size n_col+1 */
153.1941 +    double knobs [COLAMD_KNOBS],/* parameters */
153.1942 +    Int *p_n_row2,              /* number of non-dense, non-empty rows */
153.1943 +    Int *p_n_col2,              /* number of non-dense, non-empty columns */
153.1944 +    Int *p_max_deg              /* maximum row degree */
153.1945 +)
153.1946 +{
153.1947 +    /* === Local variables ================================================== */
153.1948 +
153.1949 +    Int c ;                     /* a column index */
153.1950 +    Int r, row ;                /* a row index */
153.1951 +    Int *cp ;                   /* a column pointer */
153.1952 +    Int deg ;                   /* degree of a row or column */
153.1953 +    Int *cp_end ;               /* a pointer to the end of a column */
153.1954 +    Int *new_cp ;               /* new column pointer */
153.1955 +    Int col_length ;            /* length of pruned column */
153.1956 +    Int score ;                 /* current column score */
153.1957 +    Int n_col2 ;                /* number of non-dense, non-empty columns */
153.1958 +    Int n_row2 ;                /* number of non-dense, non-empty rows */
153.1959 +    Int dense_row_count ;       /* remove rows with more entries than this */
153.1960 +    Int dense_col_count ;       /* remove cols with more entries than this */
153.1961 +    Int min_score ;             /* smallest column score */
153.1962 +    Int max_deg ;               /* maximum row degree */
153.1963 +    Int next_col ;              /* Used to add to degree list.*/
153.1964 +
153.1965 +#ifndef NDEBUG
153.1966 +    Int debug_count ;           /* debug only. */
153.1967 +#endif /* NDEBUG */
153.1968 +
153.1969 +    /* === Extract knobs ==================================================== */
153.1970 +
153.1971 +    /* Note: if knobs contains a NaN, this is undefined: */
153.1972 +    if (knobs [COLAMD_DENSE_ROW] < 0)
153.1973 +    {
153.1974 +        /* only remove completely dense rows */
153.1975 +        dense_row_count = n_col-1 ;
153.1976 +    }
153.1977 +    else
153.1978 +    {
153.1979 +        dense_row_count = DENSE_DEGREE (knobs [COLAMD_DENSE_ROW], n_col) ;
153.1980 +    }
153.1981 +    if (knobs [COLAMD_DENSE_COL] < 0)
153.1982 +    {
153.1983 +        /* only remove completely dense columns */
153.1984 +        dense_col_count = n_row-1 ;
153.1985 +    }
153.1986 +    else
153.1987 +    {
153.1988 +        dense_col_count =
153.1989 +            DENSE_DEGREE (knobs [COLAMD_DENSE_COL], MIN (n_row, n_col)) ;
153.1990 +    }
153.1991 +
153.1992 +    DEBUG1 (("colamd: densecount: %d %d\n", dense_row_count, dense_col_count)) ;
153.1993 +    max_deg = 0 ;
153.1994 +    n_col2 = n_col ;
153.1995 +    n_row2 = n_row ;
153.1996 +
153.1997 +    /* === Kill empty columns =============================================== */
153.1998 +
153.1999 +    /* Put the empty columns at the end in their natural order, so that LU */
153.2000 +    /* factorization can proceed as far as possible. */
153.2001 +    for (c = n_col-1 ; c >= 0 ; c--)
153.2002 +    {
153.2003 +        deg = Col [c].length ;
153.2004 +        if (deg == 0)
153.2005 +        {
153.2006 +            /* this is a empty column, kill and order it last */
153.2007 +            Col [c].shared2.order = --n_col2 ;
153.2008 +            KILL_PRINCIPAL_COL (c) ;
153.2009 +        }
153.2010 +    }
153.2011 +    DEBUG1 (("colamd: null columns killed: %d\n", n_col - n_col2)) ;
153.2012 +
153.2013 +    /* === Kill dense columns =============================================== */
153.2014 +
153.2015 +    /* Put the dense columns at the end, in their natural order */
153.2016 +    for (c = n_col-1 ; c >= 0 ; c--)
153.2017 +    {
153.2018 +        /* skip any dead columns */
153.2019 +        if (COL_IS_DEAD (c))
153.2020 +        {
153.2021 +            continue ;
153.2022 +        }
153.2023 +        deg = Col [c].length ;
153.2024 +        if (deg > dense_col_count)
153.2025 +        {
153.2026 +            /* this is a dense column, kill and order it last */
153.2027 +            Col [c].shared2.order = --n_col2 ;
153.2028 +            /* decrement the row degrees */
153.2029 +            cp = &A [Col [c].start] ;
153.2030 +            cp_end = cp + Col [c].length ;
153.2031 +            while (cp < cp_end)
153.2032 +            {
153.2033 +                Row [*cp++].shared1.degree-- ;
153.2034 +            }
153.2035 +            KILL_PRINCIPAL_COL (c) ;
153.2036 +        }
153.2037 +    }
153.2038 +    DEBUG1 (("colamd: Dense and null columns killed: %d\n", n_col - n_col2)) ;
153.2039 +
153.2040 +    /* === Kill dense and empty rows ======================================== */
153.2041 +
153.2042 +    for (r = 0 ; r < n_row ; r++)
153.2043 +    {
153.2044 +        deg = Row [r].shared1.degree ;
153.2045 +        ASSERT (deg >= 0 && deg <= n_col) ;
153.2046 +        if (deg > dense_row_count || deg == 0)
153.2047 +        {
153.2048 +            /* kill a dense or empty row */
153.2049 +            KILL_ROW (r) ;
153.2050 +            --n_row2 ;
153.2051 +        }
153.2052 +        else
153.2053 +        {
153.2054 +            /* keep track of max degree of remaining rows */
153.2055 +            max_deg = MAX (max_deg, deg) ;
153.2056 +        }
153.2057 +    }
153.2058 +    DEBUG1 (("colamd: Dense and null rows killed: %d\n", n_row - n_row2)) ;
153.2059 +
153.2060 +    /* === Compute initial column scores ==================================== */
153.2061 +
153.2062 +    /* At this point the row degrees are accurate.  They reflect the number */
153.2063 +    /* of "live" (non-dense) columns in each row.  No empty rows exist. */
153.2064 +    /* Some "live" columns may contain only dead rows, however.  These are */
153.2065 +    /* pruned in the code below. */
153.2066 +
153.2067 +    /* now find the initial matlab score for each column */
153.2068 +    for (c = n_col-1 ; c >= 0 ; c--)
153.2069 +    {
153.2070 +        /* skip dead column */
153.2071 +        if (COL_IS_DEAD (c))
153.2072 +        {
153.2073 +            continue ;
153.2074 +        }
153.2075 +        score = 0 ;
153.2076 +        cp = &A [Col [c].start] ;
153.2077 +        new_cp = cp ;
153.2078 +        cp_end = cp + Col [c].length ;
153.2079 +        while (cp < cp_end)
153.2080 +        {
153.2081 +            /* get a row */
153.2082 +            row = *cp++ ;
153.2083 +            /* skip if dead */
153.2084 +            if (ROW_IS_DEAD (row))
153.2085 +            {
153.2086 +                continue ;
153.2087 +            }
153.2088 +            /* compact the column */
153.2089 +            *new_cp++ = row ;
153.2090 +            /* add row's external degree */
153.2091 +            score += Row [row].shared1.degree - 1 ;
153.2092 +            /* guard against integer overflow */
153.2093 +            score = MIN (score, n_col) ;
153.2094 +        }
153.2095 +        /* determine pruned column length */
153.2096 +        col_length = (Int) (new_cp - &A [Col [c].start]) ;
153.2097 +        if (col_length == 0)
153.2098 +        {
153.2099 +            /* a newly-made null column (all rows in this col are "dense" */
153.2100 +            /* and have already been killed) */
153.2101 +            DEBUG2 (("Newly null killed: %d\n", c)) ;
153.2102 +            Col [c].shared2.order = --n_col2 ;
153.2103 +            KILL_PRINCIPAL_COL (c) ;
153.2104 +        }
153.2105 +        else
153.2106 +        {
153.2107 +            /* set column length and set score */
153.2108 +            ASSERT (score >= 0) ;
153.2109 +            ASSERT (score <= n_col) ;
153.2110 +            Col [c].length = col_length ;
153.2111 +            Col [c].shared2.score = score ;
153.2112 +        }
153.2113 +    }
153.2114 +    DEBUG1 (("colamd: Dense, null, and newly-null columns killed: %d\n",
153.2115 +        n_col-n_col2)) ;
153.2116 +
153.2117 +    /* At this point, all empty rows and columns are dead.  All live columns */
153.2118 +    /* are "clean" (containing no dead rows) and simplicial (no supercolumns */
153.2119 +    /* yet).  Rows may contain dead columns, but all live rows contain at */
153.2120 +    /* least one live column. */
153.2121 +
153.2122 +#ifndef NDEBUG
153.2123 +    debug_structures (n_row, n_col, Row, Col, A, n_col2) ;
153.2124 +#endif /* NDEBUG */
153.2125 +
153.2126 +    /* === Initialize degree lists ========================================== */
153.2127 +
153.2128 +#ifndef NDEBUG
153.2129 +    debug_count = 0 ;
153.2130 +#endif /* NDEBUG */
153.2131 +
153.2132 +    /* clear the hash buckets */
153.2133 +    for (c = 0 ; c <= n_col ; c++)
153.2134 +    {
153.2135 +        head [c] = EMPTY ;
153.2136 +    }
153.2137 +    min_score = n_col ;
153.2138 +    /* place in reverse order, so low column indices are at the front */
153.2139 +    /* of the lists.  This is to encourage natural tie-breaking */
153.2140 +    for (c = n_col-1 ; c >= 0 ; c--)
153.2141 +    {
153.2142 +        /* only add principal columns to degree lists */
153.2143 +        if (COL_IS_ALIVE (c))
153.2144 +        {
153.2145 +            DEBUG4 (("place %d score %d minscore %d ncol %d\n",
153.2146 +                c, Col [c].shared2.score, min_score, n_col)) ;
153.2147 +
153.2148 +            /* === Add columns score to DList =============================== */
153.2149 +
153.2150 +            score = Col [c].shared2.score ;
153.2151 +
153.2152 +            ASSERT (min_score >= 0) ;
153.2153 +            ASSERT (min_score <= n_col) ;
153.2154 +            ASSERT (score >= 0) ;
153.2155 +            ASSERT (score <= n_col) ;
153.2156 +            ASSERT (head [score] >= EMPTY) ;
153.2157 +
153.2158 +            /* now add this column to dList at proper score location */
153.2159 +            next_col = head [score] ;
153.2160 +            Col [c].shared3.prev = EMPTY ;
153.2161 +            Col [c].shared4.degree_next = next_col ;
153.2162 +
153.2163 +            /* if there already was a column with the same score, set its */
153.2164 +            /* previous pointer to this new column */
153.2165 +            if (next_col != EMPTY)
153.2166 +            {
153.2167 +                Col [next_col].shared3.prev = c ;
153.2168 +            }
153.2169 +            head [score] = c ;
153.2170 +
153.2171 +            /* see if this score is less than current min */
153.2172 +            min_score = MIN (min_score, score) ;
153.2173 +
153.2174 +#ifndef NDEBUG
153.2175 +            debug_count++ ;
153.2176 +#endif /* NDEBUG */
153.2177 +
153.2178 +        }
153.2179 +    }
153.2180 +
153.2181 +#ifndef NDEBUG
153.2182 +    DEBUG1 (("colamd: Live cols %d out of %d, non-princ: %d\n",
153.2183 +        debug_count, n_col, n_col-debug_count)) ;
153.2184 +    ASSERT (debug_count == n_col2) ;
153.2185 +    debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2, max_deg) ;
153.2186 +#endif /* NDEBUG */
153.2187 +
153.2188 +    /* === Return number of remaining columns, and max row degree =========== */
153.2189 +
153.2190 +    *p_n_col2 = n_col2 ;
153.2191 +    *p_n_row2 = n_row2 ;
153.2192 +    *p_max_deg = max_deg ;
153.2193 +}
153.2194 +
153.2195 +
153.2196 +/* ========================================================================== */
153.2197 +/* === find_ordering ======================================================== */
153.2198 +/* ========================================================================== */
153.2199 +
153.2200 +/*
153.2201 +    Order the principal columns of the supercolumn form of the matrix
153.2202 +    (no supercolumns on input).  Uses a minimum approximate column minimum
153.2203 +    degree ordering method.  Not user-callable.
153.2204 +*/
153.2205 +
153.2206 +PRIVATE Int find_ordering       /* return the number of garbage collections */
153.2207 +(
153.2208 +    /* === Parameters ======================================================= */
153.2209 +
153.2210 +    Int n_row,                  /* number of rows of A */
153.2211 +    Int n_col,                  /* number of columns of A */
153.2212 +    Int Alen,                   /* size of A, 2*nnz + n_col or larger */
153.2213 +    Colamd_Row Row [],          /* of size n_row+1 */
153.2214 +    Colamd_Col Col [],          /* of size n_col+1 */
153.2215 +    Int A [],                   /* column form and row form of A */
153.2216 +    Int head [],                /* of size n_col+1 */
153.2217 +    Int n_col2,                 /* Remaining columns to order */
153.2218 +    Int max_deg,                /* Maximum row degree */
153.2219 +    Int pfree,                  /* index of first free slot (2*nnz on entry) */
153.2220 +    Int aggressive
153.2221 +)
153.2222 +{
153.2223 +    /* === Local variables ================================================== */
153.2224 +
153.2225 +    Int k ;                     /* current pivot ordering step */
153.2226 +    Int pivot_col ;             /* current pivot column */
153.2227 +    Int *cp ;                   /* a column pointer */
153.2228 +    Int *rp ;                   /* a row pointer */
153.2229 +    Int pivot_row ;             /* current pivot row */
153.2230 +    Int *new_cp ;               /* modified column pointer */
153.2231 +    Int *new_rp ;               /* modified row pointer */
153.2232 +    Int pivot_row_start ;       /* pointer to start of pivot row */
153.2233 +    Int pivot_row_degree ;      /* number of columns in pivot row */
153.2234 +    Int pivot_row_length ;      /* number of supercolumns in pivot row */
153.2235 +    Int pivot_col_score ;       /* score of pivot column */
153.2236 +    Int needed_memory ;         /* free space needed for pivot row */
153.2237 +    Int *cp_end ;               /* pointer to the end of a column */
153.2238 +    Int *rp_end ;               /* pointer to the end of a row */
153.2239 +    Int row ;                   /* a row index */
153.2240 +    Int col ;                   /* a column index */
153.2241 +    Int max_score ;             /* maximum possible score */
153.2242 +    Int cur_score ;             /* score of current column */
153.2243 +    unsigned Int hash ;         /* hash value for supernode detection */
153.2244 +    Int head_column ;           /* head of hash bucket */
153.2245 +    Int first_col ;             /* first column in hash bucket */
153.2246 +    Int tag_mark ;              /* marker value for mark array */
153.2247 +    Int row_mark ;              /* Row [row].shared2.mark */
153.2248 +    Int set_difference ;        /* set difference size of row with pivot row */
153.2249 +    Int min_score ;             /* smallest column score */
153.2250 +    Int col_thickness ;         /* "thickness" (no. of columns in a supercol) */
153.2251 +    Int max_mark ;              /* maximum value of tag_mark */
153.2252 +    Int pivot_col_thickness ;   /* number of columns represented by pivot col */
153.2253 +    Int prev_col ;              /* Used by Dlist operations. */
153.2254 +    Int next_col ;              /* Used by Dlist operations. */
153.2255 +    Int ngarbage ;              /* number of garbage collections performed */
153.2256 +
153.2257 +#ifndef NDEBUG
153.2258 +    Int debug_d ;               /* debug loop counter */
153.2259 +    Int debug_step = 0 ;        /* debug loop counter */
153.2260 +#endif /* NDEBUG */
153.2261 +
153.2262 +    /* === Initialization and clear mark ==================================== */
153.2263 +
153.2264 +    max_mark = INT_MAX - n_col ;        /* INT_MAX defined in <limits.h> */
153.2265 +    tag_mark = clear_mark (0, max_mark, n_row, Row) ;
153.2266 +    min_score = 0 ;
153.2267 +    ngarbage = 0 ;
153.2268 +    DEBUG1 (("colamd: Ordering, n_col2=%d\n", n_col2)) ;
153.2269 +
153.2270 +    /* === Order the columns ================================================ */
153.2271 +
153.2272 +    for (k = 0 ; k < n_col2 ; /* 'k' is incremented below */)
153.2273 +    {
153.2274 +
153.2275 +#ifndef NDEBUG
153.2276 +        if (debug_step % 100 == 0)
153.2277 +        {
153.2278 +            DEBUG2 (("\n...       Step k: %d out of n_col2: %d\n", k, n_col2)) ;
153.2279 +        }
153.2280 +        else
153.2281 +        {
153.2282 +            DEBUG3 (("\n----------Step k: %d out of n_col2: %d\n", k, n_col2)) ;
153.2283 +        }
153.2284 +        debug_step++ ;
153.2285 +        debug_deg_lists (n_row, n_col, Row, Col, head,
153.2286 +                min_score, n_col2-k, max_deg) ;
153.2287 +        debug_matrix (n_row, n_col, Row, Col, A) ;
153.2288 +#endif /* NDEBUG */
153.2289 +
153.2290 +        /* === Select pivot column, and order it ============================ */
153.2291 +
153.2292 +        /* make sure degree list isn't empty */
153.2293 +        ASSERT (min_score >= 0) ;
153.2294 +        ASSERT (min_score <= n_col) ;
153.2295 +        ASSERT (head [min_score] >= EMPTY) ;
153.2296 +
153.2297 +#ifndef NDEBUG
153.2298 +        for (debug_d = 0 ; debug_d < min_score ; debug_d++)
153.2299 +        {
153.2300 +            ASSERT (head [debug_d] == EMPTY) ;
153.2301 +        }
153.2302 +#endif /* NDEBUG */
153.2303 +
153.2304 +        /* get pivot column from head of minimum degree list */
153.2305 +        while (head [min_score] == EMPTY && min_score < n_col)
153.2306 +        {
153.2307 +            min_score++ ;
153.2308 +        }
153.2309 +        pivot_col = head [min_score] ;
153.2310 +        ASSERT (pivot_col >= 0 && pivot_col <= n_col) ;
153.2311 +        next_col = Col [pivot_col].shared4.degree_next ;
153.2312 +        head [min_score] = next_col ;
153.2313 +        if (next_col != EMPTY)
153.2314 +        {
153.2315 +            Col [next_col].shared3.prev = EMPTY ;
153.2316 +        }
153.2317 +
153.2318 +        ASSERT (COL_IS_ALIVE (pivot_col)) ;
153.2319 +
153.2320 +        /* remember score for defrag check */
153.2321 +        pivot_col_score = Col [pivot_col].shared2.score ;
153.2322 +
153.2323 +        /* the pivot column is the kth column in the pivot order */
153.2324 +        Col [pivot_col].shared2.order = k ;
153.2325 +
153.2326 +        /* increment order count by column thickness */
153.2327 +        pivot_col_thickness = Col [pivot_col].shared1.thickness ;
153.2328 +        k += pivot_col_thickness ;
153.2329 +        ASSERT (pivot_col_thickness > 0) ;
153.2330 +        DEBUG3 (("Pivot col: %d thick %d\n", pivot_col, pivot_col_thickness)) ;
153.2331 +
153.2332 +        /* === Garbage_collection, if necessary ============================= */
153.2333 +
153.2334 +        needed_memory = MIN (pivot_col_score, n_col - k) ;
153.2335 +        if (pfree + needed_memory >= Alen)
153.2336 +        {
153.2337 +            pfree = garbage_collection (n_row, n_col, Row, Col, A, &A [pfree]) ;
153.2338 +            ngarbage++ ;
153.2339 +            /* after garbage collection we will have enough */
153.2340 +            ASSERT (pfree + needed_memory < Alen) ;
153.2341 +            /* garbage collection has wiped out the Row[].shared2.mark array */
153.2342 +            tag_mark = clear_mark (0, max_mark, n_row, Row) ;
153.2343 +
153.2344 +#ifndef NDEBUG
153.2345 +            debug_matrix (n_row, n_col, Row, Col, A) ;
153.2346 +#endif /* NDEBUG */
153.2347 +        }
153.2348 +
153.2349 +        /* === Compute pivot row pattern ==================================== */
153.2350 +
153.2351 +        /* get starting location for this new merged row */
153.2352 +        pivot_row_start = pfree ;
153.2353 +
153.2354 +        /* initialize new row counts to zero */
153.2355 +        pivot_row_degree = 0 ;
153.2356 +
153.2357 +        /* tag pivot column as having been visited so it isn't included */
153.2358 +        /* in merged pivot row */
153.2359 +        Col [pivot_col].shared1.thickness = -pivot_col_thickness ;
153.2360 +
153.2361 +        /* pivot row is the union of all rows in the pivot column pattern */
153.2362 +        cp = &A [Col [pivot_col].start] ;
153.2363 +        cp_end = cp + Col [pivot_col].length ;
153.2364 +        while (cp < cp_end)
153.2365 +        {
153.2366 +            /* get a row */
153.2367 +            row = *cp++ ;
153.2368 +            DEBUG4 (("Pivot col pattern %d %d\n", ROW_IS_ALIVE (row), row)) ;
153.2369 +            /* skip if row is dead */
153.2370 +            if (ROW_IS_ALIVE (row))
153.2371 +            {
153.2372 +                rp = &A [Row [row].start] ;
153.2373 +                rp_end = rp + Row [row].length ;
153.2374 +                while (rp < rp_end)
153.2375 +                {
153.2376 +                    /* get a column */
153.2377 +                    col = *rp++ ;
153.2378 +                    /* add the column, if alive and untagged */
153.2379 +                    col_thickness = Col [col].shared1.thickness ;
153.2380 +                    if (col_thickness > 0 && COL_IS_ALIVE (col))
153.2381 +                    {
153.2382 +                        /* tag column in pivot row */
153.2383 +                        Col [col].shared1.thickness = -col_thickness ;
153.2384 +                        ASSERT (pfree < Alen) ;
153.2385 +                        /* place column in pivot row */
153.2386 +                        A [pfree++] = col ;
153.2387 +                        pivot_row_degree += col_thickness ;
153.2388 +                    }
153.2389 +                }
153.2390 +            }
153.2391 +        }
153.2392 +
153.2393 +        /* clear tag on pivot column */
153.2394 +        Col [pivot_col].shared1.thickness = pivot_col_thickness ;
153.2395 +        max_deg = MAX (max_deg, pivot_row_degree) ;
153.2396 +
153.2397 +#ifndef NDEBUG
153.2398 +        DEBUG3 (("check2\n")) ;
153.2399 +        debug_mark (n_row, Row, tag_mark, max_mark) ;
153.2400 +#endif /* NDEBUG */
153.2401 +
153.2402 +        /* === Kill all rows used to construct pivot row ==================== */
153.2403 +
153.2404 +        /* also kill pivot row, temporarily */
153.2405 +        cp = &A [Col [pivot_col].start] ;
153.2406 +        cp_end = cp + Col [pivot_col].length ;
153.2407 +        while (cp < cp_end)
153.2408 +        {
153.2409 +            /* may be killing an already dead row */
153.2410 +            row = *cp++ ;
153.2411 +            DEBUG3 (("Kill row in pivot col: %d\n", row)) ;
153.2412 +            KILL_ROW (row) ;
153.2413 +        }
153.2414 +
153.2415 +        /* === Select a row index to use as the new pivot row =============== */
153.2416 +
153.2417 +        pivot_row_length = pfree - pivot_row_start ;
153.2418 +        if (pivot_row_length > 0)
153.2419 +        {
153.2420 +            /* pick the "pivot" row arbitrarily (first row in col) */
153.2421 +            pivot_row = A [Col [pivot_col].start] ;
153.2422 +            DEBUG3 (("Pivotal row is %d\n", pivot_row)) ;
153.2423 +        }
153.2424 +        else
153.2425 +        {
153.2426 +            /* there is no pivot row, since it is of zero length */
153.2427 +            pivot_row = EMPTY ;
153.2428 +            ASSERT (pivot_row_length == 0) ;
153.2429 +        }
153.2430 +        ASSERT (Col [pivot_col].length > 0 || pivot_row_length == 0) ;
153.2431 +
153.2432 +        /* === Approximate degree computation =============================== */
153.2433 +
153.2434 +        /* Here begins the computation of the approximate degree.  The column */
153.2435 +        /* score is the sum of the pivot row "length", plus the size of the */
153.2436 +        /* set differences of each row in the column minus the pattern of the */
153.2437 +        /* pivot row itself.  The column ("thickness") itself is also */
153.2438 +        /* excluded from the column score (we thus use an approximate */
153.2439 +        /* external degree). */
153.2440 +
153.2441 +        /* The time taken by the following code (compute set differences, and */
153.2442 +        /* add them up) is proportional to the size of the data structure */
153.2443 +        /* being scanned - that is, the sum of the sizes of each column in */
153.2444 +        /* the pivot row.  Thus, the amortized time to compute a column score */
153.2445 +        /* is proportional to the size of that column (where size, in this */
153.2446 +        /* context, is the column "length", or the number of row indices */
153.2447 +        /* in that column).  The number of row indices in a column is */
153.2448 +        /* monotonically non-decreasing, from the length of the original */
153.2449 +        /* column on input to colamd. */
153.2450 +
153.2451 +        /* === Compute set differences ====================================== */
153.2452 +
153.2453 +        DEBUG3 (("** Computing set differences phase. **\n")) ;
153.2454 +
153.2455 +        /* pivot row is currently dead - it will be revived later. */
153.2456 +
153.2457 +        DEBUG3 (("Pivot row: ")) ;
153.2458 +        /* for each column in pivot row */
153.2459 +        rp = &A [pivot_row_start] ;
153.2460 +        rp_end = rp + pivot_row_length ;
153.2461 +        while (rp < rp_end)
153.2462 +        {
153.2463 +            col = *rp++ ;
153.2464 +            ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
153.2465 +            DEBUG3 (("Col: %d\n", col)) ;
153.2466 +
153.2467 +            /* clear tags used to construct pivot row pattern */
153.2468 +            col_thickness = -Col [col].shared1.thickness ;
153.2469 +            ASSERT (col_thickness > 0) ;
153.2470 +            Col [col].shared1.thickness = col_thickness ;
153.2471 +
153.2472 +            /* === Remove column from degree list =========================== */
153.2473 +
153.2474 +            cur_score = Col [col].shared2.score ;
153.2475 +            prev_col = Col [col].shared3.prev ;
153.2476 +            next_col = Col [col].shared4.degree_next ;
153.2477 +            ASSERT (cur_score >= 0) ;
153.2478 +            ASSERT (cur_score <= n_col) ;
153.2479 +            ASSERT (cur_score >= EMPTY) ;
153.2480 +            if (prev_col == EMPTY)
153.2481 +            {
153.2482 +                head [cur_score] = next_col ;
153.2483 +            }
153.2484 +            else
153.2485 +            {
153.2486 +                Col [prev_col].shared4.degree_next = next_col ;
153.2487 +            }
153.2488 +            if (next_col != EMPTY)
153.2489 +            {
153.2490 +                Col [next_col].shared3.prev = prev_col ;
153.2491 +            }
153.2492 +
153.2493 +            /* === Scan the column ========================================== */
153.2494 +
153.2495 +            cp = &A [Col [col].start] ;
153.2496 +            cp_end = cp + Col [col].length ;
153.2497 +            while (cp < cp_end)
153.2498 +            {
153.2499 +                /* get a row */
153.2500 +                row = *cp++ ;
153.2501 +                row_mark = Row [row].shared2.mark ;
153.2502 +                /* skip if dead */
153.2503 +                if (ROW_IS_MARKED_DEAD (row_mark))
153.2504 +                {
153.2505 +                    continue ;
153.2506 +                }
153.2507 +                ASSERT (row != pivot_row) ;
153.2508 +                set_difference = row_mark - tag_mark ;
153.2509 +                /* check if the row has been seen yet */
153.2510 +                if (set_difference < 0)
153.2511 +                {
153.2512 +                    ASSERT (Row [row].shared1.degree <= max_deg) ;
153.2513 +                    set_difference = Row [row].shared1.degree ;
153.2514 +                }
153.2515 +                /* subtract column thickness from this row's set difference */
153.2516 +                set_difference -= col_thickness ;
153.2517 +                ASSERT (set_difference >= 0) ;
153.2518 +                /* absorb this row if the set difference becomes zero */
153.2519 +                if (set_difference == 0 && aggressive)
153.2520 +                {
153.2521 +                    DEBUG3 (("aggressive absorption. Row: %d\n", row)) ;
153.2522 +                    KILL_ROW (row) ;
153.2523 +                }
153.2524 +                else
153.2525 +                {
153.2526 +                    /* save the new mark */
153.2527 +                    Row [row].shared2.mark = set_difference + tag_mark ;
153.2528 +                }
153.2529 +            }
153.2530 +        }
153.2531 +
153.2532 +#ifndef NDEBUG
153.2533 +        debug_deg_lists (n_row, n_col, Row, Col, head,
153.2534 +                min_score, n_col2-k-pivot_row_degree, max_deg) ;
153.2535 +#endif /* NDEBUG */
153.2536 +
153.2537 +        /* === Add up set differences for each column ======================= */
153.2538 +
153.2539 +        DEBUG3 (("** Adding set differences phase. **\n")) ;
153.2540 +
153.2541 +        /* for each column in pivot row */
153.2542 +        rp = &A [pivot_row_start] ;
153.2543 +        rp_end = rp + pivot_row_length ;
153.2544 +        while (rp < rp_end)
153.2545 +        {
153.2546 +            /* get a column */
153.2547 +            col = *rp++ ;
153.2548 +            ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
153.2549 +            hash = 0 ;
153.2550 +            cur_score = 0 ;
153.2551 +            cp = &A [Col [col].start] ;
153.2552 +            /* compact the column */
153.2553 +            new_cp = cp ;
153.2554 +            cp_end = cp + Col [col].length ;
153.2555 +
153.2556 +            DEBUG4 (("Adding set diffs for Col: %d.\n", col)) ;
153.2557 +
153.2558 +            while (cp < cp_end)
153.2559 +            {
153.2560 +                /* get a row */
153.2561 +                row = *cp++ ;
153.2562 +                ASSERT(row >= 0 && row < n_row) ;
153.2563 +                row_mark = Row [row].shared2.mark ;
153.2564 +                /* skip if dead */
153.2565 +                if (ROW_IS_MARKED_DEAD (row_mark))
153.2566 +                {
153.2567 +                    DEBUG4 ((" Row %d, dead\n", row)) ;
153.2568 +                    continue ;
153.2569 +                }
153.2570 +                DEBUG4 ((" Row %d, set diff %d\n", row, row_mark-tag_mark));
153.2571 +                ASSERT (row_mark >= tag_mark) ;
153.2572 +                /* compact the column */
153.2573 +                *new_cp++ = row ;
153.2574 +                /* compute hash function */
153.2575 +                hash += row ;
153.2576 +                /* add set difference */
153.2577 +                cur_score += row_mark - tag_mark ;
153.2578 +                /* integer overflow... */
153.2579 +                cur_score = MIN (cur_score, n_col) ;
153.2580 +            }
153.2581 +
153.2582 +            /* recompute the column's length */
153.2583 +            Col [col].length = (Int) (new_cp - &A [Col [col].start]) ;
153.2584 +
153.2585 +            /* === Further mass elimination ================================= */
153.2586 +
153.2587 +            if (Col [col].length == 0)
153.2588 +            {
153.2589 +                DEBUG4 (("further mass elimination. Col: %d\n", col)) ;
153.2590 +                /* nothing left but the pivot row in this column */
153.2591 +                KILL_PRINCIPAL_COL (col) ;
153.2592 +                pivot_row_degree -= Col [col].shared1.thickness ;
153.2593 +                ASSERT (pivot_row_degree >= 0) ;
153.2594 +                /* order it */
153.2595 +                Col [col].shared2.order = k ;
153.2596 +                /* increment order count by column thickness */
153.2597 +                k += Col [col].shared1.thickness ;
153.2598 +            }
153.2599 +            else
153.2600 +            {
153.2601 +                /* === Prepare for supercolumn detection ==================== */
153.2602 +
153.2603 +                DEBUG4 (("Preparing supercol detection for Col: %d.\n", col)) ;
153.2604 +
153.2605 +                /* save score so far */
153.2606 +                Col [col].shared2.score = cur_score ;
153.2607 +
153.2608 +                /* add column to hash table, for supercolumn detection */
153.2609 +                hash %= n_col + 1 ;
153.2610 +
153.2611 +                DEBUG4 ((" Hash = %d, n_col = %d.\n", hash, n_col)) ;
153.2612 +                ASSERT (((Int) hash) <= n_col) ;
153.2613 +
153.2614 +                head_column = head [hash] ;
153.2615 +                if (head_column > EMPTY)
153.2616 +                {
153.2617 +                    /* degree list "hash" is non-empty, use prev (shared3) of */
153.2618 +                    /* first column in degree list as head of hash bucket */
153.2619 +                    first_col = Col [head_column].shared3.headhash ;
153.2620 +                    Col [head_column].shared3.headhash = col ;
153.2621 +                }
153.2622 +                else
153.2623 +                {
153.2624 +                    /* degree list "hash" is empty, use head as hash bucket */
153.2625 +                    first_col = - (head_column + 2) ;
153.2626 +                    head [hash] = - (col + 2) ;
153.2627 +                }
153.2628 +                Col [col].shared4.hash_next = first_col ;
153.2629 +
153.2630 +                /* save hash function in Col [col].shared3.hash */
153.2631 +                Col [col].shared3.hash = (Int) hash ;
153.2632 +                ASSERT (COL_IS_ALIVE (col)) ;
153.2633 +            }
153.2634 +        }
153.2635 +
153.2636 +        /* The approximate external column degree is now computed.  */
153.2637 +
153.2638 +        /* === Supercolumn detection ======================================== */
153.2639 +
153.2640 +        DEBUG3 (("** Supercolumn detection phase. **\n")) ;
153.2641 +
153.2642 +        detect_super_cols (
153.2643 +
153.2644 +#ifndef NDEBUG
153.2645 +                n_col, Row,
153.2646 +#endif /* NDEBUG */
153.2647 +
153.2648 +                Col, A, head, pivot_row_start, pivot_row_length) ;
153.2649 +
153.2650 +        /* === Kill the pivotal column ====================================== */
153.2651 +
153.2652 +        KILL_PRINCIPAL_COL (pivot_col) ;
153.2653 +
153.2654 +        /* === Clear mark =================================================== */
153.2655 +
153.2656 +        tag_mark = clear_mark (tag_mark+max_deg+1, max_mark, n_row, Row) ;
153.2657 +
153.2658 +#ifndef NDEBUG
153.2659 +        DEBUG3 (("check3\n")) ;
153.2660 +        debug_mark (n_row, Row, tag_mark, max_mark) ;
153.2661 +#endif /* NDEBUG */
153.2662 +
153.2663 +        /* === Finalize the new pivot row, and column scores ================ */
153.2664 +
153.2665 +        DEBUG3 (("** Finalize scores phase. **\n")) ;
153.2666 +
153.2667 +        /* for each column in pivot row */
153.2668 +        rp = &A [pivot_row_start] ;
153.2669 +        /* compact the pivot row */
153.2670 +        new_rp = rp ;
153.2671 +        rp_end = rp + pivot_row_length ;
153.2672 +        while (rp < rp_end)
153.2673 +        {
153.2674 +            col = *rp++ ;
153.2675 +            /* skip dead columns */
153.2676 +            if (COL_IS_DEAD (col))
153.2677 +            {
153.2678 +                continue ;
153.2679 +            }
153.2680 +            *new_rp++ = col ;
153.2681 +            /* add new pivot row to column */
153.2682 +            A [Col [col].start + (Col [col].length++)] = pivot_row ;
153.2683 +
153.2684 +            /* retrieve score so far and add on pivot row's degree. */
153.2685 +            /* (we wait until here for this in case the pivot */
153.2686 +            /* row's degree was reduced due to mass elimination). */
153.2687 +            cur_score = Col [col].shared2.score + pivot_row_degree ;
153.2688 +
153.2689 +            /* calculate the max possible score as the number of */
153.2690 +            /* external columns minus the 'k' value minus the */
153.2691 +            /* columns thickness */
153.2692 +            max_score = n_col - k - Col [col].shared1.thickness ;
153.2693 +
153.2694 +            /* make the score the external degree of the union-of-rows */
153.2695 +            cur_score -= Col [col].shared1.thickness ;
153.2696 +
153.2697 +            /* make sure score is less or equal than the max score */
153.2698 +            cur_score = MIN (cur_score, max_score) ;
153.2699 +            ASSERT (cur_score >= 0) ;
153.2700 +
153.2701 +            /* store updated score */
153.2702 +            Col [col].shared2.score = cur_score ;
153.2703 +
153.2704 +            /* === Place column back in degree list ========================= */
153.2705 +
153.2706 +            ASSERT (min_score >= 0) ;
153.2707 +            ASSERT (min_score <= n_col) ;
153.2708 +            ASSERT (cur_score >= 0) ;
153.2709 +            ASSERT (cur_score <= n_col) ;
153.2710 +            ASSERT (head [cur_score] >= EMPTY) ;
153.2711 +            next_col = head [cur_score] ;
153.2712 +            Col [col].shared4.degree_next = next_col ;
153.2713 +            Col [col].shared3.prev = EMPTY ;
153.2714 +            if (next_col != EMPTY)
153.2715 +            {
153.2716 +                Col [next_col].shared3.prev = col ;
153.2717 +            }
153.2718 +            head [cur_score] = col ;
153.2719 +
153.2720 +            /* see if this score is less than current min */
153.2721 +            min_score = MIN (min_score, cur_score) ;
153.2722 +
153.2723 +        }
153.2724 +
153.2725 +#ifndef NDEBUG
153.2726 +        debug_deg_lists (n_row, n_col, Row, Col, head,
153.2727 +                min_score, n_col2-k, max_deg) ;
153.2728 +#endif /* NDEBUG */
153.2729 +
153.2730 +        /* === Resurrect the new pivot row ================================== */
153.2731 +
153.2732 +        if (pivot_row_degree > 0)
153.2733 +        {
153.2734 +            /* update pivot row length to reflect any cols that were killed */
153.2735 +            /* during super-col detection and mass elimination */
153.2736 +            Row [pivot_row].start  = pivot_row_start ;
153.2737 +            Row [pivot_row].length = (Int) (new_rp - &A[pivot_row_start]) ;
153.2738 +            ASSERT (Row [pivot_row].length > 0) ;
153.2739 +            Row [pivot_row].shared1.degree = pivot_row_degree ;
153.2740 +            Row [pivot_row].shared2.mark = 0 ;
153.2741 +            /* pivot row is no longer dead */
153.2742 +
153.2743 +            DEBUG1 (("Resurrect Pivot_row %d deg: %d\n",
153.2744 +                        pivot_row, pivot_row_degree)) ;
153.2745 +        }
153.2746 +    }
153.2747 +
153.2748 +    /* === All principal columns have now been ordered ====================== */
153.2749 +
153.2750 +    return (ngarbage) ;
153.2751 +}
153.2752 +
153.2753 +
153.2754 +/* ========================================================================== */
153.2755 +/* === order_children ======================================================= */
153.2756 +/* ========================================================================== */
153.2757 +
153.2758 +/*
153.2759 +    The find_ordering routine has ordered all of the principal columns (the
153.2760 +    representatives of the supercolumns).  The non-principal columns have not
153.2761 +    yet been ordered.  This routine orders those columns by walking up the
153.2762 +    parent tree (a column is a child of the column which absorbed it).  The
153.2763 +    final permutation vector is then placed in p [0 ... n_col-1], with p [0]
153.2764 +    being the first column, and p [n_col-1] being the last.  It doesn't look
153.2765 +    like it at first glance, but be assured that this routine takes time linear
153.2766 +    in the number of columns.  Although not immediately obvious, the time
153.2767 +    taken by this routine is O (n_col), that is, linear in the number of
153.2768 +    columns.  Not user-callable.
153.2769 +*/
153.2770 +
153.2771 +PRIVATE void order_children
153.2772 +(
153.2773 +    /* === Parameters ======================================================= */
153.2774 +
153.2775 +    Int n_col,                  /* number of columns of A */
153.2776 +    Colamd_Col Col [],          /* of size n_col+1 */
153.2777 +    Int p []                    /* p [0 ... n_col-1] is the column permutation*/
153.2778 +)
153.2779 +{
153.2780 +    /* === Local variables ================================================== */
153.2781 +
153.2782 +    Int i ;                     /* loop counter for all columns */
153.2783 +    Int c ;                     /* column index */
153.2784 +    Int parent ;                /* index of column's parent */
153.2785 +    Int order ;                 /* column's order */
153.2786 +
153.2787 +    /* === Order each non-principal column ================================== */
153.2788 +
153.2789 +    for (i = 0 ; i < n_col ; i++)
153.2790 +    {
153.2791 +        /* find an un-ordered non-principal column */
153.2792 +        ASSERT (COL_IS_DEAD (i)) ;
153.2793 +        if (!COL_IS_DEAD_PRINCIPAL (i) && Col [i].shared2.order == EMPTY)
153.2794 +        {
153.2795 +            parent = i ;
153.2796 +            /* once found, find its principal parent */
153.2797 +            do
153.2798 +            {
153.2799 +                parent = Col [parent].shared1.parent ;
153.2800 +            } while (!COL_IS_DEAD_PRINCIPAL (parent)) ;
153.2801 +
153.2802 +            /* now, order all un-ordered non-principal columns along path */
153.2803 +            /* to this parent.  collapse tree at the same time */
153.2804 +            c = i ;
153.2805 +            /* get order of parent */
153.2806 +            order = Col [parent].shared2.order ;
153.2807 +
153.2808 +            do
153.2809 +            {
153.2810 +                ASSERT (Col [c].shared2.order == EMPTY) ;
153.2811 +
153.2812 +                /* order this column */
153.2813 +                Col [c].shared2.order = order++ ;
153.2814 +                /* collaps tree */
153.2815 +                Col [c].shared1.parent = parent ;
153.2816 +
153.2817 +                /* get immediate parent of this column */
153.2818 +                c = Col [c].shared1.parent ;
153.2819 +
153.2820 +                /* continue until we hit an ordered column.  There are */
153.2821 +                /* guarranteed not to be anymore unordered columns */
153.2822 +                /* above an ordered column */
153.2823 +            } while (Col [c].shared2.order == EMPTY) ;
153.2824 +
153.2825 +            /* re-order the super_col parent to largest order for this group */
153.2826 +            Col [parent].shared2.order = order ;
153.2827 +        }
153.2828 +    }
153.2829 +
153.2830 +    /* === Generate the permutation ========================================= */
153.2831 +
153.2832 +    for (c = 0 ; c < n_col ; c++)
153.2833 +    {
153.2834 +        p [Col [c].shared2.order] = c ;
153.2835 +    }
153.2836 +}
153.2837 +
153.2838 +
153.2839 +/* ========================================================================== */
153.2840 +/* === detect_super_cols ==================================================== */
153.2841 +/* ========================================================================== */
153.2842 +
153.2843 +/*
153.2844 +    Detects supercolumns by finding matches between columns in the hash buckets.
153.2845 +    Check amongst columns in the set A [row_start ... row_start + row_length-1].
153.2846 +    The columns under consideration are currently *not* in the degree lists,
153.2847 +    and have already been placed in the hash buckets.
153.2848 +
153.2849 +    The hash bucket for columns whose hash function is equal to h is stored
153.2850 +    as follows:
153.2851 +
153.2852 +        if head [h] is >= 0, then head [h] contains a degree list, so:
153.2853 +
153.2854 +                head [h] is the first column in degree bucket h.
153.2855 +                Col [head [h]].headhash gives the first column in hash bucket h.
153.2856 +
153.2857 +        otherwise, the degree list is empty, and:
153.2858 +
153.2859 +                -(head [h] + 2) is the first column in hash bucket h.
153.2860 +
153.2861 +    For a column c in a hash bucket, Col [c].shared3.prev is NOT a "previous
153.2862 +    column" pointer.  Col [c].shared3.hash is used instead as the hash number
153.2863 +    for that column.  The value of Col [c].shared4.hash_next is the next column
153.2864 +    in the same hash bucket.
153.2865 +
153.2866 +    Assuming no, or "few" hash collisions, the time taken by this routine is
153.2867 +    linear in the sum of the sizes (lengths) of each column whose score has
153.2868 +    just been computed in the approximate degree computation.
153.2869 +    Not user-callable.
153.2870 +*/
153.2871 +
153.2872 +PRIVATE void detect_super_cols
153.2873 +(
153.2874 +    /* === Parameters ======================================================= */
153.2875 +
153.2876 +#ifndef NDEBUG
153.2877 +    /* these two parameters are only needed when debugging is enabled: */
153.2878 +    Int n_col,                  /* number of columns of A */
153.2879 +    Colamd_Row Row [],          /* of size n_row+1 */
153.2880 +#endif /* NDEBUG */
153.2881 +
153.2882 +    Colamd_Col Col [],          /* of size n_col+1 */
153.2883 +    Int A [],                   /* row indices of A */
153.2884 +    Int head [],                /* head of degree lists and hash buckets */
153.2885 +    Int row_start,              /* pointer to set of columns to check */
153.2886 +    Int row_length              /* number of columns to check */
153.2887 +)
153.2888 +{
153.2889 +    /* === Local variables ================================================== */
153.2890 +
153.2891 +    Int hash ;                  /* hash value for a column */
153.2892 +    Int *rp ;                   /* pointer to a row */
153.2893 +    Int c ;                     /* a column index */
153.2894 +    Int super_c ;               /* column index of the column to absorb into */
153.2895 +    Int *cp1 ;                  /* column pointer for column super_c */
153.2896 +    Int *cp2 ;                  /* column pointer for column c */
153.2897 +    Int length ;                /* length of column super_c */
153.2898 +    Int prev_c ;                /* column preceding c in hash bucket */
153.2899 +    Int i ;                     /* loop counter */
153.2900 +    Int *rp_end ;               /* pointer to the end of the row */
153.2901 +    Int col ;                   /* a column index in the row to check */
153.2902 +    Int head_column ;           /* first column in hash bucket or degree list */
153.2903 +    Int first_col ;             /* first column in hash bucket */
153.2904 +
153.2905 +    /* === Consider each column in the row ================================== */
153.2906 +
153.2907 +    rp = &A [row_start] ;
153.2908 +    rp_end = rp + row_length ;
153.2909 +    while (rp < rp_end)
153.2910 +    {
153.2911 +        col = *rp++ ;
153.2912 +        if (COL_IS_DEAD (col))
153.2913 +        {
153.2914 +            continue ;
153.2915 +        }
153.2916 +
153.2917 +        /* get hash number for this column */
153.2918 +        hash = Col [col].shared3.hash ;
153.2919 +        ASSERT (hash <= n_col) ;
153.2920 +
153.2921 +        /* === Get the first column in this hash bucket ===================== */
153.2922 +
153.2923 +        head_column = head [hash] ;
153.2924 +        if (head_column > EMPTY)
153.2925 +        {
153.2926 +            first_col = Col [head_column].shared3.headhash ;
153.2927 +        }
153.2928 +        else
153.2929 +        {
153.2930 +            first_col = - (head_column + 2) ;
153.2931 +        }
153.2932 +
153.2933 +        /* === Consider each column in the hash bucket ====================== */
153.2934 +
153.2935 +        for (super_c = first_col ; super_c != EMPTY ;
153.2936 +            super_c = Col [super_c].shared4.hash_next)
153.2937 +        {
153.2938 +            ASSERT (COL_IS_ALIVE (super_c)) ;
153.2939 +            ASSERT (Col [super_c].shared3.hash == hash) ;
153.2940 +            length = Col [super_c].length ;
153.2941 +
153.2942 +            /* prev_c is the column preceding column c in the hash bucket */
153.2943 +            prev_c = super_c ;
153.2944 +
153.2945 +            /* === Compare super_c with all columns after it ================ */
153.2946 +
153.2947 +            for (c = Col [super_c].shared4.hash_next ;
153.2948 +                 c != EMPTY ; c = Col [c].shared4.hash_next)
153.2949 +            {
153.2950 +                ASSERT (c != super_c) ;
153.2951 +                ASSERT (COL_IS_ALIVE (c)) ;
153.2952 +                ASSERT (Col [c].shared3.hash == hash) ;
153.2953 +
153.2954 +                /* not identical if lengths or scores are different */
153.2955 +                if (Col [c].length != length ||
153.2956 +                    Col [c].shared2.score != Col [super_c].shared2.score)
153.2957 +                {
153.2958 +                    prev_c = c ;
153.2959 +                    continue ;
153.2960 +                }
153.2961 +
153.2962 +                /* compare the two columns */
153.2963 +                cp1 = &A [Col [super_c].start] ;
153.2964 +                cp2 = &A [Col [c].start] ;
153.2965 +
153.2966 +                for (i = 0 ; i < length ; i++)
153.2967 +                {
153.2968 +                    /* the columns are "clean" (no dead rows) */
153.2969 +                    ASSERT (ROW_IS_ALIVE (*cp1))  ;
153.2970 +                    ASSERT (ROW_IS_ALIVE (*cp2))  ;
153.2971 +                    /* row indices will same order for both supercols, */
153.2972 +                    /* no gather scatter nessasary */
153.2973 +                    if (*cp1++ != *cp2++)
153.2974 +                    {
153.2975 +                        break ;
153.2976 +                    }
153.2977 +                }
153.2978 +
153.2979 +                /* the two columns are different if the for-loop "broke" */
153.2980 +                if (i != length)
153.2981 +                {
153.2982 +                    prev_c = c ;
153.2983 +                    continue ;
153.2984 +                }
153.2985 +
153.2986 +                /* === Got it!  two columns are identical =================== */
153.2987 +
153.2988 +                ASSERT (Col [c].shared2.score == Col [super_c].shared2.score) ;
153.2989 +
153.2990 +                Col [super_c].shared1.thickness += Col [c].shared1.thickness ;
153.2991 +                Col [c].shared1.parent = super_c ;
153.2992 +                KILL_NON_PRINCIPAL_COL (c) ;
153.2993 +                /* order c later, in order_children() */
153.2994 +                Col [c].shared2.order = EMPTY ;
153.2995 +                /* remove c from hash bucket */
153.2996 +                Col [prev_c].shared4.hash_next = Col [c].shared4.hash_next ;
153.2997 +            }
153.2998 +        }
153.2999 +
153.3000 +        /* === Empty this hash bucket ======================================= */
153.3001 +
153.3002 +        if (head_column > EMPTY)
153.3003 +        {
153.3004 +            /* corresponding degree list "hash" is not empty */
153.3005 +            Col [head_column].shared3.headhash = EMPTY ;
153.3006 +        }
153.3007 +        else
153.3008 +        {
153.3009 +            /* corresponding degree list "hash" is empty */
153.3010 +            head [hash] = EMPTY ;
153.3011 +        }
153.3012 +    }
153.3013 +}
153.3014 +
153.3015 +
153.3016 +/* ========================================================================== */
153.3017 +/* === garbage_collection =================================================== */
153.3018 +/* ========================================================================== */
153.3019 +
153.3020 +/*
153.3021 +    Defragments and compacts columns and rows in the workspace A.  Used when
153.3022 +    all avaliable memory has been used while performing row merging.  Returns
153.3023 +    the index of the first free position in A, after garbage collection.  The
153.3024 +    time taken by this routine is linear is the size of the array A, which is
153.3025 +    itself linear in the number of nonzeros in the input matrix.
153.3026 +    Not user-callable.
153.3027 +*/
153.3028 +
153.3029 +PRIVATE Int garbage_collection  /* returns the new value of pfree */
153.3030 +(
153.3031 +    /* === Parameters ======================================================= */
153.3032 +
153.3033 +    Int n_row,                  /* number of rows */
153.3034 +    Int n_col,                  /* number of columns */
153.3035 +    Colamd_Row Row [],          /* row info */
153.3036 +    Colamd_Col Col [],          /* column info */
153.3037 +    Int A [],                   /* A [0 ... Alen-1] holds the matrix */
153.3038 +    Int *pfree                  /* &A [0] ... pfree is in use */
153.3039 +)
153.3040 +{
153.3041 +    /* === Local variables ================================================== */
153.3042 +
153.3043 +    Int *psrc ;                 /* source pointer */
153.3044 +    Int *pdest ;                /* destination pointer */
153.3045 +    Int j ;                     /* counter */
153.3046 +    Int r ;                     /* a row index */
153.3047 +    Int c ;                     /* a column index */
153.3048 +    Int length ;                /* length of a row or column */
153.3049 +
153.3050 +#ifndef NDEBUG
153.3051 +    Int debug_rows ;
153.3052 +    DEBUG2 (("Defrag..\n")) ;
153.3053 +    for (psrc = &A[0] ; psrc < pfree ; psrc++) ASSERT (*psrc >= 0) ;
153.3054 +    debug_rows = 0 ;
153.3055 +#endif /* NDEBUG */
153.3056 +
153.3057 +    /* === Defragment the columns =========================================== */
153.3058 +
153.3059 +    pdest = &A[0] ;
153.3060 +    for (c = 0 ; c < n_col ; c++)
153.3061 +    {
153.3062 +        if (COL_IS_ALIVE (c))
153.3063 +        {
153.3064 +            psrc = &A [Col [c].start] ;
153.3065 +
153.3066 +            /* move and compact the column */
153.3067 +            ASSERT (pdest <= psrc) ;
153.3068 +            Col [c].start = (Int) (pdest - &A [0]) ;
153.3069 +            length = Col [c].length ;
153.3070 +            for (j = 0 ; j < length ; j++)
153.3071 +            {
153.3072 +                r = *psrc++ ;
153.3073 +                if (ROW_IS_ALIVE (r))
153.3074 +                {
153.3075 +                    *pdest++ = r ;
153.3076 +                }
153.3077 +            }
153.3078 +            Col [c].length = (Int) (pdest - &A [Col [c].start]) ;
153.3079 +        }
153.3080 +    }
153.3081 +
153.3082 +    /* === Prepare to defragment the rows =================================== */
153.3083 +
153.3084 +    for (r = 0 ; r < n_row ; r++)
153.3085 +    {
153.3086 +        if (ROW_IS_DEAD (r) || (Row [r].length == 0))
153.3087 +        {
153.3088 +            /* This row is already dead, or is of zero length.  Cannot compact
153.3089 +             * a row of zero length, so kill it.  NOTE: in the current version,
153.3090 +             * there are no zero-length live rows.  Kill the row (for the first
153.3091 +             * time, or again) just to be safe. */
153.3092 +            KILL_ROW (r) ;
153.3093 +        }
153.3094 +        else
153.3095 +        {
153.3096 +            /* save first column index in Row [r].shared2.first_column */
153.3097 +            psrc = &A [Row [r].start] ;
153.3098 +            Row [r].shared2.first_column = *psrc ;
153.3099 +            ASSERT (ROW_IS_ALIVE (r)) ;
153.3100 +            /* flag the start of the row with the one's complement of row */
153.3101 +            *psrc = ONES_COMPLEMENT (r) ;
153.3102 +#ifndef NDEBUG
153.3103 +            debug_rows++ ;
153.3104 +#endif /* NDEBUG */
153.3105 +        }
153.3106 +    }
153.3107 +
153.3108 +    /* === Defragment the rows ============================================== */
153.3109 +
153.3110 +    psrc = pdest ;
153.3111 +    while (psrc < pfree)
153.3112 +    {
153.3113 +        /* find a negative number ... the start of a row */
153.3114 +        if (*psrc++ < 0)
153.3115 +        {
153.3116 +            psrc-- ;
153.3117 +            /* get the row index */
153.3118 +            r = ONES_COMPLEMENT (*psrc) ;
153.3119 +            ASSERT (r >= 0 && r < n_row) ;
153.3120 +            /* restore first column index */
153.3121 +            *psrc = Row [r].shared2.first_column ;
153.3122 +            ASSERT (ROW_IS_ALIVE (r)) ;
153.3123 +            ASSERT (Row [r].length > 0) ;
153.3124 +            /* move and compact the row */
153.3125 +            ASSERT (pdest <= psrc) ;
153.3126 +            Row [r].start = (Int) (pdest - &A [0]) ;
153.3127 +            length = Row [r].length ;
153.3128 +            for (j = 0 ; j < length ; j++)
153.3129 +            {
153.3130 +                c = *psrc++ ;
153.3131 +                if (COL_IS_ALIVE (c))
153.3132 +                {
153.3133 +                    *pdest++ = c ;
153.3134 +                }
153.3135 +            }
153.3136 +            Row [r].length = (Int) (pdest - &A [Row [r].start]) ;
153.3137 +            ASSERT (Row [r].length > 0) ;
153.3138 +#ifndef NDEBUG
153.3139 +            debug_rows-- ;
153.3140 +#endif /* NDEBUG */
153.3141 +        }
153.3142 +    }
153.3143 +    /* ensure we found all the rows */
153.3144 +    ASSERT (debug_rows == 0) ;
153.3145 +
153.3146 +    /* === Return the new value of pfree ==================================== */
153.3147 +
153.3148 +    return ((Int) (pdest - &A [0])) ;
153.3149 +}
153.3150 +
153.3151 +
153.3152 +/* ========================================================================== */
153.3153 +/* === clear_mark =========================================================== */
153.3154 +/* ========================================================================== */
153.3155 +
153.3156 +/*
153.3157 +    Clears the Row [].shared2.mark array, and returns the new tag_mark.
153.3158 +    Return value is the new tag_mark.  Not user-callable.
153.3159 +*/
153.3160 +
153.3161 +PRIVATE Int clear_mark  /* return the new value for tag_mark */
153.3162 +(
153.3163 +    /* === Parameters ======================================================= */
153.3164 +
153.3165 +    Int tag_mark,       /* new value of tag_mark */
153.3166 +    Int max_mark,       /* max allowed value of tag_mark */
153.3167 +
153.3168 +    Int n_row,          /* number of rows in A */
153.3169 +    Colamd_Row Row []   /* Row [0 ... n_row-1].shared2.mark is set to zero */
153.3170 +)
153.3171 +{
153.3172 +    /* === Local variables ================================================== */
153.3173 +
153.3174 +    Int r ;
153.3175 +
153.3176 +    if (tag_mark <= 0 || tag_mark >= max_mark)
153.3177 +    {
153.3178 +        for (r = 0 ; r < n_row ; r++)
153.3179 +        {
153.3180 +            if (ROW_IS_ALIVE (r))
153.3181 +            {
153.3182 +                Row [r].shared2.mark = 0 ;
153.3183 +            }
153.3184 +        }
153.3185 +        tag_mark = 1 ;
153.3186 +    }
153.3187 +
153.3188 +    return (tag_mark) ;
153.3189 +}
153.3190 +
153.3191 +
153.3192 +/* ========================================================================== */
153.3193 +/* === print_report ========================================================= */
153.3194 +/* ========================================================================== */
153.3195 +
153.3196 +PRIVATE void print_report
153.3197 +(
153.3198 +    char *method,
153.3199 +    Int stats [COLAMD_STATS]
153.3200 +)
153.3201 +{
153.3202 +
153.3203 +    Int i1, i2, i3 ;
153.3204 +
153.3205 +    PRINTF (("\n%s version %d.%d, %s: ", method,
153.3206 +            COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION, COLAMD_DATE)) ;
153.3207 +
153.3208 +    if (!stats)
153.3209 +    {
153.3210 +        PRINTF (("No statistics available.\n")) ;
153.3211 +        return ;
153.3212 +    }
153.3213 +
153.3214 +    i1 = stats [COLAMD_INFO1] ;
153.3215 +    i2 = stats [COLAMD_INFO2] ;
153.3216 +    i3 = stats [COLAMD_INFO3] ;
153.3217 +
153.3218 +    if (stats [COLAMD_STATUS] >= 0)
153.3219 +    {
153.3220 +        PRINTF (("OK.  ")) ;
153.3221 +    }
153.3222 +    else
153.3223 +    {
153.3224 +        PRINTF (("ERROR.  ")) ;
153.3225 +    }
153.3226 +
153.3227 +    switch (stats [COLAMD_STATUS])
153.3228 +    {
153.3229 +
153.3230 +        case COLAMD_OK_BUT_JUMBLED:
153.3231 +
153.3232 +            PRINTF(("Matrix has unsorted or duplicate row indices.\n")) ;
153.3233 +
153.3234 +            PRINTF(("%s: number of duplicate or out-of-order row indices: %d\n",
153.3235 +            method, i3)) ;
153.3236 +
153.3237 +            PRINTF(("%s: last seen duplicate or out-of-order row index:   %d\n",
153.3238 +            method, INDEX (i2))) ;
153.3239 +
153.3240 +            PRINTF(("%s: last seen in column:                             %d",
153.3241 +            method, INDEX (i1))) ;
153.3242 +
153.3243 +            /* no break - fall through to next case instead */
153.3244 +
153.3245 +        case COLAMD_OK:
153.3246 +
153.3247 +            PRINTF(("\n")) ;
153.3248 +
153.3249 +            PRINTF(("%s: number of dense or empty rows ignored:           %d\n",
153.3250 +            method, stats [COLAMD_DENSE_ROW])) ;
153.3251 +
153.3252 +            PRINTF(("%s: number of dense or empty columns ignored:        %d\n",
153.3253 +            method, stats [COLAMD_DENSE_COL])) ;
153.3254 +
153.3255 +            PRINTF(("%s: number of garbage collections performed:         %d\n",
153.3256 +            method, stats [COLAMD_DEFRAG_COUNT])) ;
153.3257 +            break ;
153.3258 +
153.3259 +        case COLAMD_ERROR_A_not_present:
153.3260 +
153.3261 +            PRINTF(("Array A (row indices of matrix) not present.\n")) ;
153.3262 +            break ;
153.3263 +
153.3264 +        case COLAMD_ERROR_p_not_present:
153.3265 +
153.3266 +            PRINTF(("Array p (column pointers for matrix) not present.\n")) ;
153.3267 +            break ;
153.3268 +
153.3269 +        case COLAMD_ERROR_nrow_negative:
153.3270 +
153.3271 +            PRINTF(("Invalid number of rows (%d).\n", i1)) ;
153.3272 +            break ;
153.3273 +
153.3274 +        case COLAMD_ERROR_ncol_negative:
153.3275 +
153.3276 +            PRINTF(("Invalid number of columns (%d).\n", i1)) ;
153.3277 +            break ;
153.3278 +
153.3279 +        case COLAMD_ERROR_nnz_negative:
153.3280 +
153.3281 +            PRINTF(("Invalid number of nonzero entries (%d).\n", i1)) ;
153.3282 +            break ;
153.3283 +
153.3284 +        case COLAMD_ERROR_p0_nonzero:
153.3285 +
153.3286 +            PRINTF(("Invalid column pointer, p [0] = %d, must be zero.\n", i1));
153.3287 +            break ;
153.3288 +
153.3289 +        case COLAMD_ERROR_A_too_small:
153.3290 +
153.3291 +            PRINTF(("Array A too small.\n")) ;
153.3292 +            PRINTF(("        Need Alen >= %d, but given only Alen = %d.\n",
153.3293 +            i1, i2)) ;
153.3294 +            break ;
153.3295 +
153.3296 +        case COLAMD_ERROR_col_length_negative:
153.3297 +
153.3298 +            PRINTF
153.3299 +            (("Column %d has a negative number of nonzero entries (%d).\n",
153.3300 +            INDEX (i1), i2)) ;
153.3301 +            break ;
153.3302 +
153.3303 +        case COLAMD_ERROR_row_index_out_of_bounds:
153.3304 +
153.3305 +            PRINTF
153.3306 +            (("Row index (row %d) out of bounds (%d to %d) in column %d.\n",
153.3307 +            INDEX (i2), INDEX (0), INDEX (i3-1), INDEX (i1))) ;
153.3308 +            break ;
153.3309 +
153.3310 +        case COLAMD_ERROR_out_of_memory:
153.3311 +
153.3312 +            PRINTF(("Out of memory.\n")) ;
153.3313 +            break ;
153.3314 +
153.3315 +        /* v2.4: internal-error case deleted */
153.3316 +    }
153.3317 +}
153.3318 +
153.3319 +
153.3320 +
153.3321 +
153.3322 +/* ========================================================================== */
153.3323 +/* === colamd debugging routines ============================================ */
153.3324 +/* ========================================================================== */
153.3325 +
153.3326 +/* When debugging is disabled, the remainder of this file is ignored. */
153.3327 +
153.3328 +#ifndef NDEBUG
153.3329 +
153.3330 +
153.3331 +/* ========================================================================== */
153.3332 +/* === debug_structures ===================================================== */
153.3333 +/* ========================================================================== */
153.3334 +
153.3335 +/*
153.3336 +    At this point, all empty rows and columns are dead.  All live columns
153.3337 +    are "clean" (containing no dead rows) and simplicial (no supercolumns
153.3338 +    yet).  Rows may contain dead columns, but all live rows contain at
153.3339 +    least one live column.
153.3340 +*/
153.3341 +
153.3342 +PRIVATE void debug_structures
153.3343 +(
153.3344 +    /* === Parameters ======================================================= */
153.3345 +
153.3346 +    Int n_row,
153.3347 +    Int n_col,
153.3348 +    Colamd_Row Row [],
153.3349 +    Colamd_Col Col [],
153.3350 +    Int A [],
153.3351 +    Int n_col2
153.3352 +)
153.3353 +{
153.3354 +    /* === Local variables ================================================== */
153.3355 +
153.3356 +    Int i ;
153.3357 +    Int c ;
153.3358 +    Int *cp ;
153.3359 +    Int *cp_end ;
153.3360 +    Int len ;
153.3361 +    Int score ;
153.3362 +    Int r ;
153.3363 +    Int *rp ;
153.3364 +    Int *rp_end ;
153.3365 +    Int deg ;
153.3366 +
153.3367 +    /* === Check A, Row, and Col ============================================ */
153.3368 +
153.3369 +    for (c = 0 ; c < n_col ; c++)
153.3370 +    {
153.3371 +        if (COL_IS_ALIVE (c))
153.3372 +        {
153.3373 +            len = Col [c].length ;
153.3374 +            score = Col [c].shared2.score ;
153.3375 +            DEBUG4 (("initial live col %5d %5d %5d\n", c, len, score)) ;
153.3376 +            ASSERT (len > 0) ;
153.3377 +            ASSERT (score >= 0) ;
153.3378 +            ASSERT (Col [c].shared1.thickness == 1) ;
153.3379 +            cp = &A [Col [c].start] ;
153.3380 +            cp_end = cp + len ;
153.3381 +            while (cp < cp_end)
153.3382 +            {
153.3383 +                r = *cp++ ;
153.3384 +                ASSERT (ROW_IS_ALIVE (r)) ;
153.3385 +            }
153.3386 +        }
153.3387 +        else
153.3388 +        {
153.3389 +            i = Col [c].shared2.order ;
153.3390 +            ASSERT (i >= n_col2 && i < n_col) ;
153.3391 +        }
153.3392 +    }
153.3393 +
153.3394 +    for (r = 0 ; r < n_row ; r++)
153.3395 +    {
153.3396 +        if (ROW_IS_ALIVE (r))
153.3397 +        {
153.3398 +            i = 0 ;
153.3399 +            len = Row [r].length ;
153.3400 +            deg = Row [r].shared1.degree ;
153.3401 +            ASSERT (len > 0) ;
153.3402 +            ASSERT (deg > 0) ;
153.3403 +            rp = &A [Row [r].start] ;
153.3404 +            rp_end = rp + len ;
153.3405 +            while (rp < rp_end)
153.3406 +            {
153.3407 +                c = *rp++ ;
153.3408 +                if (COL_IS_ALIVE (c))
153.3409 +                {
153.3410 +                    i++ ;
153.3411 +                }
153.3412 +            }
153.3413 +            ASSERT (i > 0) ;
153.3414 +        }
153.3415 +    }
153.3416 +}
153.3417 +
153.3418 +
153.3419 +/* ========================================================================== */
153.3420 +/* === debug_deg_lists ====================================================== */
153.3421 +/* ========================================================================== */
153.3422 +
153.3423 +/*
153.3424 +    Prints the contents of the degree lists.  Counts the number of columns
153.3425 +    in the degree list and compares it to the total it should have.  Also
153.3426 +    checks the row degrees.
153.3427 +*/
153.3428 +
153.3429 +PRIVATE void debug_deg_lists
153.3430 +(
153.3431 +    /* === Parameters ======================================================= */
153.3432 +
153.3433 +    Int n_row,
153.3434 +    Int n_col,
153.3435 +    Colamd_Row Row [],
153.3436 +    Colamd_Col Col [],
153.3437 +    Int head [],
153.3438 +    Int min_score,
153.3439 +    Int should,
153.3440 +    Int max_deg
153.3441 +)
153.3442 +{
153.3443 +    /* === Local variables ================================================== */
153.3444 +
153.3445 +    Int deg ;
153.3446 +    Int col ;
153.3447 +    Int have ;
153.3448 +    Int row ;
153.3449 +
153.3450 +    /* === Check the degree lists =========================================== */
153.3451 +
153.3452 +    if (n_col > 10000 && colamd_debug <= 0)
153.3453 +    {
153.3454 +        return ;
153.3455 +    }
153.3456 +    have = 0 ;
153.3457 +    DEBUG4 (("Degree lists: %d\n", min_score)) ;
153.3458 +    for (deg = 0 ; deg <= n_col ; deg++)
153.3459 +    {
153.3460 +        col = head [deg] ;
153.3461 +        if (col == EMPTY)
153.3462 +        {
153.3463 +            continue ;
153.3464 +        }
153.3465 +        DEBUG4 (("%d:", deg)) ;
153.3466 +        while (col != EMPTY)
153.3467 +        {
153.3468 +            DEBUG4 ((" %d", col)) ;
153.3469 +            have += Col [col].shared1.thickness ;
153.3470 +            ASSERT (COL_IS_ALIVE (col)) ;
153.3471 +            col = Col [col].shared4.degree_next ;
153.3472 +        }
153.3473 +        DEBUG4 (("\n")) ;
153.3474 +    }
153.3475 +    DEBUG4 (("should %d have %d\n", should, have)) ;
153.3476 +    ASSERT (should == have) ;
153.3477 +
153.3478 +    /* === Check the row degrees ============================================ */
153.3479 +
153.3480 +    if (n_row > 10000 && colamd_debug <= 0)
153.3481 +    {
153.3482 +        return ;
153.3483 +    }
153.3484 +    for (row = 0 ; row < n_row ; row++)
153.3485 +    {
153.3486 +        if (ROW_IS_ALIVE (row))
153.3487 +        {
153.3488 +            ASSERT (Row [row].shared1.degree <= max_deg) ;
153.3489 +        }
153.3490 +    }
153.3491 +}
153.3492 +
153.3493 +
153.3494 +/* ========================================================================== */
153.3495 +/* === debug_mark =========================================================== */
153.3496 +/* ========================================================================== */
153.3497 +
153.3498 +/*
153.3499 +    Ensures that the tag_mark is less that the maximum and also ensures that
153.3500 +    each entry in the mark array is less than the tag mark.
153.3501 +*/
153.3502 +
153.3503 +PRIVATE void debug_mark
153.3504 +(
153.3505 +    /* === Parameters ======================================================= */
153.3506 +
153.3507 +    Int n_row,
153.3508 +    Colamd_Row Row [],
153.3509 +    Int tag_mark,
153.3510 +    Int max_mark
153.3511 +)
153.3512 +{
153.3513 +    /* === Local variables ================================================== */
153.3514 +
153.3515 +    Int r ;
153.3516 +
153.3517 +    /* === Check the Row marks ============================================== */
153.3518 +
153.3519 +    ASSERT (tag_mark > 0 && tag_mark <= max_mark) ;
153.3520 +    if (n_row > 10000 && colamd_debug <= 0)
153.3521 +    {
153.3522 +        return ;
153.3523 +    }
153.3524 +    for (r = 0 ; r < n_row ; r++)
153.3525 +    {
153.3526 +        ASSERT (Row [r].shared2.mark < tag_mark) ;
153.3527 +    }
153.3528 +}
153.3529 +
153.3530 +
153.3531 +/* ========================================================================== */
153.3532 +/* === debug_matrix ========================================================= */
153.3533 +/* ========================================================================== */
153.3534 +
153.3535 +/*
153.3536 +    Prints out the contents of the columns and the rows.
153.3537 +*/
153.3538 +
153.3539 +PRIVATE void debug_matrix
153.3540 +(
153.3541 +    /* === Parameters ======================================================= */
153.3542 +
153.3543 +    Int n_row,
153.3544 +    Int n_col,
153.3545 +    Colamd_Row Row [],
153.3546 +    Colamd_Col Col [],
153.3547 +    Int A []
153.3548 +)
153.3549 +{
153.3550 +    /* === Local variables ================================================== */
153.3551 +
153.3552 +    Int r ;
153.3553 +    Int c ;
153.3554 +    Int *rp ;
153.3555 +    Int *rp_end ;
153.3556 +    Int *cp ;
153.3557 +    Int *cp_end ;
153.3558 +
153.3559 +    /* === Dump the rows and columns of the matrix ========================== */
153.3560 +
153.3561 +    if (colamd_debug < 3)
153.3562 +    {
153.3563 +        return ;
153.3564 +    }
153.3565 +    DEBUG3 (("DUMP MATRIX:\n")) ;
153.3566 +    for (r = 0 ; r < n_row ; r++)
153.3567 +    {
153.3568 +        DEBUG3 (("Row %d alive? %d\n", r, ROW_IS_ALIVE (r))) ;
153.3569 +        if (ROW_IS_DEAD (r))
153.3570 +        {
153.3571 +            continue ;
153.3572 +        }
153.3573 +        DEBUG3 (("start %d length %d degree %d\n",
153.3574 +                Row [r].start, Row [r].length, Row [r].shared1.degree)) ;
153.3575 +        rp = &A [Row [r].start] ;
153.3576 +        rp_end = rp + Row [r].length ;
153.3577 +        while (rp < rp_end)
153.3578 +        {
153.3579 +            c = *rp++ ;
153.3580 +            DEBUG4 (("  %d col %d\n", COL_IS_ALIVE (c), c)) ;
153.3581 +        }
153.3582 +    }
153.3583 +
153.3584 +    for (c = 0 ; c < n_col ; c++)
153.3585 +    {
153.3586 +        DEBUG3 (("Col %d alive? %d\n", c, COL_IS_ALIVE (c))) ;
153.3587 +        if (COL_IS_DEAD (c))
153.3588 +        {
153.3589 +            continue ;
153.3590 +        }
153.3591 +        DEBUG3 (("start %d length %d shared1 %d shared2 %d\n",
153.3592 +                Col [c].start, Col [c].length,
153.3593 +                Col [c].shared1.thickness, Col [c].shared2.score)) ;
153.3594 +        cp = &A [Col [c].start] ;
153.3595 +        cp_end = cp + Col [c].length ;
153.3596 +        while (cp < cp_end)
153.3597 +        {
153.3598 +            r = *cp++ ;
153.3599 +            DEBUG4 (("  %d row %d\n", ROW_IS_ALIVE (r), r)) ;
153.3600 +        }
153.3601 +    }
153.3602 +}
153.3603 +
153.3604 +PRIVATE void colamd_get_debug
153.3605 +(
153.3606 +    char *method
153.3607 +)
153.3608 +{
153.3609 +    FILE *f ;
153.3610 +    colamd_debug = 0 ;          /* no debug printing */
153.3611 +    f = fopen ("debug", "r") ;
153.3612 +    if (f == (FILE *) NULL)
153.3613 +    {
153.3614 +        colamd_debug = 0 ;
153.3615 +    }
153.3616 +    else
153.3617 +    {
153.3618 +        fscanf (f, "%d", &colamd_debug) ;
153.3619 +        fclose (f) ;
153.3620 +    }
153.3621 +    DEBUG0 (("%s: debug version, D = %d (THIS WILL BE SLOW!)\n",
153.3622 +        method, colamd_debug)) ;
153.3623 +}
153.3624 +
153.3625 +#endif /* NDEBUG */
   154.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   154.2 +++ b/src/colamd/colamd.h	Mon Dec 06 13:09:21 2010 +0100
   154.3 @@ -0,0 +1,69 @@
   154.4 +/* colamd.h */
   154.5 +
   154.6 +/* Written by Andrew Makhorin <mao@gnu.org>. */
   154.7 +
   154.8 +#ifndef COLAMD_H
   154.9 +#define COLAMD_H
  154.10 +
  154.11 +#define _GLPSTD_STDIO
  154.12 +#include "glpenv.h"
  154.13 +
  154.14 +#define COLAMD_DATE "Nov 1, 2007"
  154.15 +#define COLAMD_VERSION_CODE(main, sub) ((main) * 1000 + (sub))
  154.16 +#define COLAMD_MAIN_VERSION 2
  154.17 +#define COLAMD_SUB_VERSION 7
  154.18 +#define COLAMD_SUBSUB_VERSION 1
  154.19 +#define COLAMD_VERSION \
  154.20 +        COLAMD_VERSION_CODE(COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION)
  154.21 +
  154.22 +#define COLAMD_KNOBS 20
  154.23 +#define COLAMD_STATS 20
  154.24 +#define COLAMD_DENSE_ROW 0
  154.25 +#define COLAMD_DENSE_COL 1
  154.26 +#define COLAMD_AGGRESSIVE 2
  154.27 +#define COLAMD_DEFRAG_COUNT 2
  154.28 +#define COLAMD_STATUS 3
  154.29 +#define COLAMD_INFO1 4
  154.30 +#define COLAMD_INFO2 5
  154.31 +#define COLAMD_INFO3 6
  154.32 +
  154.33 +#define COLAMD_OK                            (0)
  154.34 +#define COLAMD_OK_BUT_JUMBLED                (1)
  154.35 +#define COLAMD_ERROR_A_not_present           (-1)
  154.36 +#define COLAMD_ERROR_p_not_present           (-2)
  154.37 +#define COLAMD_ERROR_nrow_negative           (-3)
  154.38 +#define COLAMD_ERROR_ncol_negative           (-4)
  154.39 +#define COLAMD_ERROR_nnz_negative            (-5)
  154.40 +#define COLAMD_ERROR_p0_nonzero              (-6)
  154.41 +#define COLAMD_ERROR_A_too_small             (-7)
  154.42 +#define COLAMD_ERROR_col_length_negative     (-8)
  154.43 +#define COLAMD_ERROR_row_index_out_of_bounds (-9)
  154.44 +#define COLAMD_ERROR_out_of_memory           (-10)
  154.45 +#define COLAMD_ERROR_internal_error          (-999)
  154.46 +
  154.47 +#define colamd_recommended _glp_colamd_recommended
  154.48 +size_t colamd_recommended(int nnz, int n_row, int n_col);
  154.49 +
  154.50 +#define colamd_set_defaults _glp_colamd_set_defaults
  154.51 +void colamd_set_defaults(double knobs [COLAMD_KNOBS]);
  154.52 +
  154.53 +#define colamd _glp_colamd
  154.54 +int colamd(int n_row, int n_col, int Alen, int A[], int p[],
  154.55 +      double knobs[COLAMD_KNOBS], int stats[COLAMD_STATS]);
  154.56 +
  154.57 +#define symamd _glp_symamd
  154.58 +int symamd(int n, int A[], int p[], int perm[],
  154.59 +      double knobs[COLAMD_KNOBS], int stats[COLAMD_STATS],
  154.60 +      void *(*allocate)(size_t, size_t), void(*release)(void *));
  154.61 +
  154.62 +#define colamd_report _glp_colamd_report
  154.63 +void colamd_report(int stats[COLAMD_STATS]);
  154.64 +
  154.65 +#define symamd_report _glp_symamd_report
  154.66 +void symamd_report(int stats[COLAMD_STATS]);
  154.67 +
  154.68 +#define colamd_printf xprintf
  154.69 +
  154.70 +#endif
  154.71 +
  154.72 +/* eof */
   155.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   155.2 +++ b/src/glpapi.h	Mon Dec 06 13:09:21 2010 +0100
   155.3 @@ -0,0 +1,314 @@
   155.4 +/* glpapi.h (application program interface) */
   155.5 +
   155.6 +/***********************************************************************
   155.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   155.8 +*
   155.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  155.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  155.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  155.12 +*  E-mail: <mao@gnu.org>.
  155.13 +*
  155.14 +*  GLPK is free software: you can redistribute it and/or modify it
  155.15 +*  under the terms of the GNU General Public License as published by
  155.16 +*  the Free Software Foundation, either version 3 of the License, or
  155.17 +*  (at your option) any later version.
  155.18 +*
  155.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  155.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  155.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  155.22 +*  License for more details.
  155.23 +*
  155.24 +*  You should have received a copy of the GNU General Public License
  155.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  155.26 +***********************************************************************/
  155.27 +
  155.28 +#ifndef GLPAPI_H
  155.29 +#define GLPAPI_H
  155.30 +
  155.31 +#define GLP_PROB_DEFINED
  155.32 +typedef struct glp_prob glp_prob;
  155.33 +
  155.34 +#include "glpk.h"
  155.35 +#include "glpavl.h"
  155.36 +#include "glpbfd.h"
  155.37 +
  155.38 +typedef struct GLPROW GLPROW;
  155.39 +typedef struct GLPCOL GLPCOL;
  155.40 +typedef struct GLPAIJ GLPAIJ;
  155.41 +
  155.42 +#define GLP_PROB_MAGIC 0xD7D9D6C2
  155.43 +
  155.44 +struct glp_prob
  155.45 +{     /* LP/MIP problem object */
  155.46 +      int magic;
  155.47 +      /* magic value used for debugging */
  155.48 +      DMP *pool;
  155.49 +      /* memory pool to store problem object components */
  155.50 +      glp_tree *tree;
  155.51 +      /* pointer to the search tree; set by the MIP solver when this
  155.52 +         object is used in the tree as a core MIP object */
  155.53 +      void *parms;
  155.54 +      /* reserved for backward compatibility */
  155.55 +      /*--------------------------------------------------------------*/
  155.56 +      /* LP/MIP data */
  155.57 +      char *name;
  155.58 +      /* problem name (1 to 255 chars); NULL means no name is assigned
  155.59 +         to the problem */
  155.60 +      char *obj;
  155.61 +      /* objective function name (1 to 255 chars); NULL means no name
  155.62 +         is assigned to the objective function */
  155.63 +      int dir;
  155.64 +      /* optimization direction flag (objective "sense"):
  155.65 +         GLP_MIN - minimization
  155.66 +         GLP_MAX - maximization */
  155.67 +      double c0;
  155.68 +      /* constant term of the objective function ("shift") */
  155.69 +      int m_max;
  155.70 +      /* length of the array of rows (enlarged automatically) */
  155.71 +      int n_max;
  155.72 +      /* length of the array of columns (enlarged automatically) */
  155.73 +      int m;
  155.74 +      /* number of rows, 0 <= m <= m_max */
  155.75 +      int n;
  155.76 +      /* number of columns, 0 <= n <= n_max */
  155.77 +      int nnz;
  155.78 +      /* number of non-zero constraint coefficients, nnz >= 0 */
  155.79 +      GLPROW **row; /* GLPROW *row[1+m_max]; */
  155.80 +      /* row[i], 1 <= i <= m, is a pointer to i-th row */
  155.81 +      GLPCOL **col; /* GLPCOL *col[1+n_max]; */
  155.82 +      /* col[j], 1 <= j <= n, is a pointer to j-th column */
  155.83 +      AVL *r_tree;
  155.84 +      /* row index to find rows by their names; NULL means this index
  155.85 +         does not exist */
  155.86 +      AVL *c_tree;
  155.87 +      /* column index to find columns by their names; NULL means this
  155.88 +         index does not exist */
  155.89 +      /*--------------------------------------------------------------*/
  155.90 +      /* basis factorization (LP) */
  155.91 +      int valid;
  155.92 +      /* the factorization is valid only if this flag is set */
  155.93 +      int *head; /* int head[1+m_max]; */
  155.94 +      /* basis header (valid only if the factorization is valid);
  155.95 +         head[i] = k is the ordinal number of auxiliary (1 <= k <= m)
  155.96 +         or structural (m+1 <= k <= m+n) variable which corresponds to
  155.97 +         i-th basic variable xB[i], 1 <= i <= m */
  155.98 +      glp_bfcp *bfcp;
  155.99 +      /* basis factorization control parameters; may be NULL */
 155.100 +      BFD *bfd; /* BFD bfd[1:m,1:m]; */
 155.101 +      /* basis factorization driver; may be NULL */
 155.102 +      /*--------------------------------------------------------------*/
 155.103 +      /* basic solution (LP) */
 155.104 +      int pbs_stat;
 155.105 +      /* primal basic solution status:
 155.106 +         GLP_UNDEF  - primal solution is undefined
 155.107 +         GLP_FEAS   - primal solution is feasible
 155.108 +         GLP_INFEAS - primal solution is infeasible
 155.109 +         GLP_NOFEAS - no primal feasible solution exists */
 155.110 +      int dbs_stat;
 155.111 +      /* dual basic solution status:
 155.112 +         GLP_UNDEF  - dual solution is undefined
 155.113 +         GLP_FEAS   - dual solution is feasible
 155.114 +         GLP_INFEAS - dual solution is infeasible
 155.115 +         GLP_NOFEAS - no dual feasible solution exists */
 155.116 +      double obj_val;
 155.117 +      /* objective function value */
 155.118 +      int it_cnt;
 155.119 +      /* simplex method iteration count; increased by one on performing
 155.120 +         one simplex iteration */
 155.121 +      int some;
 155.122 +      /* ordinal number of some auxiliary or structural variable having
 155.123 +         certain property, 0 <= some <= m+n */
 155.124 +      /*--------------------------------------------------------------*/
 155.125 +      /* interior-point solution (LP) */
 155.126 +      int ipt_stat;
 155.127 +      /* interior-point solution status:
 155.128 +         GLP_UNDEF  - interior solution is undefined
 155.129 +         GLP_OPT    - interior solution is optimal
 155.130 +         GLP_INFEAS - interior solution is infeasible
 155.131 +         GLP_NOFEAS - no feasible solution exists */
 155.132 +      double ipt_obj;
 155.133 +      /* objective function value */
 155.134 +      /*--------------------------------------------------------------*/
 155.135 +      /* integer solution (MIP) */
 155.136 +      int mip_stat;
 155.137 +      /* integer solution status:
 155.138 +         GLP_UNDEF  - integer solution is undefined
 155.139 +         GLP_OPT    - integer solution is optimal
 155.140 +         GLP_FEAS   - integer solution is feasible
 155.141 +         GLP_NOFEAS - no integer solution exists */
 155.142 +      double mip_obj;
 155.143 +      /* objective function value */
 155.144 +};
 155.145 +
 155.146 +struct GLPROW
 155.147 +{     /* LP/MIP row (auxiliary variable) */
 155.148 +      int i;
 155.149 +      /* ordinal number (1 to m) assigned to this row */
 155.150 +      char *name;
 155.151 +      /* row name (1 to 255 chars); NULL means no name is assigned to
 155.152 +         this row */
 155.153 +      AVLNODE *node;
 155.154 +      /* pointer to corresponding node in the row index; NULL means
 155.155 +         that either the row index does not exist or this row has no
 155.156 +         name assigned */
 155.157 +#if 1 /* 20/IX-2008 */
 155.158 +      int level;
 155.159 +      unsigned char origin;
 155.160 +      unsigned char klass;
 155.161 +#endif
 155.162 +      int type;
 155.163 +      /* type of the auxiliary variable:
 155.164 +         GLP_FR - free variable
 155.165 +         GLP_LO - variable with lower bound
 155.166 +         GLP_UP - variable with upper bound
 155.167 +         GLP_DB - double-bounded variable
 155.168 +         GLP_FX - fixed variable */
 155.169 +      double lb; /* non-scaled */
 155.170 +      /* lower bound; if the row has no lower bound, lb is zero */
 155.171 +      double ub; /* non-scaled */
 155.172 +      /* upper bound; if the row has no upper bound, ub is zero */
 155.173 +      /* if the row type is GLP_FX, ub is equal to lb */
 155.174 +      GLPAIJ *ptr; /* non-scaled */
 155.175 +      /* pointer to doubly linked list of constraint coefficients which
 155.176 +         are placed in this row */
 155.177 +      double rii;
 155.178 +      /* diagonal element r[i,i] of scaling matrix R for this row;
 155.179 +         if the scaling is not used, r[i,i] is 1 */
 155.180 +      int stat;
 155.181 +      /* status of the auxiliary variable:
 155.182 +         GLP_BS - basic variable
 155.183 +         GLP_NL - non-basic variable on lower bound
 155.184 +         GLP_NU - non-basic variable on upper bound
 155.185 +         GLP_NF - non-basic free variable
 155.186 +         GLP_NS - non-basic fixed variable */
 155.187 +      int bind;
 155.188 +      /* if the auxiliary variable is basic, head[bind] refers to this
 155.189 +         row, otherwise, bind is 0; this attribute is valid only if the
 155.190 +         basis factorization is valid */
 155.191 +      double prim; /* non-scaled */
 155.192 +      /* primal value of the auxiliary variable in basic solution */
 155.193 +      double dual; /* non-scaled */
 155.194 +      /* dual value of the auxiliary variable in basic solution */
 155.195 +      double pval; /* non-scaled */
 155.196 +      /* primal value of the auxiliary variable in interior solution */
 155.197 +      double dval; /* non-scaled */
 155.198 +      /* dual value of the auxiliary variable in interior solution */
 155.199 +      double mipx; /* non-scaled */
 155.200 +      /* primal value of the auxiliary variable in integer solution */
 155.201 +};
 155.202 +
 155.203 +struct GLPCOL
 155.204 +{     /* LP/MIP column (structural variable) */
 155.205 +      int j;
 155.206 +      /* ordinal number (1 to n) assigned to this column */
 155.207 +      char *name;
 155.208 +      /* column name (1 to 255 chars); NULL means no name is assigned
 155.209 +         to this column */
 155.210 +      AVLNODE *node;
 155.211 +      /* pointer to corresponding node in the column index; NULL means
 155.212 +         that either the column index does not exist or the column has
 155.213 +         no name assigned */
 155.214 +      int kind;
 155.215 +      /* kind of the structural variable:
 155.216 +         GLP_CV - continuous variable
 155.217 +         GLP_IV - integer or binary variable */
 155.218 +      int type;
 155.219 +      /* type of the structural variable:
 155.220 +         GLP_FR - free variable
 155.221 +         GLP_LO - variable with lower bound
 155.222 +         GLP_UP - variable with upper bound
 155.223 +         GLP_DB - double-bounded variable
 155.224 +         GLP_FX - fixed variable */
 155.225 +      double lb; /* non-scaled */
 155.226 +      /* lower bound; if the column has no lower bound, lb is zero */
 155.227 +      double ub; /* non-scaled */
 155.228 +      /* upper bound; if the column has no upper bound, ub is zero */
 155.229 +      /* if the column type is GLP_FX, ub is equal to lb */
 155.230 +      double coef; /* non-scaled */
 155.231 +      /* objective coefficient at the structural variable */
 155.232 +      GLPAIJ *ptr; /* non-scaled */
 155.233 +      /* pointer to doubly linked list of constraint coefficients which
 155.234 +         are placed in this column */
 155.235 +      double sjj;
 155.236 +      /* diagonal element s[j,j] of scaling matrix S for this column;
 155.237 +         if the scaling is not used, s[j,j] is 1 */
 155.238 +      int stat;
 155.239 +      /* status of the structural variable:
 155.240 +         GLP_BS - basic variable
 155.241 +         GLP_NL - non-basic variable on lower bound
 155.242 +         GLP_NU - non-basic variable on upper bound
 155.243 +         GLP_NF - non-basic free variable
 155.244 +         GLP_NS - non-basic fixed variable */
 155.245 +      int bind;
 155.246 +      /* if the structural variable is basic, head[bind] refers to
 155.247 +         this column; otherwise, bind is 0; this attribute is valid only
 155.248 +         if the basis factorization is valid */
 155.249 +      double prim; /* non-scaled */
 155.250 +      /* primal value of the structural variable in basic solution */
 155.251 +      double dual; /* non-scaled */
 155.252 +      /* dual value of the structural variable in basic solution */
 155.253 +      double pval; /* non-scaled */
 155.254 +      /* primal value of the structural variable in interior solution */
 155.255 +      double dval; /* non-scaled */
 155.256 +      /* dual value of the structural variable in interior solution */
 155.257 +      double mipx; /* non-scaled */
 155.258 +      /* primal value of the structural variable in integer solution */
 155.259 +};
 155.260 +
 155.261 +struct GLPAIJ
 155.262 +{     /* constraint coefficient a[i,j] */
 155.263 +      GLPROW *row;
 155.264 +      /* pointer to row, where this coefficient is placed */
 155.265 +      GLPCOL *col;
 155.266 +      /* pointer to column, where this coefficient is placed */
 155.267 +      double val;
 155.268 +      /* numeric (non-zero) value of this coefficient */
 155.269 +      GLPAIJ *r_prev;
 155.270 +      /* pointer to previous coefficient in the same row */
 155.271 +      GLPAIJ *r_next;
 155.272 +      /* pointer to next coefficient in the same row */
 155.273 +      GLPAIJ *c_prev;
 155.274 +      /* pointer to previous coefficient in the same column */
 155.275 +      GLPAIJ *c_next;
 155.276 +      /* pointer to next coefficient in the same column */
 155.277 +};
 155.278 +
 155.279 +void _glp_check_kkt(glp_prob *P, int sol, int cond, double *ae_max,
 155.280 +      int *ae_ind, double *re_max, int *re_ind);
 155.281 +/* check feasibility and optimality conditions */
 155.282 +
 155.283 +#define lpx_put_solution _glp_put_solution
 155.284 +void lpx_put_solution(glp_prob *lp, int inval, const int *p_stat,
 155.285 +      const int *d_stat, const double *obj_val, const int r_stat[],
 155.286 +      const double r_prim[], const double r_dual[], const int c_stat[],
 155.287 +      const double c_prim[], const double c_dual[]);
 155.288 +/* store basic solution components */
 155.289 +
 155.290 +#define lpx_put_mip_soln _glp_put_mip_soln
 155.291 +void lpx_put_mip_soln(LPX *lp, int i_stat, double row_mipx[],
 155.292 +      double col_mipx[]);
 155.293 +/* store mixed integer solution components */
 155.294 +
 155.295 +#if 1 /* 28/XI-2009 */
 155.296 +int _glp_analyze_row(glp_prob *P, int len, const int ind[],
 155.297 +      const double val[], int type, double rhs, double eps, int *_piv,
 155.298 +      double *_x, double *_dx, double *_y, double *_dy, double *_dz);
 155.299 +/* simulate one iteration of dual simplex method */
 155.300 +#endif
 155.301 +
 155.302 +#if 1 /* 08/XII-2009 */
 155.303 +void _glp_mpl_init_rand(glp_tran *tran, int seed);
 155.304 +#endif
 155.305 +
 155.306 +#define glp_skpgen _glp_skpgen
 155.307 +void glp_skpgen(int n, int r, int type, int v, int s, int a[],
 155.308 +   int *b, int c[]);
 155.309 +/* Pisinger's 0-1 single knapsack problem generator */
 155.310 +
 155.311 +#if 1 /* 28/V-2010 */
 155.312 +int _glp_intopt1(glp_prob *P, const glp_iocp *parm);
 155.313 +#endif
 155.314 +
 155.315 +#endif
 155.316 +
 155.317 +/* eof */
   156.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   156.2 +++ b/src/glpapi01.c	Mon Dec 06 13:09:21 2010 +0100
   156.3 @@ -0,0 +1,1570 @@
   156.4 +/* glpapi01.c (problem creating and modifying routines) */
   156.5 +
   156.6 +/***********************************************************************
   156.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   156.8 +*
   156.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  156.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  156.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  156.12 +*  E-mail: <mao@gnu.org>.
  156.13 +*
  156.14 +*  GLPK is free software: you can redistribute it and/or modify it
  156.15 +*  under the terms of the GNU General Public License as published by
  156.16 +*  the Free Software Foundation, either version 3 of the License, or
  156.17 +*  (at your option) any later version.
  156.18 +*
  156.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  156.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  156.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  156.22 +*  License for more details.
  156.23 +*
  156.24 +*  You should have received a copy of the GNU General Public License
  156.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  156.26 +***********************************************************************/
  156.27 +
  156.28 +#include "glpios.h"
  156.29 +
  156.30 +/* CAUTION: DO NOT CHANGE THE LIMITS BELOW */
  156.31 +
  156.32 +#define M_MAX 100000000 /* = 100*10^6 */
  156.33 +/* maximal number of rows in the problem object */
  156.34 +
  156.35 +#define N_MAX 100000000 /* = 100*10^6 */
  156.36 +/* maximal number of columns in the problem object */
  156.37 +
  156.38 +#define NNZ_MAX 500000000 /* = 500*10^6 */
  156.39 +/* maximal number of constraint coefficients in the problem object */
  156.40 +
  156.41 +/***********************************************************************
  156.42 +*  NAME
  156.43 +*
  156.44 +*  glp_create_prob - create problem object
  156.45 +*
  156.46 +*  SYNOPSIS
  156.47 +*
  156.48 +*  glp_prob *glp_create_prob(void);
  156.49 +*
  156.50 +*  DESCRIPTION
  156.51 +*
  156.52 +*  The routine glp_create_prob creates a new problem object, which is
  156.53 +*  initially "empty", i.e. has no rows and columns.
  156.54 +*
  156.55 +*  RETURNS
  156.56 +*
  156.57 +*  The routine returns a pointer to the object created, which should be
  156.58 +*  used in any subsequent operations on this object. */
  156.59 +
  156.60 +static void create_prob(glp_prob *lp)
  156.61 +{     lp->magic = GLP_PROB_MAGIC;
  156.62 +      lp->pool = dmp_create_pool();
  156.63 +#if 0 /* 17/XI-2009 */
  156.64 +      lp->cps = xmalloc(sizeof(struct LPXCPS));
  156.65 +      lpx_reset_parms(lp);
  156.66 +#else
  156.67 +      lp->parms = NULL;
  156.68 +#endif
  156.69 +      lp->tree = NULL;
  156.70 +#if 0
  156.71 +      lp->lwa = 0;
  156.72 +      lp->cwa = NULL;
  156.73 +#endif
  156.74 +      /* LP/MIP data */
  156.75 +      lp->name = NULL;
  156.76 +      lp->obj = NULL;
  156.77 +      lp->dir = GLP_MIN;
  156.78 +      lp->c0 = 0.0;
  156.79 +      lp->m_max = 100;
  156.80 +      lp->n_max = 200;
  156.81 +      lp->m = lp->n = 0;
  156.82 +      lp->nnz = 0;
  156.83 +      lp->row = xcalloc(1+lp->m_max, sizeof(GLPROW *));
  156.84 +      lp->col = xcalloc(1+lp->n_max, sizeof(GLPCOL *));
  156.85 +      lp->r_tree = lp->c_tree = NULL;
  156.86 +      /* basis factorization */
  156.87 +      lp->valid = 0;
  156.88 +      lp->head = xcalloc(1+lp->m_max, sizeof(int));
  156.89 +      lp->bfcp = NULL;
  156.90 +      lp->bfd = NULL;
  156.91 +      /* basic solution (LP) */
  156.92 +      lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
  156.93 +      lp->obj_val = 0.0;
  156.94 +      lp->it_cnt = 0;
  156.95 +      lp->some = 0;
  156.96 +      /* interior-point solution (LP) */
  156.97 +      lp->ipt_stat = GLP_UNDEF;
  156.98 +      lp->ipt_obj = 0.0;
  156.99 +      /* integer solution (MIP) */
 156.100 +      lp->mip_stat = GLP_UNDEF;
 156.101 +      lp->mip_obj = 0.0;
 156.102 +      return;
 156.103 +}
 156.104 +
 156.105 +glp_prob *glp_create_prob(void)
 156.106 +{     glp_prob *lp;
 156.107 +      lp = xmalloc(sizeof(glp_prob));
 156.108 +      create_prob(lp);
 156.109 +      return lp;
 156.110 +}
 156.111 +
 156.112 +/***********************************************************************
 156.113 +*  NAME
 156.114 +*
 156.115 +*  glp_set_prob_name - assign (change) problem name
 156.116 +*
 156.117 +*  SYNOPSIS
 156.118 +*
 156.119 +*  void glp_set_prob_name(glp_prob *lp, const char *name);
 156.120 +*
 156.121 +*  DESCRIPTION
 156.122 +*
 156.123 +*  The routine glp_set_prob_name assigns a given symbolic name (1 up to
 156.124 +*  255 characters) to the specified problem object.
 156.125 +*
 156.126 +*  If the parameter name is NULL or empty string, the routine erases an
 156.127 +*  existing symbolic name of the problem object. */
 156.128 +
 156.129 +void glp_set_prob_name(glp_prob *lp, const char *name)
 156.130 +{     glp_tree *tree = lp->tree;
 156.131 +      if (tree != NULL && tree->reason != 0)
 156.132 +         xerror("glp_set_prob_name: operation not allowed\n");
 156.133 +      if (lp->name != NULL)
 156.134 +      {  dmp_free_atom(lp->pool, lp->name, strlen(lp->name)+1);
 156.135 +         lp->name = NULL;
 156.136 +      }
 156.137 +      if (!(name == NULL || name[0] == '\0'))
 156.138 +      {  int k;
 156.139 +         for (k = 0; name[k] != '\0'; k++)
 156.140 +         {  if (k == 256)
 156.141 +               xerror("glp_set_prob_name: problem name too long\n");
 156.142 +            if (iscntrl((unsigned char)name[k]))
 156.143 +               xerror("glp_set_prob_name: problem name contains invalid"
 156.144 +                  " character(s)\n");
 156.145 +         }
 156.146 +         lp->name = dmp_get_atom(lp->pool, strlen(name)+1);
 156.147 +         strcpy(lp->name, name);
 156.148 +      }
 156.149 +      return;
 156.150 +}
 156.151 +
 156.152 +/***********************************************************************
 156.153 +*  NAME
 156.154 +*
 156.155 +*  glp_set_obj_name - assign (change) objective function name
 156.156 +*
 156.157 +*  SYNOPSIS
 156.158 +*
 156.159 +*  void glp_set_obj_name(glp_prob *lp, const char *name);
 156.160 +*
 156.161 +*  DESCRIPTION
 156.162 +*
 156.163 +*  The routine glp_set_obj_name assigns a given symbolic name (1 up to
 156.164 +*  255 characters) to the objective function of the specified problem
 156.165 +*  object.
 156.166 +*
 156.167 +*  If the parameter name is NULL or empty string, the routine erases an
 156.168 +*  existing name of the objective function. */
 156.169 +
 156.170 +void glp_set_obj_name(glp_prob *lp, const char *name)
 156.171 +{     glp_tree *tree = lp->tree;
 156.172 +      if (tree != NULL && tree->reason != 0)
 156.173 +         xerror("glp_set_obj_name: operation not allowed\n");
 156.174 +     if (lp->obj != NULL)
 156.175 +      {  dmp_free_atom(lp->pool, lp->obj, strlen(lp->obj)+1);
 156.176 +         lp->obj = NULL;
 156.177 +      }
 156.178 +      if (!(name == NULL || name[0] == '\0'))
 156.179 +      {  int k;
 156.180 +         for (k = 0; name[k] != '\0'; k++)
 156.181 +         {  if (k == 256)
 156.182 +               xerror("glp_set_obj_name: objective name too long\n");
 156.183 +            if (iscntrl((unsigned char)name[k]))
 156.184 +               xerror("glp_set_obj_name: objective name contains invali"
 156.185 +                  "d character(s)\n");
 156.186 +         }
 156.187 +         lp->obj = dmp_get_atom(lp->pool, strlen(name)+1);
 156.188 +         strcpy(lp->obj, name);
 156.189 +      }
 156.190 +      return;
 156.191 +}
 156.192 +
 156.193 +/***********************************************************************
 156.194 +*  NAME
 156.195 +*
 156.196 +*  glp_set_obj_dir - set (change) optimization direction flag
 156.197 +*
 156.198 +*  SYNOPSIS
 156.199 +*
 156.200 +*  void glp_set_obj_dir(glp_prob *lp, int dir);
 156.201 +*
 156.202 +*  DESCRIPTION
 156.203 +*
 156.204 +*  The routine glp_set_obj_dir sets (changes) optimization direction
 156.205 +*  flag (i.e. "sense" of the objective function) as specified by the
 156.206 +*  parameter dir:
 156.207 +*
 156.208 +*  GLP_MIN - minimization;
 156.209 +*  GLP_MAX - maximization. */
 156.210 +
 156.211 +void glp_set_obj_dir(glp_prob *lp, int dir)
 156.212 +{     glp_tree *tree = lp->tree;
 156.213 +      if (tree != NULL && tree->reason != 0)
 156.214 +         xerror("glp_set_obj_dir: operation not allowed\n");
 156.215 +     if (!(dir == GLP_MIN || dir == GLP_MAX))
 156.216 +         xerror("glp_set_obj_dir: dir = %d; invalid direction flag\n",
 156.217 +            dir);
 156.218 +      lp->dir = dir;
 156.219 +      return;
 156.220 +}
 156.221 +
 156.222 +/***********************************************************************
 156.223 +*  NAME
 156.224 +*
 156.225 +*  glp_add_rows - add new rows to problem object
 156.226 +*
 156.227 +*  SYNOPSIS
 156.228 +*
 156.229 +*  int glp_add_rows(glp_prob *lp, int nrs);
 156.230 +*
 156.231 +*  DESCRIPTION
 156.232 +*
 156.233 +*  The routine glp_add_rows adds nrs rows (constraints) to the specified
 156.234 +*  problem object. New rows are always added to the end of the row list,
 156.235 +*  so the ordinal numbers of existing rows remain unchanged.
 156.236 +*
 156.237 +*  Being added each new row is initially free (unbounded) and has empty
 156.238 +*  list of the constraint coefficients.
 156.239 +*
 156.240 +*  RETURNS
 156.241 +*
 156.242 +*  The routine glp_add_rows returns the ordinal number of the first new
 156.243 +*  row added to the problem object. */
 156.244 +
 156.245 +int glp_add_rows(glp_prob *lp, int nrs)
 156.246 +{     glp_tree *tree = lp->tree;
 156.247 +      GLPROW *row;
 156.248 +      int m_new, i;
 156.249 +      /* determine new number of rows */
 156.250 +      if (nrs < 1)
 156.251 +         xerror("glp_add_rows: nrs = %d; invalid number of rows\n",
 156.252 +            nrs);
 156.253 +      if (nrs > M_MAX - lp->m)
 156.254 +         xerror("glp_add_rows: nrs = %d; too many rows\n", nrs);
 156.255 +      m_new = lp->m + nrs;
 156.256 +      /* increase the room, if necessary */
 156.257 +      if (lp->m_max < m_new)
 156.258 +      {  GLPROW **save = lp->row;
 156.259 +         while (lp->m_max < m_new)
 156.260 +         {  lp->m_max += lp->m_max;
 156.261 +            xassert(lp->m_max > 0);
 156.262 +         }
 156.263 +         lp->row = xcalloc(1+lp->m_max, sizeof(GLPROW *));
 156.264 +         memcpy(&lp->row[1], &save[1], lp->m * sizeof(GLPROW *));
 156.265 +         xfree(save);
 156.266 +         /* do not forget about the basis header */
 156.267 +         xfree(lp->head);
 156.268 +         lp->head = xcalloc(1+lp->m_max, sizeof(int));
 156.269 +      }
 156.270 +      /* add new rows to the end of the row list */
 156.271 +      for (i = lp->m+1; i <= m_new; i++)
 156.272 +      {  /* create row descriptor */
 156.273 +         lp->row[i] = row = dmp_get_atom(lp->pool, sizeof(GLPROW));
 156.274 +         row->i = i;
 156.275 +         row->name = NULL;
 156.276 +         row->node = NULL;
 156.277 +#if 1 /* 20/IX-2008 */
 156.278 +         row->level = 0;
 156.279 +         row->origin = 0;
 156.280 +         row->klass = 0;
 156.281 +         if (tree != NULL)
 156.282 +         {  switch (tree->reason)
 156.283 +            {  case 0:
 156.284 +                  break;
 156.285 +               case GLP_IROWGEN:
 156.286 +                  xassert(tree->curr != NULL);
 156.287 +                  row->level = tree->curr->level;
 156.288 +                  row->origin = GLP_RF_LAZY;
 156.289 +                  break;
 156.290 +               case GLP_ICUTGEN:
 156.291 +                  xassert(tree->curr != NULL);
 156.292 +                  row->level = tree->curr->level;
 156.293 +                  row->origin = GLP_RF_CUT;
 156.294 +                  break;
 156.295 +               default:
 156.296 +                  xassert(tree != tree);
 156.297 +            }
 156.298 +         }
 156.299 +#endif
 156.300 +         row->type = GLP_FR;
 156.301 +         row->lb = row->ub = 0.0;
 156.302 +         row->ptr = NULL;
 156.303 +         row->rii = 1.0;
 156.304 +         row->stat = GLP_BS;
 156.305 +#if 0
 156.306 +         row->bind = -1;
 156.307 +#else
 156.308 +         row->bind = 0;
 156.309 +#endif
 156.310 +         row->prim = row->dual = 0.0;
 156.311 +         row->pval = row->dval = 0.0;
 156.312 +         row->mipx = 0.0;
 156.313 +      }
 156.314 +      /* set new number of rows */
 156.315 +      lp->m = m_new;
 156.316 +      /* invalidate the basis factorization */
 156.317 +      lp->valid = 0;
 156.318 +#if 1
 156.319 +      if (tree != NULL && tree->reason != 0) tree->reopt = 1;
 156.320 +#endif
 156.321 +      /* return the ordinal number of the first row added */
 156.322 +      return m_new - nrs + 1;
 156.323 +}
 156.324 +
 156.325 +/***********************************************************************
 156.326 +*  NAME
 156.327 +*
 156.328 +*  glp_add_cols - add new columns to problem object
 156.329 +*
 156.330 +*  SYNOPSIS
 156.331 +*
 156.332 +*  int glp_add_cols(glp_prob *lp, int ncs);
 156.333 +*
 156.334 +*  DESCRIPTION
 156.335 +*
 156.336 +*  The routine glp_add_cols adds ncs columns (structural variables) to
 156.337 +*  the specified problem object. New columns are always added to the end
 156.338 +*  of the column list, so the ordinal numbers of existing columns remain
 156.339 +*  unchanged.
 156.340 +*
 156.341 +*  Being added each new column is initially fixed at zero and has empty
 156.342 +*  list of the constraint coefficients.
 156.343 +*
 156.344 +*  RETURNS
 156.345 +*
 156.346 +*  The routine glp_add_cols returns the ordinal number of the first new
 156.347 +*  column added to the problem object. */
 156.348 +
 156.349 +int glp_add_cols(glp_prob *lp, int ncs)
 156.350 +{     glp_tree *tree = lp->tree;
 156.351 +      GLPCOL *col;
 156.352 +      int n_new, j;
 156.353 +      if (tree != NULL && tree->reason != 0)
 156.354 +         xerror("glp_add_cols: operation not allowed\n");
 156.355 +      /* determine new number of columns */
 156.356 +      if (ncs < 1)
 156.357 +         xerror("glp_add_cols: ncs = %d; invalid number of columns\n",
 156.358 +            ncs);
 156.359 +      if (ncs > N_MAX - lp->n)
 156.360 +         xerror("glp_add_cols: ncs = %d; too many columns\n", ncs);
 156.361 +      n_new = lp->n + ncs;
 156.362 +      /* increase the room, if necessary */
 156.363 +      if (lp->n_max < n_new)
 156.364 +      {  GLPCOL **save = lp->col;
 156.365 +         while (lp->n_max < n_new)
 156.366 +         {  lp->n_max += lp->n_max;
 156.367 +            xassert(lp->n_max > 0);
 156.368 +         }
 156.369 +         lp->col = xcalloc(1+lp->n_max, sizeof(GLPCOL *));
 156.370 +         memcpy(&lp->col[1], &save[1], lp->n * sizeof(GLPCOL *));
 156.371 +         xfree(save);
 156.372 +      }
 156.373 +      /* add new columns to the end of the column list */
 156.374 +      for (j = lp->n+1; j <= n_new; j++)
 156.375 +      {  /* create column descriptor */
 156.376 +         lp->col[j] = col = dmp_get_atom(lp->pool, sizeof(GLPCOL));
 156.377 +         col->j = j;
 156.378 +         col->name = NULL;
 156.379 +         col->node = NULL;
 156.380 +         col->kind = GLP_CV;
 156.381 +         col->type = GLP_FX;
 156.382 +         col->lb = col->ub = 0.0;
 156.383 +         col->coef = 0.0;
 156.384 +         col->ptr = NULL;
 156.385 +         col->sjj = 1.0;
 156.386 +         col->stat = GLP_NS;
 156.387 +#if 0
 156.388 +         col->bind = -1;
 156.389 +#else
 156.390 +         col->bind = 0; /* the basis may remain valid */
 156.391 +#endif
 156.392 +         col->prim = col->dual = 0.0;
 156.393 +         col->pval = col->dval = 0.0;
 156.394 +         col->mipx = 0.0;
 156.395 +      }
 156.396 +      /* set new number of columns */
 156.397 +      lp->n = n_new;
 156.398 +      /* return the ordinal number of the first column added */
 156.399 +      return n_new - ncs + 1;
 156.400 +}
 156.401 +
 156.402 +/***********************************************************************
 156.403 +*  NAME
 156.404 +*
 156.405 +*  glp_set_row_name - assign (change) row name
 156.406 +*
 156.407 +*  SYNOPSIS
 156.408 +*
 156.409 +*  void glp_set_row_name(glp_prob *lp, int i, const char *name);
 156.410 +*
 156.411 +*  DESCRIPTION
 156.412 +*
 156.413 +*  The routine glp_set_row_name assigns a given symbolic name (1 up to
 156.414 +*  255 characters) to i-th row (auxiliary variable) of the specified
 156.415 +*  problem object.
 156.416 +*
 156.417 +*  If the parameter name is NULL or empty string, the routine erases an
 156.418 +*  existing name of i-th row. */
 156.419 +
 156.420 +void glp_set_row_name(glp_prob *lp, int i, const char *name)
 156.421 +{     glp_tree *tree = lp->tree;
 156.422 +      GLPROW *row;
 156.423 +      if (!(1 <= i && i <= lp->m))
 156.424 +         xerror("glp_set_row_name: i = %d; row number out of range\n",
 156.425 +            i);
 156.426 +      row = lp->row[i];
 156.427 +      if (tree != NULL && tree->reason != 0)
 156.428 +      {  xassert(tree->curr != NULL);
 156.429 +         xassert(row->level == tree->curr->level);
 156.430 +      }
 156.431 +      if (row->name != NULL)
 156.432 +      {  if (row->node != NULL)
 156.433 +         {  xassert(lp->r_tree != NULL);
 156.434 +            avl_delete_node(lp->r_tree, row->node);
 156.435 +            row->node = NULL;
 156.436 +         }
 156.437 +         dmp_free_atom(lp->pool, row->name, strlen(row->name)+1);
 156.438 +         row->name = NULL;
 156.439 +      }
 156.440 +      if (!(name == NULL || name[0] == '\0'))
 156.441 +      {  int k;
 156.442 +         for (k = 0; name[k] != '\0'; k++)
 156.443 +         {  if (k == 256)
 156.444 +               xerror("glp_set_row_name: i = %d; row name too long\n",
 156.445 +                  i);
 156.446 +            if (iscntrl((unsigned char)name[k]))
 156.447 +               xerror("glp_set_row_name: i = %d: row name contains inva"
 156.448 +                  "lid character(s)\n", i);
 156.449 +         }
 156.450 +         row->name = dmp_get_atom(lp->pool, strlen(name)+1);
 156.451 +         strcpy(row->name, name);
 156.452 +         if (lp->r_tree != NULL)
 156.453 +         {  xassert(row->node == NULL);
 156.454 +            row->node = avl_insert_node(lp->r_tree, row->name);
 156.455 +            avl_set_node_link(row->node, row);
 156.456 +         }
 156.457 +      }
 156.458 +      return;
 156.459 +}
 156.460 +
 156.461 +/***********************************************************************
 156.462 +*  NAME
 156.463 +*
 156.464 +*  glp_set_col_name - assign (change) column name
 156.465 +*
 156.466 +*  SYNOPSIS
 156.467 +*
 156.468 +*  void glp_set_col_name(glp_prob *lp, int j, const char *name);
 156.469 +*
 156.470 +*  DESCRIPTION
 156.471 +*
 156.472 +*  The routine glp_set_col_name assigns a given symbolic name (1 up to
 156.473 +*  255 characters) to j-th column (structural variable) of the specified
 156.474 +*  problem object.
 156.475 +*
 156.476 +*  If the parameter name is NULL or empty string, the routine erases an
 156.477 +*  existing name of j-th column. */
 156.478 +
 156.479 +void glp_set_col_name(glp_prob *lp, int j, const char *name)
 156.480 +{     glp_tree *tree = lp->tree;
 156.481 +      GLPCOL *col;
 156.482 +      if (tree != NULL && tree->reason != 0)
 156.483 +         xerror("glp_set_col_name: operation not allowed\n");
 156.484 +      if (!(1 <= j && j <= lp->n))
 156.485 +         xerror("glp_set_col_name: j = %d; column number out of range\n"
 156.486 +            , j);
 156.487 +      col = lp->col[j];
 156.488 +      if (col->name != NULL)
 156.489 +      {  if (col->node != NULL)
 156.490 +         {  xassert(lp->c_tree != NULL);
 156.491 +            avl_delete_node(lp->c_tree, col->node);
 156.492 +            col->node = NULL;
 156.493 +         }
 156.494 +         dmp_free_atom(lp->pool, col->name, strlen(col->name)+1);
 156.495 +         col->name = NULL;
 156.496 +      }
 156.497 +      if (!(name == NULL || name[0] == '\0'))
 156.498 +      {  int k;
 156.499 +         for (k = 0; name[k] != '\0'; k++)
 156.500 +         {  if (k == 256)
 156.501 +               xerror("glp_set_col_name: j = %d; column name too long\n"
 156.502 +                  , j);
 156.503 +            if (iscntrl((unsigned char)name[k]))
 156.504 +               xerror("glp_set_col_name: j = %d: column name contains i"
 156.505 +                  "nvalid character(s)\n", j);
 156.506 +         }
 156.507 +         col->name = dmp_get_atom(lp->pool, strlen(name)+1);
 156.508 +         strcpy(col->name, name);
 156.509 +         if (lp->c_tree != NULL && col->name != NULL)
 156.510 +         {  xassert(col->node == NULL);
 156.511 +            col->node = avl_insert_node(lp->c_tree, col->name);
 156.512 +            avl_set_node_link(col->node, col);
 156.513 +         }
 156.514 +      }
 156.515 +      return;
 156.516 +}
 156.517 +
 156.518 +/***********************************************************************
 156.519 +*  NAME
 156.520 +*
 156.521 +*  glp_set_row_bnds - set (change) row bounds
 156.522 +*
 156.523 +*  SYNOPSIS
 156.524 +*
 156.525 +*  void glp_set_row_bnds(glp_prob *lp, int i, int type, double lb,
 156.526 +*     double ub);
 156.527 +*
 156.528 +*  DESCRIPTION
 156.529 +*
 156.530 +*  The routine glp_set_row_bnds sets (changes) the type and bounds of
 156.531 +*  i-th row (auxiliary variable) of the specified problem object.
 156.532 +*
 156.533 +*  Parameters type, lb, and ub specify the type, lower bound, and upper
 156.534 +*  bound, respectively, as follows:
 156.535 +*
 156.536 +*     Type           Bounds        Comments
 156.537 +*     ------------------------------------------------------
 156.538 +*     GLP_FR   -inf <  x <  +inf   Free variable
 156.539 +*     GLP_LO     lb <= x <  +inf   Variable with lower bound
 156.540 +*     GLP_UP   -inf <  x <=  ub    Variable with upper bound
 156.541 +*     GLP_DB     lb <= x <=  ub    Double-bounded variable
 156.542 +*     GLP_FX           x  =  lb    Fixed variable
 156.543 +*
 156.544 +*  where x is the auxiliary variable associated with i-th row.
 156.545 +*
 156.546 +*  If the row has no lower bound, the parameter lb is ignored. If the
 156.547 +*  row has no upper bound, the parameter ub is ignored. If the row is
 156.548 +*  an equality constraint (i.e. the corresponding auxiliary variable is
 156.549 +*  of fixed type), only the parameter lb is used while the parameter ub
 156.550 +*  is ignored. */
 156.551 +
 156.552 +void glp_set_row_bnds(glp_prob *lp, int i, int type, double lb,
 156.553 +      double ub)
 156.554 +{     GLPROW *row;
 156.555 +      if (!(1 <= i && i <= lp->m))
 156.556 +         xerror("glp_set_row_bnds: i = %d; row number out of range\n",
 156.557 +            i);
 156.558 +      row = lp->row[i];
 156.559 +      row->type = type;
 156.560 +      switch (type)
 156.561 +      {  case GLP_FR:
 156.562 +            row->lb = row->ub = 0.0;
 156.563 +            if (row->stat != GLP_BS) row->stat = GLP_NF;
 156.564 +            break;
 156.565 +         case GLP_LO:
 156.566 +            row->lb = lb, row->ub = 0.0;
 156.567 +            if (row->stat != GLP_BS) row->stat = GLP_NL;
 156.568 +            break;
 156.569 +         case GLP_UP:
 156.570 +            row->lb = 0.0, row->ub = ub;
 156.571 +            if (row->stat != GLP_BS) row->stat = GLP_NU;
 156.572 +            break;
 156.573 +         case GLP_DB:
 156.574 +            row->lb = lb, row->ub = ub;
 156.575 +            if (!(row->stat == GLP_BS ||
 156.576 +                  row->stat == GLP_NL || row->stat == GLP_NU))
 156.577 +               row->stat = (fabs(lb) <= fabs(ub) ? GLP_NL : GLP_NU);
 156.578 +            break;
 156.579 +         case GLP_FX:
 156.580 +            row->lb = row->ub = lb;
 156.581 +            if (row->stat != GLP_BS) row->stat = GLP_NS;
 156.582 +            break;
 156.583 +         default:
 156.584 +            xerror("glp_set_row_bnds: i = %d; type = %d; invalid row ty"
 156.585 +               "pe\n", i, type);
 156.586 +      }
 156.587 +      return;
 156.588 +}
 156.589 +
 156.590 +/***********************************************************************
 156.591 +*  NAME
 156.592 +*
 156.593 +*  glp_set_col_bnds - set (change) column bounds
 156.594 +*
 156.595 +*  SYNOPSIS
 156.596 +*
 156.597 +*  void glp_set_col_bnds(glp_prob *lp, int j, int type, double lb,
 156.598 +*     double ub);
 156.599 +*
 156.600 +*  DESCRIPTION
 156.601 +*
 156.602 +*  The routine glp_set_col_bnds sets (changes) the type and bounds of
 156.603 +*  j-th column (structural variable) of the specified problem object.
 156.604 +*
 156.605 +*  Parameters type, lb, and ub specify the type, lower bound, and upper
 156.606 +*  bound, respectively, as follows:
 156.607 +*
 156.608 +*     Type           Bounds        Comments
 156.609 +*     ------------------------------------------------------
 156.610 +*     GLP_FR   -inf <  x <  +inf   Free variable
 156.611 +*     GLP_LO     lb <= x <  +inf   Variable with lower bound
 156.612 +*     GLP_UP   -inf <  x <=  ub    Variable with upper bound
 156.613 +*     GLP_DB     lb <= x <=  ub    Double-bounded variable
 156.614 +*     GLP_FX           x  =  lb    Fixed variable
 156.615 +*
 156.616 +*  where x is the structural variable associated with j-th column.
 156.617 +*
 156.618 +*  If the column has no lower bound, the parameter lb is ignored. If the
 156.619 +*  column has no upper bound, the parameter ub is ignored. If the column
 156.620 +*  is of fixed type, only the parameter lb is used while the parameter
 156.621 +*  ub is ignored. */
 156.622 +
 156.623 +void glp_set_col_bnds(glp_prob *lp, int j, int type, double lb,
 156.624 +      double ub)
 156.625 +{     GLPCOL *col;
 156.626 +      if (!(1 <= j && j <= lp->n))
 156.627 +         xerror("glp_set_col_bnds: j = %d; column number out of range\n"
 156.628 +            , j);
 156.629 +      col = lp->col[j];
 156.630 +      col->type = type;
 156.631 +      switch (type)
 156.632 +      {  case GLP_FR:
 156.633 +            col->lb = col->ub = 0.0;
 156.634 +            if (col->stat != GLP_BS) col->stat = GLP_NF;
 156.635 +            break;
 156.636 +         case GLP_LO:
 156.637 +            col->lb = lb, col->ub = 0.0;
 156.638 +            if (col->stat != GLP_BS) col->stat = GLP_NL;
 156.639 +            break;
 156.640 +         case GLP_UP:
 156.641 +            col->lb = 0.0, col->ub = ub;
 156.642 +            if (col->stat != GLP_BS) col->stat = GLP_NU;
 156.643 +            break;
 156.644 +         case GLP_DB:
 156.645 +            col->lb = lb, col->ub = ub;
 156.646 +            if (!(col->stat == GLP_BS ||
 156.647 +                  col->stat == GLP_NL || col->stat == GLP_NU))
 156.648 +               col->stat = (fabs(lb) <= fabs(ub) ? GLP_NL : GLP_NU);
 156.649 +            break;
 156.650 +         case GLP_FX:
 156.651 +            col->lb = col->ub = lb;
 156.652 +            if (col->stat != GLP_BS) col->stat = GLP_NS;
 156.653 +            break;
 156.654 +         default:
 156.655 +            xerror("glp_set_col_bnds: j = %d; type = %d; invalid column"
 156.656 +               " type\n", j, type);
 156.657 +      }
 156.658 +      return;
 156.659 +}
 156.660 +
 156.661 +/***********************************************************************
 156.662 +*  NAME
 156.663 +*
 156.664 +*  glp_set_obj_coef - set (change) obj. coefficient or constant term
 156.665 +*
 156.666 +*  SYNOPSIS
 156.667 +*
 156.668 +*  void glp_set_obj_coef(glp_prob *lp, int j, double coef);
 156.669 +*
 156.670 +*  DESCRIPTION
 156.671 +*
 156.672 +*  The routine glp_set_obj_coef sets (changes) objective coefficient at
 156.673 +*  j-th column (structural variable) of the specified problem object.
 156.674 +*
 156.675 +*  If the parameter j is 0, the routine sets (changes) the constant term
 156.676 +*  ("shift") of the objective function. */
 156.677 +
 156.678 +void glp_set_obj_coef(glp_prob *lp, int j, double coef)
 156.679 +{     glp_tree *tree = lp->tree;
 156.680 +      if (tree != NULL && tree->reason != 0)
 156.681 +         xerror("glp_set_obj_coef: operation not allowed\n");
 156.682 +      if (!(0 <= j && j <= lp->n))
 156.683 +         xerror("glp_set_obj_coef: j = %d; column number out of range\n"
 156.684 +            , j);
 156.685 +      if (j == 0)
 156.686 +         lp->c0 = coef;
 156.687 +      else
 156.688 +         lp->col[j]->coef = coef;
 156.689 +      return;
 156.690 +}
 156.691 +
 156.692 +/***********************************************************************
 156.693 +*  NAME
 156.694 +*
 156.695 +*  glp_set_mat_row - set (replace) row of the constraint matrix
 156.696 +*
 156.697 +*  SYNOPSIS
 156.698 +*
 156.699 +*  void glp_set_mat_row(glp_prob *lp, int i, int len, const int ind[],
 156.700 +*     const double val[]);
 156.701 +*
 156.702 +*  DESCRIPTION
 156.703 +*
 156.704 +*  The routine glp_set_mat_row stores (replaces) the contents of i-th
 156.705 +*  row of the constraint matrix of the specified problem object.
 156.706 +*
 156.707 +*  Column indices and numeric values of new row elements must be placed
 156.708 +*  in locations ind[1], ..., ind[len] and val[1], ..., val[len], where
 156.709 +*  0 <= len <= n is the new length of i-th row, n is the current number
 156.710 +*  of columns in the problem object. Elements with identical column
 156.711 +*  indices are not allowed. Zero elements are allowed, but they are not
 156.712 +*  stored in the constraint matrix.
 156.713 +*
 156.714 +*  If the parameter len is zero, the parameters ind and/or val can be
 156.715 +*  specified as NULL. */
 156.716 +
 156.717 +void glp_set_mat_row(glp_prob *lp, int i, int len, const int ind[],
 156.718 +      const double val[])
 156.719 +{     glp_tree *tree = lp->tree;
 156.720 +      GLPROW *row;
 156.721 +      GLPCOL *col;
 156.722 +      GLPAIJ *aij, *next;
 156.723 +      int j, k;
 156.724 +      /* obtain pointer to i-th row */
 156.725 +      if (!(1 <= i && i <= lp->m))
 156.726 +         xerror("glp_set_mat_row: i = %d; row number out of range\n",
 156.727 +            i);
 156.728 +      row = lp->row[i];
 156.729 +      if (tree != NULL && tree->reason != 0)
 156.730 +      {  xassert(tree->curr != NULL);
 156.731 +         xassert(row->level == tree->curr->level);
 156.732 +      }
 156.733 +      /* remove all existing elements from i-th row */
 156.734 +      while (row->ptr != NULL)
 156.735 +      {  /* take next element in the row */
 156.736 +         aij = row->ptr;
 156.737 +         /* remove the element from the row list */
 156.738 +         row->ptr = aij->r_next;
 156.739 +         /* obtain pointer to corresponding column */
 156.740 +         col = aij->col;
 156.741 +         /* remove the element from the column list */
 156.742 +         if (aij->c_prev == NULL)
 156.743 +            col->ptr = aij->c_next;
 156.744 +         else
 156.745 +            aij->c_prev->c_next = aij->c_next;
 156.746 +         if (aij->c_next == NULL)
 156.747 +            ;
 156.748 +         else
 156.749 +            aij->c_next->c_prev = aij->c_prev;
 156.750 +         /* return the element to the memory pool */
 156.751 +         dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
 156.752 +         /* if the corresponding column is basic, invalidate the basis
 156.753 +            factorization */
 156.754 +         if (col->stat == GLP_BS) lp->valid = 0;
 156.755 +      }
 156.756 +      /* store new contents of i-th row */
 156.757 +      if (!(0 <= len && len <= lp->n))
 156.758 +         xerror("glp_set_mat_row: i = %d; len = %d; invalid row length "
 156.759 +            "\n", i, len);
 156.760 +      if (len > NNZ_MAX - lp->nnz)
 156.761 +         xerror("glp_set_mat_row: i = %d; len = %d; too many constraint"
 156.762 +            " coefficients\n", i, len);
 156.763 +      for (k = 1; k <= len; k++)
 156.764 +      {  /* take number j of corresponding column */
 156.765 +         j = ind[k];
 156.766 +         /* obtain pointer to j-th column */
 156.767 +         if (!(1 <= j && j <= lp->n))
 156.768 +            xerror("glp_set_mat_row: i = %d; ind[%d] = %d; column index"
 156.769 +               " out of range\n", i, k, j);
 156.770 +         col = lp->col[j];
 156.771 +         /* if there is element with the same column index, it can only
 156.772 +            be found in the beginning of j-th column list */
 156.773 +         if (col->ptr != NULL && col->ptr->row->i == i)
 156.774 +            xerror("glp_set_mat_row: i = %d; ind[%d] = %d; duplicate co"
 156.775 +               "lumn indices not allowed\n", i, k, j);
 156.776 +         /* create new element */
 156.777 +         aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++;
 156.778 +         aij->row = row;
 156.779 +         aij->col = col;
 156.780 +         aij->val = val[k];
 156.781 +         /* add the new element to the beginning of i-th row and j-th
 156.782 +            column lists */
 156.783 +         aij->r_prev = NULL;
 156.784 +         aij->r_next = row->ptr;
 156.785 +         aij->c_prev = NULL;
 156.786 +         aij->c_next = col->ptr;
 156.787 +         if (aij->r_next != NULL) aij->r_next->r_prev = aij;
 156.788 +         if (aij->c_next != NULL) aij->c_next->c_prev = aij;
 156.789 +         row->ptr = col->ptr = aij;
 156.790 +         /* if the corresponding column is basic, invalidate the basis
 156.791 +            factorization */
 156.792 +         if (col->stat == GLP_BS && aij->val != 0.0) lp->valid = 0;
 156.793 +      }
 156.794 +      /* remove zero elements from i-th row */
 156.795 +      for (aij = row->ptr; aij != NULL; aij = next)
 156.796 +      {  next = aij->r_next;
 156.797 +         if (aij->val == 0.0)
 156.798 +         {  /* remove the element from the row list */
 156.799 +            if (aij->r_prev == NULL)
 156.800 +               row->ptr = next;
 156.801 +            else
 156.802 +               aij->r_prev->r_next = next;
 156.803 +            if (next == NULL)
 156.804 +               ;
 156.805 +            else
 156.806 +               next->r_prev = aij->r_prev;
 156.807 +            /* remove the element from the column list */
 156.808 +            xassert(aij->c_prev == NULL);
 156.809 +            aij->col->ptr = aij->c_next;
 156.810 +            if (aij->c_next != NULL) aij->c_next->c_prev = NULL;
 156.811 +            /* return the element to the memory pool */
 156.812 +            dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
 156.813 +         }
 156.814 +      }
 156.815 +      return;
 156.816 +}
 156.817 +
 156.818 +/***********************************************************************
 156.819 +*  NAME
 156.820 +*
 156.821 +*  glp_set_mat_col - set (replace) column of the constraint matrix
 156.822 +*
 156.823 +*  SYNOPSIS
 156.824 +*
 156.825 +*  void glp_set_mat_col(glp_prob *lp, int j, int len, const int ind[],
 156.826 +*     const double val[]);
 156.827 +*
 156.828 +*  DESCRIPTION
 156.829 +*
 156.830 +*  The routine glp_set_mat_col stores (replaces) the contents of j-th
 156.831 +*  column of the constraint matrix of the specified problem object.
 156.832 +*
 156.833 +*  Row indices and numeric values of new column elements must be placed
 156.834 +*  in locations ind[1], ..., ind[len] and val[1], ..., val[len], where
 156.835 +*  0 <= len <= m is the new length of j-th column, m is the current
 156.836 +*  number of rows in the problem object. Elements with identical column
 156.837 +*  indices are not allowed. Zero elements are allowed, but they are not
 156.838 +*  stored in the constraint matrix.
 156.839 +*
 156.840 +*  If the parameter len is zero, the parameters ind and/or val can be
 156.841 +*  specified as NULL. */
 156.842 +
 156.843 +void glp_set_mat_col(glp_prob *lp, int j, int len, const int ind[],
 156.844 +      const double val[])
 156.845 +{     glp_tree *tree = lp->tree;
 156.846 +      GLPROW *row;
 156.847 +      GLPCOL *col;
 156.848 +      GLPAIJ *aij, *next;
 156.849 +      int i, k;
 156.850 +      if (tree != NULL && tree->reason != 0)
 156.851 +         xerror("glp_set_mat_col: operation not allowed\n");
 156.852 +      /* obtain pointer to j-th column */
 156.853 +      if (!(1 <= j && j <= lp->n))
 156.854 +         xerror("glp_set_mat_col: j = %d; column number out of range\n",
 156.855 +            j);
 156.856 +      col = lp->col[j];
 156.857 +      /* remove all existing elements from j-th column */
 156.858 +      while (col->ptr != NULL)
 156.859 +      {  /* take next element in the column */
 156.860 +         aij = col->ptr;
 156.861 +         /* remove the element from the column list */
 156.862 +         col->ptr = aij->c_next;
 156.863 +         /* obtain pointer to corresponding row */
 156.864 +         row = aij->row;
 156.865 +         /* remove the element from the row list */
 156.866 +         if (aij->r_prev == NULL)
 156.867 +            row->ptr = aij->r_next;
 156.868 +         else
 156.869 +            aij->r_prev->r_next = aij->r_next;
 156.870 +         if (aij->r_next == NULL)
 156.871 +            ;
 156.872 +         else
 156.873 +            aij->r_next->r_prev = aij->r_prev;
 156.874 +         /* return the element to the memory pool */
 156.875 +         dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
 156.876 +      }
 156.877 +      /* store new contents of j-th column */
 156.878 +      if (!(0 <= len && len <= lp->m))
 156.879 +         xerror("glp_set_mat_col: j = %d; len = %d; invalid column leng"
 156.880 +            "th\n", j, len);
 156.881 +      if (len > NNZ_MAX - lp->nnz)
 156.882 +         xerror("glp_set_mat_col: j = %d; len = %d; too many constraint"
 156.883 +            " coefficients\n", j, len);
 156.884 +      for (k = 1; k <= len; k++)
 156.885 +      {  /* take number i of corresponding row */
 156.886 +         i = ind[k];
 156.887 +         /* obtain pointer to i-th row */
 156.888 +         if (!(1 <= i && i <= lp->m))
 156.889 +            xerror("glp_set_mat_col: j = %d; ind[%d] = %d; row index ou"
 156.890 +               "t of range\n", j, k, i);
 156.891 +         row = lp->row[i];
 156.892 +         /* if there is element with the same row index, it can only be
 156.893 +            found in the beginning of i-th row list */
 156.894 +         if (row->ptr != NULL && row->ptr->col->j == j)
 156.895 +            xerror("glp_set_mat_col: j = %d; ind[%d] = %d; duplicate ro"
 156.896 +               "w indices not allowed\n", j, k, i);
 156.897 +         /* create new element */
 156.898 +         aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++;
 156.899 +         aij->row = row;
 156.900 +         aij->col = col;
 156.901 +         aij->val = val[k];
 156.902 +         /* add the new element to the beginning of i-th row and j-th
 156.903 +            column lists */
 156.904 +         aij->r_prev = NULL;
 156.905 +         aij->r_next = row->ptr;
 156.906 +         aij->c_prev = NULL;
 156.907 +         aij->c_next = col->ptr;
 156.908 +         if (aij->r_next != NULL) aij->r_next->r_prev = aij;
 156.909 +         if (aij->c_next != NULL) aij->c_next->c_prev = aij;
 156.910 +         row->ptr = col->ptr = aij;
 156.911 +      }
 156.912 +      /* remove zero elements from j-th column */
 156.913 +      for (aij = col->ptr; aij != NULL; aij = next)
 156.914 +      {  next = aij->c_next;
 156.915 +         if (aij->val == 0.0)
 156.916 +         {  /* remove the element from the row list */
 156.917 +            xassert(aij->r_prev == NULL);
 156.918 +            aij->row->ptr = aij->r_next;
 156.919 +            if (aij->r_next != NULL) aij->r_next->r_prev = NULL;
 156.920 +            /* remove the element from the column list */
 156.921 +            if (aij->c_prev == NULL)
 156.922 +               col->ptr = next;
 156.923 +            else
 156.924 +               aij->c_prev->c_next = next;
 156.925 +            if (next == NULL)
 156.926 +               ;
 156.927 +            else
 156.928 +               next->c_prev = aij->c_prev;
 156.929 +            /* return the element to the memory pool */
 156.930 +            dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
 156.931 +         }
 156.932 +      }
 156.933 +      /* if j-th column is basic, invalidate the basis factorization */
 156.934 +      if (col->stat == GLP_BS) lp->valid = 0;
 156.935 +      return;
 156.936 +}
 156.937 +
 156.938 +/***********************************************************************
 156.939 +*  NAME
 156.940 +*
 156.941 +*  glp_load_matrix - load (replace) the whole constraint matrix
 156.942 +*
 156.943 +*  SYNOPSIS
 156.944 +*
 156.945 +*  void glp_load_matrix(glp_prob *lp, int ne, const int ia[],
 156.946 +*     const int ja[], const double ar[]);
 156.947 +*
 156.948 +*  DESCRIPTION
 156.949 +*
 156.950 +*  The routine glp_load_matrix loads the constraint matrix passed in
 156.951 +*  the arrays ia, ja, and ar into the specified problem object. Before
 156.952 +*  loading the current contents of the constraint matrix is destroyed.
 156.953 +*
 156.954 +*  Constraint coefficients (elements of the constraint matrix) must be
 156.955 +*  specified as triplets (ia[k], ja[k], ar[k]) for k = 1, ..., ne,
 156.956 +*  where ia[k] is the row index, ja[k] is the column index, ar[k] is a
 156.957 +*  numeric value of corresponding constraint coefficient. The parameter
 156.958 +*  ne specifies the total number of (non-zero) elements in the matrix
 156.959 +*  to be loaded. Coefficients with identical indices are not allowed.
 156.960 +*  Zero coefficients are allowed, however, they are not stored in the
 156.961 +*  constraint matrix.
 156.962 +*
 156.963 +*  If the parameter ne is zero, the parameters ia, ja, and ar can be
 156.964 +*  specified as NULL. */
 156.965 +
 156.966 +void glp_load_matrix(glp_prob *lp, int ne, const int ia[],
 156.967 +      const int ja[], const double ar[])
 156.968 +{     glp_tree *tree = lp->tree;
 156.969 +      GLPROW *row;
 156.970 +      GLPCOL *col;
 156.971 +      GLPAIJ *aij, *next;
 156.972 +      int i, j, k;
 156.973 +      if (tree != NULL && tree->reason != 0)
 156.974 +         xerror("glp_load_matrix: operation not allowed\n");
 156.975 +      /* clear the constraint matrix */
 156.976 +      for (i = 1; i <= lp->m; i++)
 156.977 +      {  row = lp->row[i];
 156.978 +         while (row->ptr != NULL)
 156.979 +         {  aij = row->ptr;
 156.980 +            row->ptr = aij->r_next;
 156.981 +            dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
 156.982 +         }
 156.983 +      }
 156.984 +      xassert(lp->nnz == 0);
 156.985 +      for (j = 1; j <= lp->n; j++) lp->col[j]->ptr = NULL;
 156.986 +      /* load the new contents of the constraint matrix and build its
 156.987 +         row lists */
 156.988 +      if (ne < 0)
 156.989 +         xerror("glp_load_matrix: ne = %d; invalid number of constraint"
 156.990 +            " coefficients\n", ne);
 156.991 +      if (ne > NNZ_MAX)
 156.992 +         xerror("glp_load_matrix: ne = %d; too many constraint coeffici"
 156.993 +            "ents\n", ne);
 156.994 +      for (k = 1; k <= ne; k++)
 156.995 +      {  /* take indices of new element */
 156.996 +         i = ia[k], j = ja[k];
 156.997 +         /* obtain pointer to i-th row */
 156.998 +         if (!(1 <= i && i <= lp->m))
 156.999 +            xerror("glp_load_matrix: ia[%d] = %d; row index out of rang"
156.1000 +               "e\n", k, i);
156.1001 +         row = lp->row[i];
156.1002 +         /* obtain pointer to j-th column */
156.1003 +         if (!(1 <= j && j <= lp->n))
156.1004 +            xerror("glp_load_matrix: ja[%d] = %d; column index out of r"
156.1005 +               "ange\n", k, j);
156.1006 +         col = lp->col[j];
156.1007 +         /* create new element */
156.1008 +         aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++;
156.1009 +         aij->row = row;
156.1010 +         aij->col = col;
156.1011 +         aij->val = ar[k];
156.1012 +         /* add the new element to the beginning of i-th row list */
156.1013 +         aij->r_prev = NULL;
156.1014 +         aij->r_next = row->ptr;
156.1015 +         if (aij->r_next != NULL) aij->r_next->r_prev = aij;
156.1016 +         row->ptr = aij;
156.1017 +      }
156.1018 +      xassert(lp->nnz == ne);
156.1019 +      /* build column lists of the constraint matrix and check elements
156.1020 +         with identical indices */
156.1021 +      for (i = 1; i <= lp->m; i++)
156.1022 +      {  for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
156.1023 +         {  /* obtain pointer to corresponding column */
156.1024 +            col = aij->col;
156.1025 +            /* if there is element with identical indices, it can only
156.1026 +               be found in the beginning of j-th column list */
156.1027 +            if (col->ptr != NULL && col->ptr->row->i == i)
156.1028 +            {  for (k = 1; k <= ne; k++)
156.1029 +                  if (ia[k] == i && ja[k] == col->j) break;
156.1030 +               xerror("glp_load_mat: ia[%d] = %d; ja[%d] = %d; duplicat"
156.1031 +                  "e indices not allowed\n", k, i, k, col->j);
156.1032 +            }
156.1033 +            /* add the element to the beginning of j-th column list */
156.1034 +            aij->c_prev = NULL;
156.1035 +            aij->c_next = col->ptr;
156.1036 +            if (aij->c_next != NULL) aij->c_next->c_prev = aij;
156.1037 +            col->ptr = aij;
156.1038 +         }
156.1039 +      }
156.1040 +      /* remove zero elements from the constraint matrix */
156.1041 +      for (i = 1; i <= lp->m; i++)
156.1042 +      {  row = lp->row[i];
156.1043 +         for (aij = row->ptr; aij != NULL; aij = next)
156.1044 +         {  next = aij->r_next;
156.1045 +            if (aij->val == 0.0)
156.1046 +            {  /* remove the element from the row list */
156.1047 +               if (aij->r_prev == NULL)
156.1048 +                  row->ptr = next;
156.1049 +               else
156.1050 +                  aij->r_prev->r_next = next;
156.1051 +               if (next == NULL)
156.1052 +                  ;
156.1053 +               else
156.1054 +                  next->r_prev = aij->r_prev;
156.1055 +               /* remove the element from the column list */
156.1056 +               if (aij->c_prev == NULL)
156.1057 +                  aij->col->ptr = aij->c_next;
156.1058 +               else
156.1059 +                  aij->c_prev->c_next = aij->c_next;
156.1060 +               if (aij->c_next == NULL)
156.1061 +                  ;
156.1062 +               else
156.1063 +                  aij->c_next->c_prev = aij->c_prev;
156.1064 +               /* return the element to the memory pool */
156.1065 +               dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
156.1066 +            }
156.1067 +         }
156.1068 +      }
156.1069 +      /* invalidate the basis factorization */
156.1070 +      lp->valid = 0;
156.1071 +      return;
156.1072 +}
156.1073 +
156.1074 +/***********************************************************************
156.1075 +*  NAME
156.1076 +*
156.1077 +*  glp_check_dup - check for duplicate elements in sparse matrix
156.1078 +*
156.1079 +*  SYNOPSIS
156.1080 +*
156.1081 +*  int glp_check_dup(int m, int n, int ne, const int ia[],
156.1082 +*     const int ja[]);
156.1083 +*
156.1084 +*  DESCRIPTION
156.1085 +*
156.1086 +*  The routine glp_check_dup checks for duplicate elements (that is,
156.1087 +*  elements with identical indices) in a sparse matrix specified in the
156.1088 +*  coordinate format.
156.1089 +*
156.1090 +*  The parameters m and n specifies, respectively, the number of rows
156.1091 +*  and columns in the matrix, m >= 0, n >= 0.
156.1092 +*
156.1093 +*  The parameter ne specifies the number of (structurally) non-zero
156.1094 +*  elements in the matrix, ne >= 0.
156.1095 +*
156.1096 +*  Elements of the matrix are specified as doublets (ia[k],ja[k]) for
156.1097 +*  k = 1,...,ne, where ia[k] is a row index, ja[k] is a column index.
156.1098 +*
156.1099 +*  The routine glp_check_dup can be used prior to a call to the routine
156.1100 +*  glp_load_matrix to check that the constraint matrix to be loaded has
156.1101 +*  no duplicate elements.
156.1102 +*
156.1103 +*  RETURNS
156.1104 +*
156.1105 +*  The routine glp_check_dup returns one of the following values:
156.1106 +*
156.1107 +*   0 - the matrix has no duplicate elements;
156.1108 +*
156.1109 +*  -k - indices ia[k] or/and ja[k] are out of range;
156.1110 +*
156.1111 +*  +k - element (ia[k],ja[k]) is duplicate. */
156.1112 +
156.1113 +int glp_check_dup(int m, int n, int ne, const int ia[], const int ja[])
156.1114 +{     int i, j, k, *ptr, *next, ret;
156.1115 +      char *flag;
156.1116 +      if (m < 0)
156.1117 +         xerror("glp_check_dup: m = %d; invalid parameter\n");
156.1118 +      if (n < 0)
156.1119 +         xerror("glp_check_dup: n = %d; invalid parameter\n");
156.1120 +      if (ne < 0)
156.1121 +         xerror("glp_check_dup: ne = %d; invalid parameter\n");
156.1122 +      if (ne > 0 && ia == NULL)
156.1123 +         xerror("glp_check_dup: ia = %p; invalid parameter\n", ia);
156.1124 +      if (ne > 0 && ja == NULL)
156.1125 +         xerror("glp_check_dup: ja = %p; invalid parameter\n", ja);
156.1126 +      for (k = 1; k <= ne; k++)
156.1127 +      {  i = ia[k], j = ja[k];
156.1128 +         if (!(1 <= i && i <= m && 1 <= j && j <= n))
156.1129 +         {  ret = -k;
156.1130 +            goto done;
156.1131 +         }
156.1132 +      }
156.1133 +      if (m == 0 || n == 0)
156.1134 +      {  ret = 0;
156.1135 +         goto done;
156.1136 +      }
156.1137 +      /* allocate working arrays */
156.1138 +      ptr = xcalloc(1+m, sizeof(int));
156.1139 +      next = xcalloc(1+ne, sizeof(int));
156.1140 +      flag = xcalloc(1+n, sizeof(char));
156.1141 +      /* build row lists */
156.1142 +      for (i = 1; i <= m; i++)
156.1143 +         ptr[i] = 0;
156.1144 +      for (k = 1; k <= ne; k++)
156.1145 +      {  i = ia[k];
156.1146 +         next[k] = ptr[i];
156.1147 +         ptr[i] = k;
156.1148 +      }
156.1149 +      /* clear column flags */
156.1150 +      for (j = 1; j <= n; j++)
156.1151 +         flag[j] = 0;
156.1152 +      /* check for duplicate elements */
156.1153 +      for (i = 1; i <= m; i++)
156.1154 +      {  for (k = ptr[i]; k != 0; k = next[k])
156.1155 +         {  j = ja[k];
156.1156 +            if (flag[j])
156.1157 +            {  /* find first element (i,j) */
156.1158 +               for (k = 1; k <= ne; k++)
156.1159 +                  if (ia[k] == i && ja[k] == j) break;
156.1160 +               xassert(k <= ne);
156.1161 +               /* find next (duplicate) element (i,j) */
156.1162 +               for (k++; k <= ne; k++)
156.1163 +                  if (ia[k] == i && ja[k] == j) break;
156.1164 +               xassert(k <= ne);
156.1165 +               ret = +k;
156.1166 +               goto skip;
156.1167 +            }
156.1168 +            flag[j] = 1;
156.1169 +         }
156.1170 +         /* clear column flags */
156.1171 +         for (k = ptr[i]; k != 0; k = next[k])
156.1172 +            flag[ja[k]] = 0;
156.1173 +      }
156.1174 +      /* no duplicate element found */
156.1175 +      ret = 0;
156.1176 +skip: /* free working arrays */
156.1177 +      xfree(ptr);
156.1178 +      xfree(next);
156.1179 +      xfree(flag);
156.1180 +done: return ret;
156.1181 +}
156.1182 +
156.1183 +/***********************************************************************
156.1184 +*  NAME
156.1185 +*
156.1186 +*  glp_sort_matrix - sort elements of the constraint matrix
156.1187 +*
156.1188 +*  SYNOPSIS
156.1189 +*
156.1190 +*  void glp_sort_matrix(glp_prob *P);
156.1191 +*
156.1192 +*  DESCRIPTION
156.1193 +*
156.1194 +*  The routine glp_sort_matrix sorts elements of the constraint matrix
156.1195 +*  rebuilding its row and column linked lists. On exit from the routine
156.1196 +*  the constraint matrix is not changed, however, elements in the row
156.1197 +*  linked lists become ordered by ascending column indices, and the
156.1198 +*  elements in the column linked lists become ordered by ascending row
156.1199 +*  indices. */
156.1200 +
156.1201 +void glp_sort_matrix(glp_prob *P)
156.1202 +{     GLPAIJ *aij;
156.1203 +      int i, j;
156.1204 +      if (P == NULL || P->magic != GLP_PROB_MAGIC)
156.1205 +         xerror("glp_sort_matrix: P = %p; invalid problem object\n",
156.1206 +            P);
156.1207 +      /* rebuild row linked lists */
156.1208 +      for (i = P->m; i >= 1; i--)
156.1209 +         P->row[i]->ptr = NULL;
156.1210 +      for (j = P->n; j >= 1; j--)
156.1211 +      {  for (aij = P->col[j]->ptr; aij != NULL; aij = aij->c_next)
156.1212 +         {  i = aij->row->i;
156.1213 +            aij->r_prev = NULL;
156.1214 +            aij->r_next = P->row[i]->ptr;
156.1215 +            if (aij->r_next != NULL) aij->r_next->r_prev = aij;
156.1216 +            P->row[i]->ptr = aij;
156.1217 +         }
156.1218 +      }
156.1219 +      /* rebuild column linked lists */
156.1220 +      for (j = P->n; j >= 1; j--)
156.1221 +         P->col[j]->ptr = NULL;
156.1222 +      for (i = P->m; i >= 1; i--)
156.1223 +      {  for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next)
156.1224 +         {  j = aij->col->j;
156.1225 +            aij->c_prev = NULL;
156.1226 +            aij->c_next = P->col[j]->ptr;
156.1227 +            if (aij->c_next != NULL) aij->c_next->c_prev = aij;
156.1228 +            P->col[j]->ptr = aij;
156.1229 +         }
156.1230 +      }
156.1231 +      return;
156.1232 +}
156.1233 +
156.1234 +/***********************************************************************
156.1235 +*  NAME
156.1236 +*
156.1237 +*  glp_del_rows - delete rows from problem object
156.1238 +*
156.1239 +*  SYNOPSIS
156.1240 +*
156.1241 +*  void glp_del_rows(glp_prob *lp, int nrs, const int num[]);
156.1242 +*
156.1243 +*  DESCRIPTION
156.1244 +*
156.1245 +*  The routine glp_del_rows deletes rows from the specified problem
156.1246 +*  object. Ordinal numbers of rows to be deleted should be placed in
156.1247 +*  locations num[1], ..., num[nrs], where nrs > 0.
156.1248 +*
156.1249 +*  Note that deleting rows involves changing ordinal numbers of other
156.1250 +*  rows remaining in the problem object. New ordinal numbers of the
156.1251 +*  remaining rows are assigned under the assumption that the original
156.1252 +*  order of rows is not changed. */
156.1253 +
156.1254 +void glp_del_rows(glp_prob *lp, int nrs, const int num[])
156.1255 +{     glp_tree *tree = lp->tree;
156.1256 +      GLPROW *row;
156.1257 +      int i, k, m_new;
156.1258 +      /* mark rows to be deleted */
156.1259 +      if (!(1 <= nrs && nrs <= lp->m))
156.1260 +         xerror("glp_del_rows: nrs = %d; invalid number of rows\n",
156.1261 +            nrs);
156.1262 +      for (k = 1; k <= nrs; k++)
156.1263 +      {  /* take the number of row to be deleted */
156.1264 +         i = num[k];
156.1265 +         /* obtain pointer to i-th row */
156.1266 +         if (!(1 <= i && i <= lp->m))
156.1267 +            xerror("glp_del_rows: num[%d] = %d; row number out of range"
156.1268 +               "\n", k, i);
156.1269 +         row = lp->row[i];
156.1270 +         if (tree != NULL && tree->reason != 0)
156.1271 +         {  if (!(tree->reason == GLP_IROWGEN ||
156.1272 +                  tree->reason == GLP_ICUTGEN))
156.1273 +               xerror("glp_del_rows: operation not allowed\n");
156.1274 +            xassert(tree->curr != NULL);
156.1275 +            if (row->level != tree->curr->level)
156.1276 +               xerror("glp_del_rows: num[%d] = %d; invalid attempt to d"
156.1277 +                  "elete row created not in current subproblem\n", k,i);
156.1278 +            if (row->stat != GLP_BS)
156.1279 +               xerror("glp_del_rows: num[%d] = %d; invalid attempt to d"
156.1280 +                  "elete active row (constraint)\n", k, i);
156.1281 +            tree->reinv = 1;
156.1282 +         }
156.1283 +         /* check that the row is not marked yet */
156.1284 +         if (row->i == 0)
156.1285 +            xerror("glp_del_rows: num[%d] = %d; duplicate row numbers n"
156.1286 +               "ot allowed\n", k, i);
156.1287 +         /* erase symbolic name assigned to the row */
156.1288 +         glp_set_row_name(lp, i, NULL);
156.1289 +         xassert(row->node == NULL);
156.1290 +         /* erase corresponding row of the constraint matrix */
156.1291 +         glp_set_mat_row(lp, i, 0, NULL, NULL);
156.1292 +         xassert(row->ptr == NULL);
156.1293 +         /* mark the row to be deleted */
156.1294 +         row->i = 0;
156.1295 +      }
156.1296 +      /* delete all marked rows from the row list */
156.1297 +      m_new = 0;
156.1298 +      for (i = 1; i <= lp->m; i++)
156.1299 +      {  /* obtain pointer to i-th row */
156.1300 +         row = lp->row[i];
156.1301 +         /* check if the row is marked */
156.1302 +         if (row->i == 0)
156.1303 +         {  /* it is marked, delete it */
156.1304 +            dmp_free_atom(lp->pool, row, sizeof(GLPROW));
156.1305 +         }
156.1306 +         else
156.1307 +         {  /* it is not marked; keep it */
156.1308 +            row->i = ++m_new;
156.1309 +            lp->row[row->i] = row;
156.1310 +         }
156.1311 +      }
156.1312 +      /* set new number of rows */
156.1313 +      lp->m = m_new;
156.1314 +      /* invalidate the basis factorization */
156.1315 +      lp->valid = 0;
156.1316 +      return;
156.1317 +}
156.1318 +
156.1319 +/***********************************************************************
156.1320 +*  NAME
156.1321 +*
156.1322 +*  glp_del_cols - delete columns from problem object
156.1323 +*
156.1324 +*  SYNOPSIS
156.1325 +*
156.1326 +*  void glp_del_cols(glp_prob *lp, int ncs, const int num[]);
156.1327 +*
156.1328 +*  DESCRIPTION
156.1329 +*
156.1330 +*  The routine glp_del_cols deletes columns from the specified problem
156.1331 +*  object. Ordinal numbers of columns to be deleted should be placed in
156.1332 +*  locations num[1], ..., num[ncs], where ncs > 0.
156.1333 +*
156.1334 +*  Note that deleting columns involves changing ordinal numbers of
156.1335 +*  other columns remaining in the problem object. New ordinal numbers
156.1336 +*  of the remaining columns are assigned under the assumption that the
156.1337 +*  original order of columns is not changed. */
156.1338 +
156.1339 +void glp_del_cols(glp_prob *lp, int ncs, const int num[])
156.1340 +{     glp_tree *tree = lp->tree;
156.1341 +      GLPCOL *col;
156.1342 +      int j, k, n_new;
156.1343 +      if (tree != NULL && tree->reason != 0)
156.1344 +         xerror("glp_del_cols: operation not allowed\n");
156.1345 +      /* mark columns to be deleted */
156.1346 +      if (!(1 <= ncs && ncs <= lp->n))
156.1347 +         xerror("glp_del_cols: ncs = %d; invalid number of columns\n",
156.1348 +            ncs);
156.1349 +      for (k = 1; k <= ncs; k++)
156.1350 +      {  /* take the number of column to be deleted */
156.1351 +         j = num[k];
156.1352 +         /* obtain pointer to j-th column */
156.1353 +         if (!(1 <= j && j <= lp->n))
156.1354 +            xerror("glp_del_cols: num[%d] = %d; column number out of ra"
156.1355 +               "nge", k, j);
156.1356 +         col = lp->col[j];
156.1357 +         /* check that the column is not marked yet */
156.1358 +         if (col->j == 0)
156.1359 +            xerror("glp_del_cols: num[%d] = %d; duplicate column number"
156.1360 +               "s not allowed\n", k, j);
156.1361 +         /* erase symbolic name assigned to the column */
156.1362 +         glp_set_col_name(lp, j, NULL);
156.1363 +         xassert(col->node == NULL);
156.1364 +         /* erase corresponding column of the constraint matrix */
156.1365 +         glp_set_mat_col(lp, j, 0, NULL, NULL);
156.1366 +         xassert(col->ptr == NULL);
156.1367 +         /* mark the column to be deleted */
156.1368 +         col->j = 0;
156.1369 +         /* if it is basic, invalidate the basis factorization */
156.1370 +         if (col->stat == GLP_BS) lp->valid = 0;
156.1371 +      }
156.1372 +      /* delete all marked columns from the column list */
156.1373 +      n_new = 0;
156.1374 +      for (j = 1; j <= lp->n; j++)
156.1375 +      {  /* obtain pointer to j-th column */
156.1376 +         col = lp->col[j];
156.1377 +         /* check if the column is marked */
156.1378 +         if (col->j == 0)
156.1379 +         {  /* it is marked; delete it */
156.1380 +            dmp_free_atom(lp->pool, col, sizeof(GLPCOL));
156.1381 +         }
156.1382 +         else
156.1383 +         {  /* it is not marked; keep it */
156.1384 +            col->j = ++n_new;
156.1385 +            lp->col[col->j] = col;
156.1386 +         }
156.1387 +      }
156.1388 +      /* set new number of columns */
156.1389 +      lp->n = n_new;
156.1390 +      /* if the basis header is still valid, adjust it */
156.1391 +      if (lp->valid)
156.1392 +      {  int m = lp->m;
156.1393 +         int *head = lp->head;
156.1394 +         for (j = 1; j <= n_new; j++)
156.1395 +         {  k = lp->col[j]->bind;
156.1396 +            if (k != 0)
156.1397 +            {  xassert(1 <= k && k <= m);
156.1398 +               head[k] = m + j;
156.1399 +            }
156.1400 +         }
156.1401 +      }
156.1402 +      return;
156.1403 +}
156.1404 +
156.1405 +/***********************************************************************
156.1406 +*  NAME
156.1407 +*
156.1408 +*  glp_copy_prob - copy problem object content
156.1409 +*
156.1410 +*  SYNOPSIS
156.1411 +*
156.1412 +*  void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names);
156.1413 +*
156.1414 +*  DESCRIPTION
156.1415 +*
156.1416 +*  The routine glp_copy_prob copies the content of the problem object
156.1417 +*  prob to the problem object dest.
156.1418 +*
156.1419 +*  The parameter names is a flag. If it is non-zero, the routine also
156.1420 +*  copies all symbolic names; otherwise, if it is zero, symbolic names
156.1421 +*  are not copied. */
156.1422 +
156.1423 +void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names)
156.1424 +{     glp_tree *tree = dest->tree;
156.1425 +      glp_bfcp bfcp;
156.1426 +      int i, j, len, *ind;
156.1427 +      double *val;
156.1428 +      if (tree != NULL && tree->reason != 0)
156.1429 +         xerror("glp_copy_prob: operation not allowed\n");
156.1430 +      if (dest == prob)
156.1431 +         xerror("glp_copy_prob: copying problem object to itself not al"
156.1432 +            "lowed\n");
156.1433 +      if (!(names == GLP_ON || names == GLP_OFF))
156.1434 +         xerror("glp_copy_prob: names = %d; invalid parameter\n",
156.1435 +            names);
156.1436 +      glp_erase_prob(dest);
156.1437 +      if (names && prob->name != NULL)
156.1438 +         glp_set_prob_name(dest, prob->name);
156.1439 +      if (names && prob->obj != NULL)
156.1440 +         glp_set_obj_name(dest, prob->obj);
156.1441 +      dest->dir = prob->dir;
156.1442 +      dest->c0 = prob->c0;
156.1443 +      if (prob->m > 0)
156.1444 +         glp_add_rows(dest, prob->m);
156.1445 +      if (prob->n > 0)
156.1446 +         glp_add_cols(dest, prob->n);
156.1447 +      glp_get_bfcp(prob, &bfcp);
156.1448 +      glp_set_bfcp(dest, &bfcp);
156.1449 +      dest->pbs_stat = prob->pbs_stat;
156.1450 +      dest->dbs_stat = prob->dbs_stat;
156.1451 +      dest->obj_val = prob->obj_val;
156.1452 +      dest->some = prob->some;
156.1453 +      dest->ipt_stat = prob->ipt_stat;
156.1454 +      dest->ipt_obj = prob->ipt_obj;
156.1455 +      dest->mip_stat = prob->mip_stat;
156.1456 +      dest->mip_obj = prob->mip_obj;
156.1457 +      for (i = 1; i <= prob->m; i++)
156.1458 +      {  GLPROW *to = dest->row[i];
156.1459 +         GLPROW *from = prob->row[i];
156.1460 +         if (names && from->name != NULL)
156.1461 +            glp_set_row_name(dest, i, from->name);
156.1462 +         to->type = from->type;
156.1463 +         to->lb = from->lb;
156.1464 +         to->ub = from->ub;
156.1465 +         to->rii = from->rii;
156.1466 +         to->stat = from->stat;
156.1467 +         to->prim = from->prim;
156.1468 +         to->dual = from->dual;
156.1469 +         to->pval = from->pval;
156.1470 +         to->dval = from->dval;
156.1471 +         to->mipx = from->mipx;
156.1472 +      }
156.1473 +      ind = xcalloc(1+prob->m, sizeof(int));
156.1474 +      val = xcalloc(1+prob->m, sizeof(double));
156.1475 +      for (j = 1; j <= prob->n; j++)
156.1476 +      {  GLPCOL *to = dest->col[j];
156.1477 +         GLPCOL *from = prob->col[j];
156.1478 +         if (names && from->name != NULL)
156.1479 +            glp_set_col_name(dest, j, from->name);
156.1480 +         to->kind = from->kind;
156.1481 +         to->type = from->type;
156.1482 +         to->lb = from->lb;
156.1483 +         to->ub = from->ub;
156.1484 +         to->coef = from->coef;
156.1485 +         len = glp_get_mat_col(prob, j, ind, val);
156.1486 +         glp_set_mat_col(dest, j, len, ind, val);
156.1487 +         to->sjj = from->sjj;
156.1488 +         to->stat = from->stat;
156.1489 +         to->prim = from->prim;
156.1490 +         to->dual = from->dual;
156.1491 +         to->pval = from->pval;
156.1492 +         to->dval = from->dval;
156.1493 +         to->mipx = from->mipx;
156.1494 +      }
156.1495 +      xfree(ind);
156.1496 +      xfree(val);
156.1497 +      return;
156.1498 +}
156.1499 +
156.1500 +/***********************************************************************
156.1501 +*  NAME
156.1502 +*
156.1503 +*  glp_erase_prob - erase problem object content
156.1504 +*
156.1505 +*  SYNOPSIS
156.1506 +*
156.1507 +*  void glp_erase_prob(glp_prob *lp);
156.1508 +*
156.1509 +*  DESCRIPTION
156.1510 +*
156.1511 +*  The routine glp_erase_prob erases the content of the specified
156.1512 +*  problem object. The effect of this operation is the same as if the
156.1513 +*  problem object would be deleted with the routine glp_delete_prob and
156.1514 +*  then created anew with the routine glp_create_prob, with exception
156.1515 +*  that the handle (pointer) to the problem object remains valid. */
156.1516 +
156.1517 +static void delete_prob(glp_prob *lp);
156.1518 +
156.1519 +void glp_erase_prob(glp_prob *lp)
156.1520 +{     glp_tree *tree = lp->tree;
156.1521 +      if (tree != NULL && tree->reason != 0)
156.1522 +         xerror("glp_erase_prob: operation not allowed\n");
156.1523 +      delete_prob(lp);
156.1524 +      create_prob(lp);
156.1525 +      return;
156.1526 +}
156.1527 +
156.1528 +/***********************************************************************
156.1529 +*  NAME
156.1530 +*
156.1531 +*  glp_delete_prob - delete problem object
156.1532 +*
156.1533 +*  SYNOPSIS
156.1534 +*
156.1535 +*  void glp_delete_prob(glp_prob *lp);
156.1536 +*
156.1537 +*  DESCRIPTION
156.1538 +*
156.1539 +*  The routine glp_delete_prob deletes the specified problem object and
156.1540 +*  frees all the memory allocated to it. */
156.1541 +
156.1542 +static void delete_prob(glp_prob *lp)
156.1543 +{     lp->magic = 0x3F3F3F3F;
156.1544 +      dmp_delete_pool(lp->pool);
156.1545 +#if 0 /* 17/XI-2009 */
156.1546 +      xfree(lp->cps);
156.1547 +#else
156.1548 +      if (lp->parms != NULL) xfree(lp->parms);
156.1549 +#endif
156.1550 +      xassert(lp->tree == NULL);
156.1551 +#if 0
156.1552 +      if (lp->cwa != NULL) xfree(lp->cwa);
156.1553 +#endif
156.1554 +      xfree(lp->row);
156.1555 +      xfree(lp->col);
156.1556 +      if (lp->r_tree != NULL) avl_delete_tree(lp->r_tree);
156.1557 +      if (lp->c_tree != NULL) avl_delete_tree(lp->c_tree);
156.1558 +      xfree(lp->head);
156.1559 +      if (lp->bfcp != NULL) xfree(lp->bfcp);
156.1560 +      if (lp->bfd != NULL) bfd_delete_it(lp->bfd);
156.1561 +      return;
156.1562 +}
156.1563 +
156.1564 +void glp_delete_prob(glp_prob *lp)
156.1565 +{     glp_tree *tree = lp->tree;
156.1566 +      if (tree != NULL && tree->reason != 0)
156.1567 +         xerror("glp_delete_prob: operation not allowed\n");
156.1568 +      delete_prob(lp);
156.1569 +      xfree(lp);
156.1570 +      return;
156.1571 +}
156.1572 +
156.1573 +/* eof */
   157.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   157.2 +++ b/src/glpapi02.c	Mon Dec 06 13:09:21 2010 +0100
   157.3 @@ -0,0 +1,491 @@
   157.4 +/* glpapi02.c (problem retrieving routines) */
   157.5 +
   157.6 +/***********************************************************************
   157.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   157.8 +*
   157.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  157.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  157.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  157.12 +*  E-mail: <mao@gnu.org>.
  157.13 +*
  157.14 +*  GLPK is free software: you can redistribute it and/or modify it
  157.15 +*  under the terms of the GNU General Public License as published by
  157.16 +*  the Free Software Foundation, either version 3 of the License, or
  157.17 +*  (at your option) any later version.
  157.18 +*
  157.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  157.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  157.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  157.22 +*  License for more details.
  157.23 +*
  157.24 +*  You should have received a copy of the GNU General Public License
  157.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  157.26 +***********************************************************************/
  157.27 +
  157.28 +#include "glpapi.h"
  157.29 +
  157.30 +/***********************************************************************
  157.31 +*  NAME
  157.32 +*
  157.33 +*  glp_get_prob_name - retrieve problem name
  157.34 +*
  157.35 +*  SYNOPSIS
  157.36 +*
  157.37 +*  const char *glp_get_prob_name(glp_prob *lp);
  157.38 +*
  157.39 +*  RETURNS
  157.40 +*
  157.41 +*  The routine glp_get_prob_name returns a pointer to an internal
  157.42 +*  buffer, which contains symbolic name of the problem. However, if the
  157.43 +*  problem has no assigned name, the routine returns NULL. */
  157.44 +
  157.45 +const char *glp_get_prob_name(glp_prob *lp)
  157.46 +{     char *name;
  157.47 +      name = lp->name;
  157.48 +      return name;
  157.49 +}
  157.50 +
  157.51 +/***********************************************************************
  157.52 +*  NAME
  157.53 +*
  157.54 +*  glp_get_obj_name - retrieve objective function name
  157.55 +*
  157.56 +*  SYNOPSIS
  157.57 +*
  157.58 +*  const char *glp_get_obj_name(glp_prob *lp);
  157.59 +*
  157.60 +*  RETURNS
  157.61 +*
  157.62 +*  The routine glp_get_obj_name returns a pointer to an internal
  157.63 +*  buffer, which contains a symbolic name of the objective function.
  157.64 +*  However, if the objective function has no assigned name, the routine
  157.65 +*  returns NULL. */
  157.66 +
  157.67 +const char *glp_get_obj_name(glp_prob *lp)
  157.68 +{     char *name;
  157.69 +      name = lp->obj;
  157.70 +      return name;
  157.71 +}
  157.72 +
  157.73 +/***********************************************************************
  157.74 +*  NAME
  157.75 +*
  157.76 +*  glp_get_obj_dir - retrieve optimization direction flag
  157.77 +*
  157.78 +*  SYNOPSIS
  157.79 +*
  157.80 +*  int glp_get_obj_dir(glp_prob *lp);
  157.81 +*
  157.82 +*  RETURNS
  157.83 +*
  157.84 +*  The routine glp_get_obj_dir returns the optimization direction flag
  157.85 +*  (i.e. "sense" of the objective function):
  157.86 +*
  157.87 +*  GLP_MIN - minimization;
  157.88 +*  GLP_MAX - maximization. */
  157.89 +
  157.90 +int glp_get_obj_dir(glp_prob *lp)
  157.91 +{     int dir = lp->dir;
  157.92 +      return dir;
  157.93 +}
  157.94 +
  157.95 +/***********************************************************************
  157.96 +*  NAME
  157.97 +*
  157.98 +*  glp_get_num_rows - retrieve number of rows
  157.99 +*
 157.100 +*  SYNOPSIS
 157.101 +*
 157.102 +*  int glp_get_num_rows(glp_prob *lp);
 157.103 +*
 157.104 +*  RETURNS
 157.105 +*
 157.106 +*  The routine glp_get_num_rows returns the current number of rows in
 157.107 +*  the specified problem object. */
 157.108 +
 157.109 +int glp_get_num_rows(glp_prob *lp)
 157.110 +{     int m = lp->m;
 157.111 +      return m;
 157.112 +}
 157.113 +
 157.114 +/***********************************************************************
 157.115 +*  NAME
 157.116 +*
 157.117 +*  glp_get_num_cols - retrieve number of columns
 157.118 +*
 157.119 +*  SYNOPSIS
 157.120 +*
 157.121 +*  int glp_get_num_cols(glp_prob *lp);
 157.122 +*
 157.123 +*  RETURNS
 157.124 +*
 157.125 +*  The routine glp_get_num_cols returns the current number of columns
 157.126 +*  in the specified problem object. */
 157.127 +
 157.128 +int glp_get_num_cols(glp_prob *lp)
 157.129 +{     int n = lp->n;
 157.130 +      return n;
 157.131 +}
 157.132 +
 157.133 +/***********************************************************************
 157.134 +*  NAME
 157.135 +*
 157.136 +*  glp_get_row_name - retrieve row name
 157.137 +*
 157.138 +*  SYNOPSIS
 157.139 +*
 157.140 +*  const char *glp_get_row_name(glp_prob *lp, int i);
 157.141 +*
 157.142 +*  RETURNS
 157.143 +*
 157.144 +*  The routine glp_get_row_name returns a pointer to an internal
 157.145 +*  buffer, which contains symbolic name of i-th row. However, if i-th
 157.146 +*  row has no assigned name, the routine returns NULL. */
 157.147 +
 157.148 +const char *glp_get_row_name(glp_prob *lp, int i)
 157.149 +{     char *name;
 157.150 +      if (!(1 <= i && i <= lp->m))
 157.151 +         xerror("glp_get_row_name: i = %d; row number out of range\n",
 157.152 +            i);
 157.153 +      name = lp->row[i]->name;
 157.154 +      return name;
 157.155 +}
 157.156 +
 157.157 +/***********************************************************************
 157.158 +*  NAME
 157.159 +*
 157.160 +*  glp_get_col_name - retrieve column name
 157.161 +*
 157.162 +*  SYNOPSIS
 157.163 +*
 157.164 +*  const char *glp_get_col_name(glp_prob *lp, int j);
 157.165 +*
 157.166 +*  RETURNS
 157.167 +*
 157.168 +*  The routine glp_get_col_name returns a pointer to an internal
 157.169 +*  buffer, which contains symbolic name of j-th column. However, if j-th
 157.170 +*  column has no assigned name, the routine returns NULL. */
 157.171 +
 157.172 +const char *glp_get_col_name(glp_prob *lp, int j)
 157.173 +{     char *name;
 157.174 +      if (!(1 <= j && j <= lp->n))
 157.175 +         xerror("glp_get_col_name: j = %d; column number out of range\n"
 157.176 +            , j);
 157.177 +      name = lp->col[j]->name;
 157.178 +      return name;
 157.179 +}
 157.180 +
 157.181 +/***********************************************************************
 157.182 +*  NAME
 157.183 +*
 157.184 +*  glp_get_row_type - retrieve row type
 157.185 +*
 157.186 +*  SYNOPSIS
 157.187 +*
 157.188 +*  int glp_get_row_type(glp_prob *lp, int i);
 157.189 +*
 157.190 +*  RETURNS
 157.191 +*
 157.192 +*  The routine glp_get_row_type returns the type of i-th row, i.e. the
 157.193 +*  type of corresponding auxiliary variable, as follows:
 157.194 +*
 157.195 +*  GLP_FR - free (unbounded) variable;
 157.196 +*  GLP_LO - variable with lower bound;
 157.197 +*  GLP_UP - variable with upper bound;
 157.198 +*  GLP_DB - double-bounded variable;
 157.199 +*  GLP_FX - fixed variable. */
 157.200 +
 157.201 +int glp_get_row_type(glp_prob *lp, int i)
 157.202 +{     if (!(1 <= i && i <= lp->m))
 157.203 +         xerror("glp_get_row_type: i = %d; row number out of range\n",
 157.204 +            i);
 157.205 +      return lp->row[i]->type;
 157.206 +}
 157.207 +
 157.208 +/***********************************************************************
 157.209 +*  NAME
 157.210 +*
 157.211 +*  glp_get_row_lb - retrieve row lower bound
 157.212 +*
 157.213 +*  SYNOPSIS
 157.214 +*
 157.215 +*  double glp_get_row_lb(glp_prob *lp, int i);
 157.216 +*
 157.217 +*  RETURNS
 157.218 +*
 157.219 +*  The routine glp_get_row_lb returns the lower bound of i-th row, i.e.
 157.220 +*  the lower bound of corresponding auxiliary variable. However, if the
 157.221 +*  row has no lower bound, the routine returns -DBL_MAX. */
 157.222 +
 157.223 +double glp_get_row_lb(glp_prob *lp, int i)
 157.224 +{     double lb;
 157.225 +      if (!(1 <= i && i <= lp->m))
 157.226 +         xerror("glp_get_row_lb: i = %d; row number out of range\n", i);
 157.227 +      switch (lp->row[i]->type)
 157.228 +      {  case GLP_FR:
 157.229 +         case GLP_UP:
 157.230 +            lb = -DBL_MAX; break;
 157.231 +         case GLP_LO:
 157.232 +         case GLP_DB:
 157.233 +         case GLP_FX:
 157.234 +            lb = lp->row[i]->lb; break;
 157.235 +         default:
 157.236 +            xassert(lp != lp);
 157.237 +      }
 157.238 +      return lb;
 157.239 +}
 157.240 +
 157.241 +/***********************************************************************
 157.242 +*  NAME
 157.243 +*
 157.244 +*  glp_get_row_ub - retrieve row upper bound
 157.245 +*
 157.246 +*  SYNOPSIS
 157.247 +*
 157.248 +*  double glp_get_row_ub(glp_prob *lp, int i);
 157.249 +*
 157.250 +*  RETURNS
 157.251 +*
 157.252 +*  The routine glp_get_row_ub returns the upper bound of i-th row, i.e.
 157.253 +*  the upper bound of corresponding auxiliary variable. However, if the
 157.254 +*  row has no upper bound, the routine returns +DBL_MAX. */
 157.255 +
 157.256 +double glp_get_row_ub(glp_prob *lp, int i)
 157.257 +{     double ub;
 157.258 +      if (!(1 <= i && i <= lp->m))
 157.259 +         xerror("glp_get_row_ub: i = %d; row number out of range\n", i);
 157.260 +      switch (lp->row[i]->type)
 157.261 +      {  case GLP_FR:
 157.262 +         case GLP_LO:
 157.263 +            ub = +DBL_MAX; break;
 157.264 +         case GLP_UP:
 157.265 +         case GLP_DB:
 157.266 +         case GLP_FX:
 157.267 +            ub = lp->row[i]->ub; break;
 157.268 +         default:
 157.269 +            xassert(lp != lp);
 157.270 +      }
 157.271 +      return ub;
 157.272 +}
 157.273 +
 157.274 +/***********************************************************************
 157.275 +*  NAME
 157.276 +*
 157.277 +*  glp_get_col_type - retrieve column type
 157.278 +*
 157.279 +*  SYNOPSIS
 157.280 +*
 157.281 +*  int glp_get_col_type(glp_prob *lp, int j);
 157.282 +*
 157.283 +*  RETURNS
 157.284 +*
 157.285 +*  The routine glp_get_col_type returns the type of j-th column, i.e.
 157.286 +*  the type of corresponding structural variable, as follows:
 157.287 +*
 157.288 +*  GLP_FR - free (unbounded) variable;
 157.289 +*  GLP_LO - variable with lower bound;
 157.290 +*  GLP_UP - variable with upper bound;
 157.291 +*  GLP_DB - double-bounded variable;
 157.292 +*  GLP_FX - fixed variable. */
 157.293 +
 157.294 +int glp_get_col_type(glp_prob *lp, int j)
 157.295 +{     if (!(1 <= j && j <= lp->n))
 157.296 +         xerror("glp_get_col_type: j = %d; column number out of range\n"
 157.297 +            , j);
 157.298 +      return lp->col[j]->type;
 157.299 +}
 157.300 +
 157.301 +/***********************************************************************
 157.302 +*  NAME
 157.303 +*
 157.304 +*  glp_get_col_lb - retrieve column lower bound
 157.305 +*
 157.306 +*  SYNOPSIS
 157.307 +*
 157.308 +*  double glp_get_col_lb(glp_prob *lp, int j);
 157.309 +*
 157.310 +*  RETURNS
 157.311 +*
 157.312 +*  The routine glp_get_col_lb returns the lower bound of j-th column,
 157.313 +*  i.e. the lower bound of corresponding structural variable. However,
 157.314 +*  if the column has no lower bound, the routine returns -DBL_MAX. */
 157.315 +
 157.316 +double glp_get_col_lb(glp_prob *lp, int j)
 157.317 +{     double lb;
 157.318 +      if (!(1 <= j && j <= lp->n))
 157.319 +         xerror("glp_get_col_lb: j = %d; column number out of range\n",
 157.320 +            j);
 157.321 +      switch (lp->col[j]->type)
 157.322 +      {  case GLP_FR:
 157.323 +         case GLP_UP:
 157.324 +            lb = -DBL_MAX; break;
 157.325 +         case GLP_LO:
 157.326 +         case GLP_DB:
 157.327 +         case GLP_FX:
 157.328 +            lb = lp->col[j]->lb; break;
 157.329 +         default:
 157.330 +            xassert(lp != lp);
 157.331 +      }
 157.332 +      return lb;
 157.333 +}
 157.334 +
 157.335 +/***********************************************************************
 157.336 +*  NAME
 157.337 +*
 157.338 +*  glp_get_col_ub - retrieve column upper bound
 157.339 +*
 157.340 +*  SYNOPSIS
 157.341 +*
 157.342 +*  double glp_get_col_ub(glp_prob *lp, int j);
 157.343 +*
 157.344 +*  RETURNS
 157.345 +*
 157.346 +*  The routine glp_get_col_ub returns the upper bound of j-th column,
 157.347 +*  i.e. the upper bound of corresponding structural variable. However,
 157.348 +*  if the column has no upper bound, the routine returns +DBL_MAX. */
 157.349 +
 157.350 +double glp_get_col_ub(glp_prob *lp, int j)
 157.351 +{     double ub;
 157.352 +      if (!(1 <= j && j <= lp->n))
 157.353 +         xerror("glp_get_col_ub: j = %d; column number out of range\n",
 157.354 +            j);
 157.355 +      switch (lp->col[j]->type)
 157.356 +      {  case GLP_FR:
 157.357 +         case GLP_LO:
 157.358 +            ub = +DBL_MAX; break;
 157.359 +         case GLP_UP:
 157.360 +         case GLP_DB:
 157.361 +         case GLP_FX:
 157.362 +            ub = lp->col[j]->ub; break;
 157.363 +         default:
 157.364 +            xassert(lp != lp);
 157.365 +      }
 157.366 +      return ub;
 157.367 +}
 157.368 +
 157.369 +/***********************************************************************
 157.370 +*  NAME
 157.371 +*
 157.372 +*  glp_get_obj_coef - retrieve obj. coefficient or constant term
 157.373 +*
 157.374 +*  SYNOPSIS
 157.375 +*
 157.376 +*  double glp_get_obj_coef(glp_prob *lp, int j);
 157.377 +*
 157.378 +*  RETURNS
 157.379 +*
 157.380 +*  The routine glp_get_obj_coef returns the objective coefficient at
 157.381 +*  j-th structural variable (column) of the specified problem object.
 157.382 +*
 157.383 +*  If the parameter j is zero, the routine returns the constant term
 157.384 +*  ("shift") of the objective function. */
 157.385 +
 157.386 +double glp_get_obj_coef(glp_prob *lp, int j)
 157.387 +{     if (!(0 <= j && j <= lp->n))
 157.388 +         xerror("glp_get_obj_coef: j = %d; column number out of range\n"
 157.389 +            , j);
 157.390 +      return j == 0 ? lp->c0 : lp->col[j]->coef;
 157.391 +}
 157.392 +
 157.393 +/***********************************************************************
 157.394 +*  NAME
 157.395 +*
 157.396 +*  glp_get_num_nz - retrieve number of constraint coefficients
 157.397 +*
 157.398 +*  SYNOPSIS
 157.399 +*
 157.400 +*  int glp_get_num_nz(glp_prob *lp);
 157.401 +*
 157.402 +*  RETURNS
 157.403 +*
 157.404 +*  The routine glp_get_num_nz returns the number of (non-zero) elements
 157.405 +*  in the constraint matrix of the specified problem object. */
 157.406 +
 157.407 +int glp_get_num_nz(glp_prob *lp)
 157.408 +{     int nnz = lp->nnz;
 157.409 +      return nnz;
 157.410 +}
 157.411 +
 157.412 +/***********************************************************************
 157.413 +*  NAME
 157.414 +*
 157.415 +*  glp_get_mat_row - retrieve row of the constraint matrix
 157.416 +*
 157.417 +*  SYNOPSIS
 157.418 +*
 157.419 +*  int glp_get_mat_row(glp_prob *lp, int i, int ind[], double val[]);
 157.420 +*
 157.421 +*  DESCRIPTION
 157.422 +*
 157.423 +*  The routine glp_get_mat_row scans (non-zero) elements of i-th row
 157.424 +*  of the constraint matrix of the specified problem object and stores
 157.425 +*  their column indices and numeric values to locations ind[1], ...,
 157.426 +*  ind[len] and val[1], ..., val[len], respectively, where 0 <= len <= n
 157.427 +*  is the number of elements in i-th row, n is the number of columns.
 157.428 +*
 157.429 +*  The parameter ind and/or val can be specified as NULL, in which case
 157.430 +*  corresponding information is not stored.
 157.431 +*
 157.432 +*  RETURNS
 157.433 +*
 157.434 +*  The routine glp_get_mat_row returns the length len, i.e. the number
 157.435 +*  of (non-zero) elements in i-th row. */
 157.436 +
 157.437 +int glp_get_mat_row(glp_prob *lp, int i, int ind[], double val[])
 157.438 +{     GLPAIJ *aij;
 157.439 +      int len;
 157.440 +      if (!(1 <= i && i <= lp->m))
 157.441 +         xerror("glp_get_mat_row: i = %d; row number out of range\n",
 157.442 +            i);
 157.443 +      len = 0;
 157.444 +      for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
 157.445 +      {  len++;
 157.446 +         if (ind != NULL) ind[len] = aij->col->j;
 157.447 +         if (val != NULL) val[len] = aij->val;
 157.448 +      }
 157.449 +      xassert(len <= lp->n);
 157.450 +      return len;
 157.451 +}
 157.452 +
 157.453 +/***********************************************************************
 157.454 +*  NAME
 157.455 +*
 157.456 +*  glp_get_mat_col - retrieve column of the constraint matrix
 157.457 +*
 157.458 +*  SYNOPSIS
 157.459 +*
 157.460 +*  int glp_get_mat_col(glp_prob *lp, int j, int ind[], double val[]);
 157.461 +*
 157.462 +*  DESCRIPTION
 157.463 +*
 157.464 +*  The routine glp_get_mat_col scans (non-zero) elements of j-th column
 157.465 +*  of the constraint matrix of the specified problem object and stores
 157.466 +*  their row indices and numeric values to locations ind[1], ...,
 157.467 +*  ind[len] and val[1], ..., val[len], respectively, where 0 <= len <= m
 157.468 +*  is the number of elements in j-th column, m is the number of rows.
 157.469 +*
 157.470 +*  The parameter ind or/and val can be specified as NULL, in which case
 157.471 +*  corresponding information is not stored.
 157.472 +*
 157.473 +*  RETURNS
 157.474 +*
 157.475 +*  The routine glp_get_mat_col returns the length len, i.e. the number
 157.476 +*  of (non-zero) elements in j-th column. */
 157.477 +
 157.478 +int glp_get_mat_col(glp_prob *lp, int j, int ind[], double val[])
 157.479 +{     GLPAIJ *aij;
 157.480 +      int len;
 157.481 +      if (!(1 <= j && j <= lp->n))
 157.482 +         xerror("glp_get_mat_col: j = %d; column number out of range\n",
 157.483 +            j);
 157.484 +      len = 0;
 157.485 +      for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next)
 157.486 +      {  len++;
 157.487 +         if (ind != NULL) ind[len] = aij->row->i;
 157.488 +         if (val != NULL) val[len] = aij->val;
 157.489 +      }
 157.490 +      xassert(len <= lp->m);
 157.491 +      return len;
 157.492 +}
 157.493 +
 157.494 +/* eof */
   158.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   158.2 +++ b/src/glpapi03.c	Mon Dec 06 13:09:21 2010 +0100
   158.3 @@ -0,0 +1,166 @@
   158.4 +/* glpapi03.c (row and column searching routines) */
   158.5 +
   158.6 +/***********************************************************************
   158.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   158.8 +*
   158.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  158.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  158.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  158.12 +*  E-mail: <mao@gnu.org>.
  158.13 +*
  158.14 +*  GLPK is free software: you can redistribute it and/or modify it
  158.15 +*  under the terms of the GNU General Public License as published by
  158.16 +*  the Free Software Foundation, either version 3 of the License, or
  158.17 +*  (at your option) any later version.
  158.18 +*
  158.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  158.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  158.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  158.22 +*  License for more details.
  158.23 +*
  158.24 +*  You should have received a copy of the GNU General Public License
  158.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  158.26 +***********************************************************************/
  158.27 +
  158.28 +#include "glpapi.h"
  158.29 +
  158.30 +/***********************************************************************
  158.31 +*  NAME
  158.32 +*
  158.33 +*  glp_create_index - create the name index
  158.34 +*
  158.35 +*  SYNOPSIS
  158.36 +*
  158.37 +*  void glp_create_index(glp_prob *lp);
  158.38 +*
  158.39 +*  DESCRIPTION
  158.40 +*
  158.41 +*  The routine glp_create_index creates the name index for the
  158.42 +*  specified problem object. The name index is an auxiliary data
  158.43 +*  structure, which is intended to quickly (i.e. for logarithmic time)
  158.44 +*  find rows and columns by their names.
  158.45 +*
  158.46 +*  This routine can be called at any time. If the name index already
  158.47 +*  exists, the routine does nothing. */
  158.48 +
  158.49 +void glp_create_index(glp_prob *lp)
  158.50 +{     GLPROW *row;
  158.51 +      GLPCOL *col;
  158.52 +      int i, j;
  158.53 +      /* create row name index */
  158.54 +      if (lp->r_tree == NULL)
  158.55 +      {  lp->r_tree = avl_create_tree(avl_strcmp, NULL);
  158.56 +         for (i = 1; i <= lp->m; i++)
  158.57 +         {  row = lp->row[i];
  158.58 +            xassert(row->node == NULL);
  158.59 +            if (row->name != NULL)
  158.60 +            {  row->node = avl_insert_node(lp->r_tree, row->name);
  158.61 +               avl_set_node_link(row->node, row);
  158.62 +            }
  158.63 +         }
  158.64 +      }
  158.65 +      /* create column name index */
  158.66 +      if (lp->c_tree == NULL)
  158.67 +      {  lp->c_tree = avl_create_tree(avl_strcmp, NULL);
  158.68 +         for (j = 1; j <= lp->n; j++)
  158.69 +         {  col = lp->col[j];
  158.70 +            xassert(col->node == NULL);
  158.71 +            if (col->name != NULL)
  158.72 +            {  col->node = avl_insert_node(lp->c_tree, col->name);
  158.73 +               avl_set_node_link(col->node, col);
  158.74 +            }
  158.75 +         }
  158.76 +      }
  158.77 +      return;
  158.78 +}
  158.79 +
  158.80 +/***********************************************************************
  158.81 +*  NAME
  158.82 +*
  158.83 +*  glp_find_row - find row by its name
  158.84 +*
  158.85 +*  SYNOPSIS
  158.86 +*
  158.87 +*  int glp_find_row(glp_prob *lp, const char *name);
  158.88 +*
  158.89 +*  RETURNS
  158.90 +*
  158.91 +*  The routine glp_find_row returns the ordinal number of a row,
  158.92 +*  which is assigned (by the routine glp_set_row_name) the specified
  158.93 +*  symbolic name. If no such row exists, the routine returns 0. */
  158.94 +
  158.95 +int glp_find_row(glp_prob *lp, const char *name)
  158.96 +{     AVLNODE *node;
  158.97 +      int i = 0;
  158.98 +      if (lp->r_tree == NULL)
  158.99 +         xerror("glp_find_row: row name index does not exist\n");
 158.100 +      if (!(name == NULL || name[0] == '\0' || strlen(name) > 255))
 158.101 +      {  node = avl_find_node(lp->r_tree, name);
 158.102 +         if (node != NULL)
 158.103 +            i = ((GLPROW *)avl_get_node_link(node))->i;
 158.104 +      }
 158.105 +      return i;
 158.106 +}
 158.107 +
 158.108 +/***********************************************************************
 158.109 +*  NAME
 158.110 +*
 158.111 +*  glp_find_col - find column by its name
 158.112 +*
 158.113 +*  SYNOPSIS
 158.114 +*
 158.115 +*  int glp_find_col(glp_prob *lp, const char *name);
 158.116 +*
 158.117 +*  RETURNS
 158.118 +*
 158.119 +*  The routine glp_find_col returns the ordinal number of a column,
 158.120 +*  which is assigned (by the routine glp_set_col_name) the specified
 158.121 +*  symbolic name. If no such column exists, the routine returns 0. */
 158.122 +
 158.123 +int glp_find_col(glp_prob *lp, const char *name)
 158.124 +{     AVLNODE *node;
 158.125 +      int j = 0;
 158.126 +      if (lp->c_tree == NULL)
 158.127 +         xerror("glp_find_col: column name index does not exist\n");
 158.128 +      if (!(name == NULL || name[0] == '\0' || strlen(name) > 255))
 158.129 +      {  node = avl_find_node(lp->c_tree, name);
 158.130 +         if (node != NULL)
 158.131 +            j = ((GLPCOL *)avl_get_node_link(node))->j;
 158.132 +      }
 158.133 +      return j;
 158.134 +}
 158.135 +
 158.136 +/***********************************************************************
 158.137 +*  NAME
 158.138 +*
 158.139 +*  glp_delete_index - delete the name index
 158.140 +*
 158.141 +*  SYNOPSIS
 158.142 +*
 158.143 +*  void glp_delete_index(glp_prob *lp);
 158.144 +*
 158.145 +*  DESCRIPTION
 158.146 +*
 158.147 +*  The routine glp_delete_index deletes the name index previously
 158.148 +*  created by the routine glp_create_index and frees the memory
 158.149 +*  allocated to this auxiliary data structure.
 158.150 +*
 158.151 +*  This routine can be called at any time. If the name index does not
 158.152 +*  exist, the routine does nothing. */
 158.153 +
 158.154 +void glp_delete_index(glp_prob *lp)
 158.155 +{     int i, j;
 158.156 +      /* delete row name index */
 158.157 +      if (lp->r_tree != NULL)
 158.158 +      {  for (i = 1; i <= lp->m; i++) lp->row[i]->node = NULL;
 158.159 +         avl_delete_tree(lp->r_tree), lp->r_tree = NULL;
 158.160 +      }
 158.161 +      /* delete column name index */
 158.162 +      if (lp->c_tree != NULL)
 158.163 +      {  for (j = 1; j <= lp->n; j++) lp->col[j]->node = NULL;
 158.164 +         avl_delete_tree(lp->c_tree), lp->c_tree = NULL;
 158.165 +      }
 158.166 +      return;
 158.167 +}
 158.168 +
 158.169 +/* eof */
   159.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   159.2 +++ b/src/glpapi04.c	Mon Dec 06 13:09:21 2010 +0100
   159.3 @@ -0,0 +1,156 @@
   159.4 +/* glpapi04.c (problem scaling routines) */
   159.5 +
   159.6 +/***********************************************************************
   159.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   159.8 +*
   159.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  159.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  159.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  159.12 +*  E-mail: <mao@gnu.org>.
  159.13 +*
  159.14 +*  GLPK is free software: you can redistribute it and/or modify it
  159.15 +*  under the terms of the GNU General Public License as published by
  159.16 +*  the Free Software Foundation, either version 3 of the License, or
  159.17 +*  (at your option) any later version.
  159.18 +*
  159.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  159.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  159.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  159.22 +*  License for more details.
  159.23 +*
  159.24 +*  You should have received a copy of the GNU General Public License
  159.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  159.26 +***********************************************************************/
  159.27 +
  159.28 +#include "glpapi.h"
  159.29 +
  159.30 +/***********************************************************************
  159.31 +*  NAME
  159.32 +*
  159.33 +*  glp_set_rii - set (change) row scale factor
  159.34 +*
  159.35 +*  SYNOPSIS
  159.36 +*
  159.37 +*  void glp_set_rii(glp_prob *lp, int i, double rii);
  159.38 +*
  159.39 +*  DESCRIPTION
  159.40 +*
  159.41 +*  The routine glp_set_rii sets (changes) the scale factor r[i,i] for
  159.42 +*  i-th row of the specified problem object. */
  159.43 +
  159.44 +void glp_set_rii(glp_prob *lp, int i, double rii)
  159.45 +{     if (!(1 <= i && i <= lp->m))
  159.46 +         xerror("glp_set_rii: i = %d; row number out of range\n", i);
  159.47 +      if (rii <= 0.0)
  159.48 +         xerror("glp_set_rii: i = %d; rii = %g; invalid scale factor\n",
  159.49 +            i, rii);
  159.50 +      if (lp->valid && lp->row[i]->rii != rii)
  159.51 +      {  GLPAIJ *aij;
  159.52 +         for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
  159.53 +         {  if (aij->col->stat == GLP_BS)
  159.54 +            {  /* invalidate the basis factorization */
  159.55 +               lp->valid = 0;
  159.56 +               break;
  159.57 +            }
  159.58 +         }
  159.59 +      }
  159.60 +      lp->row[i]->rii = rii;
  159.61 +      return;
  159.62 +}
  159.63 +
  159.64 +/***********************************************************************
  159.65 +*  NAME
  159.66 +*
  159.67 +*  glp_set sjj - set (change) column scale factor
  159.68 +*
  159.69 +*  SYNOPSIS
  159.70 +*
  159.71 +*  void glp_set_sjj(glp_prob *lp, int j, double sjj);
  159.72 +*
  159.73 +*  DESCRIPTION
  159.74 +*
  159.75 +*  The routine glp_set_sjj sets (changes) the scale factor s[j,j] for
  159.76 +*  j-th column of the specified problem object. */
  159.77 +
  159.78 +void glp_set_sjj(glp_prob *lp, int j, double sjj)
  159.79 +{     if (!(1 <= j && j <= lp->n))
  159.80 +         xerror("glp_set_sjj: j = %d; column number out of range\n", j);
  159.81 +      if (sjj <= 0.0)
  159.82 +         xerror("glp_set_sjj: j = %d; sjj = %g; invalid scale factor\n",
  159.83 +            j, sjj);
  159.84 +      if (lp->valid && lp->col[j]->sjj != sjj && lp->col[j]->stat ==
  159.85 +         GLP_BS)
  159.86 +      {  /* invalidate the basis factorization */
  159.87 +         lp->valid = 0;
  159.88 +      }
  159.89 +      lp->col[j]->sjj = sjj;
  159.90 +      return;
  159.91 +}
  159.92 +
  159.93 +/***********************************************************************
  159.94 +*  NAME
  159.95 +*
  159.96 +*  glp_get_rii - retrieve row scale factor
  159.97 +*
  159.98 +*  SYNOPSIS
  159.99 +*
 159.100 +*  double glp_get_rii(glp_prob *lp, int i);
 159.101 +*
 159.102 +*  RETURNS
 159.103 +*
 159.104 +*  The routine glp_get_rii returns current scale factor r[i,i] for i-th
 159.105 +*  row of the specified problem object. */
 159.106 +
 159.107 +double glp_get_rii(glp_prob *lp, int i)
 159.108 +{     if (!(1 <= i && i <= lp->m))
 159.109 +         xerror("glp_get_rii: i = %d; row number out of range\n", i);
 159.110 +      return lp->row[i]->rii;
 159.111 +}
 159.112 +
 159.113 +/***********************************************************************
 159.114 +*  NAME
 159.115 +*
 159.116 +*  glp_get_sjj - retrieve column scale factor
 159.117 +*
 159.118 +*  SYNOPSIS
 159.119 +*
 159.120 +*  double glp_get_sjj(glp_prob *lp, int j);
 159.121 +*
 159.122 +*  RETURNS
 159.123 +*
 159.124 +*  The routine glp_get_sjj returns current scale factor s[j,j] for j-th
 159.125 +*  column of the specified problem object. */
 159.126 +
 159.127 +double glp_get_sjj(glp_prob *lp, int j)
 159.128 +{     if (!(1 <= j && j <= lp->n))
 159.129 +         xerror("glp_get_sjj: j = %d; column number out of range\n", j);
 159.130 +      return lp->col[j]->sjj;
 159.131 +}
 159.132 +
 159.133 +/***********************************************************************
 159.134 +*  NAME
 159.135 +*
 159.136 +*  glp_unscale_prob - unscale problem data
 159.137 +*
 159.138 +*  SYNOPSIS
 159.139 +*
 159.140 +*  void glp_unscale_prob(glp_prob *lp);
 159.141 +*
 159.142 +*  DESCRIPTION
 159.143 +*
 159.144 +*  The routine glp_unscale_prob performs unscaling of problem data for
 159.145 +*  the specified problem object.
 159.146 +*
 159.147 +*  "Unscaling" means replacing the current scaling matrices R and S by
 159.148 +*  unity matrices that cancels the scaling effect. */
 159.149 +
 159.150 +void glp_unscale_prob(glp_prob *lp)
 159.151 +{     int m = glp_get_num_rows(lp);
 159.152 +      int n = glp_get_num_cols(lp);
 159.153 +      int i, j;
 159.154 +      for (i = 1; i <= m; i++) glp_set_rii(lp, i, 1.0);
 159.155 +      for (j = 1; j <= n; j++) glp_set_sjj(lp, j, 1.0);
 159.156 +      return;
 159.157 +}
 159.158 +
 159.159 +/* eof */
   160.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   160.2 +++ b/src/glpapi05.c	Mon Dec 06 13:09:21 2010 +0100
   160.3 @@ -0,0 +1,168 @@
   160.4 +/* glpapi05.c (LP basis constructing routines) */
   160.5 +
   160.6 +/***********************************************************************
   160.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   160.8 +*
   160.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  160.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  160.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  160.12 +*  E-mail: <mao@gnu.org>.
  160.13 +*
  160.14 +*  GLPK is free software: you can redistribute it and/or modify it
  160.15 +*  under the terms of the GNU General Public License as published by
  160.16 +*  the Free Software Foundation, either version 3 of the License, or
  160.17 +*  (at your option) any later version.
  160.18 +*
  160.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  160.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  160.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  160.22 +*  License for more details.
  160.23 +*
  160.24 +*  You should have received a copy of the GNU General Public License
  160.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  160.26 +***********************************************************************/
  160.27 +
  160.28 +#include "glpapi.h"
  160.29 +
  160.30 +/***********************************************************************
  160.31 +*  NAME
  160.32 +*
  160.33 +*  glp_set_row_stat - set (change) row status
  160.34 +*
  160.35 +*  SYNOPSIS
  160.36 +*
  160.37 +*  void glp_set_row_stat(glp_prob *lp, int i, int stat);
  160.38 +*
  160.39 +*  DESCRIPTION
  160.40 +*
  160.41 +*  The routine glp_set_row_stat sets (changes) status of the auxiliary
  160.42 +*  variable associated with i-th row.
  160.43 +*
  160.44 +*  The new status of the auxiliary variable should be specified by the
  160.45 +*  parameter stat as follows:
  160.46 +*
  160.47 +*  GLP_BS - basic variable;
  160.48 +*  GLP_NL - non-basic variable;
  160.49 +*  GLP_NU - non-basic variable on its upper bound; if the variable is
  160.50 +*           not double-bounded, this means the same as GLP_NL (only in
  160.51 +*           case of this routine);
  160.52 +*  GLP_NF - the same as GLP_NL (only in case of this routine);
  160.53 +*  GLP_NS - the same as GLP_NL (only in case of this routine). */
  160.54 +
  160.55 +void glp_set_row_stat(glp_prob *lp, int i, int stat)
  160.56 +{     GLPROW *row;
  160.57 +      if (!(1 <= i && i <= lp->m))
  160.58 +         xerror("glp_set_row_stat: i = %d; row number out of range\n",
  160.59 +            i);
  160.60 +      if (!(stat == GLP_BS || stat == GLP_NL || stat == GLP_NU ||
  160.61 +            stat == GLP_NF || stat == GLP_NS))
  160.62 +         xerror("glp_set_row_stat: i = %d; stat = %d; invalid status\n",
  160.63 +            i, stat);
  160.64 +      row = lp->row[i];
  160.65 +      if (stat != GLP_BS)
  160.66 +      {  switch (row->type)
  160.67 +         {  case GLP_FR: stat = GLP_NF; break;
  160.68 +            case GLP_LO: stat = GLP_NL; break;
  160.69 +            case GLP_UP: stat = GLP_NU; break;
  160.70 +            case GLP_DB: if (stat != GLP_NU) stat = GLP_NL; break;
  160.71 +            case GLP_FX: stat = GLP_NS; break;
  160.72 +            default: xassert(row != row);
  160.73 +         }
  160.74 +      }
  160.75 +      if (row->stat == GLP_BS && stat != GLP_BS ||
  160.76 +          row->stat != GLP_BS && stat == GLP_BS)
  160.77 +      {  /* invalidate the basis factorization */
  160.78 +         lp->valid = 0;
  160.79 +      }
  160.80 +      row->stat = stat;
  160.81 +      return;
  160.82 +}
  160.83 +
  160.84 +/***********************************************************************
  160.85 +*  NAME
  160.86 +*
  160.87 +*  glp_set_col_stat - set (change) column status
  160.88 +*
  160.89 +*  SYNOPSIS
  160.90 +*
  160.91 +*  void glp_set_col_stat(glp_prob *lp, int j, int stat);
  160.92 +*
  160.93 +*  DESCRIPTION
  160.94 +*
  160.95 +*  The routine glp_set_col_stat sets (changes) status of the structural
  160.96 +*  variable associated with j-th column.
  160.97 +*
  160.98 +*  The new status of the structural variable should be specified by the
  160.99 +*  parameter stat as follows:
 160.100 +*
 160.101 +*  GLP_BS - basic variable;
 160.102 +*  GLP_NL - non-basic variable;
 160.103 +*  GLP_NU - non-basic variable on its upper bound; if the variable is
 160.104 +*           not double-bounded, this means the same as GLP_NL (only in
 160.105 +*           case of this routine);
 160.106 +*  GLP_NF - the same as GLP_NL (only in case of this routine);
 160.107 +*  GLP_NS - the same as GLP_NL (only in case of this routine). */
 160.108 +
 160.109 +void glp_set_col_stat(glp_prob *lp, int j, int stat)
 160.110 +{     GLPCOL *col;
 160.111 +      if (!(1 <= j && j <= lp->n))
 160.112 +         xerror("glp_set_col_stat: j = %d; column number out of range\n"
 160.113 +            , j);
 160.114 +      if (!(stat == GLP_BS || stat == GLP_NL || stat == GLP_NU ||
 160.115 +            stat == GLP_NF || stat == GLP_NS))
 160.116 +         xerror("glp_set_col_stat: j = %d; stat = %d; invalid status\n",
 160.117 +            j, stat);
 160.118 +      col = lp->col[j];
 160.119 +      if (stat != GLP_BS)
 160.120 +      {  switch (col->type)
 160.121 +         {  case GLP_FR: stat = GLP_NF; break;
 160.122 +            case GLP_LO: stat = GLP_NL; break;
 160.123 +            case GLP_UP: stat = GLP_NU; break;
 160.124 +            case GLP_DB: if (stat != GLP_NU) stat = GLP_NL; break;
 160.125 +            case GLP_FX: stat = GLP_NS; break;
 160.126 +            default: xassert(col != col);
 160.127 +         }
 160.128 +      }
 160.129 +      if (col->stat == GLP_BS && stat != GLP_BS ||
 160.130 +          col->stat != GLP_BS && stat == GLP_BS)
 160.131 +      {  /* invalidate the basis factorization */
 160.132 +         lp->valid = 0;
 160.133 +      }
 160.134 +      col->stat = stat;
 160.135 +      return;
 160.136 +}
 160.137 +
 160.138 +/***********************************************************************
 160.139 +*  NAME
 160.140 +*
 160.141 +*  glp_std_basis - construct standard initial LP basis
 160.142 +*
 160.143 +*  SYNOPSIS
 160.144 +*
 160.145 +*  void glp_std_basis(glp_prob *lp);
 160.146 +*
 160.147 +*  DESCRIPTION
 160.148 +*
 160.149 +*  The routine glp_std_basis builds the "standard" (trivial) initial
 160.150 +*  basis for the specified problem object.
 160.151 +*
 160.152 +*  In the "standard" basis all auxiliary variables are basic, and all
 160.153 +*  structural variables are non-basic. */
 160.154 +
 160.155 +void glp_std_basis(glp_prob *lp)
 160.156 +{     int i, j;
 160.157 +      /* make all auxiliary variables basic */
 160.158 +      for (i = 1; i <= lp->m; i++)
 160.159 +         glp_set_row_stat(lp, i, GLP_BS);
 160.160 +      /* make all structural variables non-basic */
 160.161 +      for (j = 1; j <= lp->n; j++)
 160.162 +      {  GLPCOL *col = lp->col[j];
 160.163 +         if (col->type == GLP_DB && fabs(col->lb) > fabs(col->ub))
 160.164 +            glp_set_col_stat(lp, j, GLP_NU);
 160.165 +         else
 160.166 +            glp_set_col_stat(lp, j, GLP_NL);
 160.167 +      }
 160.168 +      return;
 160.169 +}
 160.170 +
 160.171 +/* eof */
   161.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   161.2 +++ b/src/glpapi06.c	Mon Dec 06 13:09:21 2010 +0100
   161.3 @@ -0,0 +1,806 @@
   161.4 +/* glpapi06.c (simplex method routines) */
   161.5 +
   161.6 +/***********************************************************************
   161.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   161.8 +*
   161.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  161.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  161.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  161.12 +*  E-mail: <mao@gnu.org>.
  161.13 +*
  161.14 +*  GLPK is free software: you can redistribute it and/or modify it
  161.15 +*  under the terms of the GNU General Public License as published by
  161.16 +*  the Free Software Foundation, either version 3 of the License, or
  161.17 +*  (at your option) any later version.
  161.18 +*
  161.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  161.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  161.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  161.22 +*  License for more details.
  161.23 +*
  161.24 +*  You should have received a copy of the GNU General Public License
  161.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  161.26 +***********************************************************************/
  161.27 +
  161.28 +#include "glpios.h"
  161.29 +#include "glpnpp.h"
  161.30 +#include "glpspx.h"
  161.31 +
  161.32 +/***********************************************************************
  161.33 +*  NAME
  161.34 +*
  161.35 +*  glp_simplex - solve LP problem with the simplex method
  161.36 +*
  161.37 +*  SYNOPSIS
  161.38 +*
  161.39 +*  int glp_simplex(glp_prob *P, const glp_smcp *parm);
  161.40 +*
  161.41 +*  DESCRIPTION
  161.42 +*
  161.43 +*  The routine glp_simplex is a driver to the LP solver based on the
  161.44 +*  simplex method. This routine retrieves problem data from the
  161.45 +*  specified problem object, calls the solver to solve the problem
  161.46 +*  instance, and stores results of computations back into the problem
  161.47 +*  object.
  161.48 +*
  161.49 +*  The simplex solver has a set of control parameters. Values of the
  161.50 +*  control parameters can be passed in a structure glp_smcp, which the
  161.51 +*  parameter parm points to.
  161.52 +*
  161.53 +*  The parameter parm can be specified as NULL, in which case the LP
  161.54 +*  solver uses default settings.
  161.55 +*
  161.56 +*  RETURNS
  161.57 +*
  161.58 +*  0  The LP problem instance has been successfully solved. This code
  161.59 +*     does not necessarily mean that the solver has found optimal
  161.60 +*     solution. It only means that the solution process was successful.
  161.61 +*
  161.62 +*  GLP_EBADB
  161.63 +*     Unable to start the search, because the initial basis specified
  161.64 +*     in the problem object is invalid--the number of basic (auxiliary
  161.65 +*     and structural) variables is not the same as the number of rows in
  161.66 +*     the problem object.
  161.67 +*
  161.68 +*  GLP_ESING
  161.69 +*     Unable to start the search, because the basis matrix correspodning
  161.70 +*     to the initial basis is singular within the working precision.
  161.71 +*
  161.72 +*  GLP_ECOND
  161.73 +*     Unable to start the search, because the basis matrix correspodning
  161.74 +*     to the initial basis is ill-conditioned, i.e. its condition number
  161.75 +*     is too large.
  161.76 +*
  161.77 +*  GLP_EBOUND
  161.78 +*     Unable to start the search, because some double-bounded variables
  161.79 +*     have incorrect bounds.
  161.80 +*
  161.81 +*  GLP_EFAIL
  161.82 +*     The search was prematurely terminated due to the solver failure.
  161.83 +*
  161.84 +*  GLP_EOBJLL
  161.85 +*     The search was prematurely terminated, because the objective
  161.86 +*     function being maximized has reached its lower limit and continues
  161.87 +*     decreasing (dual simplex only).
  161.88 +*
  161.89 +*  GLP_EOBJUL
  161.90 +*     The search was prematurely terminated, because the objective
  161.91 +*     function being minimized has reached its upper limit and continues
  161.92 +*     increasing (dual simplex only).
  161.93 +*
  161.94 +*  GLP_EITLIM
  161.95 +*     The search was prematurely terminated, because the simplex
  161.96 +*     iteration limit has been exceeded.
  161.97 +*
  161.98 +*  GLP_ETMLIM
  161.99 +*     The search was prematurely terminated, because the time limit has
 161.100 +*     been exceeded.
 161.101 +*
 161.102 +*  GLP_ENOPFS
 161.103 +*     The LP problem instance has no primal feasible solution (only if
 161.104 +*     the LP presolver is used).
 161.105 +*
 161.106 +*  GLP_ENODFS
 161.107 +*     The LP problem instance has no dual feasible solution (only if the
 161.108 +*     LP presolver is used). */
 161.109 +
 161.110 +static void trivial_lp(glp_prob *P, const glp_smcp *parm)
 161.111 +{     /* solve trivial LP which has empty constraint matrix */
 161.112 +      GLPROW *row;
 161.113 +      GLPCOL *col;
 161.114 +      int i, j;
 161.115 +      double p_infeas, d_infeas, zeta;
 161.116 +      P->valid = 0;
 161.117 +      P->pbs_stat = P->dbs_stat = GLP_FEAS;
 161.118 +      P->obj_val = P->c0;
 161.119 +      P->some = 0;
 161.120 +      p_infeas = d_infeas = 0.0;
 161.121 +      /* make all auxiliary variables basic */
 161.122 +      for (i = 1; i <= P->m; i++)
 161.123 +      {  row = P->row[i];
 161.124 +         row->stat = GLP_BS;
 161.125 +         row->prim = row->dual = 0.0;
 161.126 +         /* check primal feasibility */
 161.127 +         if (row->type == GLP_LO || row->type == GLP_DB ||
 161.128 +             row->type == GLP_FX)
 161.129 +         {  /* row has lower bound */
 161.130 +            if (row->lb > + parm->tol_bnd)
 161.131 +            {  P->pbs_stat = GLP_NOFEAS;
 161.132 +               if (P->some == 0 && parm->meth != GLP_PRIMAL)
 161.133 +                  P->some = i;
 161.134 +            }
 161.135 +            if (p_infeas < + row->lb)
 161.136 +               p_infeas = + row->lb;
 161.137 +         }
 161.138 +         if (row->type == GLP_UP || row->type == GLP_DB ||
 161.139 +             row->type == GLP_FX)
 161.140 +         {  /* row has upper bound */
 161.141 +            if (row->ub < - parm->tol_bnd)
 161.142 +            {  P->pbs_stat = GLP_NOFEAS;
 161.143 +               if (P->some == 0 && parm->meth != GLP_PRIMAL)
 161.144 +                  P->some = i;
 161.145 +            }
 161.146 +            if (p_infeas < - row->ub)
 161.147 +               p_infeas = - row->ub;
 161.148 +         }
 161.149 +      }
 161.150 +      /* determine scale factor for the objective row */
 161.151 +      zeta = 1.0;
 161.152 +      for (j = 1; j <= P->n; j++)
 161.153 +      {  col = P->col[j];
 161.154 +         if (zeta < fabs(col->coef)) zeta = fabs(col->coef);
 161.155 +      }
 161.156 +      zeta = (P->dir == GLP_MIN ? +1.0 : -1.0) / zeta;
 161.157 +      /* make all structural variables non-basic */
 161.158 +      for (j = 1; j <= P->n; j++)
 161.159 +      {  col = P->col[j];
 161.160 +         if (col->type == GLP_FR)
 161.161 +            col->stat = GLP_NF, col->prim = 0.0;
 161.162 +         else if (col->type == GLP_LO)
 161.163 +lo:         col->stat = GLP_NL, col->prim = col->lb;
 161.164 +         else if (col->type == GLP_UP)
 161.165 +up:         col->stat = GLP_NU, col->prim = col->ub;
 161.166 +         else if (col->type == GLP_DB)
 161.167 +         {  if (zeta * col->coef > 0.0)
 161.168 +               goto lo;
 161.169 +            else if (zeta * col->coef < 0.0)
 161.170 +               goto up;
 161.171 +            else if (fabs(col->lb) <= fabs(col->ub))
 161.172 +               goto lo;
 161.173 +            else
 161.174 +               goto up;
 161.175 +         }
 161.176 +         else if (col->type == GLP_FX)
 161.177 +            col->stat = GLP_NS, col->prim = col->lb;
 161.178 +         col->dual = col->coef;
 161.179 +         P->obj_val += col->coef * col->prim;
 161.180 +         /* check dual feasibility */
 161.181 +         if (col->type == GLP_FR || col->type == GLP_LO)
 161.182 +         {  /* column has no upper bound */
 161.183 +            if (zeta * col->dual < - parm->tol_dj)
 161.184 +            {  P->dbs_stat = GLP_NOFEAS;
 161.185 +               if (P->some == 0 && parm->meth == GLP_PRIMAL)
 161.186 +                  P->some = P->m + j;
 161.187 +            }
 161.188 +            if (d_infeas < - zeta * col->dual)
 161.189 +               d_infeas = - zeta * col->dual;
 161.190 +         }
 161.191 +         if (col->type == GLP_FR || col->type == GLP_UP)
 161.192 +         {  /* column has no lower bound */
 161.193 +            if (zeta * col->dual > + parm->tol_dj)
 161.194 +            {  P->dbs_stat = GLP_NOFEAS;
 161.195 +               if (P->some == 0 && parm->meth == GLP_PRIMAL)
 161.196 +                  P->some = P->m + j;
 161.197 +            }
 161.198 +            if (d_infeas < + zeta * col->dual)
 161.199 +               d_infeas = + zeta * col->dual;
 161.200 +         }
 161.201 +      }
 161.202 +      /* simulate the simplex solver output */
 161.203 +      if (parm->msg_lev >= GLP_MSG_ON && parm->out_dly == 0)
 161.204 +      {  xprintf("~%6d: obj = %17.9e  infeas = %10.3e\n", P->it_cnt,
 161.205 +            P->obj_val, parm->meth == GLP_PRIMAL ? p_infeas : d_infeas);
 161.206 +      }
 161.207 +      if (parm->msg_lev >= GLP_MSG_ALL && parm->out_dly == 0)
 161.208 +      {  if (P->pbs_stat == GLP_FEAS && P->dbs_stat == GLP_FEAS)
 161.209 +            xprintf("OPTIMAL SOLUTION FOUND\n");
 161.210 +         else if (P->pbs_stat == GLP_NOFEAS)
 161.211 +            xprintf("PROBLEM HAS NO FEASIBLE SOLUTION\n");
 161.212 +         else if (parm->meth == GLP_PRIMAL)
 161.213 +            xprintf("PROBLEM HAS UNBOUNDED SOLUTION\n");
 161.214 +         else
 161.215 +            xprintf("PROBLEM HAS NO DUAL FEASIBLE SOLUTION\n");
 161.216 +      }
 161.217 +      return;
 161.218 +}
 161.219 +
 161.220 +static int solve_lp(glp_prob *P, const glp_smcp *parm)
 161.221 +{     /* solve LP directly without using the preprocessor */
 161.222 +      int ret;
 161.223 +      if (!glp_bf_exists(P))
 161.224 +      {  ret = glp_factorize(P);
 161.225 +         if (ret == 0)
 161.226 +            ;
 161.227 +         else if (ret == GLP_EBADB)
 161.228 +         {  if (parm->msg_lev >= GLP_MSG_ERR)
 161.229 +               xprintf("glp_simplex: initial basis is invalid\n");
 161.230 +         }
 161.231 +         else if (ret == GLP_ESING)
 161.232 +         {  if (parm->msg_lev >= GLP_MSG_ERR)
 161.233 +               xprintf("glp_simplex: initial basis is singular\n");
 161.234 +         }
 161.235 +         else if (ret == GLP_ECOND)
 161.236 +         {  if (parm->msg_lev >= GLP_MSG_ERR)
 161.237 +               xprintf(
 161.238 +                  "glp_simplex: initial basis is ill-conditioned\n");
 161.239 +         }
 161.240 +         else
 161.241 +            xassert(ret != ret);
 161.242 +         if (ret != 0) goto done;
 161.243 +      }
 161.244 +      if (parm->meth == GLP_PRIMAL)
 161.245 +         ret = spx_primal(P, parm);
 161.246 +      else if (parm->meth == GLP_DUALP)
 161.247 +      {  ret = spx_dual(P, parm);
 161.248 +         if (ret == GLP_EFAIL && P->valid)
 161.249 +            ret = spx_primal(P, parm);
 161.250 +      }
 161.251 +      else if (parm->meth == GLP_DUAL)
 161.252 +         ret = spx_dual(P, parm);
 161.253 +      else
 161.254 +         xassert(parm != parm);
 161.255 +done: return ret;
 161.256 +}
 161.257 +
 161.258 +static int preprocess_and_solve_lp(glp_prob *P, const glp_smcp *parm)
 161.259 +{     /* solve LP using the preprocessor */
 161.260 +      NPP *npp;
 161.261 +      glp_prob *lp = NULL;
 161.262 +      glp_bfcp bfcp;
 161.263 +      int ret;
 161.264 +      if (parm->msg_lev >= GLP_MSG_ALL)
 161.265 +         xprintf("Preprocessing...\n");
 161.266 +      /* create preprocessor workspace */
 161.267 +      npp = npp_create_wksp();
 161.268 +      /* load original problem into the preprocessor workspace */
 161.269 +      npp_load_prob(npp, P, GLP_OFF, GLP_SOL, GLP_OFF);
 161.270 +      /* process LP prior to applying primal/dual simplex method */
 161.271 +      ret = npp_simplex(npp, parm);
 161.272 +      if (ret == 0)
 161.273 +         ;
 161.274 +      else if (ret == GLP_ENOPFS)
 161.275 +      {  if (parm->msg_lev >= GLP_MSG_ALL)
 161.276 +            xprintf("PROBLEM HAS NO PRIMAL FEASIBLE SOLUTION\n");
 161.277 +      }
 161.278 +      else if (ret == GLP_ENODFS)
 161.279 +      {  if (parm->msg_lev >= GLP_MSG_ALL)
 161.280 +            xprintf("PROBLEM HAS NO DUAL FEASIBLE SOLUTION\n");
 161.281 +      }
 161.282 +      else
 161.283 +         xassert(ret != ret);
 161.284 +      if (ret != 0) goto done;
 161.285 +      /* build transformed LP */
 161.286 +      lp = glp_create_prob();
 161.287 +      npp_build_prob(npp, lp);
 161.288 +      /* if the transformed LP is empty, it has empty solution, which
 161.289 +         is optimal */
 161.290 +      if (lp->m == 0 && lp->n == 0)
 161.291 +      {  lp->pbs_stat = lp->dbs_stat = GLP_FEAS;
 161.292 +         lp->obj_val = lp->c0;
 161.293 +         if (parm->msg_lev >= GLP_MSG_ON && parm->out_dly == 0)
 161.294 +         {  xprintf("~%6d: obj = %17.9e  infeas = %10.3e\n", P->it_cnt,
 161.295 +               lp->obj_val, 0.0);
 161.296 +         }
 161.297 +         if (parm->msg_lev >= GLP_MSG_ALL)
 161.298 +            xprintf("OPTIMAL SOLUTION FOUND BY LP PREPROCESSOR\n");
 161.299 +         goto post;
 161.300 +      }
 161.301 +      if (parm->msg_lev >= GLP_MSG_ALL)
 161.302 +      {  xprintf("%d row%s, %d column%s, %d non-zero%s\n",
 161.303 +            lp->m, lp->m == 1 ? "" : "s", lp->n, lp->n == 1 ? "" : "s",
 161.304 +            lp->nnz, lp->nnz == 1 ? "" : "s");
 161.305 +      }
 161.306 +      /* inherit basis factorization control parameters */
 161.307 +      glp_get_bfcp(P, &bfcp);
 161.308 +      glp_set_bfcp(lp, &bfcp);
 161.309 +      /* scale the transformed problem */
 161.310 +      {  ENV *env = get_env_ptr();
 161.311 +         int term_out = env->term_out;
 161.312 +         if (!term_out || parm->msg_lev < GLP_MSG_ALL)
 161.313 +            env->term_out = GLP_OFF;
 161.314 +         else
 161.315 +            env->term_out = GLP_ON;
 161.316 +         glp_scale_prob(lp, GLP_SF_AUTO);
 161.317 +         env->term_out = term_out;
 161.318 +      }
 161.319 +      /* build advanced initial basis */
 161.320 +      {  ENV *env = get_env_ptr();
 161.321 +         int term_out = env->term_out;
 161.322 +         if (!term_out || parm->msg_lev < GLP_MSG_ALL)
 161.323 +            env->term_out = GLP_OFF;
 161.324 +         else
 161.325 +            env->term_out = GLP_ON;
 161.326 +         glp_adv_basis(lp, 0);
 161.327 +         env->term_out = term_out;
 161.328 +      }
 161.329 +      /* solve the transformed LP */
 161.330 +      lp->it_cnt = P->it_cnt;
 161.331 +      ret = solve_lp(lp, parm);
 161.332 +      P->it_cnt = lp->it_cnt;
 161.333 +      /* only optimal solution can be postprocessed */
 161.334 +      if (!(ret == 0 && lp->pbs_stat == GLP_FEAS && lp->dbs_stat ==
 161.335 +            GLP_FEAS))
 161.336 +      {  if (parm->msg_lev >= GLP_MSG_ERR)
 161.337 +            xprintf("glp_simplex: unable to recover undefined or non-op"
 161.338 +               "timal solution\n");
 161.339 +         if (ret == 0)
 161.340 +         {  if (lp->pbs_stat == GLP_NOFEAS)
 161.341 +               ret = GLP_ENOPFS;
 161.342 +            else if (lp->dbs_stat == GLP_NOFEAS)
 161.343 +               ret = GLP_ENODFS;
 161.344 +            else
 161.345 +               xassert(lp != lp);
 161.346 +         }
 161.347 +         goto done;
 161.348 +      }
 161.349 +post: /* postprocess solution from the transformed LP */
 161.350 +      npp_postprocess(npp, lp);
 161.351 +      /* the transformed LP is no longer needed */
 161.352 +      glp_delete_prob(lp), lp = NULL;
 161.353 +      /* store solution to the original problem */
 161.354 +      npp_unload_sol(npp, P);
 161.355 +      /* the original LP has been successfully solved */
 161.356 +      ret = 0;
 161.357 +done: /* delete the transformed LP, if it exists */
 161.358 +      if (lp != NULL) glp_delete_prob(lp);
 161.359 +      /* delete preprocessor workspace */
 161.360 +      npp_delete_wksp(npp);
 161.361 +      return ret;
 161.362 +}
 161.363 +
 161.364 +int glp_simplex(glp_prob *P, const glp_smcp *parm)
 161.365 +{     /* solve LP problem with the simplex method */
 161.366 +      glp_smcp _parm;
 161.367 +      int i, j, ret;
 161.368 +      /* check problem object */
 161.369 +      if (P == NULL || P->magic != GLP_PROB_MAGIC)
 161.370 +         xerror("glp_simplex: P = %p; invalid problem object\n", P);
 161.371 +      if (P->tree != NULL && P->tree->reason != 0)
 161.372 +         xerror("glp_simplex: operation not allowed\n");
 161.373 +      /* check control parameters */
 161.374 +      if (parm == NULL)
 161.375 +         parm = &_parm, glp_init_smcp((glp_smcp *)parm);
 161.376 +      if (!(parm->msg_lev == GLP_MSG_OFF ||
 161.377 +            parm->msg_lev == GLP_MSG_ERR ||
 161.378 +            parm->msg_lev == GLP_MSG_ON  ||
 161.379 +            parm->msg_lev == GLP_MSG_ALL ||
 161.380 +            parm->msg_lev == GLP_MSG_DBG))
 161.381 +         xerror("glp_simplex: msg_lev = %d; invalid parameter\n",
 161.382 +            parm->msg_lev);
 161.383 +      if (!(parm->meth == GLP_PRIMAL ||
 161.384 +            parm->meth == GLP_DUALP  ||
 161.385 +            parm->meth == GLP_DUAL))
 161.386 +         xerror("glp_simplex: meth = %d; invalid parameter\n",
 161.387 +            parm->meth);
 161.388 +      if (!(parm->pricing == GLP_PT_STD ||
 161.389 +            parm->pricing == GLP_PT_PSE))
 161.390 +         xerror("glp_simplex: pricing = %d; invalid parameter\n",
 161.391 +            parm->pricing);
 161.392 +      if (!(parm->r_test == GLP_RT_STD ||
 161.393 +            parm->r_test == GLP_RT_HAR))
 161.394 +         xerror("glp_simplex: r_test = %d; invalid parameter\n",
 161.395 +            parm->r_test);
 161.396 +      if (!(0.0 < parm->tol_bnd && parm->tol_bnd < 1.0))
 161.397 +         xerror("glp_simplex: tol_bnd = %g; invalid parameter\n",
 161.398 +            parm->tol_bnd);
 161.399 +      if (!(0.0 < parm->tol_dj && parm->tol_dj < 1.0))
 161.400 +         xerror("glp_simplex: tol_dj = %g; invalid parameter\n",
 161.401 +            parm->tol_dj);
 161.402 +      if (!(0.0 < parm->tol_piv && parm->tol_piv < 1.0))
 161.403 +         xerror("glp_simplex: tol_piv = %g; invalid parameter\n",
 161.404 +            parm->tol_piv);
 161.405 +      if (parm->it_lim < 0)
 161.406 +         xerror("glp_simplex: it_lim = %d; invalid parameter\n",
 161.407 +            parm->it_lim);
 161.408 +      if (parm->tm_lim < 0)
 161.409 +         xerror("glp_simplex: tm_lim = %d; invalid parameter\n",
 161.410 +            parm->tm_lim);
 161.411 +      if (parm->out_frq < 1)
 161.412 +         xerror("glp_simplex: out_frq = %d; invalid parameter\n",
 161.413 +            parm->out_frq);
 161.414 +      if (parm->out_dly < 0)
 161.415 +         xerror("glp_simplex: out_dly = %d; invalid parameter\n",
 161.416 +            parm->out_dly);
 161.417 +      if (!(parm->presolve == GLP_ON || parm->presolve == GLP_OFF))
 161.418 +         xerror("glp_simplex: presolve = %d; invalid parameter\n",
 161.419 +            parm->presolve);
 161.420 +      /* basic solution is currently undefined */
 161.421 +      P->pbs_stat = P->dbs_stat = GLP_UNDEF;
 161.422 +      P->obj_val = 0.0;
 161.423 +      P->some = 0;
 161.424 +      /* check bounds of double-bounded variables */
 161.425 +      for (i = 1; i <= P->m; i++)
 161.426 +      {  GLPROW *row = P->row[i];
 161.427 +         if (row->type == GLP_DB && row->lb >= row->ub)
 161.428 +         {  if (parm->msg_lev >= GLP_MSG_ERR)
 161.429 +               xprintf("glp_simplex: row %d: lb = %g, ub = %g; incorrec"
 161.430 +                  "t bounds\n", i, row->lb, row->ub);
 161.431 +            ret = GLP_EBOUND;
 161.432 +            goto done;
 161.433 +         }
 161.434 +      }
 161.435 +      for (j = 1; j <= P->n; j++)
 161.436 +      {  GLPCOL *col = P->col[j];
 161.437 +         if (col->type == GLP_DB && col->lb >= col->ub)
 161.438 +         {  if (parm->msg_lev >= GLP_MSG_ERR)
 161.439 +               xprintf("glp_simplex: column %d: lb = %g, ub = %g; incor"
 161.440 +                  "rect bounds\n", j, col->lb, col->ub);
 161.441 +            ret = GLP_EBOUND;
 161.442 +            goto done;
 161.443 +         }
 161.444 +      }
 161.445 +      /* solve LP problem */
 161.446 +      if (parm->msg_lev >= GLP_MSG_ALL)
 161.447 +      {  xprintf("GLPK Simplex Optimizer, v%s\n", glp_version());
 161.448 +         xprintf("%d row%s, %d column%s, %d non-zero%s\n",
 161.449 +            P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s",
 161.450 +            P->nnz, P->nnz == 1 ? "" : "s");
 161.451 +      }
 161.452 +      if (P->nnz == 0)
 161.453 +         trivial_lp(P, parm), ret = 0;
 161.454 +      else if (!parm->presolve)
 161.455 +         ret = solve_lp(P, parm);
 161.456 +      else
 161.457 +         ret = preprocess_and_solve_lp(P, parm);
 161.458 +done: /* return to the application program */
 161.459 +      return ret;
 161.460 +}
 161.461 +
 161.462 +/***********************************************************************
 161.463 +*  NAME
 161.464 +*
 161.465 +*  glp_init_smcp - initialize simplex method control parameters
 161.466 +*
 161.467 +*  SYNOPSIS
 161.468 +*
 161.469 +*  void glp_init_smcp(glp_smcp *parm);
 161.470 +*
 161.471 +*  DESCRIPTION
 161.472 +*
 161.473 +*  The routine glp_init_smcp initializes control parameters, which are
 161.474 +*  used by the simplex solver, with default values.
 161.475 +*
 161.476 +*  Default values of the control parameters are stored in a glp_smcp
 161.477 +*  structure, which the parameter parm points to. */
 161.478 +
 161.479 +void glp_init_smcp(glp_smcp *parm)
 161.480 +{     parm->msg_lev = GLP_MSG_ALL;
 161.481 +      parm->meth = GLP_PRIMAL;
 161.482 +      parm->pricing = GLP_PT_PSE;
 161.483 +      parm->r_test = GLP_RT_HAR;
 161.484 +      parm->tol_bnd = 1e-7;
 161.485 +      parm->tol_dj = 1e-7;
 161.486 +      parm->tol_piv = 1e-10;
 161.487 +      parm->obj_ll = -DBL_MAX;
 161.488 +      parm->obj_ul = +DBL_MAX;
 161.489 +      parm->it_lim = INT_MAX;
 161.490 +      parm->tm_lim = INT_MAX;
 161.491 +      parm->out_frq = 500;
 161.492 +      parm->out_dly = 0;
 161.493 +      parm->presolve = GLP_OFF;
 161.494 +      return;
 161.495 +}
 161.496 +
 161.497 +/***********************************************************************
 161.498 +*  NAME
 161.499 +*
 161.500 +*  glp_get_status - retrieve generic status of basic solution
 161.501 +*
 161.502 +*  SYNOPSIS
 161.503 +*
 161.504 +*  int glp_get_status(glp_prob *lp);
 161.505 +*
 161.506 +*  RETURNS
 161.507 +*
 161.508 +*  The routine glp_get_status reports the generic status of the basic
 161.509 +*  solution for the specified problem object as follows:
 161.510 +*
 161.511 +*  GLP_OPT    - solution is optimal;
 161.512 +*  GLP_FEAS   - solution is feasible;
 161.513 +*  GLP_INFEAS - solution is infeasible;
 161.514 +*  GLP_NOFEAS - problem has no feasible solution;
 161.515 +*  GLP_UNBND  - problem has unbounded solution;
 161.516 +*  GLP_UNDEF  - solution is undefined. */
 161.517 +
 161.518 +int glp_get_status(glp_prob *lp)
 161.519 +{     int status;
 161.520 +      status = glp_get_prim_stat(lp);
 161.521 +      switch (status)
 161.522 +      {  case GLP_FEAS:
 161.523 +            switch (glp_get_dual_stat(lp))
 161.524 +            {  case GLP_FEAS:
 161.525 +                  status = GLP_OPT;
 161.526 +                  break;
 161.527 +               case GLP_NOFEAS:
 161.528 +                  status = GLP_UNBND;
 161.529 +                  break;
 161.530 +               case GLP_UNDEF:
 161.531 +               case GLP_INFEAS:
 161.532 +                  status = status;
 161.533 +                  break;
 161.534 +               default:
 161.535 +                  xassert(lp != lp);
 161.536 +            }
 161.537 +            break;
 161.538 +         case GLP_UNDEF:
 161.539 +         case GLP_INFEAS:
 161.540 +         case GLP_NOFEAS:
 161.541 +            status = status;
 161.542 +            break;
 161.543 +         default:
 161.544 +            xassert(lp != lp);
 161.545 +      }
 161.546 +      return status;
 161.547 +}
 161.548 +
 161.549 +/***********************************************************************
 161.550 +*  NAME
 161.551 +*
 161.552 +*  glp_get_prim_stat - retrieve status of primal basic solution
 161.553 +*
 161.554 +*  SYNOPSIS
 161.555 +*
 161.556 +*  int glp_get_prim_stat(glp_prob *lp);
 161.557 +*
 161.558 +*  RETURNS
 161.559 +*
 161.560 +*  The routine glp_get_prim_stat reports the status of the primal basic
 161.561 +*  solution for the specified problem object as follows:
 161.562 +*
 161.563 +*  GLP_UNDEF  - primal solution is undefined;
 161.564 +*  GLP_FEAS   - primal solution is feasible;
 161.565 +*  GLP_INFEAS - primal solution is infeasible;
 161.566 +*  GLP_NOFEAS - no primal feasible solution exists. */
 161.567 +
 161.568 +int glp_get_prim_stat(glp_prob *lp)
 161.569 +{     int pbs_stat = lp->pbs_stat;
 161.570 +      return pbs_stat;
 161.571 +}
 161.572 +
 161.573 +/***********************************************************************
 161.574 +*  NAME
 161.575 +*
 161.576 +*  glp_get_dual_stat - retrieve status of dual basic solution
 161.577 +*
 161.578 +*  SYNOPSIS
 161.579 +*
 161.580 +*  int glp_get_dual_stat(glp_prob *lp);
 161.581 +*
 161.582 +*  RETURNS
 161.583 +*
 161.584 +*  The routine glp_get_dual_stat reports the status of the dual basic
 161.585 +*  solution for the specified problem object as follows:
 161.586 +*
 161.587 +*  GLP_UNDEF  - dual solution is undefined;
 161.588 +*  GLP_FEAS   - dual solution is feasible;
 161.589 +*  GLP_INFEAS - dual solution is infeasible;
 161.590 +*  GLP_NOFEAS - no dual feasible solution exists. */
 161.591 +
 161.592 +int glp_get_dual_stat(glp_prob *lp)
 161.593 +{     int dbs_stat = lp->dbs_stat;
 161.594 +      return dbs_stat;
 161.595 +}
 161.596 +
 161.597 +/***********************************************************************
 161.598 +*  NAME
 161.599 +*
 161.600 +*  glp_get_obj_val - retrieve objective value (basic solution)
 161.601 +*
 161.602 +*  SYNOPSIS
 161.603 +*
 161.604 +*  double glp_get_obj_val(glp_prob *lp);
 161.605 +*
 161.606 +*  RETURNS
 161.607 +*
 161.608 +*  The routine glp_get_obj_val returns value of the objective function
 161.609 +*  for basic solution. */
 161.610 +
 161.611 +double glp_get_obj_val(glp_prob *lp)
 161.612 +{     /*struct LPXCPS *cps = lp->cps;*/
 161.613 +      double z;
 161.614 +      z = lp->obj_val;
 161.615 +      /*if (cps->round && fabs(z) < 1e-9) z = 0.0;*/
 161.616 +      return z;
 161.617 +}
 161.618 +
 161.619 +/***********************************************************************
 161.620 +*  NAME
 161.621 +*
 161.622 +*  glp_get_row_stat - retrieve row status
 161.623 +*
 161.624 +*  SYNOPSIS
 161.625 +*
 161.626 +*  int glp_get_row_stat(glp_prob *lp, int i);
 161.627 +*
 161.628 +*  RETURNS
 161.629 +*
 161.630 +*  The routine glp_get_row_stat returns current status assigned to the
 161.631 +*  auxiliary variable associated with i-th row as follows:
 161.632 +*
 161.633 +*  GLP_BS - basic variable;
 161.634 +*  GLP_NL - non-basic variable on its lower bound;
 161.635 +*  GLP_NU - non-basic variable on its upper bound;
 161.636 +*  GLP_NF - non-basic free (unbounded) variable;
 161.637 +*  GLP_NS - non-basic fixed variable. */
 161.638 +
 161.639 +int glp_get_row_stat(glp_prob *lp, int i)
 161.640 +{     if (!(1 <= i && i <= lp->m))
 161.641 +         xerror("glp_get_row_stat: i = %d; row number out of range\n",
 161.642 +            i);
 161.643 +      return lp->row[i]->stat;
 161.644 +}
 161.645 +
 161.646 +/***********************************************************************
 161.647 +*  NAME
 161.648 +*
 161.649 +*  glp_get_row_prim - retrieve row primal value (basic solution)
 161.650 +*
 161.651 +*  SYNOPSIS
 161.652 +*
 161.653 +*  double glp_get_row_prim(glp_prob *lp, int i);
 161.654 +*
 161.655 +*  RETURNS
 161.656 +*
 161.657 +*  The routine glp_get_row_prim returns primal value of the auxiliary
 161.658 +*  variable associated with i-th row. */
 161.659 +
 161.660 +double glp_get_row_prim(glp_prob *lp, int i)
 161.661 +{     /*struct LPXCPS *cps = lp->cps;*/
 161.662 +      double prim;
 161.663 +      if (!(1 <= i && i <= lp->m))
 161.664 +         xerror("glp_get_row_prim: i = %d; row number out of range\n",
 161.665 +            i);
 161.666 +      prim = lp->row[i]->prim;
 161.667 +      /*if (cps->round && fabs(prim) < 1e-9) prim = 0.0;*/
 161.668 +      return prim;
 161.669 +}
 161.670 +
 161.671 +/***********************************************************************
 161.672 +*  NAME
 161.673 +*
 161.674 +*  glp_get_row_dual - retrieve row dual value (basic solution)
 161.675 +*
 161.676 +*  SYNOPSIS
 161.677 +*
 161.678 +*  double glp_get_row_dual(glp_prob *lp, int i);
 161.679 +*
 161.680 +*  RETURNS
 161.681 +*
 161.682 +*  The routine glp_get_row_dual returns dual value (i.e. reduced cost)
 161.683 +*  of the auxiliary variable associated with i-th row. */
 161.684 +
 161.685 +double glp_get_row_dual(glp_prob *lp, int i)
 161.686 +{     /*struct LPXCPS *cps = lp->cps;*/
 161.687 +      double dual;
 161.688 +      if (!(1 <= i && i <= lp->m))
 161.689 +         xerror("glp_get_row_dual: i = %d; row number out of range\n",
 161.690 +            i);
 161.691 +      dual = lp->row[i]->dual;
 161.692 +      /*if (cps->round && fabs(dual) < 1e-9) dual = 0.0;*/
 161.693 +      return dual;
 161.694 +}
 161.695 +
 161.696 +/***********************************************************************
 161.697 +*  NAME
 161.698 +*
 161.699 +*  glp_get_col_stat - retrieve column status
 161.700 +*
 161.701 +*  SYNOPSIS
 161.702 +*
 161.703 +*  int glp_get_col_stat(glp_prob *lp, int j);
 161.704 +*
 161.705 +*  RETURNS
 161.706 +*
 161.707 +*  The routine glp_get_col_stat returns current status assigned to the
 161.708 +*  structural variable associated with j-th column as follows:
 161.709 +*
 161.710 +*  GLP_BS - basic variable;
 161.711 +*  GLP_NL - non-basic variable on its lower bound;
 161.712 +*  GLP_NU - non-basic variable on its upper bound;
 161.713 +*  GLP_NF - non-basic free (unbounded) variable;
 161.714 +*  GLP_NS - non-basic fixed variable. */
 161.715 +
 161.716 +int glp_get_col_stat(glp_prob *lp, int j)
 161.717 +{     if (!(1 <= j && j <= lp->n))
 161.718 +         xerror("glp_get_col_stat: j = %d; column number out of range\n"
 161.719 +            , j);
 161.720 +      return lp->col[j]->stat;
 161.721 +}
 161.722 +
 161.723 +/***********************************************************************
 161.724 +*  NAME
 161.725 +*
 161.726 +*  glp_get_col_prim - retrieve column primal value (basic solution)
 161.727 +*
 161.728 +*  SYNOPSIS
 161.729 +*
 161.730 +*  double glp_get_col_prim(glp_prob *lp, int j);
 161.731 +*
 161.732 +*  RETURNS
 161.733 +*
 161.734 +*  The routine glp_get_col_prim returns primal value of the structural
 161.735 +*  variable associated with j-th column. */
 161.736 +
 161.737 +double glp_get_col_prim(glp_prob *lp, int j)
 161.738 +{     /*struct LPXCPS *cps = lp->cps;*/
 161.739 +      double prim;
 161.740 +      if (!(1 <= j && j <= lp->n))
 161.741 +         xerror("glp_get_col_prim: j = %d; column number out of range\n"
 161.742 +            , j);
 161.743 +      prim = lp->col[j]->prim;
 161.744 +      /*if (cps->round && fabs(prim) < 1e-9) prim = 0.0;*/
 161.745 +      return prim;
 161.746 +}
 161.747 +
 161.748 +/***********************************************************************
 161.749 +*  NAME
 161.750 +*
 161.751 +*  glp_get_col_dual - retrieve column dual value (basic solution)
 161.752 +*
 161.753 +*  SYNOPSIS
 161.754 +*
 161.755 +*  double glp_get_col_dual(glp_prob *lp, int j);
 161.756 +*
 161.757 +*  RETURNS
 161.758 +*
 161.759 +*  The routine glp_get_col_dual returns dual value (i.e. reduced cost)
 161.760 +*  of the structural variable associated with j-th column. */
 161.761 +
 161.762 +double glp_get_col_dual(glp_prob *lp, int j)
 161.763 +{     /*struct LPXCPS *cps = lp->cps;*/
 161.764 +      double dual;
 161.765 +      if (!(1 <= j && j <= lp->n))
 161.766 +         xerror("glp_get_col_dual: j = %d; column number out of range\n"
 161.767 +            , j);
 161.768 +      dual = lp->col[j]->dual;
 161.769 +      /*if (cps->round && fabs(dual) < 1e-9) dual = 0.0;*/
 161.770 +      return dual;
 161.771 +}
 161.772 +
 161.773 +/***********************************************************************
 161.774 +*  NAME
 161.775 +*
 161.776 +*  glp_get_unbnd_ray - determine variable causing unboundedness
 161.777 +*
 161.778 +*  SYNOPSIS
 161.779 +*
 161.780 +*  int glp_get_unbnd_ray(glp_prob *lp);
 161.781 +*
 161.782 +*  RETURNS
 161.783 +*
 161.784 +*  The routine glp_get_unbnd_ray returns the number k of a variable,
 161.785 +*  which causes primal or dual unboundedness. If 1 <= k <= m, it is
 161.786 +*  k-th auxiliary variable, and if m+1 <= k <= m+n, it is (k-m)-th
 161.787 +*  structural variable, where m is the number of rows, n is the number
 161.788 +*  of columns in the problem object. If such variable is not defined,
 161.789 +*  the routine returns 0.
 161.790 +*
 161.791 +*  COMMENTS
 161.792 +*
 161.793 +*  If it is not exactly known which version of the simplex solver
 161.794 +*  detected unboundedness, i.e. whether the unboundedness is primal or
 161.795 +*  dual, it is sufficient to check the status of the variable reported
 161.796 +*  with the routine glp_get_row_stat or glp_get_col_stat. If the
 161.797 +*  variable is non-basic, the unboundedness is primal, otherwise, if
 161.798 +*  the variable is basic, the unboundedness is dual (the latter case
 161.799 +*  means that the problem has no primal feasible dolution). */
 161.800 +
 161.801 +int glp_get_unbnd_ray(glp_prob *lp)
 161.802 +{     int k;
 161.803 +      k = lp->some;
 161.804 +      xassert(k >= 0);
 161.805 +      if (k > lp->m + lp->n) k = 0;
 161.806 +      return k;
 161.807 +}
 161.808 +
 161.809 +/* eof */
   162.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   162.2 +++ b/src/glpapi07.c	Mon Dec 06 13:09:21 2010 +0100
   162.3 @@ -0,0 +1,451 @@
   162.4 +/* glpapi07.c (exact simplex solver) */
   162.5 +
   162.6 +/***********************************************************************
   162.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   162.8 +*
   162.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  162.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  162.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  162.12 +*  E-mail: <mao@gnu.org>.
  162.13 +*
  162.14 +*  GLPK is free software: you can redistribute it and/or modify it
  162.15 +*  under the terms of the GNU General Public License as published by
  162.16 +*  the Free Software Foundation, either version 3 of the License, or
  162.17 +*  (at your option) any later version.
  162.18 +*
  162.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  162.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  162.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  162.22 +*  License for more details.
  162.23 +*
  162.24 +*  You should have received a copy of the GNU General Public License
  162.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  162.26 +***********************************************************************/
  162.27 +
  162.28 +#include "glpapi.h"
  162.29 +#include "glpssx.h"
  162.30 +
  162.31 +/***********************************************************************
  162.32 +*  NAME
  162.33 +*
  162.34 +*  glp_exact - solve LP problem in exact arithmetic
  162.35 +*
  162.36 +*  SYNOPSIS
  162.37 +*
  162.38 +*  int glp_exact(glp_prob *lp, const glp_smcp *parm);
  162.39 +*
  162.40 +*  DESCRIPTION
  162.41 +*
  162.42 +*  The routine glp_exact is a tentative implementation of the primal
  162.43 +*  two-phase simplex method based on exact (rational) arithmetic. It is
  162.44 +*  similar to the routine glp_simplex, however, for all internal
  162.45 +*  computations it uses arithmetic of rational numbers, which is exact
  162.46 +*  in mathematical sense, i.e. free of round-off errors unlike floating
  162.47 +*  point arithmetic.
  162.48 +*
  162.49 +*  Note that the routine glp_exact uses inly two control parameters
  162.50 +*  passed in the structure glp_smcp, namely, it_lim and tm_lim.
  162.51 +*
  162.52 +*  RETURNS
  162.53 +*
  162.54 +*  0  The LP problem instance has been successfully solved. This code
  162.55 +*     does not necessarily mean that the solver has found optimal
  162.56 +*     solution. It only means that the solution process was successful.
  162.57 +*
  162.58 +*  GLP_EBADB
  162.59 +*     Unable to start the search, because the initial basis specified
  162.60 +*     in the problem object is invalid--the number of basic (auxiliary
  162.61 +*     and structural) variables is not the same as the number of rows in
  162.62 +*     the problem object.
  162.63 +*
  162.64 +*  GLP_ESING
  162.65 +*     Unable to start the search, because the basis matrix correspodning
  162.66 +*     to the initial basis is exactly singular.
  162.67 +*
  162.68 +*  GLP_EBOUND
  162.69 +*     Unable to start the search, because some double-bounded variables
  162.70 +*     have incorrect bounds.
  162.71 +*
  162.72 +*  GLP_EFAIL
  162.73 +*     The problem has no rows/columns.
  162.74 +*
  162.75 +*  GLP_EITLIM
  162.76 +*     The search was prematurely terminated, because the simplex
  162.77 +*     iteration limit has been exceeded.
  162.78 +*
  162.79 +*  GLP_ETMLIM
  162.80 +*     The search was prematurely terminated, because the time limit has
  162.81 +*     been exceeded. */
  162.82 +
  162.83 +static void set_d_eps(mpq_t x, double val)
  162.84 +{     /* convert double val to rational x obtaining a more adequate
  162.85 +         fraction than provided by mpq_set_d due to allowing a small
  162.86 +         approximation error specified by a given relative tolerance;
  162.87 +         for example, mpq_set_d would give the following
  162.88 +         1/3 ~= 0.333333333333333314829616256247391... ->
  162.89 +             -> 6004799503160661/18014398509481984
  162.90 +         while this routine gives exactly 1/3 */
  162.91 +      int s, n, j;
  162.92 +      double f, p, q, eps = 1e-9;
  162.93 +      mpq_t temp;
  162.94 +      xassert(-DBL_MAX <= val && val <= +DBL_MAX);
  162.95 +#if 1 /* 30/VII-2008 */
  162.96 +      if (val == floor(val))
  162.97 +      {  /* if val is integral, do not approximate */
  162.98 +         mpq_set_d(x, val);
  162.99 +         goto done;
 162.100 +      }
 162.101 +#endif
 162.102 +      if (val > 0.0)
 162.103 +         s = +1;
 162.104 +      else if (val < 0.0)
 162.105 +         s = -1;
 162.106 +      else
 162.107 +      {  mpq_set_si(x, 0, 1);
 162.108 +         goto done;
 162.109 +      }
 162.110 +      f = frexp(fabs(val), &n);
 162.111 +      /* |val| = f * 2^n, where 0.5 <= f < 1.0 */
 162.112 +      fp2rat(f, 0.1 * eps, &p, &q);
 162.113 +      /* f ~= p / q, where p and q are integers */
 162.114 +      mpq_init(temp);
 162.115 +      mpq_set_d(x, p);
 162.116 +      mpq_set_d(temp, q);
 162.117 +      mpq_div(x, x, temp);
 162.118 +      mpq_set_si(temp, 1, 1);
 162.119 +      for (j = 1; j <= abs(n); j++)
 162.120 +         mpq_add(temp, temp, temp);
 162.121 +      if (n > 0)
 162.122 +         mpq_mul(x, x, temp);
 162.123 +      else if (n < 0)
 162.124 +         mpq_div(x, x, temp);
 162.125 +      mpq_clear(temp);
 162.126 +      if (s < 0) mpq_neg(x, x);
 162.127 +      /* check that the desired tolerance has been attained */
 162.128 +      xassert(fabs(val - mpq_get_d(x)) <= eps * (1.0 + fabs(val)));
 162.129 +done: return;
 162.130 +}
 162.131 +
 162.132 +static void load_data(SSX *ssx, LPX *lp)
 162.133 +{     /* load LP problem data into simplex solver workspace */
 162.134 +      int m = ssx->m;
 162.135 +      int n = ssx->n;
 162.136 +      int nnz = ssx->A_ptr[n+1]-1;
 162.137 +      int j, k, type, loc, len, *ind;
 162.138 +      double lb, ub, coef, *val;
 162.139 +      xassert(lpx_get_num_rows(lp) == m);
 162.140 +      xassert(lpx_get_num_cols(lp) == n);
 162.141 +      xassert(lpx_get_num_nz(lp) == nnz);
 162.142 +      /* types and bounds of rows and columns */
 162.143 +      for (k = 1; k <= m+n; k++)
 162.144 +      {  if (k <= m)
 162.145 +         {  type = lpx_get_row_type(lp, k);
 162.146 +            lb = lpx_get_row_lb(lp, k);
 162.147 +            ub = lpx_get_row_ub(lp, k);
 162.148 +         }
 162.149 +         else
 162.150 +         {  type = lpx_get_col_type(lp, k-m);
 162.151 +            lb = lpx_get_col_lb(lp, k-m);
 162.152 +            ub = lpx_get_col_ub(lp, k-m);
 162.153 +         }
 162.154 +         switch (type)
 162.155 +         {  case LPX_FR: type = SSX_FR; break;
 162.156 +            case LPX_LO: type = SSX_LO; break;
 162.157 +            case LPX_UP: type = SSX_UP; break;
 162.158 +            case LPX_DB: type = SSX_DB; break;
 162.159 +            case LPX_FX: type = SSX_FX; break;
 162.160 +            default: xassert(type != type);
 162.161 +         }
 162.162 +         ssx->type[k] = type;
 162.163 +         set_d_eps(ssx->lb[k], lb);
 162.164 +         set_d_eps(ssx->ub[k], ub);
 162.165 +      }
 162.166 +      /* optimization direction */
 162.167 +      switch (lpx_get_obj_dir(lp))
 162.168 +      {  case LPX_MIN: ssx->dir = SSX_MIN; break;
 162.169 +         case LPX_MAX: ssx->dir = SSX_MAX; break;
 162.170 +         default: xassert(lp != lp);
 162.171 +      }
 162.172 +      /* objective coefficients */
 162.173 +      for (k = 0; k <= m+n; k++)
 162.174 +      {  if (k == 0)
 162.175 +            coef = lpx_get_obj_coef(lp, 0);
 162.176 +         else if (k <= m)
 162.177 +            coef = 0.0;
 162.178 +         else
 162.179 +            coef = lpx_get_obj_coef(lp, k-m);
 162.180 +         set_d_eps(ssx->coef[k], coef);
 162.181 +      }
 162.182 +      /* constraint coefficients */
 162.183 +      ind = xcalloc(1+m, sizeof(int));
 162.184 +      val = xcalloc(1+m, sizeof(double));
 162.185 +      loc = 0;
 162.186 +      for (j = 1; j <= n; j++)
 162.187 +      {  ssx->A_ptr[j] = loc+1;
 162.188 +         len = lpx_get_mat_col(lp, j, ind, val);
 162.189 +         for (k = 1; k <= len; k++)
 162.190 +         {  loc++;
 162.191 +            ssx->A_ind[loc] = ind[k];
 162.192 +            set_d_eps(ssx->A_val[loc], val[k]);
 162.193 +         }
 162.194 +      }
 162.195 +      xassert(loc == nnz);
 162.196 +      xfree(ind);
 162.197 +      xfree(val);
 162.198 +      return;
 162.199 +}
 162.200 +
 162.201 +static int load_basis(SSX *ssx, LPX *lp)
 162.202 +{     /* load current LP basis into simplex solver workspace */
 162.203 +      int m = ssx->m;
 162.204 +      int n = ssx->n;
 162.205 +      int *type = ssx->type;
 162.206 +      int *stat = ssx->stat;
 162.207 +      int *Q_row = ssx->Q_row;
 162.208 +      int *Q_col = ssx->Q_col;
 162.209 +      int i, j, k;
 162.210 +      xassert(lpx_get_num_rows(lp) == m);
 162.211 +      xassert(lpx_get_num_cols(lp) == n);
 162.212 +      /* statuses of rows and columns */
 162.213 +      for (k = 1; k <= m+n; k++)
 162.214 +      {  if (k <= m)
 162.215 +            stat[k] = lpx_get_row_stat(lp, k);
 162.216 +         else
 162.217 +            stat[k] = lpx_get_col_stat(lp, k-m);
 162.218 +         switch (stat[k])
 162.219 +         {  case LPX_BS:
 162.220 +               stat[k] = SSX_BS;
 162.221 +               break;
 162.222 +            case LPX_NL:
 162.223 +               stat[k] = SSX_NL;
 162.224 +               xassert(type[k] == SSX_LO || type[k] == SSX_DB);
 162.225 +               break;
 162.226 +            case LPX_NU:
 162.227 +               stat[k] = SSX_NU;
 162.228 +               xassert(type[k] == SSX_UP || type[k] == SSX_DB);
 162.229 +               break;
 162.230 +            case LPX_NF:
 162.231 +               stat[k] = SSX_NF;
 162.232 +               xassert(type[k] == SSX_FR);
 162.233 +               break;
 162.234 +            case LPX_NS:
 162.235 +               stat[k] = SSX_NS;
 162.236 +               xassert(type[k] == SSX_FX);
 162.237 +               break;
 162.238 +            default:
 162.239 +               xassert(stat != stat);
 162.240 +         }
 162.241 +      }
 162.242 +      /* build permutation matix Q */
 162.243 +      i = j = 0;
 162.244 +      for (k = 1; k <= m+n; k++)
 162.245 +      {  if (stat[k] == SSX_BS)
 162.246 +         {  i++;
 162.247 +            if (i > m) return 1;
 162.248 +            Q_row[k] = i, Q_col[i] = k;
 162.249 +         }
 162.250 +         else
 162.251 +         {  j++;
 162.252 +            if (j > n) return 1;
 162.253 +            Q_row[k] = m+j, Q_col[m+j] = k;
 162.254 +         }
 162.255 +      }
 162.256 +      xassert(i == m && j == n);
 162.257 +      return 0;
 162.258 +}
 162.259 +
 162.260 +int glp_exact(glp_prob *lp, const glp_smcp *parm)
 162.261 +{     glp_smcp _parm;
 162.262 +      SSX *ssx;
 162.263 +      int m = lpx_get_num_rows(lp);
 162.264 +      int n = lpx_get_num_cols(lp);
 162.265 +      int nnz = lpx_get_num_nz(lp);
 162.266 +      int i, j, k, type, pst, dst, ret, *stat;
 162.267 +      double lb, ub, *prim, *dual, sum;
 162.268 +      if (parm == NULL)
 162.269 +         parm = &_parm, glp_init_smcp((glp_smcp *)parm);
 162.270 +      /* check control parameters */
 162.271 +      if (parm->it_lim < 0)
 162.272 +         xerror("glp_exact: it_lim = %d; invalid parameter\n",
 162.273 +            parm->it_lim);
 162.274 +      if (parm->tm_lim < 0)
 162.275 +         xerror("glp_exact: tm_lim = %d; invalid parameter\n",
 162.276 +            parm->tm_lim);
 162.277 +      /* the problem must have at least one row and one column */
 162.278 +      if (!(m > 0 && n > 0))
 162.279 +      {  xprintf("glp_exact: problem has no rows/columns\n");
 162.280 +         return GLP_EFAIL;
 162.281 +      }
 162.282 +#if 1
 162.283 +      /* basic solution is currently undefined */
 162.284 +      lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
 162.285 +      lp->obj_val = 0.0;
 162.286 +      lp->some = 0;
 162.287 +#endif
 162.288 +      /* check that all double-bounded variables have correct bounds */
 162.289 +      for (k = 1; k <= m+n; k++)
 162.290 +      {  if (k <= m)
 162.291 +         {  type = lpx_get_row_type(lp, k);
 162.292 +            lb = lpx_get_row_lb(lp, k);
 162.293 +            ub = lpx_get_row_ub(lp, k);
 162.294 +         }
 162.295 +         else
 162.296 +         {  type = lpx_get_col_type(lp, k-m);
 162.297 +            lb = lpx_get_col_lb(lp, k-m);
 162.298 +            ub = lpx_get_col_ub(lp, k-m);
 162.299 +         }
 162.300 +         if (type == LPX_DB && lb >= ub)
 162.301 +         {  xprintf("glp_exact: %s %d has invalid bounds\n",
 162.302 +               k <= m ? "row" : "column", k <= m ? k : k-m);
 162.303 +            return GLP_EBOUND;
 162.304 +         }
 162.305 +      }
 162.306 +      /* create the simplex solver workspace */
 162.307 +      xprintf("glp_exact: %d rows, %d columns, %d non-zeros\n",
 162.308 +         m, n, nnz);
 162.309 +#ifdef HAVE_GMP
 162.310 +      xprintf("GNU MP bignum library is being used\n");
 162.311 +#else
 162.312 +      xprintf("GLPK bignum module is being used\n");
 162.313 +      xprintf("(Consider installing GNU MP to attain a much better perf"
 162.314 +         "ormance.)\n");
 162.315 +#endif
 162.316 +      ssx = ssx_create(m, n, nnz);
 162.317 +      /* load LP problem data into the workspace */
 162.318 +      load_data(ssx, lp);
 162.319 +      /* load current LP basis into the workspace */
 162.320 +      if (load_basis(ssx, lp))
 162.321 +      {  xprintf("glp_exact: initial LP basis is invalid\n");
 162.322 +         ret = GLP_EBADB;
 162.323 +         goto done;
 162.324 +      }
 162.325 +      /* inherit some control parameters from the LP object */
 162.326 +#if 0
 162.327 +      ssx->it_lim = lpx_get_int_parm(lp, LPX_K_ITLIM);
 162.328 +      ssx->it_cnt = lpx_get_int_parm(lp, LPX_K_ITCNT);
 162.329 +      ssx->tm_lim = lpx_get_real_parm(lp, LPX_K_TMLIM);
 162.330 +#else
 162.331 +      ssx->it_lim = parm->it_lim;
 162.332 +      ssx->it_cnt = lp->it_cnt;
 162.333 +      ssx->tm_lim = (double)parm->tm_lim / 1000.0;
 162.334 +#endif
 162.335 +      ssx->out_frq = 5.0;
 162.336 +      ssx->tm_beg = xtime();
 162.337 +      ssx->tm_lag = xlset(0);
 162.338 +      /* solve LP */
 162.339 +      ret = ssx_driver(ssx);
 162.340 +      /* copy back some statistics to the LP object */
 162.341 +#if 0
 162.342 +      lpx_set_int_parm(lp, LPX_K_ITLIM, ssx->it_lim);
 162.343 +      lpx_set_int_parm(lp, LPX_K_ITCNT, ssx->it_cnt);
 162.344 +      lpx_set_real_parm(lp, LPX_K_TMLIM, ssx->tm_lim);
 162.345 +#else
 162.346 +      lp->it_cnt = ssx->it_cnt;
 162.347 +#endif
 162.348 +      /* analyze the return code */
 162.349 +      switch (ret)
 162.350 +      {  case 0:
 162.351 +            /* optimal solution found */
 162.352 +            ret = 0;
 162.353 +            pst = LPX_P_FEAS, dst = LPX_D_FEAS;
 162.354 +            break;
 162.355 +         case 1:
 162.356 +            /* problem has no feasible solution */
 162.357 +            ret = 0;
 162.358 +            pst = LPX_P_NOFEAS, dst = LPX_D_INFEAS;
 162.359 +            break;
 162.360 +         case 2:
 162.361 +            /* problem has unbounded solution */
 162.362 +            ret = 0;
 162.363 +            pst = LPX_P_FEAS, dst = LPX_D_NOFEAS;
 162.364 +#if 1
 162.365 +            xassert(1 <= ssx->q && ssx->q <= n);
 162.366 +            lp->some = ssx->Q_col[m + ssx->q];
 162.367 +            xassert(1 <= lp->some && lp->some <= m+n);
 162.368 +#endif
 162.369 +            break;
 162.370 +         case 3:
 162.371 +            /* iteration limit exceeded (phase I) */
 162.372 +            ret = GLP_EITLIM;
 162.373 +            pst = LPX_P_INFEAS, dst = LPX_D_INFEAS;
 162.374 +            break;
 162.375 +         case 4:
 162.376 +            /* iteration limit exceeded (phase II) */
 162.377 +            ret = GLP_EITLIM;
 162.378 +            pst = LPX_P_FEAS, dst = LPX_D_INFEAS;
 162.379 +            break;
 162.380 +         case 5:
 162.381 +            /* time limit exceeded (phase I) */
 162.382 +            ret = GLP_ETMLIM;
 162.383 +            pst = LPX_P_INFEAS, dst = LPX_D_INFEAS;
 162.384 +            break;
 162.385 +         case 6:
 162.386 +            /* time limit exceeded (phase II) */
 162.387 +            ret = GLP_ETMLIM;
 162.388 +            pst = LPX_P_FEAS, dst = LPX_D_INFEAS;
 162.389 +            break;
 162.390 +         case 7:
 162.391 +            /* initial basis matrix is singular */
 162.392 +            ret = GLP_ESING;
 162.393 +            goto done;
 162.394 +         default:
 162.395 +            xassert(ret != ret);
 162.396 +      }
 162.397 +      /* obtain final basic solution components */
 162.398 +      stat = xcalloc(1+m+n, sizeof(int));
 162.399 +      prim = xcalloc(1+m+n, sizeof(double));
 162.400 +      dual = xcalloc(1+m+n, sizeof(double));
 162.401 +      for (k = 1; k <= m+n; k++)
 162.402 +      {  if (ssx->stat[k] == SSX_BS)
 162.403 +         {  i = ssx->Q_row[k]; /* x[k] = xB[i] */
 162.404 +            xassert(1 <= i && i <= m);
 162.405 +            stat[k] = LPX_BS;
 162.406 +            prim[k] = mpq_get_d(ssx->bbar[i]);
 162.407 +            dual[k] = 0.0;
 162.408 +         }
 162.409 +         else
 162.410 +         {  j = ssx->Q_row[k] - m; /* x[k] = xN[j] */
 162.411 +            xassert(1 <= j && j <= n);
 162.412 +            switch (ssx->stat[k])
 162.413 +            {  case SSX_NF:
 162.414 +                  stat[k] = LPX_NF;
 162.415 +                  prim[k] = 0.0;
 162.416 +                  break;
 162.417 +               case SSX_NL:
 162.418 +                  stat[k] = LPX_NL;
 162.419 +                  prim[k] = mpq_get_d(ssx->lb[k]);
 162.420 +                  break;
 162.421 +               case SSX_NU:
 162.422 +                  stat[k] = LPX_NU;
 162.423 +                  prim[k] = mpq_get_d(ssx->ub[k]);
 162.424 +                  break;
 162.425 +               case SSX_NS:
 162.426 +                  stat[k] = LPX_NS;
 162.427 +                  prim[k] = mpq_get_d(ssx->lb[k]);
 162.428 +                  break;
 162.429 +               default:
 162.430 +                  xassert(ssx != ssx);
 162.431 +            }
 162.432 +            dual[k] = mpq_get_d(ssx->cbar[j]);
 162.433 +         }
 162.434 +      }
 162.435 +      /* and store them into the LP object */
 162.436 +      pst = pst - LPX_P_UNDEF + GLP_UNDEF;
 162.437 +      dst = dst - LPX_D_UNDEF + GLP_UNDEF;
 162.438 +      for (k = 1; k <= m+n; k++)
 162.439 +         stat[k] = stat[k] - LPX_BS + GLP_BS;
 162.440 +      sum = lpx_get_obj_coef(lp, 0);
 162.441 +      for (j = 1; j <= n; j++)
 162.442 +         sum += lpx_get_obj_coef(lp, j) * prim[m+j];
 162.443 +      lpx_put_solution(lp, 1, &pst, &dst, &sum,
 162.444 +         &stat[0], &prim[0], &dual[0], &stat[m], &prim[m], &dual[m]);
 162.445 +      xfree(stat);
 162.446 +      xfree(prim);
 162.447 +      xfree(dual);
 162.448 +done: /* delete the simplex solver workspace */
 162.449 +      ssx_delete(ssx);
 162.450 +      /* return to the application program */
 162.451 +      return ret;
 162.452 +}
 162.453 +
 162.454 +/* eof */
   163.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   163.2 +++ b/src/glpapi08.c	Mon Dec 06 13:09:21 2010 +0100
   163.3 @@ -0,0 +1,389 @@
   163.4 +/* glpapi08.c (interior-point method routines) */
   163.5 +
   163.6 +/***********************************************************************
   163.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   163.8 +*
   163.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  163.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  163.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  163.12 +*  E-mail: <mao@gnu.org>.
  163.13 +*
  163.14 +*  GLPK is free software: you can redistribute it and/or modify it
  163.15 +*  under the terms of the GNU General Public License as published by
  163.16 +*  the Free Software Foundation, either version 3 of the License, or
  163.17 +*  (at your option) any later version.
  163.18 +*
  163.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  163.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  163.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  163.22 +*  License for more details.
  163.23 +*
  163.24 +*  You should have received a copy of the GNU General Public License
  163.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  163.26 +***********************************************************************/
  163.27 +
  163.28 +#include "glpapi.h"
  163.29 +#include "glpipm.h"
  163.30 +#include "glpnpp.h"
  163.31 +
  163.32 +/***********************************************************************
  163.33 +*  NAME
  163.34 +*
  163.35 +*  glp_interior - solve LP problem with the interior-point method
  163.36 +*
  163.37 +*  SYNOPSIS
  163.38 +*
  163.39 +*  int glp_interior(glp_prob *P, const glp_iptcp *parm);
  163.40 +*
  163.41 +*  The routine glp_interior is a driver to the LP solver based on the
  163.42 +*  interior-point method.
  163.43 +*
  163.44 +*  The interior-point solver has a set of control parameters. Values of
  163.45 +*  the control parameters can be passed in a structure glp_iptcp, which
  163.46 +*  the parameter parm points to.
  163.47 +*
  163.48 +*  Currently this routine implements an easy variant of the primal-dual
  163.49 +*  interior-point method based on Mehrotra's technique.
  163.50 +*
  163.51 +*  This routine transforms the original LP problem to an equivalent LP
  163.52 +*  problem in the standard formulation (all constraints are equalities,
  163.53 +*  all variables are non-negative), calls the routine ipm_main to solve
  163.54 +*  the transformed problem, and then transforms an obtained solution to
  163.55 +*  the solution of the original problem.
  163.56 +*
  163.57 +*  RETURNS
  163.58 +*
  163.59 +*  0  The LP problem instance has been successfully solved. This code
  163.60 +*     does not necessarily mean that the solver has found optimal
  163.61 +*     solution. It only means that the solution process was successful.
  163.62 +*
  163.63 +*  GLP_EFAIL
  163.64 +*     The problem has no rows/columns.
  163.65 +*
  163.66 +*  GLP_ENOCVG
  163.67 +*     Very slow convergence or divergence.
  163.68 +*
  163.69 +*  GLP_EITLIM
  163.70 +*     Iteration limit exceeded.
  163.71 +*
  163.72 +*  GLP_EINSTAB
  163.73 +*     Numerical instability on solving Newtonian system. */
  163.74 +
  163.75 +static void transform(NPP *npp)
  163.76 +{     /* transform LP to the standard formulation */
  163.77 +      NPPROW *row, *prev_row;
  163.78 +      NPPCOL *col, *prev_col;
  163.79 +      for (row = npp->r_tail; row != NULL; row = prev_row)
  163.80 +      {  prev_row = row->prev;
  163.81 +         if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
  163.82 +            npp_free_row(npp, row);
  163.83 +         else if (row->lb == -DBL_MAX)
  163.84 +            npp_leq_row(npp, row);
  163.85 +         else if (row->ub == +DBL_MAX)
  163.86 +            npp_geq_row(npp, row);
  163.87 +         else if (row->lb != row->ub)
  163.88 +         {  if (fabs(row->lb) < fabs(row->ub))
  163.89 +               npp_geq_row(npp, row);
  163.90 +            else
  163.91 +               npp_leq_row(npp, row);
  163.92 +         }
  163.93 +      }
  163.94 +      for (col = npp->c_tail; col != NULL; col = prev_col)
  163.95 +      {  prev_col = col->prev;
  163.96 +         if (col->lb == -DBL_MAX && col->ub == +DBL_MAX)
  163.97 +            npp_free_col(npp, col);
  163.98 +         else if (col->lb == -DBL_MAX)
  163.99 +            npp_ubnd_col(npp, col);
 163.100 +         else if (col->ub == +DBL_MAX)
 163.101 +         {  if (col->lb != 0.0)
 163.102 +               npp_lbnd_col(npp, col);
 163.103 +         }
 163.104 +         else if (col->lb != col->ub)
 163.105 +         {  if (fabs(col->lb) < fabs(col->ub))
 163.106 +            {  if (col->lb != 0.0)
 163.107 +                  npp_lbnd_col(npp, col);
 163.108 +            }
 163.109 +            else
 163.110 +               npp_ubnd_col(npp, col);
 163.111 +            npp_dbnd_col(npp, col);
 163.112 +         }
 163.113 +         else
 163.114 +            npp_fixed_col(npp, col);
 163.115 +      }
 163.116 +      for (row = npp->r_head; row != NULL; row = row->next)
 163.117 +         xassert(row->lb == row->ub);
 163.118 +      for (col = npp->c_head; col != NULL; col = col->next)
 163.119 +         xassert(col->lb == 0.0 && col->ub == +DBL_MAX);
 163.120 +      return;
 163.121 +}
 163.122 +
 163.123 +int glp_interior(glp_prob *P, const glp_iptcp *parm)
 163.124 +{     glp_iptcp _parm;
 163.125 +      GLPROW *row;
 163.126 +      GLPCOL *col;
 163.127 +      NPP *npp = NULL;
 163.128 +      glp_prob *prob = NULL;
 163.129 +      int i, j, ret;
 163.130 +      /* check control parameters */
 163.131 +      if (parm == NULL)
 163.132 +         glp_init_iptcp(&_parm), parm = &_parm;
 163.133 +      if (!(parm->msg_lev == GLP_MSG_OFF ||
 163.134 +            parm->msg_lev == GLP_MSG_ERR ||
 163.135 +            parm->msg_lev == GLP_MSG_ON  ||
 163.136 +            parm->msg_lev == GLP_MSG_ALL))
 163.137 +         xerror("glp_interior: msg_lev = %d; invalid parameter\n",
 163.138 +            parm->msg_lev);
 163.139 +      if (!(parm->ord_alg == GLP_ORD_NONE ||
 163.140 +            parm->ord_alg == GLP_ORD_QMD ||
 163.141 +            parm->ord_alg == GLP_ORD_AMD ||
 163.142 +            parm->ord_alg == GLP_ORD_SYMAMD))
 163.143 +         xerror("glp_interior: ord_alg = %d; invalid parameter\n",
 163.144 +            parm->ord_alg);
 163.145 +      /* interior-point solution is currently undefined */
 163.146 +      P->ipt_stat = GLP_UNDEF;
 163.147 +      P->ipt_obj = 0.0;
 163.148 +      /* check bounds of double-bounded variables */
 163.149 +      for (i = 1; i <= P->m; i++)
 163.150 +      {  row = P->row[i];
 163.151 +         if (row->type == GLP_DB && row->lb >= row->ub)
 163.152 +         {  if (parm->msg_lev >= GLP_MSG_ERR)
 163.153 +               xprintf("glp_interior: row %d: lb = %g, ub = %g; incorre"
 163.154 +                  "ct bounds\n", i, row->lb, row->ub);
 163.155 +            ret = GLP_EBOUND;
 163.156 +            goto done;
 163.157 +         }
 163.158 +      }
 163.159 +      for (j = 1; j <= P->n; j++)
 163.160 +      {  col = P->col[j];
 163.161 +         if (col->type == GLP_DB && col->lb >= col->ub)
 163.162 +         {  if (parm->msg_lev >= GLP_MSG_ERR)
 163.163 +               xprintf("glp_interior: column %d: lb = %g, ub = %g; inco"
 163.164 +                  "rrect bounds\n", j, col->lb, col->ub);
 163.165 +            ret = GLP_EBOUND;
 163.166 +            goto done;
 163.167 +         }
 163.168 +      }
 163.169 +      /* transform LP to the standard formulation */
 163.170 +      if (parm->msg_lev >= GLP_MSG_ALL)
 163.171 +         xprintf("Original LP has %d row(s), %d column(s), and %d non-z"
 163.172 +            "ero(s)\n", P->m, P->n, P->nnz);
 163.173 +      npp = npp_create_wksp();
 163.174 +      npp_load_prob(npp, P, GLP_OFF, GLP_IPT, GLP_ON);
 163.175 +      transform(npp);
 163.176 +      prob = glp_create_prob();
 163.177 +      npp_build_prob(npp, prob);
 163.178 +      if (parm->msg_lev >= GLP_MSG_ALL)
 163.179 +         xprintf("Working LP has %d row(s), %d column(s), and %d non-ze"
 163.180 +            "ro(s)\n", prob->m, prob->n, prob->nnz);
 163.181 +#if 1
 163.182 +      /* currently empty problem cannot be solved */
 163.183 +      if (!(prob->m > 0 && prob->n > 0))
 163.184 +      {  if (parm->msg_lev >= GLP_MSG_ERR)
 163.185 +            xprintf("glp_interior: unable to solve empty problem\n");
 163.186 +         ret = GLP_EFAIL;
 163.187 +         goto done;
 163.188 +      }
 163.189 +#endif
 163.190 +      /* scale the resultant LP */
 163.191 +      {  ENV *env = get_env_ptr();
 163.192 +         int term_out = env->term_out;
 163.193 +         env->term_out = GLP_OFF;
 163.194 +         glp_scale_prob(prob, GLP_SF_EQ);
 163.195 +         env->term_out = term_out;
 163.196 +      }
 163.197 +      /* warn about dense columns */
 163.198 +      if (parm->msg_lev >= GLP_MSG_ON && prob->m >= 200)
 163.199 +      {  int len, cnt = 0;
 163.200 +         for (j = 1; j <= prob->n; j++)
 163.201 +         {  len = glp_get_mat_col(prob, j, NULL, NULL);
 163.202 +            if ((double)len >= 0.20 * (double)prob->m) cnt++;
 163.203 +         }
 163.204 +         if (cnt == 1)
 163.205 +            xprintf("WARNING: PROBLEM HAS ONE DENSE COLUMN\n");
 163.206 +         else if (cnt > 0)
 163.207 +            xprintf("WARNING: PROBLEM HAS %d DENSE COLUMNS\n", cnt);
 163.208 +      }
 163.209 +      /* solve the transformed LP */
 163.210 +      ret = ipm_solve(prob, parm);
 163.211 +      /* postprocess solution from the transformed LP */
 163.212 +      npp_postprocess(npp, prob);
 163.213 +      /* and store solution to the original LP */
 163.214 +      npp_unload_sol(npp, P);
 163.215 +done: /* free working program objects */
 163.216 +      if (npp != NULL) npp_delete_wksp(npp);
 163.217 +      if (prob != NULL) glp_delete_prob(prob);
 163.218 +      /* return to the application program */
 163.219 +      return ret;
 163.220 +}
 163.221 +
 163.222 +/***********************************************************************
 163.223 +*  NAME
 163.224 +*
 163.225 +*  glp_init_iptcp - initialize interior-point solver control parameters
 163.226 +*
 163.227 +*  SYNOPSIS
 163.228 +*
 163.229 +*  void glp_init_iptcp(glp_iptcp *parm);
 163.230 +*
 163.231 +*  DESCRIPTION
 163.232 +*
 163.233 +*  The routine glp_init_iptcp initializes control parameters, which are
 163.234 +*  used by the interior-point solver, with default values.
 163.235 +*
 163.236 +*  Default values of the control parameters are stored in the glp_iptcp
 163.237 +*  structure, which the parameter parm points to. */
 163.238 +
 163.239 +void glp_init_iptcp(glp_iptcp *parm)
 163.240 +{     parm->msg_lev = GLP_MSG_ALL;
 163.241 +      parm->ord_alg = GLP_ORD_AMD;
 163.242 +      return;
 163.243 +}
 163.244 +
 163.245 +/***********************************************************************
 163.246 +*  NAME
 163.247 +*
 163.248 +*  glp_ipt_status - retrieve status of interior-point solution
 163.249 +*
 163.250 +*  SYNOPSIS
 163.251 +*
 163.252 +*  int glp_ipt_status(glp_prob *lp);
 163.253 +*
 163.254 +*  RETURNS
 163.255 +*
 163.256 +*  The routine glp_ipt_status reports the status of solution found by
 163.257 +*  the interior-point solver as follows:
 163.258 +*
 163.259 +*  GLP_UNDEF  - interior-point solution is undefined;
 163.260 +*  GLP_OPT    - interior-point solution is optimal;
 163.261 +*  GLP_INFEAS - interior-point solution is infeasible;
 163.262 +*  GLP_NOFEAS - no feasible solution exists. */
 163.263 +
 163.264 +int glp_ipt_status(glp_prob *lp)
 163.265 +{     int ipt_stat = lp->ipt_stat;
 163.266 +      return ipt_stat;
 163.267 +}
 163.268 +
 163.269 +/***********************************************************************
 163.270 +*  NAME
 163.271 +*
 163.272 +*  glp_ipt_obj_val - retrieve objective value (interior point)
 163.273 +*
 163.274 +*  SYNOPSIS
 163.275 +*
 163.276 +*  double glp_ipt_obj_val(glp_prob *lp);
 163.277 +*
 163.278 +*  RETURNS
 163.279 +*
 163.280 +*  The routine glp_ipt_obj_val returns value of the objective function
 163.281 +*  for interior-point solution. */
 163.282 +
 163.283 +double glp_ipt_obj_val(glp_prob *lp)
 163.284 +{     /*struct LPXCPS *cps = lp->cps;*/
 163.285 +      double z;
 163.286 +      z = lp->ipt_obj;
 163.287 +      /*if (cps->round && fabs(z) < 1e-9) z = 0.0;*/
 163.288 +      return z;
 163.289 +}
 163.290 +
 163.291 +/***********************************************************************
 163.292 +*  NAME
 163.293 +*
 163.294 +*  glp_ipt_row_prim - retrieve row primal value (interior point)
 163.295 +*
 163.296 +*  SYNOPSIS
 163.297 +*
 163.298 +*  double glp_ipt_row_prim(glp_prob *lp, int i);
 163.299 +*
 163.300 +*  RETURNS
 163.301 +*
 163.302 +*  The routine glp_ipt_row_prim returns primal value of the auxiliary
 163.303 +*  variable associated with i-th row. */
 163.304 +
 163.305 +double glp_ipt_row_prim(glp_prob *lp, int i)
 163.306 +{     /*struct LPXCPS *cps = lp->cps;*/
 163.307 +      double pval;
 163.308 +      if (!(1 <= i && i <= lp->m))
 163.309 +         xerror("glp_ipt_row_prim: i = %d; row number out of range\n",
 163.310 +            i);
 163.311 +      pval = lp->row[i]->pval;
 163.312 +      /*if (cps->round && fabs(pval) < 1e-9) pval = 0.0;*/
 163.313 +      return pval;
 163.314 +}
 163.315 +
 163.316 +/***********************************************************************
 163.317 +*  NAME
 163.318 +*
 163.319 +*  glp_ipt_row_dual - retrieve row dual value (interior point)
 163.320 +*
 163.321 +*  SYNOPSIS
 163.322 +*
 163.323 +*  double glp_ipt_row_dual(glp_prob *lp, int i);
 163.324 +*
 163.325 +*  RETURNS
 163.326 +*
 163.327 +*  The routine glp_ipt_row_dual returns dual value (i.e. reduced cost)
 163.328 +*  of the auxiliary variable associated with i-th row. */
 163.329 +
 163.330 +double glp_ipt_row_dual(glp_prob *lp, int i)
 163.331 +{     /*struct LPXCPS *cps = lp->cps;*/
 163.332 +      double dval;
 163.333 +      if (!(1 <= i && i <= lp->m))
 163.334 +         xerror("glp_ipt_row_dual: i = %d; row number out of range\n",
 163.335 +            i);
 163.336 +      dval = lp->row[i]->dval;
 163.337 +      /*if (cps->round && fabs(dval) < 1e-9) dval = 0.0;*/
 163.338 +      return dval;
 163.339 +}
 163.340 +
 163.341 +/***********************************************************************
 163.342 +*  NAME
 163.343 +*
 163.344 +*  glp_ipt_col_prim - retrieve column primal value (interior point)
 163.345 +*
 163.346 +*  SYNOPSIS
 163.347 +*
 163.348 +*  double glp_ipt_col_prim(glp_prob *lp, int j);
 163.349 +*
 163.350 +*  RETURNS
 163.351 +*
 163.352 +*  The routine glp_ipt_col_prim returns primal value of the structural
 163.353 +*  variable associated with j-th column. */
 163.354 +
 163.355 +double glp_ipt_col_prim(glp_prob *lp, int j)
 163.356 +{     /*struct LPXCPS *cps = lp->cps;*/
 163.357 +      double pval;
 163.358 +      if (!(1 <= j && j <= lp->n))
 163.359 +         xerror("glp_ipt_col_prim: j = %d; column number out of range\n"
 163.360 +            , j);
 163.361 +      pval = lp->col[j]->pval;
 163.362 +      /*if (cps->round && fabs(pval) < 1e-9) pval = 0.0;*/
 163.363 +      return pval;
 163.364 +}
 163.365 +
 163.366 +/***********************************************************************
 163.367 +*  NAME
 163.368 +*
 163.369 +*  glp_ipt_col_dual - retrieve column dual value (interior point)
 163.370 +*
 163.371 +*  SYNOPSIS
 163.372 +*
 163.373 +*  #include "glplpx.h"
 163.374 +*  double glp_ipt_col_dual(glp_prob *lp, int j);
 163.375 +*
 163.376 +*  RETURNS
 163.377 +*
 163.378 +*  The routine glp_ipt_col_dual returns dual value (i.e. reduced cost)
 163.379 +*  of the structural variable associated with j-th column. */
 163.380 +
 163.381 +double glp_ipt_col_dual(glp_prob *lp, int j)
 163.382 +{     /*struct LPXCPS *cps = lp->cps;*/
 163.383 +      double dval;
 163.384 +      if (!(1 <= j && j <= lp->n))
 163.385 +         xerror("glp_ipt_col_dual: j = %d; column number out of range\n"
 163.386 +            , j);
 163.387 +      dval = lp->col[j]->dval;
 163.388 +      /*if (cps->round && fabs(dval) < 1e-9) dval = 0.0;*/
 163.389 +      return dval;
 163.390 +}
 163.391 +
 163.392 +/* eof */
   164.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   164.2 +++ b/src/glpapi09.c	Mon Dec 06 13:09:21 2010 +0100
   164.3 @@ -0,0 +1,741 @@
   164.4 +/* glpapi09.c (mixed integer programming routines) */
   164.5 +
   164.6 +/***********************************************************************
   164.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   164.8 +*
   164.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  164.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  164.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  164.12 +*  E-mail: <mao@gnu.org>.
  164.13 +*
  164.14 +*  GLPK is free software: you can redistribute it and/or modify it
  164.15 +*  under the terms of the GNU General Public License as published by
  164.16 +*  the Free Software Foundation, either version 3 of the License, or
  164.17 +*  (at your option) any later version.
  164.18 +*
  164.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  164.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  164.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  164.22 +*  License for more details.
  164.23 +*
  164.24 +*  You should have received a copy of the GNU General Public License
  164.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  164.26 +***********************************************************************/
  164.27 +
  164.28 +#include "glpios.h"
  164.29 +#include "glpnpp.h"
  164.30 +
  164.31 +/***********************************************************************
  164.32 +*  NAME
  164.33 +*
  164.34 +*  glp_set_col_kind - set (change) column kind
  164.35 +*
  164.36 +*  SYNOPSIS
  164.37 +*
  164.38 +*  void glp_set_col_kind(glp_prob *mip, int j, int kind);
  164.39 +*
  164.40 +*  DESCRIPTION
  164.41 +*
  164.42 +*  The routine glp_set_col_kind sets (changes) the kind of j-th column
  164.43 +*  (structural variable) as specified by the parameter kind:
  164.44 +*
  164.45 +*  GLP_CV - continuous variable;
  164.46 +*  GLP_IV - integer variable;
  164.47 +*  GLP_BV - binary variable. */
  164.48 +
  164.49 +void glp_set_col_kind(glp_prob *mip, int j, int kind)
  164.50 +{     GLPCOL *col;
  164.51 +      if (!(1 <= j && j <= mip->n))
  164.52 +         xerror("glp_set_col_kind: j = %d; column number out of range\n"
  164.53 +            , j);
  164.54 +      col = mip->col[j];
  164.55 +      switch (kind)
  164.56 +      {  case GLP_CV:
  164.57 +            col->kind = GLP_CV;
  164.58 +            break;
  164.59 +         case GLP_IV:
  164.60 +            col->kind = GLP_IV;
  164.61 +            break;
  164.62 +         case GLP_BV:
  164.63 +            col->kind = GLP_IV;
  164.64 +            if (!(col->type == GLP_DB && col->lb == 0.0 && col->ub ==
  164.65 +               1.0)) glp_set_col_bnds(mip, j, GLP_DB, 0.0, 1.0);
  164.66 +            break;
  164.67 +         default:
  164.68 +            xerror("glp_set_col_kind: j = %d; kind = %d; invalid column"
  164.69 +               " kind\n", j, kind);
  164.70 +      }
  164.71 +      return;
  164.72 +}
  164.73 +
  164.74 +/***********************************************************************
  164.75 +*  NAME
  164.76 +*
  164.77 +*  glp_get_col_kind - retrieve column kind
  164.78 +*
  164.79 +*  SYNOPSIS
  164.80 +*
  164.81 +*  int glp_get_col_kind(glp_prob *mip, int j);
  164.82 +*
  164.83 +*  RETURNS
  164.84 +*
  164.85 +*  The routine glp_get_col_kind returns the kind of j-th column, i.e.
  164.86 +*  the kind of corresponding structural variable, as follows:
  164.87 +*
  164.88 +*  GLP_CV - continuous variable;
  164.89 +*  GLP_IV - integer variable;
  164.90 +*  GLP_BV - binary variable */
  164.91 +
  164.92 +int glp_get_col_kind(glp_prob *mip, int j)
  164.93 +{     GLPCOL *col;
  164.94 +      int kind;
  164.95 +      if (!(1 <= j && j <= mip->n))
  164.96 +         xerror("glp_get_col_kind: j = %d; column number out of range\n"
  164.97 +            , j);
  164.98 +      col = mip->col[j];
  164.99 +      kind = col->kind;
 164.100 +      switch (kind)
 164.101 +      {  case GLP_CV:
 164.102 +            break;
 164.103 +         case GLP_IV:
 164.104 +            if (col->type == GLP_DB && col->lb == 0.0 && col->ub == 1.0)
 164.105 +               kind = GLP_BV;
 164.106 +            break;
 164.107 +         default:
 164.108 +            xassert(kind != kind);
 164.109 +      }
 164.110 +      return kind;
 164.111 +}
 164.112 +
 164.113 +/***********************************************************************
 164.114 +*  NAME
 164.115 +*
 164.116 +*  glp_get_num_int - retrieve number of integer columns
 164.117 +*
 164.118 +*  SYNOPSIS
 164.119 +*
 164.120 +*  int glp_get_num_int(glp_prob *mip);
 164.121 +*
 164.122 +*  RETURNS
 164.123 +*
 164.124 +*  The routine glp_get_num_int returns the current number of columns,
 164.125 +*  which are marked as integer. */
 164.126 +
 164.127 +int glp_get_num_int(glp_prob *mip)
 164.128 +{     GLPCOL *col;
 164.129 +      int j, count = 0;
 164.130 +      for (j = 1; j <= mip->n; j++)
 164.131 +      {  col = mip->col[j];
 164.132 +         if (col->kind == GLP_IV) count++;
 164.133 +      }
 164.134 +      return count;
 164.135 +}
 164.136 +
 164.137 +/***********************************************************************
 164.138 +*  NAME
 164.139 +*
 164.140 +*  glp_get_num_bin - retrieve number of binary columns
 164.141 +*
 164.142 +*  SYNOPSIS
 164.143 +*
 164.144 +*  int glp_get_num_bin(glp_prob *mip);
 164.145 +*
 164.146 +*  RETURNS
 164.147 +*
 164.148 +*  The routine glp_get_num_bin returns the current number of columns,
 164.149 +*  which are marked as binary. */
 164.150 +
 164.151 +int glp_get_num_bin(glp_prob *mip)
 164.152 +{     GLPCOL *col;
 164.153 +      int j, count = 0;
 164.154 +      for (j = 1; j <= mip->n; j++)
 164.155 +      {  col = mip->col[j];
 164.156 +         if (col->kind == GLP_IV && col->type == GLP_DB && col->lb ==
 164.157 +            0.0 && col->ub == 1.0) count++;
 164.158 +      }
 164.159 +      return count;
 164.160 +}
 164.161 +
 164.162 +/***********************************************************************
 164.163 +*  NAME
 164.164 +*
 164.165 +*  glp_intopt - solve MIP problem with the branch-and-bound method
 164.166 +*
 164.167 +*  SYNOPSIS
 164.168 +*
 164.169 +*  int glp_intopt(glp_prob *P, const glp_iocp *parm);
 164.170 +*
 164.171 +*  DESCRIPTION
 164.172 +*
 164.173 +*  The routine glp_intopt is a driver to the MIP solver based on the
 164.174 +*  branch-and-bound method.
 164.175 +*
 164.176 +*  On entry the problem object should contain optimal solution to LP
 164.177 +*  relaxation (which can be obtained with the routine glp_simplex).
 164.178 +*
 164.179 +*  The MIP solver has a set of control parameters. Values of the control
 164.180 +*  parameters can be passed in a structure glp_iocp, which the parameter
 164.181 +*  parm points to.
 164.182 +*
 164.183 +*  The parameter parm can be specified as NULL, in which case the MIP
 164.184 +*  solver uses default settings.
 164.185 +*
 164.186 +*  RETURNS
 164.187 +*
 164.188 +*  0  The MIP problem instance has been successfully solved. This code
 164.189 +*     does not necessarily mean that the solver has found optimal
 164.190 +*     solution. It only means that the solution process was successful.
 164.191 +*
 164.192 +*  GLP_EBOUND
 164.193 +*     Unable to start the search, because some double-bounded variables
 164.194 +*     have incorrect bounds or some integer variables have non-integer
 164.195 +*     (fractional) bounds.
 164.196 +*
 164.197 +*  GLP_EROOT
 164.198 +*     Unable to start the search, because optimal basis for initial LP
 164.199 +*     relaxation is not provided.
 164.200 +*
 164.201 +*  GLP_EFAIL
 164.202 +*     The search was prematurely terminated due to the solver failure.
 164.203 +*
 164.204 +*  GLP_EMIPGAP
 164.205 +*     The search was prematurely terminated, because the relative mip
 164.206 +*     gap tolerance has been reached.
 164.207 +*
 164.208 +*  GLP_ETMLIM
 164.209 +*     The search was prematurely terminated, because the time limit has
 164.210 +*     been exceeded.
 164.211 +*
 164.212 +*  GLP_ENOPFS
 164.213 +*     The MIP problem instance has no primal feasible solution (only if
 164.214 +*     the MIP presolver is used).
 164.215 +*
 164.216 +*  GLP_ENODFS
 164.217 +*     LP relaxation of the MIP problem instance has no dual feasible
 164.218 +*     solution (only if the MIP presolver is used).
 164.219 +*
 164.220 +*  GLP_ESTOP
 164.221 +*     The search was prematurely terminated by application. */
 164.222 +
 164.223 +static int solve_mip(glp_prob *P, const glp_iocp *parm)
 164.224 +{     /* solve MIP directly without using the preprocessor */
 164.225 +      glp_tree *T;
 164.226 +      int ret;
 164.227 +      /* optimal basis to LP relaxation must be provided */
 164.228 +      if (glp_get_status(P) != GLP_OPT)
 164.229 +      {  if (parm->msg_lev >= GLP_MSG_ERR)
 164.230 +            xprintf("glp_intopt: optimal basis to initial LP relaxation"
 164.231 +               " not provided\n");
 164.232 +         ret = GLP_EROOT;
 164.233 +         goto done;
 164.234 +      }
 164.235 +      /* it seems all is ok */
 164.236 +      if (parm->msg_lev >= GLP_MSG_ALL)
 164.237 +         xprintf("Integer optimization begins...\n");
 164.238 +      /* create the branch-and-bound tree */
 164.239 +      T = ios_create_tree(P, parm);
 164.240 +      /* solve the problem instance */
 164.241 +      ret = ios_driver(T);
 164.242 +      /* delete the branch-and-bound tree */
 164.243 +      ios_delete_tree(T);
 164.244 +      /* analyze exit code reported by the mip driver */
 164.245 +      if (ret == 0)
 164.246 +      {  if (P->mip_stat == GLP_FEAS)
 164.247 +         {  if (parm->msg_lev >= GLP_MSG_ALL)
 164.248 +               xprintf("INTEGER OPTIMAL SOLUTION FOUND\n");
 164.249 +            P->mip_stat = GLP_OPT;
 164.250 +         }
 164.251 +         else
 164.252 +         {  if (parm->msg_lev >= GLP_MSG_ALL)
 164.253 +               xprintf("PROBLEM HAS NO INTEGER FEASIBLE SOLUTION\n");
 164.254 +            P->mip_stat = GLP_NOFEAS;
 164.255 +         }
 164.256 +      }
 164.257 +      else if (ret == GLP_EMIPGAP)
 164.258 +      {  if (parm->msg_lev >= GLP_MSG_ALL)
 164.259 +            xprintf("RELATIVE MIP GAP TOLERANCE REACHED; SEARCH TERMINA"
 164.260 +               "TED\n");
 164.261 +      }
 164.262 +      else if (ret == GLP_ETMLIM)
 164.263 +      {  if (parm->msg_lev >= GLP_MSG_ALL)
 164.264 +            xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
 164.265 +      }
 164.266 +      else if (ret == GLP_EFAIL)
 164.267 +      {  if (parm->msg_lev >= GLP_MSG_ERR)
 164.268 +            xprintf("glp_intopt: cannot solve current LP relaxation\n");
 164.269 +      }
 164.270 +      else if (ret == GLP_ESTOP)
 164.271 +      {  if (parm->msg_lev >= GLP_MSG_ALL)
 164.272 +            xprintf("SEARCH TERMINATED BY APPLICATION\n");
 164.273 +      }
 164.274 +      else
 164.275 +         xassert(ret != ret);
 164.276 +done: return ret;
 164.277 +}
 164.278 +
 164.279 +static int preprocess_and_solve_mip(glp_prob *P, const glp_iocp *parm)
 164.280 +{     /* solve MIP using the preprocessor */
 164.281 +      ENV *env = get_env_ptr();
 164.282 +      int term_out = env->term_out;
 164.283 +      NPP *npp;
 164.284 +      glp_prob *mip = NULL;
 164.285 +      glp_bfcp bfcp;
 164.286 +      glp_smcp smcp;
 164.287 +      int ret;
 164.288 +      if (parm->msg_lev >= GLP_MSG_ALL)
 164.289 +         xprintf("Preprocessing...\n");
 164.290 +      /* create preprocessor workspace */
 164.291 +      npp = npp_create_wksp();
 164.292 +      /* load original problem into the preprocessor workspace */
 164.293 +      npp_load_prob(npp, P, GLP_OFF, GLP_MIP, GLP_OFF);
 164.294 +      /* process MIP prior to applying the branch-and-bound method */
 164.295 +      if (!term_out || parm->msg_lev < GLP_MSG_ALL)
 164.296 +         env->term_out = GLP_OFF;
 164.297 +      else
 164.298 +         env->term_out = GLP_ON;
 164.299 +      ret = npp_integer(npp, parm);
 164.300 +      env->term_out = term_out;
 164.301 +      if (ret == 0)
 164.302 +         ;
 164.303 +      else if (ret == GLP_ENOPFS)
 164.304 +      {  if (parm->msg_lev >= GLP_MSG_ALL)
 164.305 +            xprintf("PROBLEM HAS NO PRIMAL FEASIBLE SOLUTION\n");
 164.306 +      }
 164.307 +      else if (ret == GLP_ENODFS)
 164.308 +      {  if (parm->msg_lev >= GLP_MSG_ALL)
 164.309 +            xprintf("LP RELAXATION HAS NO DUAL FEASIBLE SOLUTION\n");
 164.310 +      }
 164.311 +      else
 164.312 +         xassert(ret != ret);
 164.313 +      if (ret != 0) goto done;
 164.314 +      /* build transformed MIP */
 164.315 +      mip = glp_create_prob();
 164.316 +      npp_build_prob(npp, mip);
 164.317 +      /* if the transformed MIP is empty, it has empty solution, which
 164.318 +         is optimal */
 164.319 +      if (mip->m == 0 && mip->n == 0)
 164.320 +      {  mip->mip_stat = GLP_OPT;
 164.321 +         mip->mip_obj = mip->c0;
 164.322 +         if (parm->msg_lev >= GLP_MSG_ALL)
 164.323 +         {  xprintf("Objective value = %17.9e\n", mip->mip_obj);
 164.324 +            xprintf("INTEGER OPTIMAL SOLUTION FOUND BY MIP PREPROCESSOR"
 164.325 +               "\n");
 164.326 +         }
 164.327 +         goto post;
 164.328 +      }
 164.329 +      /* display some statistics */
 164.330 +      if (parm->msg_lev >= GLP_MSG_ALL)
 164.331 +      {  int ni = glp_get_num_int(mip);
 164.332 +         int nb = glp_get_num_bin(mip);
 164.333 +         char s[50];
 164.334 +         xprintf("%d row%s, %d column%s, %d non-zero%s\n",
 164.335 +            mip->m, mip->m == 1 ? "" : "s", mip->n, mip->n == 1 ? "" :
 164.336 +            "s", mip->nnz, mip->nnz == 1 ? "" : "s");
 164.337 +         if (nb == 0)
 164.338 +            strcpy(s, "none of");
 164.339 +         else if (ni == 1 && nb == 1)
 164.340 +            strcpy(s, "");
 164.341 +         else if (nb == 1)
 164.342 +            strcpy(s, "one of");
 164.343 +         else if (nb == ni)
 164.344 +            strcpy(s, "all of");
 164.345 +         else
 164.346 +            sprintf(s, "%d of", nb);
 164.347 +         xprintf("%d integer variable%s, %s which %s binary\n",
 164.348 +            ni, ni == 1 ? "" : "s", s, nb == 1 ? "is" : "are");
 164.349 +      }
 164.350 +      /* inherit basis factorization control parameters */
 164.351 +      glp_get_bfcp(P, &bfcp);
 164.352 +      glp_set_bfcp(mip, &bfcp);
 164.353 +      /* scale the transformed problem */
 164.354 +      if (!term_out || parm->msg_lev < GLP_MSG_ALL)
 164.355 +         env->term_out = GLP_OFF;
 164.356 +      else
 164.357 +         env->term_out = GLP_ON;
 164.358 +      glp_scale_prob(mip,
 164.359 +         GLP_SF_GM | GLP_SF_EQ | GLP_SF_2N | GLP_SF_SKIP);
 164.360 +      env->term_out = term_out;
 164.361 +      /* build advanced initial basis */
 164.362 +      if (!term_out || parm->msg_lev < GLP_MSG_ALL)
 164.363 +         env->term_out = GLP_OFF;
 164.364 +      else
 164.365 +         env->term_out = GLP_ON;
 164.366 +      glp_adv_basis(mip, 0);
 164.367 +      env->term_out = term_out;
 164.368 +      /* solve initial LP relaxation */
 164.369 +      if (parm->msg_lev >= GLP_MSG_ALL)
 164.370 +         xprintf("Solving LP relaxation...\n");
 164.371 +      glp_init_smcp(&smcp);
 164.372 +      smcp.msg_lev = parm->msg_lev;
 164.373 +      mip->it_cnt = P->it_cnt;
 164.374 +      ret = glp_simplex(mip, &smcp);
 164.375 +      P->it_cnt = mip->it_cnt;
 164.376 +      if (ret != 0)
 164.377 +      {  if (parm->msg_lev >= GLP_MSG_ERR)
 164.378 +            xprintf("glp_intopt: cannot solve LP relaxation\n");
 164.379 +         ret = GLP_EFAIL;
 164.380 +         goto done;
 164.381 +      }
 164.382 +      /* check status of the basic solution */
 164.383 +      ret = glp_get_status(mip);
 164.384 +      if (ret == GLP_OPT)
 164.385 +         ret = 0;
 164.386 +      else if (ret == GLP_NOFEAS)
 164.387 +         ret = GLP_ENOPFS;
 164.388 +      else if (ret == GLP_UNBND)
 164.389 +         ret = GLP_ENODFS;
 164.390 +      else
 164.391 +         xassert(ret != ret);
 164.392 +      if (ret != 0) goto done;
 164.393 +      /* solve the transformed MIP */
 164.394 +      mip->it_cnt = P->it_cnt;
 164.395 +      ret = solve_mip(mip, parm);
 164.396 +      P->it_cnt = mip->it_cnt;
 164.397 +      /* only integer feasible solution can be postprocessed */
 164.398 +      if (!(mip->mip_stat == GLP_OPT || mip->mip_stat == GLP_FEAS))
 164.399 +      {  P->mip_stat = mip->mip_stat;
 164.400 +         goto done;
 164.401 +      }
 164.402 +      /* postprocess solution from the transformed MIP */
 164.403 +post: npp_postprocess(npp, mip);
 164.404 +      /* the transformed MIP is no longer needed */
 164.405 +      glp_delete_prob(mip), mip = NULL;
 164.406 +      /* store solution to the original problem */
 164.407 +      npp_unload_sol(npp, P);
 164.408 +done: /* delete the transformed MIP, if it exists */
 164.409 +      if (mip != NULL) glp_delete_prob(mip);
 164.410 +      /* delete preprocessor workspace */
 164.411 +      npp_delete_wksp(npp);
 164.412 +      return ret;
 164.413 +}
 164.414 +
 164.415 +#ifndef HAVE_ALIEN_SOLVER /* 28/V-2010 */
 164.416 +int _glp_intopt1(glp_prob *P, const glp_iocp *parm)
 164.417 +{     xassert(P == P);
 164.418 +      xassert(parm == parm);
 164.419 +      xprintf("glp_intopt: no alien solver is available\n");
 164.420 +      return GLP_EFAIL;
 164.421 +}
 164.422 +#endif
 164.423 +
 164.424 +int glp_intopt(glp_prob *P, const glp_iocp *parm)
 164.425 +{     /* solve MIP problem with the branch-and-bound method */
 164.426 +      glp_iocp _parm;
 164.427 +      int i, j, ret;
 164.428 +      /* check problem object */
 164.429 +      if (P == NULL || P->magic != GLP_PROB_MAGIC)
 164.430 +         xerror("glp_intopt: P = %p; invalid problem object\n", P);
 164.431 +      if (P->tree != NULL)
 164.432 +         xerror("glp_intopt: operation not allowed\n");
 164.433 +      /* check control parameters */
 164.434 +      if (parm == NULL)
 164.435 +         parm = &_parm, glp_init_iocp((glp_iocp *)parm);
 164.436 +      if (!(parm->msg_lev == GLP_MSG_OFF ||
 164.437 +            parm->msg_lev == GLP_MSG_ERR ||
 164.438 +            parm->msg_lev == GLP_MSG_ON  ||
 164.439 +            parm->msg_lev == GLP_MSG_ALL ||
 164.440 +            parm->msg_lev == GLP_MSG_DBG))
 164.441 +         xerror("glp_intopt: msg_lev = %d; invalid parameter\n",
 164.442 +            parm->msg_lev);
 164.443 +      if (!(parm->br_tech == GLP_BR_FFV ||
 164.444 +            parm->br_tech == GLP_BR_LFV ||
 164.445 +            parm->br_tech == GLP_BR_MFV ||
 164.446 +            parm->br_tech == GLP_BR_DTH ||
 164.447 +            parm->br_tech == GLP_BR_PCH))
 164.448 +         xerror("glp_intopt: br_tech = %d; invalid parameter\n",
 164.449 +            parm->br_tech);
 164.450 +      if (!(parm->bt_tech == GLP_BT_DFS ||
 164.451 +            parm->bt_tech == GLP_BT_BFS ||
 164.452 +            parm->bt_tech == GLP_BT_BLB ||
 164.453 +            parm->bt_tech == GLP_BT_BPH))
 164.454 +         xerror("glp_intopt: bt_tech = %d; invalid parameter\n",
 164.455 +            parm->bt_tech);
 164.456 +      if (!(0.0 < parm->tol_int && parm->tol_int < 1.0))
 164.457 +         xerror("glp_intopt: tol_int = %g; invalid parameter\n",
 164.458 +            parm->tol_int);
 164.459 +      if (!(0.0 < parm->tol_obj && parm->tol_obj < 1.0))
 164.460 +         xerror("glp_intopt: tol_obj = %g; invalid parameter\n",
 164.461 +            parm->tol_obj);
 164.462 +      if (parm->tm_lim < 0)
 164.463 +         xerror("glp_intopt: tm_lim = %d; invalid parameter\n",
 164.464 +            parm->tm_lim);
 164.465 +      if (parm->out_frq < 0)
 164.466 +         xerror("glp_intopt: out_frq = %d; invalid parameter\n",
 164.467 +            parm->out_frq);
 164.468 +      if (parm->out_dly < 0)
 164.469 +         xerror("glp_intopt: out_dly = %d; invalid parameter\n",
 164.470 +            parm->out_dly);
 164.471 +      if (!(0 <= parm->cb_size && parm->cb_size <= 256))
 164.472 +         xerror("glp_intopt: cb_size = %d; invalid parameter\n",
 164.473 +            parm->cb_size);
 164.474 +      if (!(parm->pp_tech == GLP_PP_NONE ||
 164.475 +            parm->pp_tech == GLP_PP_ROOT ||
 164.476 +            parm->pp_tech == GLP_PP_ALL))
 164.477 +         xerror("glp_intopt: pp_tech = %d; invalid parameter\n",
 164.478 +            parm->pp_tech);
 164.479 +      if (parm->mip_gap < 0.0)
 164.480 +         xerror("glp_intopt: mip_gap = %g; invalid parameter\n",
 164.481 +            parm->mip_gap);
 164.482 +      if (!(parm->mir_cuts == GLP_ON || parm->mir_cuts == GLP_OFF))
 164.483 +         xerror("glp_intopt: mir_cuts = %d; invalid parameter\n",
 164.484 +            parm->mir_cuts);
 164.485 +      if (!(parm->gmi_cuts == GLP_ON || parm->gmi_cuts == GLP_OFF))
 164.486 +         xerror("glp_intopt: gmi_cuts = %d; invalid parameter\n",
 164.487 +            parm->gmi_cuts);
 164.488 +      if (!(parm->cov_cuts == GLP_ON || parm->cov_cuts == GLP_OFF))
 164.489 +         xerror("glp_intopt: cov_cuts = %d; invalid parameter\n",
 164.490 +            parm->cov_cuts);
 164.491 +      if (!(parm->clq_cuts == GLP_ON || parm->clq_cuts == GLP_OFF))
 164.492 +         xerror("glp_intopt: clq_cuts = %d; invalid parameter\n",
 164.493 +            parm->clq_cuts);
 164.494 +      if (!(parm->presolve == GLP_ON || parm->presolve == GLP_OFF))
 164.495 +         xerror("glp_intopt: presolve = %d; invalid parameter\n",
 164.496 +            parm->presolve);
 164.497 +      if (!(parm->binarize == GLP_ON || parm->binarize == GLP_OFF))
 164.498 +         xerror("glp_intopt: binarize = %d; invalid parameter\n",
 164.499 +            parm->binarize);
 164.500 +      if (!(parm->fp_heur == GLP_ON || parm->fp_heur == GLP_OFF))
 164.501 +         xerror("glp_intopt: fp_heur = %d; invalid parameter\n",
 164.502 +            parm->fp_heur);
 164.503 +#if 1 /* 28/V-2010 */
 164.504 +      if (!(parm->alien == GLP_ON || parm->alien == GLP_OFF))
 164.505 +         xerror("glp_intopt: alien = %d; invalid parameter\n",
 164.506 +            parm->alien);
 164.507 +#endif
 164.508 +      /* integer solution is currently undefined */
 164.509 +      P->mip_stat = GLP_UNDEF;
 164.510 +      P->mip_obj = 0.0;
 164.511 +      /* check bounds of double-bounded variables */
 164.512 +      for (i = 1; i <= P->m; i++)
 164.513 +      {  GLPROW *row = P->row[i];
 164.514 +         if (row->type == GLP_DB && row->lb >= row->ub)
 164.515 +         {  if (parm->msg_lev >= GLP_MSG_ERR)
 164.516 +               xprintf("glp_intopt: row %d: lb = %g, ub = %g; incorrect"
 164.517 +                  " bounds\n", i, row->lb, row->ub);
 164.518 +            ret = GLP_EBOUND;
 164.519 +            goto done;
 164.520 +         }
 164.521 +      }
 164.522 +      for (j = 1; j <= P->n; j++)
 164.523 +      {  GLPCOL *col = P->col[j];
 164.524 +         if (col->type == GLP_DB && col->lb >= col->ub)
 164.525 +         {  if (parm->msg_lev >= GLP_MSG_ERR)
 164.526 +               xprintf("glp_intopt: column %d: lb = %g, ub = %g; incorr"
 164.527 +                  "ect bounds\n", j, col->lb, col->ub);
 164.528 +            ret = GLP_EBOUND;
 164.529 +            goto done;
 164.530 +         }
 164.531 +      }
 164.532 +      /* bounds of all integer variables must be integral */
 164.533 +      for (j = 1; j <= P->n; j++)
 164.534 +      {  GLPCOL *col = P->col[j];
 164.535 +         if (col->kind != GLP_IV) continue;
 164.536 +         if (col->type == GLP_LO || col->type == GLP_DB)
 164.537 +         {  if (col->lb != floor(col->lb))
 164.538 +            {  if (parm->msg_lev >= GLP_MSG_ERR)
 164.539 +                  xprintf("glp_intopt: integer column %d has non-intege"
 164.540 +                     "r lower bound %g\n", j, col->lb);
 164.541 +               ret = GLP_EBOUND;
 164.542 +               goto done;
 164.543 +            }
 164.544 +         }
 164.545 +         if (col->type == GLP_UP || col->type == GLP_DB)
 164.546 +         {  if (col->ub != floor(col->ub))
 164.547 +            {  if (parm->msg_lev >= GLP_MSG_ERR)
 164.548 +                  xprintf("glp_intopt: integer column %d has non-intege"
 164.549 +                     "r upper bound %g\n", j, col->ub);
 164.550 +               ret = GLP_EBOUND;
 164.551 +               goto done;
 164.552 +            }
 164.553 +         }
 164.554 +         if (col->type == GLP_FX)
 164.555 +         {  if (col->lb != floor(col->lb))
 164.556 +            {  if (parm->msg_lev >= GLP_MSG_ERR)
 164.557 +                  xprintf("glp_intopt: integer column %d has non-intege"
 164.558 +                     "r fixed value %g\n", j, col->lb);
 164.559 +               ret = GLP_EBOUND;
 164.560 +               goto done;
 164.561 +            }
 164.562 +         }
 164.563 +      }
 164.564 +      /* solve MIP problem */
 164.565 +      if (parm->msg_lev >= GLP_MSG_ALL)
 164.566 +      {  int ni = glp_get_num_int(P);
 164.567 +         int nb = glp_get_num_bin(P);
 164.568 +         char s[50];
 164.569 +         xprintf("GLPK Integer Optimizer, v%s\n", glp_version());
 164.570 +         xprintf("%d row%s, %d column%s, %d non-zero%s\n",
 164.571 +            P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s",
 164.572 +            P->nnz, P->nnz == 1 ? "" : "s");
 164.573 +         if (nb == 0)
 164.574 +            strcpy(s, "none of");
 164.575 +         else if (ni == 1 && nb == 1)
 164.576 +            strcpy(s, "");
 164.577 +         else if (nb == 1)
 164.578 +            strcpy(s, "one of");
 164.579 +         else if (nb == ni)
 164.580 +            strcpy(s, "all of");
 164.581 +         else
 164.582 +            sprintf(s, "%d of", nb);
 164.583 +         xprintf("%d integer variable%s, %s which %s binary\n",
 164.584 +            ni, ni == 1 ? "" : "s", s, nb == 1 ? "is" : "are");
 164.585 +      }
 164.586 +#if 1 /* 28/V-2010 */
 164.587 +      if (parm->alien)
 164.588 +      {  /* use alien integer optimizer */
 164.589 +         ret = _glp_intopt1(P, parm);
 164.590 +         goto done;
 164.591 +      }
 164.592 +#endif
 164.593 +      if (!parm->presolve)
 164.594 +         ret = solve_mip(P, parm);
 164.595 +      else
 164.596 +         ret = preprocess_and_solve_mip(P, parm);
 164.597 +done: /* return to the application program */
 164.598 +      return ret;
 164.599 +}
 164.600 +
 164.601 +/***********************************************************************
 164.602 +*  NAME
 164.603 +*
 164.604 +*  glp_init_iocp - initialize integer optimizer control parameters
 164.605 +*
 164.606 +*  SYNOPSIS
 164.607 +*
 164.608 +*  void glp_init_iocp(glp_iocp *parm);
 164.609 +*
 164.610 +*  DESCRIPTION
 164.611 +*
 164.612 +*  The routine glp_init_iocp initializes control parameters, which are
 164.613 +*  used by the integer optimizer, with default values.
 164.614 +*
 164.615 +*  Default values of the control parameters are stored in a glp_iocp
 164.616 +*  structure, which the parameter parm points to. */
 164.617 +
 164.618 +void glp_init_iocp(glp_iocp *parm)
 164.619 +{     parm->msg_lev = GLP_MSG_ALL;
 164.620 +      parm->br_tech = GLP_BR_DTH;
 164.621 +      parm->bt_tech = GLP_BT_BLB;
 164.622 +      parm->tol_int = 1e-5;
 164.623 +      parm->tol_obj = 1e-7;
 164.624 +      parm->tm_lim = INT_MAX;
 164.625 +      parm->out_frq = 5000;
 164.626 +      parm->out_dly = 10000;
 164.627 +      parm->cb_func = NULL;
 164.628 +      parm->cb_info = NULL;
 164.629 +      parm->cb_size = 0;
 164.630 +      parm->pp_tech = GLP_PP_ALL;
 164.631 +      parm->mip_gap = 0.0;
 164.632 +      parm->mir_cuts = GLP_OFF;
 164.633 +      parm->gmi_cuts = GLP_OFF;
 164.634 +      parm->cov_cuts = GLP_OFF;
 164.635 +      parm->clq_cuts = GLP_OFF;
 164.636 +      parm->presolve = GLP_OFF;
 164.637 +      parm->binarize = GLP_OFF;
 164.638 +      parm->fp_heur = GLP_OFF;
 164.639 +#if 1 /* 28/V-2010 */
 164.640 +      parm->alien = GLP_OFF;
 164.641 +#endif
 164.642 +      return;
 164.643 +}
 164.644 +
 164.645 +/***********************************************************************
 164.646 +*  NAME
 164.647 +*
 164.648 +*  glp_mip_status - retrieve status of MIP solution
 164.649 +*
 164.650 +*  SYNOPSIS
 164.651 +*
 164.652 +*  int glp_mip_status(glp_prob *mip);
 164.653 +*
 164.654 +*  RETURNS
 164.655 +*
 164.656 +*  The routine lpx_mip_status reports the status of MIP solution found
 164.657 +*  by the branch-and-bound solver as follows:
 164.658 +*
 164.659 +*  GLP_UNDEF  - MIP solution is undefined;
 164.660 +*  GLP_OPT    - MIP solution is integer optimal;
 164.661 +*  GLP_FEAS   - MIP solution is integer feasible but its optimality
 164.662 +*               (or non-optimality) has not been proven, perhaps due to
 164.663 +*               premature termination of the search;
 164.664 +*  GLP_NOFEAS - problem has no integer feasible solution (proven by the
 164.665 +*               solver). */
 164.666 +
 164.667 +int glp_mip_status(glp_prob *mip)
 164.668 +{     int mip_stat = mip->mip_stat;
 164.669 +      return mip_stat;
 164.670 +}
 164.671 +
 164.672 +/***********************************************************************
 164.673 +*  NAME
 164.674 +*
 164.675 +*  glp_mip_obj_val - retrieve objective value (MIP solution)
 164.676 +*
 164.677 +*  SYNOPSIS
 164.678 +*
 164.679 +*  double glp_mip_obj_val(glp_prob *mip);
 164.680 +*
 164.681 +*  RETURNS
 164.682 +*
 164.683 +*  The routine glp_mip_obj_val returns value of the objective function
 164.684 +*  for MIP solution. */
 164.685 +
 164.686 +double glp_mip_obj_val(glp_prob *mip)
 164.687 +{     /*struct LPXCPS *cps = mip->cps;*/
 164.688 +      double z;
 164.689 +      z = mip->mip_obj;
 164.690 +      /*if (cps->round && fabs(z) < 1e-9) z = 0.0;*/
 164.691 +      return z;
 164.692 +}
 164.693 +
 164.694 +/***********************************************************************
 164.695 +*  NAME
 164.696 +*
 164.697 +*  glp_mip_row_val - retrieve row value (MIP solution)
 164.698 +*
 164.699 +*  SYNOPSIS
 164.700 +*
 164.701 +*  double glp_mip_row_val(glp_prob *mip, int i);
 164.702 +*
 164.703 +*  RETURNS
 164.704 +*
 164.705 +*  The routine glp_mip_row_val returns value of the auxiliary variable
 164.706 +*  associated with i-th row. */
 164.707 +
 164.708 +double glp_mip_row_val(glp_prob *mip, int i)
 164.709 +{     /*struct LPXCPS *cps = mip->cps;*/
 164.710 +      double mipx;
 164.711 +      if (!(1 <= i && i <= mip->m))
 164.712 +         xerror("glp_mip_row_val: i = %d; row number out of range\n", i)
 164.713 +            ;
 164.714 +      mipx = mip->row[i]->mipx;
 164.715 +      /*if (cps->round && fabs(mipx) < 1e-9) mipx = 0.0;*/
 164.716 +      return mipx;
 164.717 +}
 164.718 +
 164.719 +/***********************************************************************
 164.720 +*  NAME
 164.721 +*
 164.722 +*  glp_mip_col_val - retrieve column value (MIP solution)
 164.723 +*
 164.724 +*  SYNOPSIS
 164.725 +*
 164.726 +*  double glp_mip_col_val(glp_prob *mip, int j);
 164.727 +*
 164.728 +*  RETURNS
 164.729 +*
 164.730 +*  The routine glp_mip_col_val returns value of the structural variable
 164.731 +*  associated with j-th column. */
 164.732 +
 164.733 +double glp_mip_col_val(glp_prob *mip, int j)
 164.734 +{     /*struct LPXCPS *cps = mip->cps;*/
 164.735 +      double mipx;
 164.736 +      if (!(1 <= j && j <= mip->n))
 164.737 +         xerror("glp_mip_col_val: j = %d; column number out of range\n",
 164.738 +            j);
 164.739 +      mipx = mip->col[j]->mipx;
 164.740 +      /*if (cps->round && fabs(mipx) < 1e-9) mipx = 0.0;*/
 164.741 +      return mipx;
 164.742 +}
 164.743 +
 164.744 +/* eof */
   165.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   165.2 +++ b/src/glpapi10.c	Mon Dec 06 13:09:21 2010 +0100
   165.3 @@ -0,0 +1,282 @@
   165.4 +/* glpapi10.c (solution checking routines) */
   165.5 +
   165.6 +/***********************************************************************
   165.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   165.8 +*
   165.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  165.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  165.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  165.12 +*  E-mail: <mao@gnu.org>.
  165.13 +*
  165.14 +*  GLPK is free software: you can redistribute it and/or modify it
  165.15 +*  under the terms of the GNU General Public License as published by
  165.16 +*  the Free Software Foundation, either version 3 of the License, or
  165.17 +*  (at your option) any later version.
  165.18 +*
  165.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  165.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  165.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  165.22 +*  License for more details.
  165.23 +*
  165.24 +*  You should have received a copy of the GNU General Public License
  165.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  165.26 +***********************************************************************/
  165.27 +
  165.28 +#include "glpapi.h"
  165.29 +
  165.30 +void _glp_check_kkt(glp_prob *P, int sol, int cond, double *_ae_max,
  165.31 +      int *_ae_ind, double *_re_max, int *_re_ind)
  165.32 +{     /* check feasibility and optimality conditions */
  165.33 +      int m = P->m;
  165.34 +      int n = P->n;
  165.35 +      GLPROW *row;
  165.36 +      GLPCOL *col;
  165.37 +      GLPAIJ *aij;
  165.38 +      int i, j, ae_ind, re_ind;
  165.39 +      double e, sp, sn, t, ae_max, re_max;
  165.40 +      if (!(sol == GLP_SOL || sol == GLP_IPT || sol == GLP_MIP))
  165.41 +         xerror("glp_check_kkt: sol = %d; invalid solution indicator\n",
  165.42 +            sol);
  165.43 +      if (!(cond == GLP_KKT_PE || cond == GLP_KKT_PB ||
  165.44 +            cond == GLP_KKT_DE || cond == GLP_KKT_DB ||
  165.45 +            cond == GLP_KKT_CS))
  165.46 +         xerror("glp_check_kkt: cond = %d; invalid condition indicator "
  165.47 +            "\n", cond);
  165.48 +      ae_max = re_max = 0.0;
  165.49 +      ae_ind = re_ind = 0;
  165.50 +      if (cond == GLP_KKT_PE)
  165.51 +      {  /* xR - A * xS = 0 */
  165.52 +         for (i = 1; i <= m; i++)
  165.53 +         {  row = P->row[i];
  165.54 +            sp = sn = 0.0;
  165.55 +            /* t := xR[i] */
  165.56 +            if (sol == GLP_SOL)
  165.57 +               t = row->prim;
  165.58 +            else if (sol == GLP_IPT)
  165.59 +               t = row->pval;
  165.60 +            else if (sol == GLP_MIP)
  165.61 +               t = row->mipx;
  165.62 +            else
  165.63 +               xassert(sol != sol);
  165.64 +            if (t >= 0.0) sp += t; else sn -= t;
  165.65 +            for (aij = row->ptr; aij != NULL; aij = aij->r_next)
  165.66 +            {  col = aij->col;
  165.67 +               /* t := - a[i,j] * xS[j] */
  165.68 +               if (sol == GLP_SOL)
  165.69 +                  t = - aij->val * col->prim;
  165.70 +               else if (sol == GLP_IPT)
  165.71 +                  t = - aij->val * col->pval;
  165.72 +               else if (sol == GLP_MIP)
  165.73 +                  t = - aij->val * col->mipx;
  165.74 +               else
  165.75 +                  xassert(sol != sol);
  165.76 +               if (t >= 0.0) sp += t; else sn -= t;
  165.77 +            }
  165.78 +            /* absolute error */
  165.79 +            e = fabs(sp - sn);
  165.80 +            if (ae_max < e)
  165.81 +               ae_max = e, ae_ind = i;
  165.82 +            /* relative error */
  165.83 +            e /= (1.0 + sp + sn);
  165.84 +            if (re_max < e)
  165.85 +               re_max = e, re_ind = i;
  165.86 +         }
  165.87 +      }
  165.88 +      else if (cond == GLP_KKT_PB)
  165.89 +      {  /* lR <= xR <= uR */
  165.90 +         for (i = 1; i <= m; i++)
  165.91 +         {  row = P->row[i];
  165.92 +            /* t := xR[i] */
  165.93 +            if (sol == GLP_SOL)
  165.94 +               t = row->prim;
  165.95 +            else if (sol == GLP_IPT)
  165.96 +               t = row->pval;
  165.97 +            else if (sol == GLP_MIP)
  165.98 +               t = row->mipx;
  165.99 +            else
 165.100 +               xassert(sol != sol);
 165.101 +            /* check lower bound */
 165.102 +            if (row->type == GLP_LO || row->type == GLP_DB ||
 165.103 +                row->type == GLP_FX)
 165.104 +            {  if (t < row->lb)
 165.105 +               {  /* absolute error */
 165.106 +                  e = row->lb - t;
 165.107 +                  if (ae_max < e)
 165.108 +                     ae_max = e, ae_ind = i;
 165.109 +                  /* relative error */
 165.110 +                  e /= (1.0 + fabs(row->lb));
 165.111 +                  if (re_max < e)
 165.112 +                     re_max = e, re_ind = i;
 165.113 +               }
 165.114 +            }
 165.115 +            /* check upper bound */
 165.116 +            if (row->type == GLP_UP || row->type == GLP_DB ||
 165.117 +                row->type == GLP_FX)
 165.118 +            {  if (t > row->ub)
 165.119 +               {  /* absolute error */
 165.120 +                  e = t - row->ub;
 165.121 +                  if (ae_max < e)
 165.122 +                     ae_max = e, ae_ind = i;
 165.123 +                  /* relative error */
 165.124 +                  e /= (1.0 + fabs(row->ub));
 165.125 +                  if (re_max < e)
 165.126 +                     re_max = e, re_ind = i;
 165.127 +               }
 165.128 +            }
 165.129 +         }
 165.130 +         /* lS <= xS <= uS */
 165.131 +         for (j = 1; j <= n; j++)
 165.132 +         {  col = P->col[j];
 165.133 +            /* t := xS[j] */
 165.134 +            if (sol == GLP_SOL)
 165.135 +               t = col->prim;
 165.136 +            else if (sol == GLP_IPT)
 165.137 +               t = col->pval;
 165.138 +            else if (sol == GLP_MIP)
 165.139 +               t = col->mipx;
 165.140 +            else
 165.141 +               xassert(sol != sol);
 165.142 +            /* check lower bound */
 165.143 +            if (col->type == GLP_LO || col->type == GLP_DB ||
 165.144 +                col->type == GLP_FX)
 165.145 +            {  if (t < col->lb)
 165.146 +               {  /* absolute error */
 165.147 +                  e = col->lb - t;
 165.148 +                  if (ae_max < e)
 165.149 +                     ae_max = e, ae_ind = m+j;
 165.150 +                  /* relative error */
 165.151 +                  e /= (1.0 + fabs(col->lb));
 165.152 +                  if (re_max < e)
 165.153 +                     re_max = e, re_ind = m+j;
 165.154 +               }
 165.155 +            }
 165.156 +            /* check upper bound */
 165.157 +            if (col->type == GLP_UP || col->type == GLP_DB ||
 165.158 +                col->type == GLP_FX)
 165.159 +            {  if (t > col->ub)
 165.160 +               {  /* absolute error */
 165.161 +                  e = t - col->ub;
 165.162 +                  if (ae_max < e)
 165.163 +                     ae_max = e, ae_ind = m+j;
 165.164 +                  /* relative error */
 165.165 +                  e /= (1.0 + fabs(col->ub));
 165.166 +                  if (re_max < e)
 165.167 +                     re_max = e, re_ind = m+j;
 165.168 +               }
 165.169 +            }
 165.170 +         }
 165.171 +      }
 165.172 +      else if (cond == GLP_KKT_DE)
 165.173 +      {  /* A' * (lambdaR - cR) + (lambdaS - cS) = 0 */
 165.174 +         for (j = 1; j <= n; j++)
 165.175 +         {  col = P->col[j];
 165.176 +            sp = sn = 0.0;
 165.177 +            /* t := lambdaS[j] - cS[j] */
 165.178 +            if (sol == GLP_SOL)
 165.179 +               t = col->dual - col->coef;
 165.180 +            else if (sol == GLP_IPT)
 165.181 +               t = col->dval - col->coef;
 165.182 +            else
 165.183 +               xassert(sol != sol);
 165.184 +            if (t >= 0.0) sp += t; else sn -= t;
 165.185 +            for (aij = col->ptr; aij != NULL; aij = aij->c_next)
 165.186 +            {  row = aij->row;
 165.187 +               /* t := a[i,j] * (lambdaR[i] - cR[i]) */
 165.188 +               if (sol == GLP_SOL)
 165.189 +                  t = aij->val * row->dual;
 165.190 +               else if (sol == GLP_IPT)
 165.191 +                  t = aij->val * row->dval;
 165.192 +               else
 165.193 +                  xassert(sol != sol);
 165.194 +               if (t >= 0.0) sp += t; else sn -= t;
 165.195 +            }
 165.196 +            /* absolute error */
 165.197 +            e = fabs(sp - sn);
 165.198 +            if (ae_max < e)
 165.199 +               ae_max = e, ae_ind = m+j;
 165.200 +            /* relative error */
 165.201 +            e /= (1.0 + sp + sn);
 165.202 +            if (re_max < e)
 165.203 +               re_max = e, re_ind = m+j;
 165.204 +         }
 165.205 +      }
 165.206 +      else if (cond == GLP_KKT_DB)
 165.207 +      {  /* check lambdaR */
 165.208 +         for (i = 1; i <= m; i++)
 165.209 +         {  row = P->row[i];
 165.210 +            /* t := lambdaR[i] */
 165.211 +            if (sol == GLP_SOL)
 165.212 +               t = row->dual;
 165.213 +            else if (sol == GLP_IPT)
 165.214 +               t = row->dval;
 165.215 +            else
 165.216 +               xassert(sol != sol);
 165.217 +            /* correct sign */
 165.218 +            if (P->dir == GLP_MIN)
 165.219 +               t = + t;
 165.220 +            else if (P->dir == GLP_MAX)
 165.221 +               t = - t;
 165.222 +            else
 165.223 +               xassert(P != P);
 165.224 +            /* check for positivity */
 165.225 +            if (row->type == GLP_FR || row->type == GLP_LO)
 165.226 +            {  if (t < 0.0)
 165.227 +               {  e = - t;
 165.228 +                  if (ae_max < e)
 165.229 +                     ae_max = re_max = e, ae_ind = re_ind = i;
 165.230 +               }
 165.231 +            }
 165.232 +            /* check for negativity */
 165.233 +            if (row->type == GLP_FR || row->type == GLP_UP)
 165.234 +            {  if (t > 0.0)
 165.235 +               {  e = + t;
 165.236 +                  if (ae_max < e)
 165.237 +                     ae_max = re_max = e, ae_ind = re_ind = i;
 165.238 +               }
 165.239 +            }
 165.240 +         }
 165.241 +         /* check lambdaS */
 165.242 +         for (j = 1; j <= n; j++)
 165.243 +         {  col = P->col[j];
 165.244 +            /* t := lambdaS[j] */
 165.245 +            if (sol == GLP_SOL)
 165.246 +               t = col->dual;
 165.247 +            else if (sol == GLP_IPT)
 165.248 +               t = col->dval;
 165.249 +            else
 165.250 +               xassert(sol != sol);
 165.251 +            /* correct sign */
 165.252 +            if (P->dir == GLP_MIN)
 165.253 +               t = + t;
 165.254 +            else if (P->dir == GLP_MAX)
 165.255 +               t = - t;
 165.256 +            else
 165.257 +               xassert(P != P);
 165.258 +            /* check for positivity */
 165.259 +            if (col->type == GLP_FR || col->type == GLP_LO)
 165.260 +            {  if (t < 0.0)
 165.261 +               {  e = - t;
 165.262 +                  if (ae_max < e)
 165.263 +                     ae_max = re_max = e, ae_ind = re_ind = m+j;
 165.264 +               }
 165.265 +            }
 165.266 +            /* check for negativity */
 165.267 +            if (col->type == GLP_FR || col->type == GLP_UP)
 165.268 +            {  if (t > 0.0)
 165.269 +               {  e = + t;
 165.270 +                  if (ae_max < e)
 165.271 +                     ae_max = re_max = e, ae_ind = re_ind = m+j;
 165.272 +               }
 165.273 +            }
 165.274 +         }
 165.275 +      }
 165.276 +      else
 165.277 +         xassert(cond != cond);
 165.278 +      if (_ae_max != NULL) *_ae_max = ae_max;
 165.279 +      if (_ae_ind != NULL) *_ae_ind = ae_ind;
 165.280 +      if (_re_max != NULL) *_re_max = re_max;
 165.281 +      if (_re_ind != NULL) *_re_ind = re_ind;
 165.282 +      return;
 165.283 +}
 165.284 +
 165.285 +/* eof */
   166.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   166.2 +++ b/src/glpapi11.c	Mon Dec 06 13:09:21 2010 +0100
   166.3 @@ -0,0 +1,1217 @@
   166.4 +/* glpapi11.c (utility routines) */
   166.5 +
   166.6 +/***********************************************************************
   166.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   166.8 +*
   166.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  166.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  166.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  166.12 +*  E-mail: <mao@gnu.org>.
  166.13 +*
  166.14 +*  GLPK is free software: you can redistribute it and/or modify it
  166.15 +*  under the terms of the GNU General Public License as published by
  166.16 +*  the Free Software Foundation, either version 3 of the License, or
  166.17 +*  (at your option) any later version.
  166.18 +*
  166.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  166.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  166.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  166.22 +*  License for more details.
  166.23 +*
  166.24 +*  You should have received a copy of the GNU General Public License
  166.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  166.26 +***********************************************************************/
  166.27 +
  166.28 +#include "glpapi.h"
  166.29 +
  166.30 +int glp_print_sol(glp_prob *P, const char *fname)
  166.31 +{     /* write basic solution in printable format */
  166.32 +      XFILE *fp;
  166.33 +      GLPROW *row;
  166.34 +      GLPCOL *col;
  166.35 +      int i, j, t, ae_ind, re_ind, ret;
  166.36 +      double ae_max, re_max;
  166.37 +      xprintf("Writing basic solution to `%s'...\n", fname);
  166.38 +      fp = xfopen(fname, "w");
  166.39 +      if (fp == NULL)
  166.40 +      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
  166.41 +         ret = 1;
  166.42 +         goto done;
  166.43 +      }
  166.44 +      xfprintf(fp, "%-12s%s\n", "Problem:",
  166.45 +         P->name == NULL ? "" : P->name);
  166.46 +      xfprintf(fp, "%-12s%d\n", "Rows:", P->m);
  166.47 +      xfprintf(fp, "%-12s%d\n", "Columns:", P->n);
  166.48 +      xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz);
  166.49 +      t = glp_get_status(P);
  166.50 +      xfprintf(fp, "%-12s%s\n", "Status:",
  166.51 +         t == GLP_OPT    ? "OPTIMAL" :
  166.52 +         t == GLP_FEAS   ? "FEASIBLE" :
  166.53 +         t == GLP_INFEAS ? "INFEASIBLE (INTERMEDIATE)" :
  166.54 +         t == GLP_NOFEAS ? "INFEASIBLE (FINAL)" :
  166.55 +         t == GLP_UNBND  ? "UNBOUNDED" :
  166.56 +         t == GLP_UNDEF  ? "UNDEFINED" : "???");
  166.57 +      xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
  166.58 +         P->obj == NULL ? "" : P->obj,
  166.59 +         P->obj == NULL ? "" : " = ", P->obj_val,
  166.60 +         P->dir == GLP_MIN ? "MINimum" :
  166.61 +         P->dir == GLP_MAX ? "MAXimum" : "???");
  166.62 +      xfprintf(fp, "\n");
  166.63 +      xfprintf(fp, "   No.   Row name   St   Activity     Lower bound  "
  166.64 +         " Upper bound    Marginal\n");
  166.65 +      xfprintf(fp, "------ ------------ -- ------------- ------------- "
  166.66 +         "------------- -------------\n");
  166.67 +      for (i = 1; i <= P->m; i++)
  166.68 +      {  row = P->row[i];
  166.69 +         xfprintf(fp, "%6d ", i);
  166.70 +         if (row->name == NULL || strlen(row->name) <= 12)
  166.71 +            xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name);
  166.72 +         else
  166.73 +            xfprintf(fp, "%s\n%20s", row->name, "");
  166.74 +         xfprintf(fp, "%s ",
  166.75 +            row->stat == GLP_BS ? "B " :
  166.76 +            row->stat == GLP_NL ? "NL" :
  166.77 +            row->stat == GLP_NU ? "NU" :
  166.78 +            row->stat == GLP_NF ? "NF" :
  166.79 +            row->stat == GLP_NS ? "NS" : "??");
  166.80 +         xfprintf(fp, "%13.6g ",
  166.81 +            fabs(row->prim) <= 1e-9 ? 0.0 : row->prim);
  166.82 +         if (row->type == GLP_LO || row->type == GLP_DB ||
  166.83 +             row->type == GLP_FX)
  166.84 +            xfprintf(fp, "%13.6g ", row->lb);
  166.85 +         else
  166.86 +            xfprintf(fp, "%13s ", "");
  166.87 +         if (row->type == GLP_UP || row->type == GLP_DB)
  166.88 +            xfprintf(fp, "%13.6g ", row->ub);
  166.89 +         else
  166.90 +            xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : "");
  166.91 +         if (row->stat != GLP_BS)
  166.92 +         {  if (fabs(row->dual) <= 1e-9)
  166.93 +               xfprintf(fp, "%13s", "< eps");
  166.94 +            else
  166.95 +               xfprintf(fp, "%13.6g ", row->dual);
  166.96 +         }
  166.97 +         xfprintf(fp, "\n");
  166.98 +      }
  166.99 +      xfprintf(fp, "\n");
 166.100 +      xfprintf(fp, "   No. Column name  St   Activity     Lower bound  "
 166.101 +         " Upper bound    Marginal\n");
 166.102 +      xfprintf(fp, "------ ------------ -- ------------- ------------- "
 166.103 +         "------------- -------------\n");
 166.104 +      for (j = 1; j <= P->n; j++)
 166.105 +      {  col = P->col[j];
 166.106 +         xfprintf(fp, "%6d ", j);
 166.107 +         if (col->name == NULL || strlen(col->name) <= 12)
 166.108 +            xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name);
 166.109 +         else
 166.110 +            xfprintf(fp, "%s\n%20s", col->name, "");
 166.111 +         xfprintf(fp, "%s ",
 166.112 +            col->stat == GLP_BS ? "B " :
 166.113 +            col->stat == GLP_NL ? "NL" :
 166.114 +            col->stat == GLP_NU ? "NU" :
 166.115 +            col->stat == GLP_NF ? "NF" :
 166.116 +            col->stat == GLP_NS ? "NS" : "??");
 166.117 +         xfprintf(fp, "%13.6g ",
 166.118 +            fabs(col->prim) <= 1e-9 ? 0.0 : col->prim);
 166.119 +         if (col->type == GLP_LO || col->type == GLP_DB ||
 166.120 +             col->type == GLP_FX)
 166.121 +            xfprintf(fp, "%13.6g ", col->lb);
 166.122 +         else
 166.123 +            xfprintf(fp, "%13s ", "");
 166.124 +         if (col->type == GLP_UP || col->type == GLP_DB)
 166.125 +            xfprintf(fp, "%13.6g ", col->ub);
 166.126 +         else
 166.127 +            xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : "");
 166.128 +         if (col->stat != GLP_BS)
 166.129 +         {  if (fabs(col->dual) <= 1e-9)
 166.130 +               xfprintf(fp, "%13s", "< eps");
 166.131 +            else
 166.132 +               xfprintf(fp, "%13.6g ", col->dual);
 166.133 +         }
 166.134 +         xfprintf(fp, "\n");
 166.135 +      }
 166.136 +      xfprintf(fp, "\n");
 166.137 +      xfprintf(fp, "Karush-Kuhn-Tucker optimality conditions:\n");
 166.138 +      xfprintf(fp, "\n");
 166.139 +      _glp_check_kkt(P, GLP_SOL, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
 166.140 +         &re_ind);
 166.141 +      xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n",
 166.142 +         ae_max, ae_ind);
 166.143 +      xfprintf(fp, "        max.rel.err = %.2e on row %d\n",
 166.144 +         re_max, re_ind);
 166.145 +      xfprintf(fp, "%8s%s\n", "",
 166.146 +         re_max <= 1e-9 ? "High quality" :
 166.147 +         re_max <= 1e-6 ? "Medium quality" :
 166.148 +         re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS WRONG");
 166.149 +      xfprintf(fp, "\n");
 166.150 +      _glp_check_kkt(P, GLP_SOL, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
 166.151 +         &re_ind);
 166.152 +      xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n",
 166.153 +            ae_max, ae_ind <= P->m ? "row" : "column",
 166.154 +            ae_ind <= P->m ? ae_ind : ae_ind - P->m);
 166.155 +      xfprintf(fp, "        max.rel.err = %.2e on %s %d\n",
 166.156 +            re_max, re_ind <= P->m ? "row" : "column",
 166.157 +            re_ind <= P->m ? re_ind : re_ind - P->m);
 166.158 +      xfprintf(fp, "%8s%s\n", "",
 166.159 +         re_max <= 1e-9 ? "High quality" :
 166.160 +         re_max <= 1e-6 ? "Medium quality" :
 166.161 +         re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS INFEASIBL"
 166.162 +            "E");
 166.163 +      xfprintf(fp, "\n");
 166.164 +      _glp_check_kkt(P, GLP_SOL, GLP_KKT_DE, &ae_max, &ae_ind, &re_max,
 166.165 +         &re_ind);
 166.166 +      xfprintf(fp, "KKT.DE: max.abs.err = %.2e on column %d\n",
 166.167 +         ae_max, ae_ind == 0 ? 0 : ae_ind - P->m);
 166.168 +      xfprintf(fp, "        max.rel.err = %.2e on column %d\n",
 166.169 +         re_max, re_ind == 0 ? 0 : re_ind - P->m);
 166.170 +      xfprintf(fp, "%8s%s\n", "",
 166.171 +         re_max <= 1e-9 ? "High quality" :
 166.172 +         re_max <= 1e-6 ? "Medium quality" :
 166.173 +         re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS WRONG");
 166.174 +      xfprintf(fp, "\n");
 166.175 +      _glp_check_kkt(P, GLP_SOL, GLP_KKT_DB, &ae_max, &ae_ind, &re_max,
 166.176 +         &re_ind);
 166.177 +      xfprintf(fp, "KKT.DB: max.abs.err = %.2e on %s %d\n",
 166.178 +            ae_max, ae_ind <= P->m ? "row" : "column",
 166.179 +            ae_ind <= P->m ? ae_ind : ae_ind - P->m);
 166.180 +      xfprintf(fp, "        max.rel.err = %.2e on %s %d\n",
 166.181 +            re_max, re_ind <= P->m ? "row" : "column",
 166.182 +            re_ind <= P->m ? re_ind : re_ind - P->m);
 166.183 +      xfprintf(fp, "%8s%s\n", "",
 166.184 +         re_max <= 1e-9 ? "High quality" :
 166.185 +         re_max <= 1e-6 ? "Medium quality" :
 166.186 +         re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS INFEASIBLE")
 166.187 +            ;
 166.188 +      xfprintf(fp, "\n");
 166.189 +      xfprintf(fp, "End of output\n");
 166.190 +      xfflush(fp);
 166.191 +      if (xferror(fp))
 166.192 +      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
 166.193 +         ret = 1;
 166.194 +         goto done;
 166.195 +      }
 166.196 +      ret = 0;
 166.197 +done: if (fp != NULL) xfclose(fp);
 166.198 +      return ret;
 166.199 +}
 166.200 +
 166.201 +/***********************************************************************
 166.202 +*  NAME
 166.203 +*
 166.204 +*  glp_read_sol - read basic solution from text file
 166.205 +*
 166.206 +*  SYNOPSIS
 166.207 +*
 166.208 +*  int glp_read_sol(glp_prob *lp, const char *fname);
 166.209 +*
 166.210 +*  DESCRIPTION
 166.211 +*
 166.212 +*  The routine glp_read_sol reads basic solution from a text file whose
 166.213 +*  name is specified by the parameter fname into the problem object.
 166.214 +*
 166.215 +*  For the file format see description of the routine glp_write_sol.
 166.216 +*
 166.217 +*  RETURNS
 166.218 +*
 166.219 +*  On success the routine returns zero, otherwise non-zero. */
 166.220 +
 166.221 +int glp_read_sol(glp_prob *lp, const char *fname)
 166.222 +{     glp_data *data;
 166.223 +      jmp_buf jump;
 166.224 +      int i, j, k, ret = 0;
 166.225 +      xprintf("Reading basic solution from `%s'...\n", fname);
 166.226 +      data = glp_sdf_open_file(fname);
 166.227 +      if (data == NULL)
 166.228 +      {  ret = 1;
 166.229 +         goto done;
 166.230 +      }
 166.231 +      if (setjmp(jump))
 166.232 +      {  ret = 1;
 166.233 +         goto done;
 166.234 +      }
 166.235 +      glp_sdf_set_jump(data, jump);
 166.236 +      /* number of rows, number of columns */
 166.237 +      k = glp_sdf_read_int(data);
 166.238 +      if (k != lp->m)
 166.239 +         glp_sdf_error(data, "wrong number of rows\n");
 166.240 +      k = glp_sdf_read_int(data);
 166.241 +      if (k != lp->n)
 166.242 +         glp_sdf_error(data, "wrong number of columns\n");
 166.243 +      /* primal status, dual status, objective value */
 166.244 +      k = glp_sdf_read_int(data);
 166.245 +      if (!(k == GLP_UNDEF || k == GLP_FEAS || k == GLP_INFEAS ||
 166.246 +            k == GLP_NOFEAS))
 166.247 +         glp_sdf_error(data, "invalid primal status\n");
 166.248 +      lp->pbs_stat = k;
 166.249 +      k = glp_sdf_read_int(data);
 166.250 +      if (!(k == GLP_UNDEF || k == GLP_FEAS || k == GLP_INFEAS ||
 166.251 +            k == GLP_NOFEAS))
 166.252 +         glp_sdf_error(data, "invalid dual status\n");
 166.253 +      lp->dbs_stat = k;
 166.254 +      lp->obj_val = glp_sdf_read_num(data);
 166.255 +      /* rows (auxiliary variables) */
 166.256 +      for (i = 1; i <= lp->m; i++)
 166.257 +      {  GLPROW *row = lp->row[i];
 166.258 +         /* status, primal value, dual value */
 166.259 +         k = glp_sdf_read_int(data);
 166.260 +         if (!(k == GLP_BS || k == GLP_NL || k == GLP_NU ||
 166.261 +               k == GLP_NF || k == GLP_NS))
 166.262 +            glp_sdf_error(data, "invalid row status\n");
 166.263 +         glp_set_row_stat(lp, i, k);
 166.264 +         row->prim = glp_sdf_read_num(data);
 166.265 +         row->dual = glp_sdf_read_num(data);
 166.266 +      }
 166.267 +      /* columns (structural variables) */
 166.268 +      for (j = 1; j <= lp->n; j++)
 166.269 +      {  GLPCOL *col = lp->col[j];
 166.270 +         /* status, primal value, dual value */
 166.271 +         k = glp_sdf_read_int(data);
 166.272 +         if (!(k == GLP_BS || k == GLP_NL || k == GLP_NU ||
 166.273 +               k == GLP_NF || k == GLP_NS))
 166.274 +            glp_sdf_error(data, "invalid column status\n");
 166.275 +         glp_set_col_stat(lp, j, k);
 166.276 +         col->prim = glp_sdf_read_num(data);
 166.277 +         col->dual = glp_sdf_read_num(data);
 166.278 +      }
 166.279 +      xprintf("%d lines were read\n", glp_sdf_line(data));
 166.280 +done: if (ret) lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
 166.281 +      if (data != NULL) glp_sdf_close_file(data);
 166.282 +      return ret;
 166.283 +}
 166.284 +
 166.285 +/***********************************************************************
 166.286 +*  NAME
 166.287 +*
 166.288 +*  glp_write_sol - write basic solution to text file
 166.289 +*
 166.290 +*  SYNOPSIS
 166.291 +*
 166.292 +*  int glp_write_sol(glp_prob *lp, const char *fname);
 166.293 +*
 166.294 +*  DESCRIPTION
 166.295 +*
 166.296 +*  The routine glp_write_sol writes the current basic solution to a
 166.297 +*  text file whose name is specified by the parameter fname. This file
 166.298 +*  can be read back with the routine glp_read_sol.
 166.299 +*
 166.300 +*  RETURNS
 166.301 +*
 166.302 +*  On success the routine returns zero, otherwise non-zero.
 166.303 +*
 166.304 +*  FILE FORMAT
 166.305 +*
 166.306 +*  The file created by the routine glp_write_sol is a plain text file,
 166.307 +*  which contains the following information:
 166.308 +*
 166.309 +*     m n
 166.310 +*     p_stat d_stat obj_val
 166.311 +*     r_stat[1] r_prim[1] r_dual[1]
 166.312 +*     . . .
 166.313 +*     r_stat[m] r_prim[m] r_dual[m]
 166.314 +*     c_stat[1] c_prim[1] c_dual[1]
 166.315 +*     . . .
 166.316 +*     c_stat[n] c_prim[n] c_dual[n]
 166.317 +*
 166.318 +*  where:
 166.319 +*  m is the number of rows (auxiliary variables);
 166.320 +*  n is the number of columns (structural variables);
 166.321 +*  p_stat is the primal status of the basic solution (GLP_UNDEF = 1,
 166.322 +*     GLP_FEAS = 2, GLP_INFEAS = 3, or GLP_NOFEAS = 4);
 166.323 +*  d_stat is the dual status of the basic solution (GLP_UNDEF = 1,
 166.324 +*     GLP_FEAS = 2, GLP_INFEAS = 3, or GLP_NOFEAS = 4);
 166.325 +*  obj_val is the objective value;
 166.326 +*  r_stat[i], i = 1,...,m, is the status of i-th row (GLP_BS = 1,
 166.327 +*     GLP_NL = 2, GLP_NU = 3, GLP_NF = 4, or GLP_NS = 5);
 166.328 +*  r_prim[i], i = 1,...,m, is the primal value of i-th row;
 166.329 +*  r_dual[i], i = 1,...,m, is the dual value of i-th row;
 166.330 +*  c_stat[j], j = 1,...,n, is the status of j-th column (GLP_BS = 1,
 166.331 +*     GLP_NL = 2, GLP_NU = 3, GLP_NF = 4, or GLP_NS = 5);
 166.332 +*  c_prim[j], j = 1,...,n, is the primal value of j-th column;
 166.333 +*  c_dual[j], j = 1,...,n, is the dual value of j-th column. */
 166.334 +
 166.335 +int glp_write_sol(glp_prob *lp, const char *fname)
 166.336 +{     XFILE *fp;
 166.337 +      int i, j, ret = 0;
 166.338 +      xprintf("Writing basic solution to `%s'...\n", fname);
 166.339 +      fp = xfopen(fname, "w");
 166.340 +      if (fp == NULL)
 166.341 +      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
 166.342 +         ret = 1;
 166.343 +         goto done;
 166.344 +      }
 166.345 +      /* number of rows, number of columns */
 166.346 +      xfprintf(fp, "%d %d\n", lp->m, lp->n);
 166.347 +      /* primal status, dual status, objective value */
 166.348 +      xfprintf(fp, "%d %d %.*g\n", lp->pbs_stat, lp->dbs_stat, DBL_DIG,
 166.349 +         lp->obj_val);
 166.350 +      /* rows (auxiliary variables) */
 166.351 +      for (i = 1; i <= lp->m; i++)
 166.352 +      {  GLPROW *row = lp->row[i];
 166.353 +         /* status, primal value, dual value */
 166.354 +         xfprintf(fp, "%d %.*g %.*g\n", row->stat, DBL_DIG, row->prim,
 166.355 +            DBL_DIG, row->dual);
 166.356 +      }
 166.357 +      /* columns (structural variables) */
 166.358 +      for (j = 1; j <= lp->n; j++)
 166.359 +      {  GLPCOL *col = lp->col[j];
 166.360 +         /* status, primal value, dual value */
 166.361 +         xfprintf(fp, "%d %.*g %.*g\n", col->stat, DBL_DIG, col->prim,
 166.362 +            DBL_DIG, col->dual);
 166.363 +      }
 166.364 +      xfflush(fp);
 166.365 +      if (xferror(fp))
 166.366 +      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
 166.367 +         ret = 1;
 166.368 +         goto done;
 166.369 +      }
 166.370 +      xprintf("%d lines were written\n", 2 + lp->m + lp->n);
 166.371 +done: if (fp != NULL) xfclose(fp);
 166.372 +      return ret;
 166.373 +}
 166.374 +
 166.375 +/**********************************************************************/
 166.376 +
 166.377 +static char *format(char buf[13+1], double x)
 166.378 +{     /* format floating-point number in MPS/360-like style */
 166.379 +      if (x == -DBL_MAX)
 166.380 +         strcpy(buf, "         -Inf");
 166.381 +      else if (x == +DBL_MAX)
 166.382 +         strcpy(buf, "         +Inf");
 166.383 +      else if (fabs(x) <= 999999.99998)
 166.384 +      {  sprintf(buf, "%13.5f", x);
 166.385 +#if 1
 166.386 +         if (strcmp(buf, "      0.00000") == 0 ||
 166.387 +             strcmp(buf, "     -0.00000") == 0)
 166.388 +            strcpy(buf, "       .     ");
 166.389 +         else if (memcmp(buf, "      0.", 8) == 0)
 166.390 +            memcpy(buf, "       .", 8);
 166.391 +         else if (memcmp(buf, "     -0.", 8) == 0)
 166.392 +            memcpy(buf, "      -.", 8);
 166.393 +#endif
 166.394 +      }
 166.395 +      else
 166.396 +         sprintf(buf, "%13.6g", x);
 166.397 +      return buf;
 166.398 +}
 166.399 +
 166.400 +int glp_print_ranges(glp_prob *P, int len, const int list[],
 166.401 +      int flags, const char *fname)
 166.402 +{     /* print sensitivity analysis report */
 166.403 +      XFILE *fp = NULL;
 166.404 +      GLPROW *row;
 166.405 +      GLPCOL *col;
 166.406 +      int m, n, pass, k, t, numb, type, stat, var1, var2, count, page,
 166.407 +         ret;
 166.408 +      double lb, ub, slack, coef, prim, dual, value1, value2, coef1,
 166.409 +         coef2, obj1, obj2;
 166.410 +      const char *name, *limit;
 166.411 +      char buf[13+1];
 166.412 +      /* sanity checks */
 166.413 +      if (P == NULL || P->magic != GLP_PROB_MAGIC)
 166.414 +         xerror("glp_print_ranges: P = %p; invalid problem object\n",
 166.415 +            P);
 166.416 +      m = P->m, n = P->n;
 166.417 +      if (len < 0)
 166.418 +         xerror("glp_print_ranges: len = %d; invalid list length\n",
 166.419 +            len);
 166.420 +      if (len > 0)
 166.421 +      {  if (list == NULL)
 166.422 +            xerror("glp_print_ranges: list = %p: invalid parameter\n",
 166.423 +               list);
 166.424 +         for (t = 1; t <= len; t++)
 166.425 +         {  k = list[t];
 166.426 +            if (!(1 <= k && k <= m+n))
 166.427 +               xerror("glp_print_ranges: list[%d] = %d; row/column numb"
 166.428 +                  "er out of range\n", t, k);
 166.429 +         }
 166.430 +      }
 166.431 +      if (flags != 0)
 166.432 +         xerror("glp_print_ranges: flags = %d; invalid parameter\n",
 166.433 +            flags);
 166.434 +      if (fname == NULL)
 166.435 +         xerror("glp_print_ranges: fname = %p; invalid parameter\n",
 166.436 +            fname);
 166.437 +      if (glp_get_status(P) != GLP_OPT)
 166.438 +      {  xprintf("glp_print_ranges: optimal basic solution required\n");
 166.439 +         ret = 1;
 166.440 +         goto done;
 166.441 +      }
 166.442 +      if (!glp_bf_exists(P))
 166.443 +      {  xprintf("glp_print_ranges: basis factorization required\n");
 166.444 +         ret = 2;
 166.445 +         goto done;
 166.446 +      }
 166.447 +      /* start reporting */
 166.448 +      xprintf("Write sensitivity analysis report to `%s'...\n", fname);
 166.449 +      fp = xfopen(fname, "w");
 166.450 +      if (fp == NULL)
 166.451 +      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
 166.452 +         ret = 3;
 166.453 +         goto done;
 166.454 +      }
 166.455 +      page = count = 0;
 166.456 +      for (pass = 1; pass <= 2; pass++)
 166.457 +      for (t = 1; t <= (len == 0 ? m+n : len); t++)
 166.458 +      {  if (t == 1) count = 0;
 166.459 +         k = (len == 0 ? t : list[t]);
 166.460 +         if (pass == 1 && k > m || pass == 2 && k <= m)
 166.461 +            continue;
 166.462 +         if (count == 0)
 166.463 +         {  xfprintf(fp, "GLPK %-4s - SENSITIVITY ANALYSIS REPORT%73sPa"
 166.464 +               "ge%4d\n", glp_version(), "", ++page);
 166.465 +            xfprintf(fp, "\n");
 166.466 +            xfprintf(fp, "%-12s%s\n", "Problem:",
 166.467 +               P->name == NULL ? "" : P->name);
 166.468 +            xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
 166.469 +               P->obj == NULL ? "" : P->obj,
 166.470 +               P->obj == NULL ? "" : " = ", P->obj_val,
 166.471 +               P->dir == GLP_MIN ? "MINimum" :
 166.472 +               P->dir == GLP_MAX ? "MAXimum" : "???");
 166.473 +            xfprintf(fp, "\n");
 166.474 +            xfprintf(fp, "%6s %-12s %2s %13s %13s %13s  %13s %13s %13s "
 166.475 +               "%s\n", "No.", pass == 1 ? "Row name" : "Column name",
 166.476 +               "St", "Activity", pass == 1 ? "Slack" : "Obj coef",
 166.477 +               "Lower bound", "Activity", "Obj coef", "Obj value at",
 166.478 +               "Limiting");
 166.479 +            xfprintf(fp, "%6s %-12s %2s %13s %13s %13s  %13s %13s %13s "
 166.480 +               "%s\n", "", "", "", "", "Marginal", "Upper bound",
 166.481 +               "range", "range", "break point", "variable");
 166.482 +            xfprintf(fp, "------ ------------ -- ------------- --------"
 166.483 +               "----- -------------  ------------- ------------- ------"
 166.484 +               "------- ------------\n");
 166.485 +         }
 166.486 +         if (pass == 1)
 166.487 +         {  numb = k;
 166.488 +            xassert(1 <= numb && numb <= m);
 166.489 +            row = P->row[numb];
 166.490 +            name = row->name;
 166.491 +            type = row->type;
 166.492 +            lb = glp_get_row_lb(P, numb);
 166.493 +            ub = glp_get_row_ub(P, numb);
 166.494 +            coef = 0.0;
 166.495 +            stat = row->stat;
 166.496 +            prim = row->prim;
 166.497 +            if (type == GLP_FR)
 166.498 +               slack = - prim;
 166.499 +            else if (type == GLP_LO)
 166.500 +               slack = lb - prim;
 166.501 +            else if (type == GLP_UP || type == GLP_DB || type == GLP_FX)
 166.502 +               slack = ub - prim;
 166.503 +            dual = row->dual;
 166.504 +         }
 166.505 +         else
 166.506 +         {  numb = k - m;
 166.507 +            xassert(1 <= numb && numb <= n);
 166.508 +            col = P->col[numb];
 166.509 +            name = col->name;
 166.510 +            lb = glp_get_col_lb(P, numb);
 166.511 +            ub = glp_get_col_ub(P, numb);
 166.512 +            coef = col->coef;
 166.513 +            stat = col->stat;
 166.514 +            prim = col->prim;
 166.515 +            slack = 0.0;
 166.516 +            dual = col->dual;
 166.517 +         }
 166.518 +         if (stat != GLP_BS)
 166.519 +         {  glp_analyze_bound(P, k, &value1, &var1, &value2, &var2);
 166.520 +            if (stat == GLP_NF)
 166.521 +               coef1 = coef2 = coef;
 166.522 +            else if (stat == GLP_NS)
 166.523 +               coef1 = -DBL_MAX, coef2 = +DBL_MAX;
 166.524 +            else if (stat == GLP_NL && P->dir == GLP_MIN ||
 166.525 +                     stat == GLP_NU && P->dir == GLP_MAX)
 166.526 +               coef1 = coef - dual, coef2 = +DBL_MAX;
 166.527 +            else
 166.528 +               coef1 = -DBL_MAX, coef2 = coef - dual;
 166.529 +            if (value1 == -DBL_MAX)
 166.530 +            {  if (dual < -1e-9)
 166.531 +                  obj1 = +DBL_MAX;
 166.532 +               else if (dual > +1e-9)
 166.533 +                  obj1 = -DBL_MAX;
 166.534 +               else
 166.535 +                  obj1 = P->obj_val;
 166.536 +            }
 166.537 +            else
 166.538 +               obj1 = P->obj_val + dual * (value1 - prim);
 166.539 +            if (value2 == +DBL_MAX)
 166.540 +            {  if (dual < -1e-9)
 166.541 +                  obj2 = -DBL_MAX;
 166.542 +               else if (dual > +1e-9)
 166.543 +                  obj2 = +DBL_MAX;
 166.544 +               else
 166.545 +                  obj2 = P->obj_val;
 166.546 +            }
 166.547 +            else
 166.548 +               obj2 = P->obj_val + dual * (value2 - prim);
 166.549 +         }
 166.550 +         else
 166.551 +         {  glp_analyze_coef(P, k, &coef1, &var1, &value1, &coef2,
 166.552 +               &var2, &value2);
 166.553 +            if (coef1 == -DBL_MAX)
 166.554 +            {  if (prim < -1e-9)
 166.555 +                  obj1 = +DBL_MAX;
 166.556 +               else if (prim > +1e-9)
 166.557 +                  obj1 = -DBL_MAX;
 166.558 +               else
 166.559 +                  obj1 = P->obj_val;
 166.560 +            }
 166.561 +            else
 166.562 +               obj1 = P->obj_val + (coef1 - coef) * prim;
 166.563 +            if (coef2 == +DBL_MAX)
 166.564 +            {  if (prim < -1e-9)
 166.565 +                  obj2 = -DBL_MAX;
 166.566 +               else if (prim > +1e-9)
 166.567 +                  obj2 = +DBL_MAX;
 166.568 +               else
 166.569 +                  obj2 = P->obj_val;
 166.570 +            }
 166.571 +            else
 166.572 +               obj2 = P->obj_val + (coef2 - coef) * prim;
 166.573 +         }
 166.574 +         /*** first line ***/
 166.575 +         /* row/column number */
 166.576 +         xfprintf(fp, "%6d", numb);
 166.577 +         /* row/column name */
 166.578 +         xfprintf(fp, " %-12.12s", name == NULL ? "" : name);
 166.579 +         if (name != NULL && strlen(name) > 12)
 166.580 +            xfprintf(fp, "%s\n%6s %12s", name+12, "", "");
 166.581 +         /* row/column status */
 166.582 +         xfprintf(fp, " %2s",
 166.583 +            stat == GLP_BS ? "BS" : stat == GLP_NL ? "NL" :
 166.584 +            stat == GLP_NU ? "NU" : stat == GLP_NF ? "NF" :
 166.585 +            stat == GLP_NS ? "NS" : "??");
 166.586 +         /* row/column activity */
 166.587 +         xfprintf(fp, " %s", format(buf, prim));
 166.588 +         /* row slack, column objective coefficient */
 166.589 +         xfprintf(fp, " %s", format(buf, k <= m ? slack : coef));
 166.590 +         /* row/column lower bound */
 166.591 +         xfprintf(fp, " %s", format(buf, lb));
 166.592 +         /* row/column activity range */
 166.593 +         xfprintf(fp, "  %s", format(buf, value1));
 166.594 +         /* row/column objective coefficient range */
 166.595 +         xfprintf(fp, " %s", format(buf, coef1));
 166.596 +         /* objective value at break point */
 166.597 +         xfprintf(fp, " %s", format(buf, obj1));
 166.598 +         /* limiting variable name */
 166.599 +         if (var1 != 0)
 166.600 +         {  if (var1 <= m)
 166.601 +               limit = glp_get_row_name(P, var1);
 166.602 +            else
 166.603 +               limit = glp_get_col_name(P, var1 - m);
 166.604 +            if (limit != NULL)
 166.605 +               xfprintf(fp, " %s", limit);
 166.606 +         }
 166.607 +         xfprintf(fp, "\n");
 166.608 +         /*** second line ***/
 166.609 +         xfprintf(fp, "%6s %-12s %2s %13s", "", "", "", "");
 166.610 +         /* row/column reduced cost */
 166.611 +         xfprintf(fp, " %s", format(buf, dual));
 166.612 +         /* row/column upper bound */
 166.613 +         xfprintf(fp, " %s", format(buf, ub));
 166.614 +         /* row/column activity range */
 166.615 +         xfprintf(fp, "  %s", format(buf, value2));
 166.616 +         /* row/column objective coefficient range */
 166.617 +         xfprintf(fp, " %s", format(buf, coef2));
 166.618 +         /* objective value at break point */
 166.619 +         xfprintf(fp, " %s", format(buf, obj2));
 166.620 +         /* limiting variable name */
 166.621 +         if (var2 != 0)
 166.622 +         {  if (var2 <= m)
 166.623 +               limit = glp_get_row_name(P, var2);
 166.624 +            else
 166.625 +               limit = glp_get_col_name(P, var2 - m);
 166.626 +            if (limit != NULL)
 166.627 +               xfprintf(fp, " %s", limit);
 166.628 +         }
 166.629 +         xfprintf(fp, "\n");
 166.630 +         xfprintf(fp, "\n");
 166.631 +         /* print 10 items per page */
 166.632 +         count = (count + 1) % 10;
 166.633 +      }
 166.634 +      xfprintf(fp, "End of report\n");
 166.635 +      xfflush(fp);
 166.636 +      if (xferror(fp))
 166.637 +      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
 166.638 +         ret = 4;
 166.639 +         goto done;
 166.640 +      }
 166.641 +      ret = 0;
 166.642 +done: if (fp != NULL) xfclose(fp);
 166.643 +      return ret;
 166.644 +}
 166.645 +
 166.646 +/**********************************************************************/
 166.647 +
 166.648 +int glp_print_ipt(glp_prob *P, const char *fname)
 166.649 +{     /* write interior-point solution in printable format */
 166.650 +      XFILE *fp;
 166.651 +      GLPROW *row;
 166.652 +      GLPCOL *col;
 166.653 +      int i, j, t, ae_ind, re_ind, ret;
 166.654 +      double ae_max, re_max;
 166.655 +      xprintf("Writing interior-point solution to `%s'...\n", fname);
 166.656 +      fp = xfopen(fname, "w");
 166.657 +      if (fp == NULL)
 166.658 +      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
 166.659 +         ret = 1;
 166.660 +         goto done;
 166.661 +      }
 166.662 +      xfprintf(fp, "%-12s%s\n", "Problem:",
 166.663 +         P->name == NULL ? "" : P->name);
 166.664 +      xfprintf(fp, "%-12s%d\n", "Rows:", P->m);
 166.665 +      xfprintf(fp, "%-12s%d\n", "Columns:", P->n);
 166.666 +      xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz);
 166.667 +      t = glp_ipt_status(P);
 166.668 +      xfprintf(fp, "%-12s%s\n", "Status:",
 166.669 +         t == GLP_OPT    ? "OPTIMAL" :
 166.670 +         t == GLP_UNDEF  ? "UNDEFINED" :
 166.671 +         t == GLP_INFEAS ? "INFEASIBLE (INTERMEDIATE)" :
 166.672 +         t == GLP_NOFEAS ? "INFEASIBLE (FINAL)" : "???");
 166.673 +      xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
 166.674 +         P->obj == NULL ? "" : P->obj,
 166.675 +         P->obj == NULL ? "" : " = ", P->ipt_obj,
 166.676 +         P->dir == GLP_MIN ? "MINimum" :
 166.677 +         P->dir == GLP_MAX ? "MAXimum" : "???");
 166.678 +      xfprintf(fp, "\n");
 166.679 +      xfprintf(fp, "   No.   Row name        Activity     Lower bound  "
 166.680 +         " Upper bound    Marginal\n");
 166.681 +      xfprintf(fp, "------ ------------    ------------- ------------- "
 166.682 +         "------------- -------------\n");
 166.683 +      for (i = 1; i <= P->m; i++)
 166.684 +      {  row = P->row[i];
 166.685 +         xfprintf(fp, "%6d ", i);
 166.686 +         if (row->name == NULL || strlen(row->name) <= 12)
 166.687 +            xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name);
 166.688 +         else
 166.689 +            xfprintf(fp, "%s\n%20s", row->name, "");
 166.690 +         xfprintf(fp, "%3s", "");
 166.691 +         xfprintf(fp, "%13.6g ",
 166.692 +            fabs(row->pval) <= 1e-9 ? 0.0 : row->pval);
 166.693 +         if (row->type == GLP_LO || row->type == GLP_DB ||
 166.694 +             row->type == GLP_FX)
 166.695 +            xfprintf(fp, "%13.6g ", row->lb);
 166.696 +         else
 166.697 +            xfprintf(fp, "%13s ", "");
 166.698 +         if (row->type == GLP_UP || row->type == GLP_DB)
 166.699 +            xfprintf(fp, "%13.6g ", row->ub);
 166.700 +         else
 166.701 +            xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : "");
 166.702 +         if (fabs(row->dval) <= 1e-9)
 166.703 +            xfprintf(fp, "%13s", "< eps");
 166.704 +         else
 166.705 +            xfprintf(fp, "%13.6g ", row->dval);
 166.706 +         xfprintf(fp, "\n");
 166.707 +      }
 166.708 +      xfprintf(fp, "\n");
 166.709 +      xfprintf(fp, "   No. Column name       Activity     Lower bound  "
 166.710 +         " Upper bound    Marginal\n");
 166.711 +      xfprintf(fp, "------ ------------    ------------- ------------- "
 166.712 +         "------------- -------------\n");
 166.713 +      for (j = 1; j <= P->n; j++)
 166.714 +      {  col = P->col[j];
 166.715 +         xfprintf(fp, "%6d ", j);
 166.716 +         if (col->name == NULL || strlen(col->name) <= 12)
 166.717 +            xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name);
 166.718 +         else
 166.719 +            xfprintf(fp, "%s\n%20s", col->name, "");
 166.720 +         xfprintf(fp, "%3s", "");
 166.721 +         xfprintf(fp, "%13.6g ",
 166.722 +            fabs(col->pval) <= 1e-9 ? 0.0 : col->pval);
 166.723 +         if (col->type == GLP_LO || col->type == GLP_DB ||
 166.724 +             col->type == GLP_FX)
 166.725 +            xfprintf(fp, "%13.6g ", col->lb);
 166.726 +         else
 166.727 +            xfprintf(fp, "%13s ", "");
 166.728 +         if (col->type == GLP_UP || col->type == GLP_DB)
 166.729 +            xfprintf(fp, "%13.6g ", col->ub);
 166.730 +         else
 166.731 +            xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : "");
 166.732 +         if (fabs(col->dval) <= 1e-9)
 166.733 +            xfprintf(fp, "%13s", "< eps");
 166.734 +         else
 166.735 +            xfprintf(fp, "%13.6g ", col->dval);
 166.736 +         xfprintf(fp, "\n");
 166.737 +      }
 166.738 +      xfprintf(fp, "\n");
 166.739 +      xfprintf(fp, "Karush-Kuhn-Tucker optimality conditions:\n");
 166.740 +      xfprintf(fp, "\n");
 166.741 +      _glp_check_kkt(P, GLP_IPT, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
 166.742 +         &re_ind);
 166.743 +      xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n",
 166.744 +         ae_max, ae_ind);
 166.745 +      xfprintf(fp, "        max.rel.err = %.2e on row %d\n",
 166.746 +         re_max, re_ind);
 166.747 +      xfprintf(fp, "%8s%s\n", "",
 166.748 +         re_max <= 1e-9 ? "High quality" :
 166.749 +         re_max <= 1e-6 ? "Medium quality" :
 166.750 +         re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS WRONG");
 166.751 +      xfprintf(fp, "\n");
 166.752 +      _glp_check_kkt(P, GLP_IPT, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
 166.753 +         &re_ind);
 166.754 +      xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n",
 166.755 +            ae_max, ae_ind <= P->m ? "row" : "column",
 166.756 +            ae_ind <= P->m ? ae_ind : ae_ind - P->m);
 166.757 +      xfprintf(fp, "        max.rel.err = %.2e on %s %d\n",
 166.758 +            re_max, re_ind <= P->m ? "row" : "column",
 166.759 +            re_ind <= P->m ? re_ind : re_ind - P->m);
 166.760 +      xfprintf(fp, "%8s%s\n", "",
 166.761 +         re_max <= 1e-9 ? "High quality" :
 166.762 +         re_max <= 1e-6 ? "Medium quality" :
 166.763 +         re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS INFEASIBL"
 166.764 +            "E");
 166.765 +      xfprintf(fp, "\n");
 166.766 +      _glp_check_kkt(P, GLP_IPT, GLP_KKT_DE, &ae_max, &ae_ind, &re_max,
 166.767 +         &re_ind);
 166.768 +      xfprintf(fp, "KKT.DE: max.abs.err = %.2e on column %d\n",
 166.769 +         ae_max, ae_ind == 0 ? 0 : ae_ind - P->m);
 166.770 +      xfprintf(fp, "        max.rel.err = %.2e on column %d\n",
 166.771 +         re_max, re_ind == 0 ? 0 : re_ind - P->m);
 166.772 +      xfprintf(fp, "%8s%s\n", "",
 166.773 +         re_max <= 1e-9 ? "High quality" :
 166.774 +         re_max <= 1e-6 ? "Medium quality" :
 166.775 +         re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS WRONG");
 166.776 +      xfprintf(fp, "\n");
 166.777 +      _glp_check_kkt(P, GLP_IPT, GLP_KKT_DB, &ae_max, &ae_ind, &re_max,
 166.778 +         &re_ind);
 166.779 +      xfprintf(fp, "KKT.DB: max.abs.err = %.2e on %s %d\n",
 166.780 +            ae_max, ae_ind <= P->m ? "row" : "column",
 166.781 +            ae_ind <= P->m ? ae_ind : ae_ind - P->m);
 166.782 +      xfprintf(fp, "        max.rel.err = %.2e on %s %d\n",
 166.783 +            re_max, re_ind <= P->m ? "row" : "column",
 166.784 +            re_ind <= P->m ? re_ind : re_ind - P->m);
 166.785 +      xfprintf(fp, "%8s%s\n", "",
 166.786 +         re_max <= 1e-9 ? "High quality" :
 166.787 +         re_max <= 1e-6 ? "Medium quality" :
 166.788 +         re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS INFEASIBLE")
 166.789 +            ;
 166.790 +      xfprintf(fp, "\n");
 166.791 +      xfprintf(fp, "End of output\n");
 166.792 +      xfflush(fp);
 166.793 +      if (xferror(fp))
 166.794 +      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
 166.795 +         ret = 1;
 166.796 +         goto done;
 166.797 +      }
 166.798 +      ret = 0;
 166.799 +done: if (fp != NULL) xfclose(fp);
 166.800 +      return ret;
 166.801 +}
 166.802 +
 166.803 +/***********************************************************************
 166.804 +*  NAME
 166.805 +*
 166.806 +*  glp_read_ipt - read interior-point solution from text file
 166.807 +*
 166.808 +*  SYNOPSIS
 166.809 +*
 166.810 +*  int glp_read_ipt(glp_prob *lp, const char *fname);
 166.811 +*
 166.812 +*  DESCRIPTION
 166.813 +*
 166.814 +*  The routine glp_read_ipt reads interior-point solution from a text
 166.815 +*  file whose name is specified by the parameter fname into the problem
 166.816 +*  object.
 166.817 +*
 166.818 +*  For the file format see description of the routine glp_write_ipt.
 166.819 +*
 166.820 +*  RETURNS
 166.821 +*
 166.822 +*  On success the routine returns zero, otherwise non-zero. */
 166.823 +
 166.824 +int glp_read_ipt(glp_prob *lp, const char *fname)
 166.825 +{     glp_data *data;
 166.826 +      jmp_buf jump;
 166.827 +      int i, j, k, ret = 0;
 166.828 +      xprintf("Reading interior-point solution from `%s'...\n", fname);
 166.829 +      data = glp_sdf_open_file(fname);
 166.830 +      if (data == NULL)
 166.831 +      {  ret = 1;
 166.832 +         goto done;
 166.833 +      }
 166.834 +      if (setjmp(jump))
 166.835 +      {  ret = 1;
 166.836 +         goto done;
 166.837 +      }
 166.838 +      glp_sdf_set_jump(data, jump);
 166.839 +      /* number of rows, number of columns */
 166.840 +      k = glp_sdf_read_int(data);
 166.841 +      if (k != lp->m)
 166.842 +         glp_sdf_error(data, "wrong number of rows\n");
 166.843 +      k = glp_sdf_read_int(data);
 166.844 +      if (k != lp->n)
 166.845 +         glp_sdf_error(data, "wrong number of columns\n");
 166.846 +      /* solution status, objective value */
 166.847 +      k = glp_sdf_read_int(data);
 166.848 +      if (!(k == GLP_UNDEF || k == GLP_OPT))
 166.849 +         glp_sdf_error(data, "invalid solution status\n");
 166.850 +      lp->ipt_stat = k;
 166.851 +      lp->ipt_obj = glp_sdf_read_num(data);
 166.852 +      /* rows (auxiliary variables) */
 166.853 +      for (i = 1; i <= lp->m; i++)
 166.854 +      {  GLPROW *row = lp->row[i];
 166.855 +         /* primal value, dual value */
 166.856 +         row->pval = glp_sdf_read_num(data);
 166.857 +         row->dval = glp_sdf_read_num(data);
 166.858 +      }
 166.859 +      /* columns (structural variables) */
 166.860 +      for (j = 1; j <= lp->n; j++)
 166.861 +      {  GLPCOL *col = lp->col[j];
 166.862 +         /* primal value, dual value */
 166.863 +         col->pval = glp_sdf_read_num(data);
 166.864 +         col->dval = glp_sdf_read_num(data);
 166.865 +      }
 166.866 +      xprintf("%d lines were read\n", glp_sdf_line(data));
 166.867 +done: if (ret) lp->ipt_stat = GLP_UNDEF;
 166.868 +      if (data != NULL) glp_sdf_close_file(data);
 166.869 +      return ret;
 166.870 +}
 166.871 +
 166.872 +/***********************************************************************
 166.873 +*  NAME
 166.874 +*
 166.875 +*  glp_write_ipt - write interior-point solution to text file
 166.876 +*
 166.877 +*  SYNOPSIS
 166.878 +*
 166.879 +*  int glp_write_ipt(glp_prob *lp, const char *fname);
 166.880 +*
 166.881 +*  DESCRIPTION
 166.882 +*
 166.883 +*  The routine glp_write_ipt writes the current interior-point solution
 166.884 +*  to a text file whose name is specified by the parameter fname. This
 166.885 +*  file can be read back with the routine glp_read_ipt.
 166.886 +*
 166.887 +*  RETURNS
 166.888 +*
 166.889 +*  On success the routine returns zero, otherwise non-zero.
 166.890 +*
 166.891 +*  FILE FORMAT
 166.892 +*
 166.893 +*  The file created by the routine glp_write_ipt is a plain text file,
 166.894 +*  which contains the following information:
 166.895 +*
 166.896 +*     m n
 166.897 +*     stat obj_val
 166.898 +*     r_prim[1] r_dual[1]
 166.899 +*     . . .
 166.900 +*     r_prim[m] r_dual[m]
 166.901 +*     c_prim[1] c_dual[1]
 166.902 +*     . . .
 166.903 +*     c_prim[n] c_dual[n]
 166.904 +*
 166.905 +*  where:
 166.906 +*  m is the number of rows (auxiliary variables);
 166.907 +*  n is the number of columns (structural variables);
 166.908 +*  stat is the solution status (GLP_UNDEF = 1 or GLP_OPT = 5);
 166.909 +*  obj_val is the objective value;
 166.910 +*  r_prim[i], i = 1,...,m, is the primal value of i-th row;
 166.911 +*  r_dual[i], i = 1,...,m, is the dual value of i-th row;
 166.912 +*  c_prim[j], j = 1,...,n, is the primal value of j-th column;
 166.913 +*  c_dual[j], j = 1,...,n, is the dual value of j-th column. */
 166.914 +
 166.915 +int glp_write_ipt(glp_prob *lp, const char *fname)
 166.916 +{     XFILE *fp;
 166.917 +      int i, j, ret = 0;
 166.918 +      xprintf("Writing interior-point solution to `%s'...\n", fname);
 166.919 +      fp = xfopen(fname, "w");
 166.920 +      if (fp == NULL)
 166.921 +      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
 166.922 +         ret = 1;
 166.923 +         goto done;
 166.924 +      }
 166.925 +      /* number of rows, number of columns */
 166.926 +      xfprintf(fp, "%d %d\n", lp->m, lp->n);
 166.927 +      /* solution status, objective value */
 166.928 +      xfprintf(fp, "%d %.*g\n", lp->ipt_stat, DBL_DIG, lp->ipt_obj);
 166.929 +      /* rows (auxiliary variables) */
 166.930 +      for (i = 1; i <= lp->m; i++)
 166.931 +      {  GLPROW *row = lp->row[i];
 166.932 +         /* primal value, dual value */
 166.933 +         xfprintf(fp, "%.*g %.*g\n", DBL_DIG, row->pval, DBL_DIG,
 166.934 +            row->dval);
 166.935 +      }
 166.936 +      /* columns (structural variables) */
 166.937 +      for (j = 1; j <= lp->n; j++)
 166.938 +      {  GLPCOL *col = lp->col[j];
 166.939 +         /* primal value, dual value */
 166.940 +         xfprintf(fp, "%.*g %.*g\n", DBL_DIG, col->pval, DBL_DIG,
 166.941 +            col->dval);
 166.942 +      }
 166.943 +      xfflush(fp);
 166.944 +      if (xferror(fp))
 166.945 +      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
 166.946 +         ret = 1;
 166.947 +         goto done;
 166.948 +      }
 166.949 +      xprintf("%d lines were written\n", 2 + lp->m + lp->n);
 166.950 +done: if (fp != NULL) xfclose(fp);
 166.951 +      return ret;
 166.952 +}
 166.953 +
 166.954 +/**********************************************************************/
 166.955 +
 166.956 +int glp_print_mip(glp_prob *P, const char *fname)
 166.957 +{     /* write MIP solution in printable format */
 166.958 +      XFILE *fp;
 166.959 +      GLPROW *row;
 166.960 +      GLPCOL *col;
 166.961 +      int i, j, t, ae_ind, re_ind, ret;
 166.962 +      double ae_max, re_max;
 166.963 +      xprintf("Writing MIP solution to `%s'...\n", fname);
 166.964 +      fp = xfopen(fname, "w");
 166.965 +      if (fp == NULL)
 166.966 +      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
 166.967 +         ret = 1;
 166.968 +         goto done;
 166.969 +      }
 166.970 +      xfprintf(fp, "%-12s%s\n", "Problem:",
 166.971 +         P->name == NULL ? "" : P->name);
 166.972 +      xfprintf(fp, "%-12s%d\n", "Rows:", P->m);
 166.973 +      xfprintf(fp, "%-12s%d (%d integer, %d binary)\n", "Columns:",
 166.974 +         P->n, glp_get_num_int(P), glp_get_num_bin(P));
 166.975 +      xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz);
 166.976 +      t = glp_mip_status(P);
 166.977 +      xfprintf(fp, "%-12s%s\n", "Status:",
 166.978 +         t == GLP_OPT    ? "INTEGER OPTIMAL" :
 166.979 +         t == GLP_FEAS   ? "INTEGER NON-OPTIMAL" :
 166.980 +         t == GLP_NOFEAS ? "INTEGER EMPTY" :
 166.981 +         t == GLP_UNDEF  ? "INTEGER UNDEFINED" : "???");
 166.982 +      xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
 166.983 +         P->obj == NULL ? "" : P->obj,
 166.984 +         P->obj == NULL ? "" : " = ", P->mip_obj,
 166.985 +         P->dir == GLP_MIN ? "MINimum" :
 166.986 +         P->dir == GLP_MAX ? "MAXimum" : "???");
 166.987 +      xfprintf(fp, "\n");
 166.988 +      xfprintf(fp, "   No.   Row name        Activity     Lower bound  "
 166.989 +         " Upper bound\n");
 166.990 +      xfprintf(fp, "------ ------------    ------------- ------------- "
 166.991 +         "-------------\n");
 166.992 +      for (i = 1; i <= P->m; i++)
 166.993 +      {  row = P->row[i];
 166.994 +         xfprintf(fp, "%6d ", i);
 166.995 +         if (row->name == NULL || strlen(row->name) <= 12)
 166.996 +            xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name);
 166.997 +         else
 166.998 +            xfprintf(fp, "%s\n%20s", row->name, "");
 166.999 +         xfprintf(fp, "%3s", "");
166.1000 +         xfprintf(fp, "%13.6g ",
166.1001 +            fabs(row->mipx) <= 1e-9 ? 0.0 : row->mipx);
166.1002 +         if (row->type == GLP_LO || row->type == GLP_DB ||
166.1003 +             row->type == GLP_FX)
166.1004 +            xfprintf(fp, "%13.6g ", row->lb);
166.1005 +         else
166.1006 +            xfprintf(fp, "%13s ", "");
166.1007 +         if (row->type == GLP_UP || row->type == GLP_DB)
166.1008 +            xfprintf(fp, "%13.6g ", row->ub);
166.1009 +         else
166.1010 +            xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : "");
166.1011 +         xfprintf(fp, "\n");
166.1012 +      }
166.1013 +      xfprintf(fp, "\n");
166.1014 +      xfprintf(fp, "   No. Column name       Activity     Lower bound  "
166.1015 +         " Upper bound\n");
166.1016 +      xfprintf(fp, "------ ------------    ------------- ------------- "
166.1017 +         "-------------\n");
166.1018 +      for (j = 1; j <= P->n; j++)
166.1019 +      {  col = P->col[j];
166.1020 +         xfprintf(fp, "%6d ", j);
166.1021 +         if (col->name == NULL || strlen(col->name) <= 12)
166.1022 +            xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name);
166.1023 +         else
166.1024 +            xfprintf(fp, "%s\n%20s", col->name, "");
166.1025 +         xfprintf(fp, "%s  ",
166.1026 +            col->kind == GLP_CV ? " " :
166.1027 +            col->kind == GLP_IV ? "*" : "?");
166.1028 +         xfprintf(fp, "%13.6g ",
166.1029 +            fabs(col->mipx) <= 1e-9 ? 0.0 : col->mipx);
166.1030 +         if (col->type == GLP_LO || col->type == GLP_DB ||
166.1031 +             col->type == GLP_FX)
166.1032 +            xfprintf(fp, "%13.6g ", col->lb);
166.1033 +         else
166.1034 +            xfprintf(fp, "%13s ", "");
166.1035 +         if (col->type == GLP_UP || col->type == GLP_DB)
166.1036 +            xfprintf(fp, "%13.6g ", col->ub);
166.1037 +         else
166.1038 +            xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : "");
166.1039 +         xfprintf(fp, "\n");
166.1040 +      }
166.1041 +      xfprintf(fp, "\n");
166.1042 +      xfprintf(fp, "Integer feasibility conditions:\n");
166.1043 +      xfprintf(fp, "\n");
166.1044 +      _glp_check_kkt(P, GLP_MIP, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
166.1045 +         &re_ind);
166.1046 +      xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n",
166.1047 +         ae_max, ae_ind);
166.1048 +      xfprintf(fp, "        max.rel.err = %.2e on row %d\n",
166.1049 +         re_max, re_ind);
166.1050 +      xfprintf(fp, "%8s%s\n", "",
166.1051 +         re_max <= 1e-9 ? "High quality" :
166.1052 +         re_max <= 1e-6 ? "Medium quality" :
166.1053 +         re_max <= 1e-3 ? "Low quality" : "SOLUTION IS WRONG");
166.1054 +      xfprintf(fp, "\n");
166.1055 +      _glp_check_kkt(P, GLP_MIP, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
166.1056 +         &re_ind);
166.1057 +      xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n",
166.1058 +            ae_max, ae_ind <= P->m ? "row" : "column",
166.1059 +            ae_ind <= P->m ? ae_ind : ae_ind - P->m);
166.1060 +      xfprintf(fp, "        max.rel.err = %.2e on %s %d\n",
166.1061 +            re_max, re_ind <= P->m ? "row" : "column",
166.1062 +            re_ind <= P->m ? re_ind : re_ind - P->m);
166.1063 +      xfprintf(fp, "%8s%s\n", "",
166.1064 +         re_max <= 1e-9 ? "High quality" :
166.1065 +         re_max <= 1e-6 ? "Medium quality" :
166.1066 +         re_max <= 1e-3 ? "Low quality" : "SOLUTION IS INFEASIBLE");
166.1067 +      xfprintf(fp, "\n");
166.1068 +      xfprintf(fp, "End of output\n");
166.1069 +      xfflush(fp);
166.1070 +      if (xferror(fp))
166.1071 +      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
166.1072 +         ret = 1;
166.1073 +         goto done;
166.1074 +      }
166.1075 +      ret = 0;
166.1076 +done: if (fp != NULL) xfclose(fp);
166.1077 +      return ret;
166.1078 +}
166.1079 +
166.1080 +/***********************************************************************
166.1081 +*  NAME
166.1082 +*
166.1083 +*  glp_read_mip - read MIP solution from text file
166.1084 +*
166.1085 +*  SYNOPSIS
166.1086 +*
166.1087 +*  int glp_read_mip(glp_prob *mip, const char *fname);
166.1088 +*
166.1089 +*  DESCRIPTION
166.1090 +*
166.1091 +*  The routine glp_read_mip reads MIP solution from a text file whose
166.1092 +*  name is specified by the parameter fname into the problem object.
166.1093 +*
166.1094 +*  For the file format see description of the routine glp_write_mip.
166.1095 +*
166.1096 +*  RETURNS
166.1097 +*
166.1098 +*  On success the routine returns zero, otherwise non-zero. */
166.1099 +
166.1100 +int glp_read_mip(glp_prob *mip, const char *fname)
166.1101 +{     glp_data *data;
166.1102 +      jmp_buf jump;
166.1103 +      int i, j, k, ret = 0;
166.1104 +      xprintf("Reading MIP solution from `%s'...\n", fname);
166.1105 +      data = glp_sdf_open_file(fname);
166.1106 +      if (data == NULL)
166.1107 +      {  ret = 1;
166.1108 +         goto done;
166.1109 +      }
166.1110 +      if (setjmp(jump))
166.1111 +      {  ret = 1;
166.1112 +         goto done;
166.1113 +      }
166.1114 +      glp_sdf_set_jump(data, jump);
166.1115 +      /* number of rows, number of columns */
166.1116 +      k = glp_sdf_read_int(data);
166.1117 +      if (k != mip->m)
166.1118 +         glp_sdf_error(data, "wrong number of rows\n");
166.1119 +      k = glp_sdf_read_int(data);
166.1120 +      if (k != mip->n)
166.1121 +         glp_sdf_error(data, "wrong number of columns\n");
166.1122 +      /* solution status, objective value */
166.1123 +      k = glp_sdf_read_int(data);
166.1124 +      if (!(k == GLP_UNDEF || k == GLP_OPT || k == GLP_FEAS ||
166.1125 +            k == GLP_NOFEAS))
166.1126 +         glp_sdf_error(data, "invalid solution status\n");
166.1127 +      mip->mip_stat = k;
166.1128 +      mip->mip_obj = glp_sdf_read_num(data);
166.1129 +      /* rows (auxiliary variables) */
166.1130 +      for (i = 1; i <= mip->m; i++)
166.1131 +      {  GLPROW *row = mip->row[i];
166.1132 +         row->mipx = glp_sdf_read_num(data);
166.1133 +      }
166.1134 +      /* columns (structural variables) */
166.1135 +      for (j = 1; j <= mip->n; j++)
166.1136 +      {  GLPCOL *col = mip->col[j];
166.1137 +         col->mipx = glp_sdf_read_num(data);
166.1138 +         if (col->kind == GLP_IV && col->mipx != floor(col->mipx))
166.1139 +            glp_sdf_error(data, "non-integer column value");
166.1140 +      }
166.1141 +      xprintf("%d lines were read\n", glp_sdf_line(data));
166.1142 +done: if (ret) mip->mip_stat = GLP_UNDEF;
166.1143 +      if (data != NULL) glp_sdf_close_file(data);
166.1144 +      return ret;
166.1145 +}
166.1146 +
166.1147 +/***********************************************************************
166.1148 +*  NAME
166.1149 +*
166.1150 +*  glp_write_mip - write MIP solution to text file
166.1151 +*
166.1152 +*  SYNOPSIS
166.1153 +*
166.1154 +*  int glp_write_mip(glp_prob *mip, const char *fname);
166.1155 +*
166.1156 +*  DESCRIPTION
166.1157 +*
166.1158 +*  The routine glp_write_mip writes the current MIP solution to a text
166.1159 +*  file whose name is specified by the parameter fname. This file can
166.1160 +*  be read back with the routine glp_read_mip.
166.1161 +*
166.1162 +*  RETURNS
166.1163 +*
166.1164 +*  On success the routine returns zero, otherwise non-zero.
166.1165 +*
166.1166 +*  FILE FORMAT
166.1167 +*
166.1168 +*  The file created by the routine glp_write_sol is a plain text file,
166.1169 +*  which contains the following information:
166.1170 +*
166.1171 +*     m n
166.1172 +*     stat obj_val
166.1173 +*     r_val[1]
166.1174 +*     . . .
166.1175 +*     r_val[m]
166.1176 +*     c_val[1]
166.1177 +*     . . .
166.1178 +*     c_val[n]
166.1179 +*
166.1180 +*  where:
166.1181 +*  m is the number of rows (auxiliary variables);
166.1182 +*  n is the number of columns (structural variables);
166.1183 +*  stat is the solution status (GLP_UNDEF = 1, GLP_FEAS = 2,
166.1184 +*     GLP_NOFEAS = 4, or GLP_OPT = 5);
166.1185 +*  obj_val is the objective value;
166.1186 +*  r_val[i], i = 1,...,m, is the value of i-th row;
166.1187 +*  c_val[j], j = 1,...,n, is the value of j-th column. */
166.1188 +
166.1189 +int glp_write_mip(glp_prob *mip, const char *fname)
166.1190 +{     XFILE *fp;
166.1191 +      int i, j, ret = 0;
166.1192 +      xprintf("Writing MIP solution to `%s'...\n", fname);
166.1193 +      fp = xfopen(fname, "w");
166.1194 +      if (fp == NULL)
166.1195 +      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
166.1196 +         ret = 1;
166.1197 +         goto done;
166.1198 +      }
166.1199 +      /* number of rows, number of columns */
166.1200 +      xfprintf(fp, "%d %d\n", mip->m, mip->n);
166.1201 +      /* solution status, objective value */
166.1202 +      xfprintf(fp, "%d %.*g\n", mip->mip_stat, DBL_DIG, mip->mip_obj);
166.1203 +      /* rows (auxiliary variables) */
166.1204 +      for (i = 1; i <= mip->m; i++)
166.1205 +         xfprintf(fp, "%.*g\n", DBL_DIG, mip->row[i]->mipx);
166.1206 +      /* columns (structural variables) */
166.1207 +      for (j = 1; j <= mip->n; j++)
166.1208 +         xfprintf(fp, "%.*g\n", DBL_DIG, mip->col[j]->mipx);
166.1209 +      xfflush(fp);
166.1210 +      if (xferror(fp))
166.1211 +      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
166.1212 +         ret = 1;
166.1213 +         goto done;
166.1214 +      }
166.1215 +      xprintf("%d lines were written\n", 2 + mip->m + mip->n);
166.1216 +done: if (fp != NULL) xfclose(fp);
166.1217 +      return ret;
166.1218 +}
166.1219 +
166.1220 +/* eof */
   167.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   167.2 +++ b/src/glpapi12.c	Mon Dec 06 13:09:21 2010 +0100
   167.3 @@ -0,0 +1,2219 @@
   167.4 +/* glpapi12.c (basis factorization and simplex tableau routines) */
   167.5 +
   167.6 +/***********************************************************************
   167.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   167.8 +*
   167.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  167.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  167.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  167.12 +*  E-mail: <mao@gnu.org>.
  167.13 +*
  167.14 +*  GLPK is free software: you can redistribute it and/or modify it
  167.15 +*  under the terms of the GNU General Public License as published by
  167.16 +*  the Free Software Foundation, either version 3 of the License, or
  167.17 +*  (at your option) any later version.
  167.18 +*
  167.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  167.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  167.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  167.22 +*  License for more details.
  167.23 +*
  167.24 +*  You should have received a copy of the GNU General Public License
  167.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  167.26 +***********************************************************************/
  167.27 +
  167.28 +#include "glpapi.h"
  167.29 +
  167.30 +/***********************************************************************
  167.31 +*  NAME
  167.32 +*
  167.33 +*  glp_bf_exists - check if the basis factorization exists
  167.34 +*
  167.35 +*  SYNOPSIS
  167.36 +*
  167.37 +*  int glp_bf_exists(glp_prob *lp);
  167.38 +*
  167.39 +*  RETURNS
  167.40 +*
  167.41 +*  If the basis factorization for the current basis associated with
  167.42 +*  the specified problem object exists and therefore is available for
  167.43 +*  computations, the routine glp_bf_exists returns non-zero. Otherwise
  167.44 +*  the routine returns zero. */
  167.45 +
  167.46 +int glp_bf_exists(glp_prob *lp)
  167.47 +{     int ret;
  167.48 +      ret = (lp->m == 0 || lp->valid);
  167.49 +      return ret;
  167.50 +}
  167.51 +
  167.52 +/***********************************************************************
  167.53 +*  NAME
  167.54 +*
  167.55 +*  glp_factorize - compute the basis factorization
  167.56 +*
  167.57 +*  SYNOPSIS
  167.58 +*
  167.59 +*  int glp_factorize(glp_prob *lp);
  167.60 +*
  167.61 +*  DESCRIPTION
  167.62 +*
  167.63 +*  The routine glp_factorize computes the basis factorization for the
  167.64 +*  current basis associated with the specified problem object.
  167.65 +*
  167.66 +*  RETURNS
  167.67 +*
  167.68 +*  0  The basis factorization has been successfully computed.
  167.69 +*
  167.70 +*  GLP_EBADB
  167.71 +*     The basis matrix is invalid, i.e. the number of basic (auxiliary
  167.72 +*     and structural) variables differs from the number of rows in the
  167.73 +*     problem object.
  167.74 +*
  167.75 +*  GLP_ESING
  167.76 +*     The basis matrix is singular within the working precision.
  167.77 +*
  167.78 +*  GLP_ECOND
  167.79 +*     The basis matrix is ill-conditioned. */
  167.80 +
  167.81 +static int b_col(void *info, int j, int ind[], double val[])
  167.82 +{     glp_prob *lp = info;
  167.83 +      int m = lp->m;
  167.84 +      GLPAIJ *aij;
  167.85 +      int k, len;
  167.86 +      xassert(1 <= j && j <= m);
  167.87 +      /* determine the ordinal number of basic auxiliary or structural
  167.88 +         variable x[k] corresponding to basic variable xB[j] */
  167.89 +      k = lp->head[j];
  167.90 +      /* build j-th column of the basic matrix, which is k-th column of
  167.91 +         the scaled augmented matrix (I | -R*A*S) */
  167.92 +      if (k <= m)
  167.93 +      {  /* x[k] is auxiliary variable */
  167.94 +         len = 1;
  167.95 +         ind[1] = k;
  167.96 +         val[1] = 1.0;
  167.97 +      }
  167.98 +      else
  167.99 +      {  /* x[k] is structural variable */
 167.100 +         len = 0;
 167.101 +         for (aij = lp->col[k-m]->ptr; aij != NULL; aij = aij->c_next)
 167.102 +         {  len++;
 167.103 +            ind[len] = aij->row->i;
 167.104 +            val[len] = - aij->row->rii * aij->val * aij->col->sjj;
 167.105 +         }
 167.106 +      }
 167.107 +      return len;
 167.108 +}
 167.109 +
 167.110 +static void copy_bfcp(glp_prob *lp);
 167.111 +
 167.112 +int glp_factorize(glp_prob *lp)
 167.113 +{     int m = lp->m;
 167.114 +      int n = lp->n;
 167.115 +      GLPROW **row = lp->row;
 167.116 +      GLPCOL **col = lp->col;
 167.117 +      int *head = lp->head;
 167.118 +      int j, k, stat, ret;
 167.119 +      /* invalidate the basis factorization */
 167.120 +      lp->valid = 0;
 167.121 +      /* build the basis header */
 167.122 +      j = 0;
 167.123 +      for (k = 1; k <= m+n; k++)
 167.124 +      {  if (k <= m)
 167.125 +         {  stat = row[k]->stat;
 167.126 +            row[k]->bind = 0;
 167.127 +         }
 167.128 +         else
 167.129 +         {  stat = col[k-m]->stat;
 167.130 +            col[k-m]->bind = 0;
 167.131 +         }
 167.132 +         if (stat == GLP_BS)
 167.133 +         {  j++;
 167.134 +            if (j > m)
 167.135 +            {  /* too many basic variables */
 167.136 +               ret = GLP_EBADB;
 167.137 +               goto fini;
 167.138 +            }
 167.139 +            head[j] = k;
 167.140 +            if (k <= m)
 167.141 +               row[k]->bind = j;
 167.142 +            else
 167.143 +               col[k-m]->bind = j;
 167.144 +         }
 167.145 +      }
 167.146 +      if (j < m)
 167.147 +      {  /* too few basic variables */
 167.148 +         ret = GLP_EBADB;
 167.149 +         goto fini;
 167.150 +      }
 167.151 +      /* try to factorize the basis matrix */
 167.152 +      if (m > 0)
 167.153 +      {  if (lp->bfd == NULL)
 167.154 +         {  lp->bfd = bfd_create_it();
 167.155 +            copy_bfcp(lp);
 167.156 +         }
 167.157 +         switch (bfd_factorize(lp->bfd, m, lp->head, b_col, lp))
 167.158 +         {  case 0:
 167.159 +               /* ok */
 167.160 +               break;
 167.161 +            case BFD_ESING:
 167.162 +               /* singular matrix */
 167.163 +               ret = GLP_ESING;
 167.164 +               goto fini;
 167.165 +            case BFD_ECOND:
 167.166 +               /* ill-conditioned matrix */
 167.167 +               ret = GLP_ECOND;
 167.168 +               goto fini;
 167.169 +            default:
 167.170 +               xassert(lp != lp);
 167.171 +         }
 167.172 +         lp->valid = 1;
 167.173 +      }
 167.174 +      /* factorization successful */
 167.175 +      ret = 0;
 167.176 +fini: /* bring the return code to the calling program */
 167.177 +      return ret;
 167.178 +}
 167.179 +
 167.180 +/***********************************************************************
 167.181 +*  NAME
 167.182 +*
 167.183 +*  glp_bf_updated - check if the basis factorization has been updated
 167.184 +*
 167.185 +*  SYNOPSIS
 167.186 +*
 167.187 +*  int glp_bf_updated(glp_prob *lp);
 167.188 +*
 167.189 +*  RETURNS
 167.190 +*
 167.191 +*  If the basis factorization has been just computed from scratch, the
 167.192 +*  routine glp_bf_updated returns zero. Otherwise, if the factorization
 167.193 +*  has been updated one or more times, the routine returns non-zero. */
 167.194 +
 167.195 +int glp_bf_updated(glp_prob *lp)
 167.196 +{     int cnt;
 167.197 +      if (!(lp->m == 0 || lp->valid))
 167.198 +         xerror("glp_bf_update: basis factorization does not exist\n");
 167.199 +#if 0 /* 15/XI-2009 */
 167.200 +      cnt = (lp->m == 0 ? 0 : lp->bfd->upd_cnt);
 167.201 +#else
 167.202 +      cnt = (lp->m == 0 ? 0 : bfd_get_count(lp->bfd));
 167.203 +#endif
 167.204 +      return cnt;
 167.205 +}
 167.206 +
 167.207 +/***********************************************************************
 167.208 +*  NAME
 167.209 +*
 167.210 +*  glp_get_bfcp - retrieve basis factorization control parameters
 167.211 +*
 167.212 +*  SYNOPSIS
 167.213 +*
 167.214 +*  void glp_get_bfcp(glp_prob *lp, glp_bfcp *parm);
 167.215 +*
 167.216 +*  DESCRIPTION
 167.217 +*
 167.218 +*  The routine glp_get_bfcp retrieves control parameters, which are
 167.219 +*  used on computing and updating the basis factorization associated
 167.220 +*  with the specified problem object.
 167.221 +*
 167.222 +*  Current values of control parameters are stored by the routine in
 167.223 +*  a glp_bfcp structure, which the parameter parm points to. */
 167.224 +
 167.225 +void glp_get_bfcp(glp_prob *lp, glp_bfcp *parm)
 167.226 +{     glp_bfcp *bfcp = lp->bfcp;
 167.227 +      if (bfcp == NULL)
 167.228 +      {  parm->type = GLP_BF_FT;
 167.229 +         parm->lu_size = 0;
 167.230 +         parm->piv_tol = 0.10;
 167.231 +         parm->piv_lim = 4;
 167.232 +         parm->suhl = GLP_ON;
 167.233 +         parm->eps_tol = 1e-15;
 167.234 +         parm->max_gro = 1e+10;
 167.235 +         parm->nfs_max = 100;
 167.236 +         parm->upd_tol = 1e-6;
 167.237 +         parm->nrs_max = 100;
 167.238 +         parm->rs_size = 0;
 167.239 +      }
 167.240 +      else
 167.241 +         memcpy(parm, bfcp, sizeof(glp_bfcp));
 167.242 +      return;
 167.243 +}
 167.244 +
 167.245 +/***********************************************************************
 167.246 +*  NAME
 167.247 +*
 167.248 +*  glp_set_bfcp - change basis factorization control parameters
 167.249 +*
 167.250 +*  SYNOPSIS
 167.251 +*
 167.252 +*  void glp_set_bfcp(glp_prob *lp, const glp_bfcp *parm);
 167.253 +*
 167.254 +*  DESCRIPTION
 167.255 +*
 167.256 +*  The routine glp_set_bfcp changes control parameters, which are used
 167.257 +*  by internal GLPK routines in computing and updating the basis
 167.258 +*  factorization associated with the specified problem object.
 167.259 +*
 167.260 +*  New values of the control parameters should be passed in a structure
 167.261 +*  glp_bfcp, which the parameter parm points to.
 167.262 +*
 167.263 +*  The parameter parm can be specified as NULL, in which case all
 167.264 +*  control parameters are reset to their default values. */
 167.265 +
 167.266 +#if 0 /* 15/XI-2009 */
 167.267 +static void copy_bfcp(glp_prob *lp)
 167.268 +{     glp_bfcp _parm, *parm = &_parm;
 167.269 +      BFD *bfd = lp->bfd;
 167.270 +      glp_get_bfcp(lp, parm);
 167.271 +      xassert(bfd != NULL);
 167.272 +      bfd->type = parm->type;
 167.273 +      bfd->lu_size = parm->lu_size;
 167.274 +      bfd->piv_tol = parm->piv_tol;
 167.275 +      bfd->piv_lim = parm->piv_lim;
 167.276 +      bfd->suhl = parm->suhl;
 167.277 +      bfd->eps_tol = parm->eps_tol;
 167.278 +      bfd->max_gro = parm->max_gro;
 167.279 +      bfd->nfs_max = parm->nfs_max;
 167.280 +      bfd->upd_tol = parm->upd_tol;
 167.281 +      bfd->nrs_max = parm->nrs_max;
 167.282 +      bfd->rs_size = parm->rs_size;
 167.283 +      return;
 167.284 +}
 167.285 +#else
 167.286 +static void copy_bfcp(glp_prob *lp)
 167.287 +{     glp_bfcp _parm, *parm = &_parm;
 167.288 +      glp_get_bfcp(lp, parm);
 167.289 +      bfd_set_parm(lp->bfd, parm);
 167.290 +      return;
 167.291 +}
 167.292 +#endif
 167.293 +
 167.294 +void glp_set_bfcp(glp_prob *lp, const glp_bfcp *parm)
 167.295 +{     glp_bfcp *bfcp = lp->bfcp;
 167.296 +      if (parm == NULL)
 167.297 +      {  /* reset to default values */
 167.298 +         if (bfcp != NULL)
 167.299 +            xfree(bfcp), lp->bfcp = NULL;
 167.300 +      }
 167.301 +      else
 167.302 +      {  /* set to specified values */
 167.303 +         if (bfcp == NULL)
 167.304 +            bfcp = lp->bfcp = xmalloc(sizeof(glp_bfcp));
 167.305 +         memcpy(bfcp, parm, sizeof(glp_bfcp));
 167.306 +         if (!(bfcp->type == GLP_BF_FT || bfcp->type == GLP_BF_BG ||
 167.307 +               bfcp->type == GLP_BF_GR))
 167.308 +            xerror("glp_set_bfcp: type = %d; invalid parameter\n",
 167.309 +               bfcp->type);
 167.310 +         if (bfcp->lu_size < 0)
 167.311 +            xerror("glp_set_bfcp: lu_size = %d; invalid parameter\n",
 167.312 +               bfcp->lu_size);
 167.313 +         if (!(0.0 < bfcp->piv_tol && bfcp->piv_tol < 1.0))
 167.314 +            xerror("glp_set_bfcp: piv_tol = %g; invalid parameter\n",
 167.315 +               bfcp->piv_tol);
 167.316 +         if (bfcp->piv_lim < 1)
 167.317 +            xerror("glp_set_bfcp: piv_lim = %d; invalid parameter\n",
 167.318 +               bfcp->piv_lim);
 167.319 +         if (!(bfcp->suhl == GLP_ON || bfcp->suhl == GLP_OFF))
 167.320 +            xerror("glp_set_bfcp: suhl = %d; invalid parameter\n",
 167.321 +               bfcp->suhl);
 167.322 +         if (!(0.0 <= bfcp->eps_tol && bfcp->eps_tol <= 1e-6))
 167.323 +            xerror("glp_set_bfcp: eps_tol = %g; invalid parameter\n",
 167.324 +               bfcp->eps_tol);
 167.325 +         if (bfcp->max_gro < 1.0)
 167.326 +            xerror("glp_set_bfcp: max_gro = %g; invalid parameter\n",
 167.327 +               bfcp->max_gro);
 167.328 +         if (!(1 <= bfcp->nfs_max && bfcp->nfs_max <= 32767))
 167.329 +            xerror("glp_set_bfcp: nfs_max = %d; invalid parameter\n",
 167.330 +               bfcp->nfs_max);
 167.331 +         if (!(0.0 < bfcp->upd_tol && bfcp->upd_tol < 1.0))
 167.332 +            xerror("glp_set_bfcp: upd_tol = %g; invalid parameter\n",
 167.333 +               bfcp->upd_tol);
 167.334 +         if (!(1 <= bfcp->nrs_max && bfcp->nrs_max <= 32767))
 167.335 +            xerror("glp_set_bfcp: nrs_max = %d; invalid parameter\n",
 167.336 +               bfcp->nrs_max);
 167.337 +         if (bfcp->rs_size < 0)
 167.338 +            xerror("glp_set_bfcp: rs_size = %d; invalid parameter\n",
 167.339 +               bfcp->nrs_max);
 167.340 +         if (bfcp->rs_size == 0)
 167.341 +            bfcp->rs_size = 20 * bfcp->nrs_max;
 167.342 +      }
 167.343 +      if (lp->bfd != NULL) copy_bfcp(lp);
 167.344 +      return;
 167.345 +}
 167.346 +
 167.347 +/***********************************************************************
 167.348 +*  NAME
 167.349 +*
 167.350 +*  glp_get_bhead - retrieve the basis header information
 167.351 +*
 167.352 +*  SYNOPSIS
 167.353 +*
 167.354 +*  int glp_get_bhead(glp_prob *lp, int k);
 167.355 +*
 167.356 +*  DESCRIPTION
 167.357 +*
 167.358 +*  The routine glp_get_bhead returns the basis header information for
 167.359 +*  the current basis associated with the specified problem object.
 167.360 +*
 167.361 +*  RETURNS
 167.362 +*
 167.363 +*  If xB[k], 1 <= k <= m, is i-th auxiliary variable (1 <= i <= m), the
 167.364 +*  routine returns i. Otherwise, if xB[k] is j-th structural variable
 167.365 +*  (1 <= j <= n), the routine returns m+j. Here m is the number of rows
 167.366 +*  and n is the number of columns in the problem object. */
 167.367 +
 167.368 +int glp_get_bhead(glp_prob *lp, int k)
 167.369 +{     if (!(lp->m == 0 || lp->valid))
 167.370 +         xerror("glp_get_bhead: basis factorization does not exist\n");
 167.371 +      if (!(1 <= k && k <= lp->m))
 167.372 +         xerror("glp_get_bhead: k = %d; index out of range\n", k);
 167.373 +      return lp->head[k];
 167.374 +}
 167.375 +
 167.376 +/***********************************************************************
 167.377 +*  NAME
 167.378 +*
 167.379 +*  glp_get_row_bind - retrieve row index in the basis header
 167.380 +*
 167.381 +*  SYNOPSIS
 167.382 +*
 167.383 +*  int glp_get_row_bind(glp_prob *lp, int i);
 167.384 +*
 167.385 +*  RETURNS
 167.386 +*
 167.387 +*  The routine glp_get_row_bind returns the index k of basic variable
 167.388 +*  xB[k], 1 <= k <= m, which is i-th auxiliary variable, 1 <= i <= m,
 167.389 +*  in the current basis associated with the specified problem object,
 167.390 +*  where m is the number of rows. However, if i-th auxiliary variable
 167.391 +*  is non-basic, the routine returns zero. */
 167.392 +
 167.393 +int glp_get_row_bind(glp_prob *lp, int i)
 167.394 +{     if (!(lp->m == 0 || lp->valid))
 167.395 +         xerror("glp_get_row_bind: basis factorization does not exist\n"
 167.396 +            );
 167.397 +      if (!(1 <= i && i <= lp->m))
 167.398 +         xerror("glp_get_row_bind: i = %d; row number out of range\n",
 167.399 +            i);
 167.400 +      return lp->row[i]->bind;
 167.401 +}
 167.402 +
 167.403 +/***********************************************************************
 167.404 +*  NAME
 167.405 +*
 167.406 +*  glp_get_col_bind - retrieve column index in the basis header
 167.407 +*
 167.408 +*  SYNOPSIS
 167.409 +*
 167.410 +*  int glp_get_col_bind(glp_prob *lp, int j);
 167.411 +*
 167.412 +*  RETURNS
 167.413 +*
 167.414 +*  The routine glp_get_col_bind returns the index k of basic variable
 167.415 +*  xB[k], 1 <= k <= m, which is j-th structural variable, 1 <= j <= n,
 167.416 +*  in the current basis associated with the specified problem object,
 167.417 +*  where m is the number of rows, n is the number of columns. However,
 167.418 +*  if j-th structural variable is non-basic, the routine returns zero.*/
 167.419 +
 167.420 +int glp_get_col_bind(glp_prob *lp, int j)
 167.421 +{     if (!(lp->m == 0 || lp->valid))
 167.422 +         xerror("glp_get_col_bind: basis factorization does not exist\n"
 167.423 +            );
 167.424 +      if (!(1 <= j && j <= lp->n))
 167.425 +         xerror("glp_get_col_bind: j = %d; column number out of range\n"
 167.426 +            , j);
 167.427 +      return lp->col[j]->bind;
 167.428 +}
 167.429 +
 167.430 +/***********************************************************************
 167.431 +*  NAME
 167.432 +*
 167.433 +*  glp_ftran - perform forward transformation (solve system B*x = b)
 167.434 +*
 167.435 +*  SYNOPSIS
 167.436 +*
 167.437 +*  void glp_ftran(glp_prob *lp, double x[]);
 167.438 +*
 167.439 +*  DESCRIPTION
 167.440 +*
 167.441 +*  The routine glp_ftran performs forward transformation, i.e. solves
 167.442 +*  the system B*x = b, where B is the basis matrix corresponding to the
 167.443 +*  current basis for the specified problem object, x is the vector of
 167.444 +*  unknowns to be computed, b is the vector of right-hand sides.
 167.445 +*
 167.446 +*  On entry elements of the vector b should be stored in dense format
 167.447 +*  in locations x[1], ..., x[m], where m is the number of rows. On exit
 167.448 +*  the routine stores elements of the vector x in the same locations.
 167.449 +*
 167.450 +*  SCALING/UNSCALING
 167.451 +*
 167.452 +*  Let A~ = (I | -A) is the augmented constraint matrix of the original
 167.453 +*  (unscaled) problem. In the scaled LP problem instead the matrix A the
 167.454 +*  scaled matrix A" = R*A*S is actually used, so
 167.455 +*
 167.456 +*     A~" = (I | A") = (I | R*A*S) = (R*I*inv(R) | R*A*S) =
 167.457 +*                                                                    (1)
 167.458 +*         = R*(I | A)*S~ = R*A~*S~,
 167.459 +*
 167.460 +*  is the scaled augmented constraint matrix, where R and S are diagonal
 167.461 +*  scaling matrices used to scale rows and columns of the matrix A, and
 167.462 +*
 167.463 +*     S~ = diag(inv(R) | S)                                          (2)
 167.464 +*
 167.465 +*  is an augmented diagonal scaling matrix.
 167.466 +*
 167.467 +*  By definition:
 167.468 +*
 167.469 +*     A~ = (B | N),                                                  (3)
 167.470 +*
 167.471 +*  where B is the basic matrix, which consists of basic columns of the
 167.472 +*  augmented constraint matrix A~, and N is a matrix, which consists of
 167.473 +*  non-basic columns of A~. From (1) it follows that:
 167.474 +*
 167.475 +*     A~" = (B" | N") = (R*B*SB | R*N*SN),                           (4)
 167.476 +*
 167.477 +*  where SB and SN are parts of the augmented scaling matrix S~, which
 167.478 +*  correspond to basic and non-basic variables, respectively. Therefore
 167.479 +*
 167.480 +*     B" = R*B*SB,                                                   (5)
 167.481 +*
 167.482 +*  which is the scaled basis matrix. */
 167.483 +
 167.484 +void glp_ftran(glp_prob *lp, double x[])
 167.485 +{     int m = lp->m;
 167.486 +      GLPROW **row = lp->row;
 167.487 +      GLPCOL **col = lp->col;
 167.488 +      int i, k;
 167.489 +      /* B*x = b ===> (R*B*SB)*(inv(SB)*x) = R*b ===>
 167.490 +         B"*x" = b", where b" = R*b, x = SB*x" */
 167.491 +      if (!(m == 0 || lp->valid))
 167.492 +         xerror("glp_ftran: basis factorization does not exist\n");
 167.493 +      /* b" := R*b */
 167.494 +      for (i = 1; i <= m; i++)
 167.495 +         x[i] *= row[i]->rii;
 167.496 +      /* x" := inv(B")*b" */
 167.497 +      if (m > 0) bfd_ftran(lp->bfd, x);
 167.498 +      /* x := SB*x" */
 167.499 +      for (i = 1; i <= m; i++)
 167.500 +      {  k = lp->head[i];
 167.501 +         if (k <= m)
 167.502 +            x[i] /= row[k]->rii;
 167.503 +         else
 167.504 +            x[i] *= col[k-m]->sjj;
 167.505 +      }
 167.506 +      return;
 167.507 +}
 167.508 +
 167.509 +/***********************************************************************
 167.510 +*  NAME
 167.511 +*
 167.512 +*  glp_btran - perform backward transformation (solve system B'*x = b)
 167.513 +*
 167.514 +*  SYNOPSIS
 167.515 +*
 167.516 +*  void glp_btran(glp_prob *lp, double x[]);
 167.517 +*
 167.518 +*  DESCRIPTION
 167.519 +*
 167.520 +*  The routine glp_btran performs backward transformation, i.e. solves
 167.521 +*  the system B'*x = b, where B' is a matrix transposed to the basis
 167.522 +*  matrix corresponding to the current basis for the specified problem
 167.523 +*  problem object, x is the vector of unknowns to be computed, b is the
 167.524 +*  vector of right-hand sides.
 167.525 +*
 167.526 +*  On entry elements of the vector b should be stored in dense format
 167.527 +*  in locations x[1], ..., x[m], where m is the number of rows. On exit
 167.528 +*  the routine stores elements of the vector x in the same locations.
 167.529 +*
 167.530 +*  SCALING/UNSCALING
 167.531 +*
 167.532 +*  See comments to the routine glp_ftran. */
 167.533 +
 167.534 +void glp_btran(glp_prob *lp, double x[])
 167.535 +{     int m = lp->m;
 167.536 +      GLPROW **row = lp->row;
 167.537 +      GLPCOL **col = lp->col;
 167.538 +      int i, k;
 167.539 +      /* B'*x = b ===> (SB*B'*R)*(inv(R)*x) = SB*b ===>
 167.540 +         (B")'*x" = b", where b" = SB*b, x = R*x" */
 167.541 +      if (!(m == 0 || lp->valid))
 167.542 +         xerror("glp_btran: basis factorization does not exist\n");
 167.543 +      /* b" := SB*b */
 167.544 +      for (i = 1; i <= m; i++)
 167.545 +      {  k = lp->head[i];
 167.546 +         if (k <= m)
 167.547 +            x[i] /= row[k]->rii;
 167.548 +         else
 167.549 +            x[i] *= col[k-m]->sjj;
 167.550 +      }
 167.551 +      /* x" := inv[(B")']*b" */
 167.552 +      if (m > 0) bfd_btran(lp->bfd, x);
 167.553 +      /* x := R*x" */
 167.554 +      for (i = 1; i <= m; i++)
 167.555 +         x[i] *= row[i]->rii;
 167.556 +      return;
 167.557 +}
 167.558 +
 167.559 +/***********************************************************************
 167.560 +*  NAME
 167.561 +*
 167.562 +*  glp_warm_up - "warm up" LP basis
 167.563 +*
 167.564 +*  SYNOPSIS
 167.565 +*
 167.566 +*  int glp_warm_up(glp_prob *P);
 167.567 +*
 167.568 +*  DESCRIPTION
 167.569 +*
 167.570 +*  The routine glp_warm_up "warms up" the LP basis for the specified
 167.571 +*  problem object using current statuses assigned to rows and columns
 167.572 +*  (that is, to auxiliary and structural variables).
 167.573 +*
 167.574 +*  This operation includes computing factorization of the basis matrix
 167.575 +*  (if it does not exist), computing primal and dual components of basic
 167.576 +*  solution, and determining the solution status.
 167.577 +*
 167.578 +*  RETURNS
 167.579 +*
 167.580 +*  0  The operation has been successfully performed.
 167.581 +*
 167.582 +*  GLP_EBADB
 167.583 +*     The basis matrix is invalid, i.e. the number of basic (auxiliary
 167.584 +*     and structural) variables differs from the number of rows in the
 167.585 +*     problem object.
 167.586 +*
 167.587 +*  GLP_ESING
 167.588 +*     The basis matrix is singular within the working precision.
 167.589 +*
 167.590 +*  GLP_ECOND
 167.591 +*     The basis matrix is ill-conditioned. */
 167.592 +
 167.593 +int glp_warm_up(glp_prob *P)
 167.594 +{     GLPROW *row;
 167.595 +      GLPCOL *col;
 167.596 +      GLPAIJ *aij;
 167.597 +      int i, j, type, ret;
 167.598 +      double eps, temp, *work;
 167.599 +      /* invalidate basic solution */
 167.600 +      P->pbs_stat = P->dbs_stat = GLP_UNDEF;
 167.601 +      P->obj_val = 0.0;
 167.602 +      P->some = 0;
 167.603 +      for (i = 1; i <= P->m; i++)
 167.604 +      {  row = P->row[i];
 167.605 +         row->prim = row->dual = 0.0;
 167.606 +      }
 167.607 +      for (j = 1; j <= P->n; j++)
 167.608 +      {  col = P->col[j];
 167.609 +         col->prim = col->dual = 0.0;
 167.610 +      }
 167.611 +      /* compute the basis factorization, if necessary */
 167.612 +      if (!glp_bf_exists(P))
 167.613 +      {  ret = glp_factorize(P);
 167.614 +         if (ret != 0) goto done;
 167.615 +      }
 167.616 +      /* allocate working array */
 167.617 +      work = xcalloc(1+P->m, sizeof(double));
 167.618 +      /* determine and store values of non-basic variables, compute
 167.619 +         vector (- N * xN) */
 167.620 +      for (i = 1; i <= P->m; i++)
 167.621 +         work[i] = 0.0;
 167.622 +      for (i = 1; i <= P->m; i++)
 167.623 +      {  row = P->row[i];
 167.624 +         if (row->stat == GLP_BS)
 167.625 +            continue;
 167.626 +         else if (row->stat == GLP_NL)
 167.627 +            row->prim = row->lb;
 167.628 +         else if (row->stat == GLP_NU)
 167.629 +            row->prim = row->ub;
 167.630 +         else if (row->stat == GLP_NF)
 167.631 +            row->prim = 0.0;
 167.632 +         else if (row->stat == GLP_NS)
 167.633 +            row->prim = row->lb;
 167.634 +         else
 167.635 +            xassert(row != row);
 167.636 +         /* N[j] is i-th column of matrix (I|-A) */
 167.637 +         work[i] -= row->prim;
 167.638 +      }
 167.639 +      for (j = 1; j <= P->n; j++)
 167.640 +      {  col = P->col[j];
 167.641 +         if (col->stat == GLP_BS)
 167.642 +            continue;
 167.643 +         else if (col->stat == GLP_NL)
 167.644 +            col->prim = col->lb;
 167.645 +         else if (col->stat == GLP_NU)
 167.646 +            col->prim = col->ub;
 167.647 +         else if (col->stat == GLP_NF)
 167.648 +            col->prim = 0.0;
 167.649 +         else if (col->stat == GLP_NS)
 167.650 +            col->prim = col->lb;
 167.651 +         else
 167.652 +            xassert(col != col);
 167.653 +         /* N[j] is (m+j)-th column of matrix (I|-A) */
 167.654 +         if (col->prim != 0.0)
 167.655 +         {  for (aij = col->ptr; aij != NULL; aij = aij->c_next)
 167.656 +               work[aij->row->i] += aij->val * col->prim;
 167.657 +         }
 167.658 +      }
 167.659 +      /* compute vector of basic variables xB = - inv(B) * N * xN */
 167.660 +      glp_ftran(P, work);
 167.661 +      /* store values of basic variables, check primal feasibility */
 167.662 +      P->pbs_stat = GLP_FEAS;
 167.663 +      for (i = 1; i <= P->m; i++)
 167.664 +      {  row = P->row[i];
 167.665 +         if (row->stat != GLP_BS)
 167.666 +            continue;
 167.667 +         row->prim = work[row->bind];
 167.668 +         type = row->type;
 167.669 +         if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
 167.670 +         {  eps = 1e-6 + 1e-9 * fabs(row->lb);
 167.671 +            if (row->prim < row->lb - eps)
 167.672 +               P->pbs_stat = GLP_INFEAS;
 167.673 +         }
 167.674 +         if (type == GLP_UP || type == GLP_DB || type == GLP_FX)
 167.675 +         {  eps = 1e-6 + 1e-9 * fabs(row->ub);
 167.676 +            if (row->prim > row->ub + eps)
 167.677 +               P->pbs_stat = GLP_INFEAS;
 167.678 +         }
 167.679 +      }
 167.680 +      for (j = 1; j <= P->n; j++)
 167.681 +      {  col = P->col[j];
 167.682 +         if (col->stat != GLP_BS)
 167.683 +            continue;
 167.684 +         col->prim = work[col->bind];
 167.685 +         type = col->type;
 167.686 +         if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
 167.687 +         {  eps = 1e-6 + 1e-9 * fabs(col->lb);
 167.688 +            if (col->prim < col->lb - eps)
 167.689 +               P->pbs_stat = GLP_INFEAS;
 167.690 +         }
 167.691 +         if (type == GLP_UP || type == GLP_DB || type == GLP_FX)
 167.692 +         {  eps = 1e-6 + 1e-9 * fabs(col->ub);
 167.693 +            if (col->prim > col->ub + eps)
 167.694 +               P->pbs_stat = GLP_INFEAS;
 167.695 +         }
 167.696 +      }
 167.697 +      /* compute value of the objective function */
 167.698 +      P->obj_val = P->c0;
 167.699 +      for (j = 1; j <= P->n; j++)
 167.700 +      {  col = P->col[j];
 167.701 +         P->obj_val += col->coef * col->prim;
 167.702 +      }
 167.703 +      /* build vector cB of objective coefficients at basic variables */
 167.704 +      for (i = 1; i <= P->m; i++)
 167.705 +         work[i] = 0.0;
 167.706 +      for (j = 1; j <= P->n; j++)
 167.707 +      {  col = P->col[j];
 167.708 +         if (col->stat == GLP_BS)
 167.709 +            work[col->bind] = col->coef;
 167.710 +      }
 167.711 +      /* compute vector of simplex multipliers pi = inv(B') * cB */
 167.712 +      glp_btran(P, work);
 167.713 +      /* compute and store reduced costs of non-basic variables d[j] =
 167.714 +         c[j] - N'[j] * pi, check dual feasibility */
 167.715 +      P->dbs_stat = GLP_FEAS;
 167.716 +      for (i = 1; i <= P->m; i++)
 167.717 +      {  row = P->row[i];
 167.718 +         if (row->stat == GLP_BS)
 167.719 +         {  row->dual = 0.0;
 167.720 +            continue;
 167.721 +         }
 167.722 +         /* N[j] is i-th column of matrix (I|-A) */
 167.723 +         row->dual = - work[i];
 167.724 +         type = row->type;
 167.725 +         temp = (P->dir == GLP_MIN ? + row->dual : - row->dual);
 167.726 +         if ((type == GLP_FR || type == GLP_LO) && temp < -1e-5 ||
 167.727 +             (type == GLP_FR || type == GLP_UP) && temp > +1e-5)
 167.728 +            P->dbs_stat = GLP_INFEAS;
 167.729 +      }
 167.730 +      for (j = 1; j <= P->n; j++)
 167.731 +      {  col = P->col[j];
 167.732 +         if (col->stat == GLP_BS)
 167.733 +         {  col->dual = 0.0;
 167.734 +            continue;
 167.735 +         }
 167.736 +         /* N[j] is (m+j)-th column of matrix (I|-A) */
 167.737 +         col->dual = col->coef;
 167.738 +         for (aij = col->ptr; aij != NULL; aij = aij->c_next)
 167.739 +            col->dual += aij->val * work[aij->row->i];
 167.740 +         type = col->type;
 167.741 +         temp = (P->dir == GLP_MIN ? + col->dual : - col->dual);
 167.742 +         if ((type == GLP_FR || type == GLP_LO) && temp < -1e-5 ||
 167.743 +             (type == GLP_FR || type == GLP_UP) && temp > +1e-5)
 167.744 +            P->dbs_stat = GLP_INFEAS;
 167.745 +      }
 167.746 +      /* free working array */
 167.747 +      xfree(work);
 167.748 +      ret = 0;
 167.749 +done: return ret;
 167.750 +}
 167.751 +
 167.752 +/***********************************************************************
 167.753 +*  NAME
 167.754 +*
 167.755 +*  glp_eval_tab_row - compute row of the simplex tableau
 167.756 +*
 167.757 +*  SYNOPSIS
 167.758 +*
 167.759 +*  int glp_eval_tab_row(glp_prob *lp, int k, int ind[], double val[]);
 167.760 +*
 167.761 +*  DESCRIPTION
 167.762 +*
 167.763 +*  The routine glp_eval_tab_row computes a row of the current simplex
 167.764 +*  tableau for the basic variable, which is specified by the number k:
 167.765 +*  if 1 <= k <= m, x[k] is k-th auxiliary variable; if m+1 <= k <= m+n,
 167.766 +*  x[k] is (k-m)-th structural variable, where m is number of rows, and
 167.767 +*  n is number of columns. The current basis must be available.
 167.768 +*
 167.769 +*  The routine stores column indices and numerical values of non-zero
 167.770 +*  elements of the computed row using sparse format to the locations
 167.771 +*  ind[1], ..., ind[len] and val[1], ..., val[len], respectively, where
 167.772 +*  0 <= len <= n is number of non-zeros returned on exit.
 167.773 +*
 167.774 +*  Element indices stored in the array ind have the same sense as the
 167.775 +*  index k, i.e. indices 1 to m denote auxiliary variables and indices
 167.776 +*  m+1 to m+n denote structural ones (all these variables are obviously
 167.777 +*  non-basic by definition).
 167.778 +*
 167.779 +*  The computed row shows how the specified basic variable x[k] = xB[i]
 167.780 +*  depends on non-basic variables:
 167.781 +*
 167.782 +*     xB[i] = alfa[i,1]*xN[1] + alfa[i,2]*xN[2] + ... + alfa[i,n]*xN[n],
 167.783 +*
 167.784 +*  where alfa[i,j] are elements of the simplex table row, xN[j] are
 167.785 +*  non-basic (auxiliary and structural) variables.
 167.786 +*
 167.787 +*  RETURNS
 167.788 +*
 167.789 +*  The routine returns number of non-zero elements in the simplex table
 167.790 +*  row stored in the arrays ind and val.
 167.791 +*
 167.792 +*  BACKGROUND
 167.793 +*
 167.794 +*  The system of equality constraints of the LP problem is:
 167.795 +*
 167.796 +*     xR = A * xS,                                                   (1)
 167.797 +*
 167.798 +*  where xR is the vector of auxliary variables, xS is the vector of
 167.799 +*  structural variables, A is the matrix of constraint coefficients.
 167.800 +*
 167.801 +*  The system (1) can be written in homogenous form as follows:
 167.802 +*
 167.803 +*     A~ * x = 0,                                                    (2)
 167.804 +*
 167.805 +*  where A~ = (I | -A) is the augmented constraint matrix (has m rows
 167.806 +*  and m+n columns), x = (xR | xS) is the vector of all (auxiliary and
 167.807 +*  structural) variables.
 167.808 +*
 167.809 +*  By definition for the current basis we have:
 167.810 +*
 167.811 +*     A~ = (B | N),                                                  (3)
 167.812 +*
 167.813 +*  where B is the basis matrix. Thus, the system (2) can be written as:
 167.814 +*
 167.815 +*     B * xB + N * xN = 0.                                           (4)
 167.816 +*
 167.817 +*  From (4) it follows that:
 167.818 +*
 167.819 +*     xB = A^ * xN,                                                  (5)
 167.820 +*
 167.821 +*  where the matrix
 167.822 +*
 167.823 +*     A^ = - inv(B) * N                                              (6)
 167.824 +*
 167.825 +*  is called the simplex table.
 167.826 +*
 167.827 +*  It is understood that i-th row of the simplex table is:
 167.828 +*
 167.829 +*     e * A^ = - e * inv(B) * N,                                     (7)
 167.830 +*
 167.831 +*  where e is a unity vector with e[i] = 1.
 167.832 +*
 167.833 +*  To compute i-th row of the simplex table the routine first computes
 167.834 +*  i-th row of the inverse:
 167.835 +*
 167.836 +*     rho = inv(B') * e,                                             (8)
 167.837 +*
 167.838 +*  where B' is a matrix transposed to B, and then computes elements of
 167.839 +*  i-th row of the simplex table as scalar products:
 167.840 +*
 167.841 +*     alfa[i,j] = - rho * N[j]   for all j,                          (9)
 167.842 +*
 167.843 +*  where N[j] is a column of the augmented constraint matrix A~, which
 167.844 +*  corresponds to some non-basic auxiliary or structural variable. */
 167.845 +
 167.846 +int glp_eval_tab_row(glp_prob *lp, int k, int ind[], double val[])
 167.847 +{     int m = lp->m;
 167.848 +      int n = lp->n;
 167.849 +      int i, t, len, lll, *iii;
 167.850 +      double alfa, *rho, *vvv;
 167.851 +      if (!(m == 0 || lp->valid))
 167.852 +         xerror("glp_eval_tab_row: basis factorization does not exist\n"
 167.853 +            );
 167.854 +      if (!(1 <= k && k <= m+n))
 167.855 +         xerror("glp_eval_tab_row: k = %d; variable number out of range"
 167.856 +            , k);
 167.857 +      /* determine xB[i] which corresponds to x[k] */
 167.858 +      if (k <= m)
 167.859 +         i = glp_get_row_bind(lp, k);
 167.860 +      else
 167.861 +         i = glp_get_col_bind(lp, k-m);
 167.862 +      if (i == 0)
 167.863 +         xerror("glp_eval_tab_row: k = %d; variable must be basic", k);
 167.864 +      xassert(1 <= i && i <= m);
 167.865 +      /* allocate working arrays */
 167.866 +      rho = xcalloc(1+m, sizeof(double));
 167.867 +      iii = xcalloc(1+m, sizeof(int));
 167.868 +      vvv = xcalloc(1+m, sizeof(double));
 167.869 +      /* compute i-th row of the inverse; see (8) */
 167.870 +      for (t = 1; t <= m; t++) rho[t] = 0.0;
 167.871 +      rho[i] = 1.0;
 167.872 +      glp_btran(lp, rho);
 167.873 +      /* compute i-th row of the simplex table */
 167.874 +      len = 0;
 167.875 +      for (k = 1; k <= m+n; k++)
 167.876 +      {  if (k <= m)
 167.877 +         {  /* x[k] is auxiliary variable, so N[k] is a unity column */
 167.878 +            if (glp_get_row_stat(lp, k) == GLP_BS) continue;
 167.879 +            /* compute alfa[i,j]; see (9) */
 167.880 +            alfa = - rho[k];
 167.881 +         }
 167.882 +         else
 167.883 +         {  /* x[k] is structural variable, so N[k] is a column of the
 167.884 +               original constraint matrix A with negative sign */
 167.885 +            if (glp_get_col_stat(lp, k-m) == GLP_BS) continue;
 167.886 +            /* compute alfa[i,j]; see (9) */
 167.887 +            lll = glp_get_mat_col(lp, k-m, iii, vvv);
 167.888 +            alfa = 0.0;
 167.889 +            for (t = 1; t <= lll; t++) alfa += rho[iii[t]] * vvv[t];
 167.890 +         }
 167.891 +         /* store alfa[i,j] */
 167.892 +         if (alfa != 0.0) len++, ind[len] = k, val[len] = alfa;
 167.893 +      }
 167.894 +      xassert(len <= n);
 167.895 +      /* free working arrays */
 167.896 +      xfree(rho);
 167.897 +      xfree(iii);
 167.898 +      xfree(vvv);
 167.899 +      /* return to the calling program */
 167.900 +      return len;
 167.901 +}
 167.902 +
 167.903 +/***********************************************************************
 167.904 +*  NAME
 167.905 +*
 167.906 +*  glp_eval_tab_col - compute column of the simplex tableau
 167.907 +*
 167.908 +*  SYNOPSIS
 167.909 +*
 167.910 +*  int glp_eval_tab_col(glp_prob *lp, int k, int ind[], double val[]);
 167.911 +*
 167.912 +*  DESCRIPTION
 167.913 +*
 167.914 +*  The routine glp_eval_tab_col computes a column of the current simplex
 167.915 +*  table for the non-basic variable, which is specified by the number k:
 167.916 +*  if 1 <= k <= m, x[k] is k-th auxiliary variable; if m+1 <= k <= m+n,
 167.917 +*  x[k] is (k-m)-th structural variable, where m is number of rows, and
 167.918 +*  n is number of columns. The current basis must be available.
 167.919 +*
 167.920 +*  The routine stores row indices and numerical values of non-zero
 167.921 +*  elements of the computed column using sparse format to the locations
 167.922 +*  ind[1], ..., ind[len] and val[1], ..., val[len] respectively, where
 167.923 +*  0 <= len <= m is number of non-zeros returned on exit.
 167.924 +*
 167.925 +*  Element indices stored in the array ind have the same sense as the
 167.926 +*  index k, i.e. indices 1 to m denote auxiliary variables and indices
 167.927 +*  m+1 to m+n denote structural ones (all these variables are obviously
 167.928 +*  basic by the definition).
 167.929 +*
 167.930 +*  The computed column shows how basic variables depend on the specified
 167.931 +*  non-basic variable x[k] = xN[j]:
 167.932 +*
 167.933 +*     xB[1] = ... + alfa[1,j]*xN[j] + ...
 167.934 +*     xB[2] = ... + alfa[2,j]*xN[j] + ...
 167.935 +*              . . . . . .
 167.936 +*     xB[m] = ... + alfa[m,j]*xN[j] + ...
 167.937 +*
 167.938 +*  where alfa[i,j] are elements of the simplex table column, xB[i] are
 167.939 +*  basic (auxiliary and structural) variables.
 167.940 +*
 167.941 +*  RETURNS
 167.942 +*
 167.943 +*  The routine returns number of non-zero elements in the simplex table
 167.944 +*  column stored in the arrays ind and val.
 167.945 +*
 167.946 +*  BACKGROUND
 167.947 +*
 167.948 +*  As it was explained in comments to the routine glp_eval_tab_row (see
 167.949 +*  above) the simplex table is the following matrix:
 167.950 +*
 167.951 +*     A^ = - inv(B) * N.                                             (1)
 167.952 +*
 167.953 +*  Therefore j-th column of the simplex table is:
 167.954 +*
 167.955 +*     A^ * e = - inv(B) * N * e = - inv(B) * N[j],                   (2)
 167.956 +*
 167.957 +*  where e is a unity vector with e[j] = 1, B is the basis matrix, N[j]
 167.958 +*  is a column of the augmented constraint matrix A~, which corresponds
 167.959 +*  to the given non-basic auxiliary or structural variable. */
 167.960 +
 167.961 +int glp_eval_tab_col(glp_prob *lp, int k, int ind[], double val[])
 167.962 +{     int m = lp->m;
 167.963 +      int n = lp->n;
 167.964 +      int t, len, stat;
 167.965 +      double *col;
 167.966 +      if (!(m == 0 || lp->valid))
 167.967 +         xerror("glp_eval_tab_col: basis factorization does not exist\n"
 167.968 +            );
 167.969 +      if (!(1 <= k && k <= m+n))
 167.970 +         xerror("glp_eval_tab_col: k = %d; variable number out of range"
 167.971 +            , k);
 167.972 +      if (k <= m)
 167.973 +         stat = glp_get_row_stat(lp, k);
 167.974 +      else
 167.975 +         stat = glp_get_col_stat(lp, k-m);
 167.976 +      if (stat == GLP_BS)
 167.977 +         xerror("glp_eval_tab_col: k = %d; variable must be non-basic",
 167.978 +            k);
 167.979 +      /* obtain column N[k] with negative sign */
 167.980 +      col = xcalloc(1+m, sizeof(double));
 167.981 +      for (t = 1; t <= m; t++) col[t] = 0.0;
 167.982 +      if (k <= m)
 167.983 +      {  /* x[k] is auxiliary variable, so N[k] is a unity column */
 167.984 +         col[k] = -1.0;
 167.985 +      }
 167.986 +      else
 167.987 +      {  /* x[k] is structural variable, so N[k] is a column of the
 167.988 +            original constraint matrix A with negative sign */
 167.989 +         len = glp_get_mat_col(lp, k-m, ind, val);
 167.990 +         for (t = 1; t <= len; t++) col[ind[t]] = val[t];
 167.991 +      }
 167.992 +      /* compute column of the simplex table, which corresponds to the
 167.993 +         specified non-basic variable x[k] */
 167.994 +      glp_ftran(lp, col);
 167.995 +      len = 0;
 167.996 +      for (t = 1; t <= m; t++)
 167.997 +      {  if (col[t] != 0.0)
 167.998 +         {  len++;
 167.999 +            ind[len] = glp_get_bhead(lp, t);
167.1000 +            val[len] = col[t];
167.1001 +         }
167.1002 +      }
167.1003 +      xfree(col);
167.1004 +      /* return to the calling program */
167.1005 +      return len;
167.1006 +}
167.1007 +
167.1008 +/***********************************************************************
167.1009 +*  NAME
167.1010 +*
167.1011 +*  glp_transform_row - transform explicitly specified row
167.1012 +*
167.1013 +*  SYNOPSIS
167.1014 +*
167.1015 +*  int glp_transform_row(glp_prob *P, int len, int ind[], double val[]);
167.1016 +*
167.1017 +*  DESCRIPTION
167.1018 +*
167.1019 +*  The routine glp_transform_row performs the same operation as the
167.1020 +*  routine glp_eval_tab_row with exception that the row to be
167.1021 +*  transformed is specified explicitly as a sparse vector.
167.1022 +*
167.1023 +*  The explicitly specified row may be thought as a linear form:
167.1024 +*
167.1025 +*     x = a[1]*x[m+1] + a[2]*x[m+2] + ... + a[n]*x[m+n],             (1)
167.1026 +*
167.1027 +*  where x is an auxiliary variable for this row, a[j] are coefficients
167.1028 +*  of the linear form, x[m+j] are structural variables.
167.1029 +*
167.1030 +*  On entry column indices and numerical values of non-zero elements of
167.1031 +*  the row should be stored in locations ind[1], ..., ind[len] and
167.1032 +*  val[1], ..., val[len], where len is the number of non-zero elements.
167.1033 +*
167.1034 +*  This routine uses the system of equality constraints and the current
167.1035 +*  basis in order to express the auxiliary variable x in (1) through the
167.1036 +*  current non-basic variables (as if the transformed row were added to
167.1037 +*  the problem object and its auxiliary variable were basic), i.e. the
167.1038 +*  resultant row has the form:
167.1039 +*
167.1040 +*     x = alfa[1]*xN[1] + alfa[2]*xN[2] + ... + alfa[n]*xN[n],       (2)
167.1041 +*
167.1042 +*  where xN[j] are non-basic (auxiliary or structural) variables, n is
167.1043 +*  the number of columns in the LP problem object.
167.1044 +*
167.1045 +*  On exit the routine stores indices and numerical values of non-zero
167.1046 +*  elements of the resultant row (2) in locations ind[1], ..., ind[len']
167.1047 +*  and val[1], ..., val[len'], where 0 <= len' <= n is the number of
167.1048 +*  non-zero elements in the resultant row returned by the routine. Note
167.1049 +*  that indices (numbers) of non-basic variables stored in the array ind
167.1050 +*  correspond to original ordinal numbers of variables: indices 1 to m
167.1051 +*  mean auxiliary variables and indices m+1 to m+n mean structural ones.
167.1052 +*
167.1053 +*  RETURNS
167.1054 +*
167.1055 +*  The routine returns len', which is the number of non-zero elements in
167.1056 +*  the resultant row stored in the arrays ind and val.
167.1057 +*
167.1058 +*  BACKGROUND
167.1059 +*
167.1060 +*  The explicitly specified row (1) is transformed in the same way as it
167.1061 +*  were the objective function row.
167.1062 +*
167.1063 +*  From (1) it follows that:
167.1064 +*
167.1065 +*     x = aB * xB + aN * xN,                                         (3)
167.1066 +*
167.1067 +*  where xB is the vector of basic variables, xN is the vector of
167.1068 +*  non-basic variables.
167.1069 +*
167.1070 +*  The simplex table, which corresponds to the current basis, is:
167.1071 +*
167.1072 +*     xB = [-inv(B) * N] * xN.                                       (4)
167.1073 +*
167.1074 +*  Therefore substituting xB from (4) to (3) we have:
167.1075 +*
167.1076 +*     x = aB * [-inv(B) * N] * xN + aN * xN =
167.1077 +*                                                                    (5)
167.1078 +*       = rho * (-N) * xN + aN * xN = alfa * xN,
167.1079 +*
167.1080 +*  where:
167.1081 +*
167.1082 +*     rho = inv(B') * aB,                                            (6)
167.1083 +*
167.1084 +*  and
167.1085 +*
167.1086 +*     alfa = aN + rho * (-N)                                         (7)
167.1087 +*
167.1088 +*  is the resultant row computed by the routine. */
167.1089 +
167.1090 +int glp_transform_row(glp_prob *P, int len, int ind[], double val[])
167.1091 +{     int i, j, k, m, n, t, lll, *iii;
167.1092 +      double alfa, *a, *aB, *rho, *vvv;
167.1093 +      if (!glp_bf_exists(P))
167.1094 +         xerror("glp_transform_row: basis factorization does not exist "
167.1095 +            "\n");
167.1096 +      m = glp_get_num_rows(P);
167.1097 +      n = glp_get_num_cols(P);
167.1098 +      /* unpack the row to be transformed to the array a */
167.1099 +      a = xcalloc(1+n, sizeof(double));
167.1100 +      for (j = 1; j <= n; j++) a[j] = 0.0;
167.1101 +      if (!(0 <= len && len <= n))
167.1102 +         xerror("glp_transform_row: len = %d; invalid row length\n",
167.1103 +            len);
167.1104 +      for (t = 1; t <= len; t++)
167.1105 +      {  j = ind[t];
167.1106 +         if (!(1 <= j && j <= n))
167.1107 +            xerror("glp_transform_row: ind[%d] = %d; column index out o"
167.1108 +               "f range\n", t, j);
167.1109 +         if (val[t] == 0.0)
167.1110 +            xerror("glp_transform_row: val[%d] = 0; zero coefficient no"
167.1111 +               "t allowed\n", t);
167.1112 +         if (a[j] != 0.0)
167.1113 +            xerror("glp_transform_row: ind[%d] = %d; duplicate column i"
167.1114 +               "ndices not allowed\n", t, j);
167.1115 +         a[j] = val[t];
167.1116 +      }
167.1117 +      /* construct the vector aB */
167.1118 +      aB = xcalloc(1+m, sizeof(double));
167.1119 +      for (i = 1; i <= m; i++)
167.1120 +      {  k = glp_get_bhead(P, i);
167.1121 +         /* xB[i] is k-th original variable */
167.1122 +         xassert(1 <= k && k <= m+n);
167.1123 +         aB[i] = (k <= m ? 0.0 : a[k-m]);
167.1124 +      }
167.1125 +      /* solve the system B'*rho = aB to compute the vector rho */
167.1126 +      rho = aB, glp_btran(P, rho);
167.1127 +      /* compute coefficients at non-basic auxiliary variables */
167.1128 +      len = 0;
167.1129 +      for (i = 1; i <= m; i++)
167.1130 +      {  if (glp_get_row_stat(P, i) != GLP_BS)
167.1131 +         {  alfa = - rho[i];
167.1132 +            if (alfa != 0.0)
167.1133 +            {  len++;
167.1134 +               ind[len] = i;
167.1135 +               val[len] = alfa;
167.1136 +            }
167.1137 +         }
167.1138 +      }
167.1139 +      /* compute coefficients at non-basic structural variables */
167.1140 +      iii = xcalloc(1+m, sizeof(int));
167.1141 +      vvv = xcalloc(1+m, sizeof(double));
167.1142 +      for (j = 1; j <= n; j++)
167.1143 +      {  if (glp_get_col_stat(P, j) != GLP_BS)
167.1144 +         {  alfa = a[j];
167.1145 +            lll = glp_get_mat_col(P, j, iii, vvv);
167.1146 +            for (t = 1; t <= lll; t++) alfa += vvv[t] * rho[iii[t]];
167.1147 +            if (alfa != 0.0)
167.1148 +            {  len++;
167.1149 +               ind[len] = m+j;
167.1150 +               val[len] = alfa;
167.1151 +            }
167.1152 +         }
167.1153 +      }
167.1154 +      xassert(len <= n);
167.1155 +      xfree(iii);
167.1156 +      xfree(vvv);
167.1157 +      xfree(aB);
167.1158 +      xfree(a);
167.1159 +      return len;
167.1160 +}
167.1161 +
167.1162 +/***********************************************************************
167.1163 +*  NAME
167.1164 +*
167.1165 +*  glp_transform_col - transform explicitly specified column
167.1166 +*
167.1167 +*  SYNOPSIS
167.1168 +*
167.1169 +*  int glp_transform_col(glp_prob *P, int len, int ind[], double val[]);
167.1170 +*
167.1171 +*  DESCRIPTION
167.1172 +*
167.1173 +*  The routine glp_transform_col performs the same operation as the
167.1174 +*  routine glp_eval_tab_col with exception that the column to be
167.1175 +*  transformed is specified explicitly as a sparse vector.
167.1176 +*
167.1177 +*  The explicitly specified column may be thought as if it were added
167.1178 +*  to the original system of equality constraints:
167.1179 +*
167.1180 +*     x[1] = a[1,1]*x[m+1] + ... + a[1,n]*x[m+n] + a[1]*x
167.1181 +*     x[2] = a[2,1]*x[m+1] + ... + a[2,n]*x[m+n] + a[2]*x            (1)
167.1182 +*        .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
167.1183 +*     x[m] = a[m,1]*x[m+1] + ... + a[m,n]*x[m+n] + a[m]*x
167.1184 +*
167.1185 +*  where x[i] are auxiliary variables, x[m+j] are structural variables,
167.1186 +*  x is a structural variable for the explicitly specified column, a[i]
167.1187 +*  are constraint coefficients for x.
167.1188 +*
167.1189 +*  On entry row indices and numerical values of non-zero elements of
167.1190 +*  the column should be stored in locations ind[1], ..., ind[len] and
167.1191 +*  val[1], ..., val[len], where len is the number of non-zero elements.
167.1192 +*
167.1193 +*  This routine uses the system of equality constraints and the current
167.1194 +*  basis in order to express the current basic variables through the
167.1195 +*  structural variable x in (1) (as if the transformed column were added
167.1196 +*  to the problem object and the variable x were non-basic), i.e. the
167.1197 +*  resultant column has the form:
167.1198 +*
167.1199 +*     xB[1] = ... + alfa[1]*x
167.1200 +*     xB[2] = ... + alfa[2]*x                                        (2)
167.1201 +*        .  .  .  .  .  .
167.1202 +*     xB[m] = ... + alfa[m]*x
167.1203 +*
167.1204 +*  where xB are basic (auxiliary and structural) variables, m is the
167.1205 +*  number of rows in the problem object.
167.1206 +*
167.1207 +*  On exit the routine stores indices and numerical values of non-zero
167.1208 +*  elements of the resultant column (2) in locations ind[1], ...,
167.1209 +*  ind[len'] and val[1], ..., val[len'], where 0 <= len' <= m is the
167.1210 +*  number of non-zero element in the resultant column returned by the
167.1211 +*  routine. Note that indices (numbers) of basic variables stored in
167.1212 +*  the array ind correspond to original ordinal numbers of variables:
167.1213 +*  indices 1 to m mean auxiliary variables and indices m+1 to m+n mean
167.1214 +*  structural ones.
167.1215 +*
167.1216 +*  RETURNS
167.1217 +*
167.1218 +*  The routine returns len', which is the number of non-zero elements
167.1219 +*  in the resultant column stored in the arrays ind and val.
167.1220 +*
167.1221 +*  BACKGROUND
167.1222 +*
167.1223 +*  The explicitly specified column (1) is transformed in the same way
167.1224 +*  as any other column of the constraint matrix using the formula:
167.1225 +*
167.1226 +*     alfa = inv(B) * a,                                             (3)
167.1227 +*
167.1228 +*  where alfa is the resultant column computed by the routine. */
167.1229 +
167.1230 +int glp_transform_col(glp_prob *P, int len, int ind[], double val[])
167.1231 +{     int i, m, t;
167.1232 +      double *a, *alfa;
167.1233 +      if (!glp_bf_exists(P))
167.1234 +         xerror("glp_transform_col: basis factorization does not exist "
167.1235 +            "\n");
167.1236 +      m = glp_get_num_rows(P);
167.1237 +      /* unpack the column to be transformed to the array a */
167.1238 +      a = xcalloc(1+m, sizeof(double));
167.1239 +      for (i = 1; i <= m; i++) a[i] = 0.0;
167.1240 +      if (!(0 <= len && len <= m))
167.1241 +         xerror("glp_transform_col: len = %d; invalid column length\n",
167.1242 +            len);
167.1243 +      for (t = 1; t <= len; t++)
167.1244 +      {  i = ind[t];
167.1245 +         if (!(1 <= i && i <= m))
167.1246 +            xerror("glp_transform_col: ind[%d] = %d; row index out of r"
167.1247 +               "ange\n", t, i);
167.1248 +         if (val[t] == 0.0)
167.1249 +            xerror("glp_transform_col: val[%d] = 0; zero coefficient no"
167.1250 +               "t allowed\n", t);
167.1251 +         if (a[i] != 0.0)
167.1252 +            xerror("glp_transform_col: ind[%d] = %d; duplicate row indi"
167.1253 +               "ces not allowed\n", t, i);
167.1254 +         a[i] = val[t];
167.1255 +      }
167.1256 +      /* solve the system B*a = alfa to compute the vector alfa */
167.1257 +      alfa = a, glp_ftran(P, alfa);
167.1258 +      /* store resultant coefficients */
167.1259 +      len = 0;
167.1260 +      for (i = 1; i <= m; i++)
167.1261 +      {  if (alfa[i] != 0.0)
167.1262 +         {  len++;
167.1263 +            ind[len] = glp_get_bhead(P, i);
167.1264 +            val[len] = alfa[i];
167.1265 +         }
167.1266 +      }
167.1267 +      xfree(a);
167.1268 +      return len;
167.1269 +}
167.1270 +
167.1271 +/***********************************************************************
167.1272 +*  NAME
167.1273 +*
167.1274 +*  glp_prim_rtest - perform primal ratio test
167.1275 +*
167.1276 +*  SYNOPSIS
167.1277 +*
167.1278 +*  int glp_prim_rtest(glp_prob *P, int len, const int ind[],
167.1279 +*     const double val[], int dir, double eps);
167.1280 +*
167.1281 +*  DESCRIPTION
167.1282 +*
167.1283 +*  The routine glp_prim_rtest performs the primal ratio test using an
167.1284 +*  explicitly specified column of the simplex table.
167.1285 +*
167.1286 +*  The current basic solution associated with the LP problem object
167.1287 +*  must be primal feasible.
167.1288 +*
167.1289 +*  The explicitly specified column of the simplex table shows how the
167.1290 +*  basic variables xB depend on some non-basic variable x (which is not
167.1291 +*  necessarily presented in the problem object):
167.1292 +*
167.1293 +*     xB[1] = ... + alfa[1] * x + ...
167.1294 +*     xB[2] = ... + alfa[2] * x + ...                                (*)
167.1295 +*         .  .  .  .  .  .  .  .
167.1296 +*     xB[m] = ... + alfa[m] * x + ...
167.1297 +*
167.1298 +*  The column (*) is specifed on entry to the routine using the sparse
167.1299 +*  format. Ordinal numbers of basic variables xB[i] should be placed in
167.1300 +*  locations ind[1], ..., ind[len], where ordinal number 1 to m denote
167.1301 +*  auxiliary variables, and ordinal numbers m+1 to m+n denote structural
167.1302 +*  variables. The corresponding non-zero coefficients alfa[i] should be
167.1303 +*  placed in locations val[1], ..., val[len]. The arrays ind and val are
167.1304 +*  not changed on exit.
167.1305 +*
167.1306 +*  The parameter dir specifies direction in which the variable x changes
167.1307 +*  on entering the basis: +1 means increasing, -1 means decreasing.
167.1308 +*
167.1309 +*  The parameter eps is an absolute tolerance (small positive number)
167.1310 +*  used by the routine to skip small alfa[j] of the row (*).
167.1311 +*
167.1312 +*  The routine determines which basic variable (among specified in
167.1313 +*  ind[1], ..., ind[len]) should leave the basis in order to keep primal
167.1314 +*  feasibility.
167.1315 +*
167.1316 +*  RETURNS
167.1317 +*
167.1318 +*  The routine glp_prim_rtest returns the index piv in the arrays ind
167.1319 +*  and val corresponding to the pivot element chosen, 1 <= piv <= len.
167.1320 +*  If the adjacent basic solution is primal unbounded and therefore the
167.1321 +*  choice cannot be made, the routine returns zero.
167.1322 +*
167.1323 +*  COMMENTS
167.1324 +*
167.1325 +*  If the non-basic variable x is presented in the LP problem object,
167.1326 +*  the column (*) can be computed with the routine glp_eval_tab_col;
167.1327 +*  otherwise it can be computed with the routine glp_transform_col. */
167.1328 +
167.1329 +int glp_prim_rtest(glp_prob *P, int len, const int ind[],
167.1330 +      const double val[], int dir, double eps)
167.1331 +{     int k, m, n, piv, t, type, stat;
167.1332 +      double alfa, big, beta, lb, ub, temp, teta;
167.1333 +      if (glp_get_prim_stat(P) != GLP_FEAS)
167.1334 +         xerror("glp_prim_rtest: basic solution is not primal feasible "
167.1335 +            "\n");
167.1336 +      if (!(dir == +1 || dir == -1))
167.1337 +         xerror("glp_prim_rtest: dir = %d; invalid parameter\n", dir);
167.1338 +      if (!(0.0 < eps && eps < 1.0))
167.1339 +         xerror("glp_prim_rtest: eps = %g; invalid parameter\n", eps);
167.1340 +      m = glp_get_num_rows(P);
167.1341 +      n = glp_get_num_cols(P);
167.1342 +      /* initial settings */
167.1343 +      piv = 0, teta = DBL_MAX, big = 0.0;
167.1344 +      /* walk through the entries of the specified column */
167.1345 +      for (t = 1; t <= len; t++)
167.1346 +      {  /* get the ordinal number of basic variable */
167.1347 +         k = ind[t];
167.1348 +         if (!(1 <= k && k <= m+n))
167.1349 +            xerror("glp_prim_rtest: ind[%d] = %d; variable number out o"
167.1350 +               "f range\n", t, k);
167.1351 +         /* determine type, bounds, status and primal value of basic
167.1352 +            variable xB[i] = x[k] in the current basic solution */
167.1353 +         if (k <= m)
167.1354 +         {  type = glp_get_row_type(P, k);
167.1355 +            lb = glp_get_row_lb(P, k);
167.1356 +            ub = glp_get_row_ub(P, k);
167.1357 +            stat = glp_get_row_stat(P, k);
167.1358 +            beta = glp_get_row_prim(P, k);
167.1359 +         }
167.1360 +         else
167.1361 +         {  type = glp_get_col_type(P, k-m);
167.1362 +            lb = glp_get_col_lb(P, k-m);
167.1363 +            ub = glp_get_col_ub(P, k-m);
167.1364 +            stat = glp_get_col_stat(P, k-m);
167.1365 +            beta = glp_get_col_prim(P, k-m);
167.1366 +         }
167.1367 +         if (stat != GLP_BS)
167.1368 +            xerror("glp_prim_rtest: ind[%d] = %d; non-basic variable no"
167.1369 +               "t allowed\n", t, k);
167.1370 +         /* determine influence coefficient at basic variable xB[i]
167.1371 +            in the explicitly specified column and turn to the case of
167.1372 +            increasing the variable x in order to simplify the program
167.1373 +            logic */
167.1374 +         alfa = (dir > 0 ? + val[t] : - val[t]);
167.1375 +         /* analyze main cases */
167.1376 +         if (type == GLP_FR)
167.1377 +         {  /* xB[i] is free variable */
167.1378 +            continue;
167.1379 +         }
167.1380 +         else if (type == GLP_LO)
167.1381 +lo:      {  /* xB[i] has an lower bound */
167.1382 +            if (alfa > - eps) continue;
167.1383 +            temp = (lb - beta) / alfa;
167.1384 +         }
167.1385 +         else if (type == GLP_UP)
167.1386 +up:      {  /* xB[i] has an upper bound */
167.1387 +            if (alfa < + eps) continue;
167.1388 +            temp = (ub - beta) / alfa;
167.1389 +         }
167.1390 +         else if (type == GLP_DB)
167.1391 +         {  /* xB[i] has both lower and upper bounds */
167.1392 +            if (alfa < 0.0) goto lo; else goto up;
167.1393 +         }
167.1394 +         else if (type == GLP_FX)
167.1395 +         {  /* xB[i] is fixed variable */
167.1396 +            if (- eps < alfa && alfa < + eps) continue;
167.1397 +            temp = 0.0;
167.1398 +         }
167.1399 +         else
167.1400 +            xassert(type != type);
167.1401 +         /* if the value of the variable xB[i] violates its lower or
167.1402 +            upper bound (slightly, because the current basis is assumed
167.1403 +            to be primal feasible), temp is negative; we can think this
167.1404 +            happens due to round-off errors and the value is exactly on
167.1405 +            the bound; this allows replacing temp by zero */
167.1406 +         if (temp < 0.0) temp = 0.0;
167.1407 +         /* apply the minimal ratio test */
167.1408 +         if (teta > temp || teta == temp && big < fabs(alfa))
167.1409 +            piv = t, teta = temp, big = fabs(alfa);
167.1410 +      }
167.1411 +      /* return index of the pivot element chosen */
167.1412 +      return piv;
167.1413 +}
167.1414 +
167.1415 +/***********************************************************************
167.1416 +*  NAME
167.1417 +*
167.1418 +*  glp_dual_rtest - perform dual ratio test
167.1419 +*
167.1420 +*  SYNOPSIS
167.1421 +*
167.1422 +*  int glp_dual_rtest(glp_prob *P, int len, const int ind[],
167.1423 +*     const double val[], int dir, double eps);
167.1424 +*
167.1425 +*  DESCRIPTION
167.1426 +*
167.1427 +*  The routine glp_dual_rtest performs the dual ratio test using an
167.1428 +*  explicitly specified row of the simplex table.
167.1429 +*
167.1430 +*  The current basic solution associated with the LP problem object
167.1431 +*  must be dual feasible.
167.1432 +*
167.1433 +*  The explicitly specified row of the simplex table is a linear form
167.1434 +*  that shows how some basic variable x (which is not necessarily
167.1435 +*  presented in the problem object) depends on non-basic variables xN:
167.1436 +*
167.1437 +*     x = alfa[1] * xN[1] + alfa[2] * xN[2] + ... + alfa[n] * xN[n]. (*)
167.1438 +*
167.1439 +*  The row (*) is specified on entry to the routine using the sparse
167.1440 +*  format. Ordinal numbers of non-basic variables xN[j] should be placed
167.1441 +*  in locations ind[1], ..., ind[len], where ordinal numbers 1 to m
167.1442 +*  denote auxiliary variables, and ordinal numbers m+1 to m+n denote
167.1443 +*  structural variables. The corresponding non-zero coefficients alfa[j]
167.1444 +*  should be placed in locations val[1], ..., val[len]. The arrays ind
167.1445 +*  and val are not changed on exit.
167.1446 +*
167.1447 +*  The parameter dir specifies direction in which the variable x changes
167.1448 +*  on leaving the basis: +1 means that x goes to its lower bound, and -1
167.1449 +*  means that x goes to its upper bound.
167.1450 +*
167.1451 +*  The parameter eps is an absolute tolerance (small positive number)
167.1452 +*  used by the routine to skip small alfa[j] of the row (*).
167.1453 +*
167.1454 +*  The routine determines which non-basic variable (among specified in
167.1455 +*  ind[1], ..., ind[len]) should enter the basis in order to keep dual
167.1456 +*  feasibility.
167.1457 +*
167.1458 +*  RETURNS
167.1459 +*
167.1460 +*  The routine glp_dual_rtest returns the index piv in the arrays ind
167.1461 +*  and val corresponding to the pivot element chosen, 1 <= piv <= len.
167.1462 +*  If the adjacent basic solution is dual unbounded and therefore the
167.1463 +*  choice cannot be made, the routine returns zero.
167.1464 +*
167.1465 +*  COMMENTS
167.1466 +*
167.1467 +*  If the basic variable x is presented in the LP problem object, the
167.1468 +*  row (*) can be computed with the routine glp_eval_tab_row; otherwise
167.1469 +*  it can be computed with the routine glp_transform_row. */
167.1470 +
167.1471 +int glp_dual_rtest(glp_prob *P, int len, const int ind[],
167.1472 +      const double val[], int dir, double eps)
167.1473 +{     int k, m, n, piv, t, stat;
167.1474 +      double alfa, big, cost, obj, temp, teta;
167.1475 +      if (glp_get_dual_stat(P) != GLP_FEAS)
167.1476 +         xerror("glp_dual_rtest: basic solution is not dual feasible\n")
167.1477 +            ;
167.1478 +      if (!(dir == +1 || dir == -1))
167.1479 +         xerror("glp_dual_rtest: dir = %d; invalid parameter\n", dir);
167.1480 +      if (!(0.0 < eps && eps < 1.0))
167.1481 +         xerror("glp_dual_rtest: eps = %g; invalid parameter\n", eps);
167.1482 +      m = glp_get_num_rows(P);
167.1483 +      n = glp_get_num_cols(P);
167.1484 +      /* take into account optimization direction */
167.1485 +      obj = (glp_get_obj_dir(P) == GLP_MIN ? +1.0 : -1.0);
167.1486 +      /* initial settings */
167.1487 +      piv = 0, teta = DBL_MAX, big = 0.0;
167.1488 +      /* walk through the entries of the specified row */
167.1489 +      for (t = 1; t <= len; t++)
167.1490 +      {  /* get ordinal number of non-basic variable */
167.1491 +         k = ind[t];
167.1492 +         if (!(1 <= k && k <= m+n))
167.1493 +            xerror("glp_dual_rtest: ind[%d] = %d; variable number out o"
167.1494 +               "f range\n", t, k);
167.1495 +         /* determine status and reduced cost of non-basic variable
167.1496 +            x[k] = xN[j] in the current basic solution */
167.1497 +         if (k <= m)
167.1498 +         {  stat = glp_get_row_stat(P, k);
167.1499 +            cost = glp_get_row_dual(P, k);
167.1500 +         }
167.1501 +         else
167.1502 +         {  stat = glp_get_col_stat(P, k-m);
167.1503 +            cost = glp_get_col_dual(P, k-m);
167.1504 +         }
167.1505 +         if (stat == GLP_BS)
167.1506 +            xerror("glp_dual_rtest: ind[%d] = %d; basic variable not al"
167.1507 +               "lowed\n", t, k);
167.1508 +         /* determine influence coefficient at non-basic variable xN[j]
167.1509 +            in the explicitly specified row and turn to the case of
167.1510 +            increasing the variable x in order to simplify the program
167.1511 +            logic */
167.1512 +         alfa = (dir > 0 ? + val[t] : - val[t]);
167.1513 +         /* analyze main cases */
167.1514 +         if (stat == GLP_NL)
167.1515 +         {  /* xN[j] is on its lower bound */
167.1516 +            if (alfa < + eps) continue;
167.1517 +            temp = (obj * cost) / alfa;
167.1518 +         }
167.1519 +         else if (stat == GLP_NU)
167.1520 +         {  /* xN[j] is on its upper bound */
167.1521 +            if (alfa > - eps) continue;
167.1522 +            temp = (obj * cost) / alfa;
167.1523 +         }
167.1524 +         else if (stat == GLP_NF)
167.1525 +         {  /* xN[j] is non-basic free variable */
167.1526 +            if (- eps < alfa && alfa < + eps) continue;
167.1527 +            temp = 0.0;
167.1528 +         }
167.1529 +         else if (stat == GLP_NS)
167.1530 +         {  /* xN[j] is non-basic fixed variable */
167.1531 +            continue;
167.1532 +         }
167.1533 +         else
167.1534 +            xassert(stat != stat);
167.1535 +         /* if the reduced cost of the variable xN[j] violates its zero
167.1536 +            bound (slightly, because the current basis is assumed to be
167.1537 +            dual feasible), temp is negative; we can think this happens
167.1538 +            due to round-off errors and the reduced cost is exact zero;
167.1539 +            this allows replacing temp by zero */
167.1540 +         if (temp < 0.0) temp = 0.0;
167.1541 +         /* apply the minimal ratio test */
167.1542 +         if (teta > temp || teta == temp && big < fabs(alfa))
167.1543 +            piv = t, teta = temp, big = fabs(alfa);
167.1544 +      }
167.1545 +      /* return index of the pivot element chosen */
167.1546 +      return piv;
167.1547 +}
167.1548 +
167.1549 +/***********************************************************************
167.1550 +*  NAME
167.1551 +*
167.1552 +*  glp_analyze_row - simulate one iteration of dual simplex method
167.1553 +*
167.1554 +*  SYNOPSIS
167.1555 +*
167.1556 +*  int glp_analyze_row(glp_prob *P, int len, const int ind[],
167.1557 +*     const double val[], int type, double rhs, double eps, int *piv,
167.1558 +*     double *x, double *dx, double *y, double *dy, double *dz);
167.1559 +*
167.1560 +*  DESCRIPTION
167.1561 +*
167.1562 +*  Let the current basis be optimal or dual feasible, and there be
167.1563 +*  specified a row (constraint), which is violated by the current basic
167.1564 +*  solution. The routine glp_analyze_row simulates one iteration of the
167.1565 +*  dual simplex method to determine some information on the adjacent
167.1566 +*  basis (see below), where the specified row becomes active constraint
167.1567 +*  (i.e. its auxiliary variable becomes non-basic).
167.1568 +*
167.1569 +*  The current basic solution associated with the problem object passed
167.1570 +*  to the routine must be dual feasible, and its primal components must
167.1571 +*  be defined.
167.1572 +*
167.1573 +*  The row to be analyzed must be previously transformed either with
167.1574 +*  the routine glp_eval_tab_row (if the row is in the problem object)
167.1575 +*  or with the routine glp_transform_row (if the row is external, i.e.
167.1576 +*  not in the problem object). This is needed to express the row only
167.1577 +*  through (auxiliary and structural) variables, which are non-basic in
167.1578 +*  the current basis:
167.1579 +*
167.1580 +*     y = alfa[1] * xN[1] + alfa[2] * xN[2] + ... + alfa[n] * xN[n],
167.1581 +*
167.1582 +*  where y is an auxiliary variable of the row, alfa[j] is an influence
167.1583 +*  coefficient, xN[j] is a non-basic variable.
167.1584 +*
167.1585 +*  The row is passed to the routine in sparse format. Ordinal numbers
167.1586 +*  of non-basic variables are stored in locations ind[1], ..., ind[len],
167.1587 +*  where numbers 1 to m denote auxiliary variables while numbers m+1 to
167.1588 +*  m+n denote structural variables. Corresponding non-zero coefficients
167.1589 +*  alfa[j] are stored in locations val[1], ..., val[len]. The arrays
167.1590 +*  ind and val are ot changed on exit.
167.1591 +*
167.1592 +*  The parameters type and rhs specify the row type and its right-hand
167.1593 +*  side as follows:
167.1594 +*
167.1595 +*     type = GLP_LO: y = sum alfa[j] * xN[j] >= rhs
167.1596 +*
167.1597 +*     type = GLP_UP: y = sum alfa[j] * xN[j] <= rhs
167.1598 +*
167.1599 +*  The parameter eps is an absolute tolerance (small positive number)
167.1600 +*  used by the routine to skip small coefficients alfa[j] on performing
167.1601 +*  the dual ratio test.
167.1602 +*
167.1603 +*  If the operation was successful, the routine stores the following
167.1604 +*  information to corresponding location (if some parameter is NULL,
167.1605 +*  its value is not stored):
167.1606 +*
167.1607 +*  piv   index in the array ind and val, 1 <= piv <= len, determining
167.1608 +*        the non-basic variable, which would enter the adjacent basis;
167.1609 +*
167.1610 +*  x     value of the non-basic variable in the current basis;
167.1611 +*
167.1612 +*  dx    difference between values of the non-basic variable in the
167.1613 +*        adjacent and current bases, dx = x.new - x.old;
167.1614 +*
167.1615 +*  y     value of the row (i.e. of its auxiliary variable) in the
167.1616 +*        current basis;
167.1617 +*
167.1618 +*  dy    difference between values of the row in the adjacent and
167.1619 +*        current bases, dy = y.new - y.old;
167.1620 +*
167.1621 +*  dz    difference between values of the objective function in the
167.1622 +*        adjacent and current bases, dz = z.new - z.old. Note that in
167.1623 +*        case of minimization dz >= 0, and in case of maximization
167.1624 +*        dz <= 0, i.e. in the adjacent basis the objective function
167.1625 +*        always gets worse (degrades). */
167.1626 +
167.1627 +int _glp_analyze_row(glp_prob *P, int len, const int ind[],
167.1628 +      const double val[], int type, double rhs, double eps, int *_piv,
167.1629 +      double *_x, double *_dx, double *_y, double *_dy, double *_dz)
167.1630 +{     int t, k, dir, piv, ret = 0;
167.1631 +      double x, dx, y, dy, dz;
167.1632 +      if (P->pbs_stat == GLP_UNDEF)
167.1633 +         xerror("glp_analyze_row: primal basic solution components are "
167.1634 +            "undefined\n");
167.1635 +      if (P->dbs_stat != GLP_FEAS)
167.1636 +         xerror("glp_analyze_row: basic solution is not dual feasible\n"
167.1637 +            );
167.1638 +      /* compute the row value y = sum alfa[j] * xN[j] in the current
167.1639 +         basis */
167.1640 +      if (!(0 <= len && len <= P->n))
167.1641 +         xerror("glp_analyze_row: len = %d; invalid row length\n", len);
167.1642 +      y = 0.0;
167.1643 +      for (t = 1; t <= len; t++)
167.1644 +      {  /* determine value of x[k] = xN[j] in the current basis */
167.1645 +         k = ind[t];
167.1646 +         if (!(1 <= k && k <= P->m+P->n))
167.1647 +            xerror("glp_analyze_row: ind[%d] = %d; row/column index out"
167.1648 +               " of range\n", t, k);
167.1649 +         if (k <= P->m)
167.1650 +         {  /* x[k] is auxiliary variable */
167.1651 +            if (P->row[k]->stat == GLP_BS)
167.1652 +               xerror("glp_analyze_row: ind[%d] = %d; basic auxiliary v"
167.1653 +                  "ariable is not allowed\n", t, k);
167.1654 +            x = P->row[k]->prim;
167.1655 +         }
167.1656 +         else
167.1657 +         {  /* x[k] is structural variable */
167.1658 +            if (P->col[k-P->m]->stat == GLP_BS)
167.1659 +               xerror("glp_analyze_row: ind[%d] = %d; basic structural "
167.1660 +                  "variable is not allowed\n", t, k);
167.1661 +            x = P->col[k-P->m]->prim;
167.1662 +         }
167.1663 +         y += val[t] * x;
167.1664 +      }
167.1665 +      /* check if the row is primal infeasible in the current basis,
167.1666 +         i.e. the constraint is violated at the current point */
167.1667 +      if (type == GLP_LO)
167.1668 +      {  if (y >= rhs)
167.1669 +         {  /* the constraint is not violated */
167.1670 +            ret = 1;
167.1671 +            goto done;
167.1672 +         }
167.1673 +         /* in the adjacent basis y goes to its lower bound */
167.1674 +         dir = +1;
167.1675 +      }
167.1676 +      else if (type == GLP_UP)
167.1677 +      {  if (y <= rhs)
167.1678 +         {  /* the constraint is not violated */
167.1679 +            ret = 1;
167.1680 +            goto done;
167.1681 +         }
167.1682 +         /* in the adjacent basis y goes to its upper bound */
167.1683 +         dir = -1;
167.1684 +      }
167.1685 +      else
167.1686 +         xerror("glp_analyze_row: type = %d; invalid parameter\n",
167.1687 +            type);
167.1688 +      /* compute dy = y.new - y.old */
167.1689 +      dy = rhs - y;
167.1690 +      /* perform dual ratio test to determine which non-basic variable
167.1691 +         should enter the adjacent basis to keep it dual feasible */
167.1692 +      piv = glp_dual_rtest(P, len, ind, val, dir, eps);
167.1693 +      if (piv == 0)
167.1694 +      {  /* no dual feasible adjacent basis exists */
167.1695 +         ret = 2;
167.1696 +         goto done;
167.1697 +      }
167.1698 +      /* non-basic variable x[k] = xN[j] should enter the basis */
167.1699 +      k = ind[piv];
167.1700 +      xassert(1 <= k && k <= P->m+P->n);
167.1701 +      /* determine its value in the current basis */
167.1702 +      if (k <= P->m)
167.1703 +         x = P->row[k]->prim;
167.1704 +      else
167.1705 +         x = P->col[k-P->m]->prim;
167.1706 +      /* compute dx = x.new - x.old = dy / alfa[j] */
167.1707 +      xassert(val[piv] != 0.0);
167.1708 +      dx = dy / val[piv];
167.1709 +      /* compute dz = z.new - z.old = d[j] * dx, where d[j] is reduced
167.1710 +         cost of xN[j] in the current basis */
167.1711 +      if (k <= P->m)
167.1712 +         dz = P->row[k]->dual * dx;
167.1713 +      else
167.1714 +         dz = P->col[k-P->m]->dual * dx;
167.1715 +      /* store the analysis results */
167.1716 +      if (_piv != NULL) *_piv = piv;
167.1717 +      if (_x   != NULL) *_x   = x;
167.1718 +      if (_dx  != NULL) *_dx  = dx;
167.1719 +      if (_y   != NULL) *_y   = y;
167.1720 +      if (_dy  != NULL) *_dy  = dy;
167.1721 +      if (_dz  != NULL) *_dz  = dz;
167.1722 +done: return ret;
167.1723 +}
167.1724 +
167.1725 +#if 0
167.1726 +int main(void)
167.1727 +{     /* example program for the routine glp_analyze_row */
167.1728 +      glp_prob *P;
167.1729 +      glp_smcp parm;
167.1730 +      int i, k, len, piv, ret, ind[1+100];
167.1731 +      double rhs, x, dx, y, dy, dz, val[1+100];
167.1732 +      P = glp_create_prob();
167.1733 +      /* read plan.mps (see glpk/examples) */
167.1734 +      ret = glp_read_mps(P, GLP_MPS_DECK, NULL, "plan.mps");
167.1735 +      glp_assert(ret == 0);
167.1736 +      /* and solve it to optimality */
167.1737 +      ret = glp_simplex(P, NULL);
167.1738 +      glp_assert(ret == 0);
167.1739 +      glp_assert(glp_get_status(P) == GLP_OPT);
167.1740 +      /* the optimal objective value is 296.217 */
167.1741 +      /* we would like to know what happens if we would add a new row
167.1742 +         (constraint) to plan.mps:
167.1743 +         .01 * bin1 + .01 * bin2 + .02 * bin4 + .02 * bin5 <= 12 */
167.1744 +      /* first, we specify this new row */
167.1745 +      glp_create_index(P);
167.1746 +      len = 0;
167.1747 +      ind[++len] = glp_find_col(P, "BIN1"), val[len] = .01;
167.1748 +      ind[++len] = glp_find_col(P, "BIN2"), val[len] = .01;
167.1749 +      ind[++len] = glp_find_col(P, "BIN4"), val[len] = .02;
167.1750 +      ind[++len] = glp_find_col(P, "BIN5"), val[len] = .02;
167.1751 +      rhs = 12;
167.1752 +      /* then we can compute value of the row (i.e. of its auxiliary
167.1753 +         variable) in the current basis to see if the constraint is
167.1754 +         violated */
167.1755 +      y = 0.0;
167.1756 +      for (k = 1; k <= len; k++)
167.1757 +         y += val[k] * glp_get_col_prim(P, ind[k]);
167.1758 +      glp_printf("y = %g\n", y);
167.1759 +      /* this prints y = 15.1372, so the constraint is violated, since
167.1760 +         we require that y <= rhs = 12 */
167.1761 +      /* now we transform the row to express it only through non-basic
167.1762 +         (auxiliary and artificial) variables */
167.1763 +      len = glp_transform_row(P, len, ind, val);
167.1764 +      /* finally, we simulate one step of the dual simplex method to
167.1765 +         obtain necessary information for the adjacent basis */
167.1766 +      ret = _glp_analyze_row(P, len, ind, val, GLP_UP, rhs, 1e-9, &piv,
167.1767 +         &x, &dx, &y, &dy, &dz);
167.1768 +      glp_assert(ret == 0);
167.1769 +      glp_printf("k = %d, x = %g; dx = %g; y = %g; dy = %g; dz = %g\n",
167.1770 +         ind[piv], x, dx, y, dy, dz);
167.1771 +      /* this prints dz = 5.64418 and means that in the adjacent basis
167.1772 +         the objective function would be 296.217 + 5.64418 = 301.861 */
167.1773 +      /* now we actually include the row into the problem object; note
167.1774 +         that the arrays ind and val are clobbered, so we need to build
167.1775 +         them once again */
167.1776 +      len = 0;
167.1777 +      ind[++len] = glp_find_col(P, "BIN1"), val[len] = .01;
167.1778 +      ind[++len] = glp_find_col(P, "BIN2"), val[len] = .01;
167.1779 +      ind[++len] = glp_find_col(P, "BIN4"), val[len] = .02;
167.1780 +      ind[++len] = glp_find_col(P, "BIN5"), val[len] = .02;
167.1781 +      rhs = 12;
167.1782 +      i = glp_add_rows(P, 1);
167.1783 +      glp_set_row_bnds(P, i, GLP_UP, 0, rhs);
167.1784 +      glp_set_mat_row(P, i, len, ind, val);
167.1785 +      /* and perform one dual simplex iteration */
167.1786 +      glp_init_smcp(&parm);
167.1787 +      parm.meth = GLP_DUAL;
167.1788 +      parm.it_lim = 1;
167.1789 +      glp_simplex(P, &parm);
167.1790 +      /* the current objective value is 301.861 */
167.1791 +      return 0;
167.1792 +}
167.1793 +#endif
167.1794 +
167.1795 +/***********************************************************************
167.1796 +*  NAME
167.1797 +*
167.1798 +*  glp_analyze_bound - analyze active bound of non-basic variable
167.1799 +*
167.1800 +*  SYNOPSIS
167.1801 +*
167.1802 +*  void glp_analyze_bound(glp_prob *P, int k, double *limit1, int *var1,
167.1803 +*     double *limit2, int *var2);
167.1804 +*
167.1805 +*  DESCRIPTION
167.1806 +*
167.1807 +*  The routine glp_analyze_bound analyzes the effect of varying the
167.1808 +*  active bound of specified non-basic variable.
167.1809 +*
167.1810 +*  The non-basic variable is specified by the parameter k, where
167.1811 +*  1 <= k <= m means auxiliary variable of corresponding row while
167.1812 +*  m+1 <= k <= m+n means structural variable (column).
167.1813 +*
167.1814 +*  Note that the current basic solution must be optimal, and the basis
167.1815 +*  factorization must exist.
167.1816 +*
167.1817 +*  Results of the analysis have the following meaning.
167.1818 +*
167.1819 +*  value1 is the minimal value of the active bound, at which the basis
167.1820 +*  still remains primal feasible and thus optimal. -DBL_MAX means that
167.1821 +*  the active bound has no lower limit.
167.1822 +*
167.1823 +*  var1 is the ordinal number of an auxiliary (1 to m) or structural
167.1824 +*  (m+1 to n) basic variable, which reaches its bound first and thereby
167.1825 +*  limits further decreasing the active bound being analyzed.
167.1826 +*  if value1 = -DBL_MAX, var1 is set to 0.
167.1827 +*
167.1828 +*  value2 is the maximal value of the active bound, at which the basis
167.1829 +*  still remains primal feasible and thus optimal. +DBL_MAX means that
167.1830 +*  the active bound has no upper limit.
167.1831 +*
167.1832 +*  var2 is the ordinal number of an auxiliary (1 to m) or structural
167.1833 +*  (m+1 to n) basic variable, which reaches its bound first and thereby
167.1834 +*  limits further increasing the active bound being analyzed.
167.1835 +*  if value2 = +DBL_MAX, var2 is set to 0. */
167.1836 +
167.1837 +void glp_analyze_bound(glp_prob *P, int k, double *value1, int *var1,
167.1838 +      double *value2, int *var2)
167.1839 +{     GLPROW *row;
167.1840 +      GLPCOL *col;
167.1841 +      int m, n, stat, kase, p, len, piv, *ind;
167.1842 +      double x, new_x, ll, uu, xx, delta, *val;
167.1843 +      /* sanity checks */
167.1844 +      if (P == NULL || P->magic != GLP_PROB_MAGIC)
167.1845 +         xerror("glp_analyze_bound: P = %p; invalid problem object\n",
167.1846 +            P);
167.1847 +      m = P->m, n = P->n;
167.1848 +      if (!(P->pbs_stat == GLP_FEAS && P->dbs_stat == GLP_FEAS))
167.1849 +         xerror("glp_analyze_bound: optimal basic solution required\n");
167.1850 +      if (!(m == 0 || P->valid))
167.1851 +         xerror("glp_analyze_bound: basis factorization required\n");
167.1852 +      if (!(1 <= k && k <= m+n))
167.1853 +         xerror("glp_analyze_bound: k = %d; variable number out of rang"
167.1854 +            "e\n", k);
167.1855 +      /* retrieve information about the specified non-basic variable
167.1856 +         x[k] whose active bound is to be analyzed */
167.1857 +      if (k <= m)
167.1858 +      {  row = P->row[k];
167.1859 +         stat = row->stat;
167.1860 +         x = row->prim;
167.1861 +      }
167.1862 +      else
167.1863 +      {  col = P->col[k-m];
167.1864 +         stat = col->stat;
167.1865 +         x = col->prim;
167.1866 +      }
167.1867 +      if (stat == GLP_BS)
167.1868 +         xerror("glp_analyze_bound: k = %d; basic variable not allowed "
167.1869 +            "\n", k);
167.1870 +      /* allocate working arrays */
167.1871 +      ind = xcalloc(1+m, sizeof(int));
167.1872 +      val = xcalloc(1+m, sizeof(double));
167.1873 +      /* compute column of the simplex table corresponding to the
167.1874 +         non-basic variable x[k] */
167.1875 +      len = glp_eval_tab_col(P, k, ind, val);
167.1876 +      xassert(0 <= len && len <= m);
167.1877 +      /* perform analysis */
167.1878 +      for (kase = -1; kase <= +1; kase += 2)
167.1879 +      {  /* kase < 0 means active bound of x[k] is decreasing;
167.1880 +            kase > 0 means active bound of x[k] is increasing */
167.1881 +         /* use the primal ratio test to determine some basic variable
167.1882 +            x[p] which reaches its bound first */
167.1883 +         piv = glp_prim_rtest(P, len, ind, val, kase, 1e-9);
167.1884 +         if (piv == 0)
167.1885 +         {  /* nothing limits changing the active bound of x[k] */
167.1886 +            p = 0;
167.1887 +            new_x = (kase < 0 ? -DBL_MAX : +DBL_MAX);
167.1888 +            goto store;
167.1889 +         }
167.1890 +         /* basic variable x[p] limits changing the active bound of
167.1891 +            x[k]; determine its value in the current basis */
167.1892 +         xassert(1 <= piv && piv <= len);
167.1893 +         p = ind[piv];
167.1894 +         if (p <= m)
167.1895 +         {  row = P->row[p];
167.1896 +            ll = glp_get_row_lb(P, row->i);
167.1897 +            uu = glp_get_row_ub(P, row->i);
167.1898 +            stat = row->stat;
167.1899 +            xx = row->prim;
167.1900 +         }
167.1901 +         else
167.1902 +         {  col = P->col[p-m];
167.1903 +            ll = glp_get_col_lb(P, col->j);
167.1904 +            uu = glp_get_col_ub(P, col->j);
167.1905 +            stat = col->stat;
167.1906 +            xx = col->prim;
167.1907 +         }
167.1908 +         xassert(stat == GLP_BS);
167.1909 +         /* determine delta x[p] = bound of x[p] - value of x[p] */
167.1910 +         if (kase < 0 && val[piv] > 0.0 ||
167.1911 +             kase > 0 && val[piv] < 0.0)
167.1912 +         {  /* delta x[p] < 0, so x[p] goes toward its lower bound */
167.1913 +            xassert(ll != -DBL_MAX);
167.1914 +            delta = ll - xx;
167.1915 +         }
167.1916 +         else
167.1917 +         {  /* delta x[p] > 0, so x[p] goes toward its upper bound */
167.1918 +            xassert(uu != +DBL_MAX);
167.1919 +            delta = uu - xx;
167.1920 +         }
167.1921 +         /* delta x[p] = alfa[p,k] * delta x[k], so new x[k] = x[k] +
167.1922 +            delta x[k] = x[k] + delta x[p] / alfa[p,k] is the value of
167.1923 +            x[k] in the adjacent basis */
167.1924 +         xassert(val[piv] != 0.0);
167.1925 +         new_x = x + delta / val[piv];
167.1926 +store:   /* store analysis results */
167.1927 +         if (kase < 0)
167.1928 +         {  if (value1 != NULL) *value1 = new_x;
167.1929 +            if (var1 != NULL) *var1 = p;
167.1930 +         }
167.1931 +         else
167.1932 +         {  if (value2 != NULL) *value2 = new_x;
167.1933 +            if (var2 != NULL) *var2 = p;
167.1934 +         }
167.1935 +      }
167.1936 +      /* free working arrays */
167.1937 +      xfree(ind);
167.1938 +      xfree(val);
167.1939 +      return;
167.1940 +}
167.1941 +
167.1942 +/***********************************************************************
167.1943 +*  NAME
167.1944 +*
167.1945 +*  glp_analyze_coef - analyze objective coefficient at basic variable
167.1946 +*
167.1947 +*  SYNOPSIS
167.1948 +*
167.1949 +*  void glp_analyze_coef(glp_prob *P, int k, double *coef1, int *var1,
167.1950 +*     double *value1, double *coef2, int *var2, double *value2);
167.1951 +*
167.1952 +*  DESCRIPTION
167.1953 +*
167.1954 +*  The routine glp_analyze_coef analyzes the effect of varying the
167.1955 +*  objective coefficient at specified basic variable.
167.1956 +*
167.1957 +*  The basic variable is specified by the parameter k, where
167.1958 +*  1 <= k <= m means auxiliary variable of corresponding row while
167.1959 +*  m+1 <= k <= m+n means structural variable (column).
167.1960 +*
167.1961 +*  Note that the current basic solution must be optimal, and the basis
167.1962 +*  factorization must exist.
167.1963 +*
167.1964 +*  Results of the analysis have the following meaning.
167.1965 +*
167.1966 +*  coef1 is the minimal value of the objective coefficient, at which
167.1967 +*  the basis still remains dual feasible and thus optimal. -DBL_MAX
167.1968 +*  means that the objective coefficient has no lower limit.
167.1969 +*
167.1970 +*  var1 is the ordinal number of an auxiliary (1 to m) or structural
167.1971 +*  (m+1 to n) non-basic variable, whose reduced cost reaches its zero
167.1972 +*  bound first and thereby limits further decreasing the objective
167.1973 +*  coefficient being analyzed. If coef1 = -DBL_MAX, var1 is set to 0.
167.1974 +*
167.1975 +*  value1 is value of the basic variable being analyzed in an adjacent
167.1976 +*  basis, which is defined as follows. Let the objective coefficient
167.1977 +*  reaches its minimal value (coef1) and continues decreasing. Then the
167.1978 +*  reduced cost of the limiting non-basic variable (var1) becomes dual
167.1979 +*  infeasible and the current basis becomes non-optimal that forces the
167.1980 +*  limiting non-basic variable to enter the basis replacing there some
167.1981 +*  basic variable that leaves the basis to keep primal feasibility.
167.1982 +*  Should note that on determining the adjacent basis current bounds
167.1983 +*  of the basic variable being analyzed are ignored as if it were free
167.1984 +*  (unbounded) variable, so it cannot leave the basis. It may happen
167.1985 +*  that no dual feasible adjacent basis exists, in which case value1 is
167.1986 +*  set to -DBL_MAX or +DBL_MAX.
167.1987 +*
167.1988 +*  coef2 is the maximal value of the objective coefficient, at which
167.1989 +*  the basis still remains dual feasible and thus optimal. +DBL_MAX
167.1990 +*  means that the objective coefficient has no upper limit.
167.1991 +*
167.1992 +*  var2 is the ordinal number of an auxiliary (1 to m) or structural
167.1993 +*  (m+1 to n) non-basic variable, whose reduced cost reaches its zero
167.1994 +*  bound first and thereby limits further increasing the objective
167.1995 +*  coefficient being analyzed. If coef2 = +DBL_MAX, var2 is set to 0.
167.1996 +*
167.1997 +*  value2 is value of the basic variable being analyzed in an adjacent
167.1998 +*  basis, which is defined exactly in the same way as value1 above with
167.1999 +*  exception that now the objective coefficient is increasing. */
167.2000 +
167.2001 +void glp_analyze_coef(glp_prob *P, int k, double *coef1, int *var1,
167.2002 +      double *value1, double *coef2, int *var2, double *value2)
167.2003 +{     GLPROW *row; GLPCOL *col;
167.2004 +      int m, n, type, stat, kase, p, q, dir, clen, cpiv, rlen, rpiv,
167.2005 +         *cind, *rind;
167.2006 +      double lb, ub, coef, x, lim_coef, new_x, d, delta, ll, uu, xx,
167.2007 +         *rval, *cval;
167.2008 +      /* sanity checks */
167.2009 +      if (P == NULL || P->magic != GLP_PROB_MAGIC)
167.2010 +         xerror("glp_analyze_coef: P = %p; invalid problem object\n",
167.2011 +            P);
167.2012 +      m = P->m, n = P->n;
167.2013 +      if (!(P->pbs_stat == GLP_FEAS && P->dbs_stat == GLP_FEAS))
167.2014 +         xerror("glp_analyze_coef: optimal basic solution required\n");
167.2015 +      if (!(m == 0 || P->valid))
167.2016 +         xerror("glp_analyze_coef: basis factorization required\n");
167.2017 +      if (!(1 <= k && k <= m+n))
167.2018 +         xerror("glp_analyze_coef: k = %d; variable number out of range"
167.2019 +            "\n", k);
167.2020 +      /* retrieve information about the specified basic variable x[k]
167.2021 +         whose objective coefficient c[k] is to be analyzed */
167.2022 +      if (k <= m)
167.2023 +      {  row = P->row[k];
167.2024 +         type = row->type;
167.2025 +         lb = row->lb;
167.2026 +         ub = row->ub;
167.2027 +         coef = 0.0;
167.2028 +         stat = row->stat;
167.2029 +         x = row->prim;
167.2030 +      }
167.2031 +      else
167.2032 +      {  col = P->col[k-m];
167.2033 +         type = col->type;
167.2034 +         lb = col->lb;
167.2035 +         ub = col->ub;
167.2036 +         coef = col->coef;
167.2037 +         stat = col->stat;
167.2038 +         x = col->prim;
167.2039 +      }
167.2040 +      if (stat != GLP_BS)
167.2041 +         xerror("glp_analyze_coef: k = %d; non-basic variable not allow"
167.2042 +            "ed\n", k);
167.2043 +      /* allocate working arrays */
167.2044 +      cind = xcalloc(1+m, sizeof(int));
167.2045 +      cval = xcalloc(1+m, sizeof(double));
167.2046 +      rind = xcalloc(1+n, sizeof(int));
167.2047 +      rval = xcalloc(1+n, sizeof(double));
167.2048 +      /* compute row of the simplex table corresponding to the basic
167.2049 +         variable x[k] */
167.2050 +      rlen = glp_eval_tab_row(P, k, rind, rval);
167.2051 +      xassert(0 <= rlen && rlen <= n);
167.2052 +      /* perform analysis */
167.2053 +      for (kase = -1; kase <= +1; kase += 2)
167.2054 +      {  /* kase < 0 means objective coefficient c[k] is decreasing;
167.2055 +            kase > 0 means objective coefficient c[k] is increasing */
167.2056 +         /* note that decreasing c[k] is equivalent to increasing dual
167.2057 +            variable lambda[k] and vice versa; we need to correctly set
167.2058 +            the dir flag as required by the routine glp_dual_rtest */
167.2059 +         if (P->dir == GLP_MIN)
167.2060 +            dir = - kase;
167.2061 +         else if (P->dir == GLP_MAX)
167.2062 +            dir = + kase;
167.2063 +         else
167.2064 +            xassert(P != P);
167.2065 +         /* use the dual ratio test to determine non-basic variable
167.2066 +            x[q] whose reduced cost d[q] reaches zero bound first */
167.2067 +         rpiv = glp_dual_rtest(P, rlen, rind, rval, dir, 1e-9);
167.2068 +         if (rpiv == 0)
167.2069 +         {  /* nothing limits changing c[k] */
167.2070 +            lim_coef = (kase < 0 ? -DBL_MAX : +DBL_MAX);
167.2071 +            q = 0;
167.2072 +            /* x[k] keeps its current value */
167.2073 +            new_x = x;
167.2074 +            goto store;
167.2075 +         }
167.2076 +         /* non-basic variable x[q] limits changing coefficient c[k];
167.2077 +            determine its status and reduced cost d[k] in the current
167.2078 +            basis */
167.2079 +         xassert(1 <= rpiv && rpiv <= rlen);
167.2080 +         q = rind[rpiv];
167.2081 +         xassert(1 <= q && q <= m+n);
167.2082 +         if (q <= m)
167.2083 +         {  row = P->row[q];
167.2084 +            stat = row->stat;
167.2085 +            d = row->dual;
167.2086 +         }
167.2087 +         else
167.2088 +         {  col = P->col[q-m];
167.2089 +            stat = col->stat;
167.2090 +            d = col->dual;
167.2091 +         }
167.2092 +         /* note that delta d[q] = new d[q] - d[q] = - d[q], because
167.2093 +            new d[q] = 0; delta d[q] = alfa[k,q] * delta c[k], so
167.2094 +            delta c[k] = delta d[q] / alfa[k,q] = - d[q] / alfa[k,q] */
167.2095 +         xassert(rval[rpiv] != 0.0);
167.2096 +         delta = - d / rval[rpiv];
167.2097 +         /* compute new c[k] = c[k] + delta c[k], which is the limiting
167.2098 +            value of the objective coefficient c[k] */
167.2099 +         lim_coef = coef + delta;
167.2100 +         /* let c[k] continue decreasing/increasing that makes d[q]
167.2101 +            dual infeasible and forces x[q] to enter the basis;
167.2102 +            to perform the primal ratio test we need to know in which
167.2103 +            direction x[q] changes on entering the basis; we determine
167.2104 +            that analyzing the sign of delta d[q] (see above), since
167.2105 +            d[q] may be close to zero having wrong sign */
167.2106 +         /* let, for simplicity, the problem is minimization */
167.2107 +         if (kase < 0 && rval[rpiv] > 0.0 ||
167.2108 +             kase > 0 && rval[rpiv] < 0.0)
167.2109 +         {  /* delta d[q] < 0, so d[q] being non-negative will become
167.2110 +               negative, so x[q] will increase */
167.2111 +            dir = +1;
167.2112 +         }
167.2113 +         else
167.2114 +         {  /* delta d[q] > 0, so d[q] being non-positive will become
167.2115 +               positive, so x[q] will decrease */
167.2116 +            dir = -1;
167.2117 +         }
167.2118 +         /* if the problem is maximization, correct the direction */
167.2119 +         if (P->dir == GLP_MAX) dir = - dir;
167.2120 +         /* check that we didn't make a silly mistake */
167.2121 +         if (dir > 0)
167.2122 +            xassert(stat == GLP_NL || stat == GLP_NF);
167.2123 +         else
167.2124 +            xassert(stat == GLP_NU || stat == GLP_NF);
167.2125 +         /* compute column of the simplex table corresponding to the
167.2126 +            non-basic variable x[q] */
167.2127 +         clen = glp_eval_tab_col(P, q, cind, cval);
167.2128 +         /* make x[k] temporarily free (unbounded) */
167.2129 +         if (k <= m)
167.2130 +         {  row = P->row[k];
167.2131 +            row->type = GLP_FR;
167.2132 +            row->lb = row->ub = 0.0;
167.2133 +         }
167.2134 +         else
167.2135 +         {  col = P->col[k-m];
167.2136 +            col->type = GLP_FR;
167.2137 +            col->lb = col->ub = 0.0;
167.2138 +         }
167.2139 +         /* use the primal ratio test to determine some basic variable
167.2140 +            which leaves the basis */
167.2141 +         cpiv = glp_prim_rtest(P, clen, cind, cval, dir, 1e-9);
167.2142 +         /* restore original bounds of the basic variable x[k] */
167.2143 +         if (k <= m)
167.2144 +         {  row = P->row[k];
167.2145 +            row->type = type;
167.2146 +            row->lb = lb, row->ub = ub;
167.2147 +         }
167.2148 +         else
167.2149 +         {  col = P->col[k-m];
167.2150 +            col->type = type;
167.2151 +            col->lb = lb, col->ub = ub;
167.2152 +         }
167.2153 +         if (cpiv == 0)
167.2154 +         {  /* non-basic variable x[q] can change unlimitedly */
167.2155 +            if (dir < 0 && rval[rpiv] > 0.0 ||
167.2156 +                dir > 0 && rval[rpiv] < 0.0)
167.2157 +            {  /* delta x[k] = alfa[k,q] * delta x[q] < 0 */
167.2158 +               new_x = -DBL_MAX;
167.2159 +            }
167.2160 +            else
167.2161 +            {  /* delta x[k] = alfa[k,q] * delta x[q] > 0 */
167.2162 +               new_x = +DBL_MAX;
167.2163 +            }
167.2164 +            goto store;
167.2165 +         }
167.2166 +         /* some basic variable x[p] limits changing non-basic variable
167.2167 +            x[q] in the adjacent basis */
167.2168 +         xassert(1 <= cpiv && cpiv <= clen);
167.2169 +         p = cind[cpiv];
167.2170 +         xassert(1 <= p && p <= m+n);
167.2171 +         xassert(p != k);
167.2172 +         if (p <= m)
167.2173 +         {  row = P->row[p];
167.2174 +            xassert(row->stat == GLP_BS);
167.2175 +            ll = glp_get_row_lb(P, row->i);
167.2176 +            uu = glp_get_row_ub(P, row->i);
167.2177 +            xx = row->prim;
167.2178 +         }
167.2179 +         else
167.2180 +         {  col = P->col[p-m];
167.2181 +            xassert(col->stat == GLP_BS);
167.2182 +            ll = glp_get_col_lb(P, col->j);
167.2183 +            uu = glp_get_col_ub(P, col->j);
167.2184 +            xx = col->prim;
167.2185 +         }
167.2186 +         /* determine delta x[p] = new x[p] - x[p] */
167.2187 +         if (dir < 0 && cval[cpiv] > 0.0 ||
167.2188 +             dir > 0 && cval[cpiv] < 0.0)
167.2189 +         {  /* delta x[p] < 0, so x[p] goes toward its lower bound */
167.2190 +            xassert(ll != -DBL_MAX);
167.2191 +            delta = ll - xx;
167.2192 +         }
167.2193 +         else
167.2194 +         {  /* delta x[p] > 0, so x[p] goes toward its upper bound */
167.2195 +            xassert(uu != +DBL_MAX);
167.2196 +            delta = uu - xx;
167.2197 +         }
167.2198 +         /* compute new x[k] = x[k] + alfa[k,q] * delta x[q], where
167.2199 +            delta x[q] = delta x[p] / alfa[p,q] */
167.2200 +         xassert(cval[cpiv] != 0.0);
167.2201 +         new_x = x + (rval[rpiv] / cval[cpiv]) * delta;
167.2202 +store:   /* store analysis results */
167.2203 +         if (kase < 0)
167.2204 +         {  if (coef1 != NULL) *coef1 = lim_coef;
167.2205 +            if (var1 != NULL) *var1 = q;
167.2206 +            if (value1 != NULL) *value1 = new_x;
167.2207 +         }
167.2208 +         else
167.2209 +         {  if (coef2 != NULL) *coef2 = lim_coef;
167.2210 +            if (var2 != NULL) *var2 = q;
167.2211 +            if (value2 != NULL) *value2 = new_x;
167.2212 +         }
167.2213 +      }
167.2214 +      /* free working arrays */
167.2215 +      xfree(cind);
167.2216 +      xfree(cval);
167.2217 +      xfree(rind);
167.2218 +      xfree(rval);
167.2219 +      return;
167.2220 +}
167.2221 +
167.2222 +/* eof */
   168.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   168.2 +++ b/src/glpapi13.c	Mon Dec 06 13:09:21 2010 +0100
   168.3 @@ -0,0 +1,702 @@
   168.4 +/* glpapi13.c (branch-and-bound interface routines) */
   168.5 +
   168.6 +/***********************************************************************
   168.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   168.8 +*
   168.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  168.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  168.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  168.12 +*  E-mail: <mao@gnu.org>.
  168.13 +*
  168.14 +*  GLPK is free software: you can redistribute it and/or modify it
  168.15 +*  under the terms of the GNU General Public License as published by
  168.16 +*  the Free Software Foundation, either version 3 of the License, or
  168.17 +*  (at your option) any later version.
  168.18 +*
  168.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  168.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  168.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  168.22 +*  License for more details.
  168.23 +*
  168.24 +*  You should have received a copy of the GNU General Public License
  168.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  168.26 +***********************************************************************/
  168.27 +
  168.28 +#include "glpios.h"
  168.29 +
  168.30 +/***********************************************************************
  168.31 +*  NAME
  168.32 +*
  168.33 +*  glp_ios_reason - determine reason for calling the callback routine
  168.34 +*
  168.35 +*  SYNOPSIS
  168.36 +*
  168.37 +*  glp_ios_reason(glp_tree *tree);
  168.38 +*
  168.39 +*  RETURNS
  168.40 +*
  168.41 +*  The routine glp_ios_reason returns a code, which indicates why the
  168.42 +*  user-defined callback routine is being called. */
  168.43 +
  168.44 +int glp_ios_reason(glp_tree *tree)
  168.45 +{     return
  168.46 +         tree->reason;
  168.47 +}
  168.48 +
  168.49 +/***********************************************************************
  168.50 +*  NAME
  168.51 +*
  168.52 +*  glp_ios_get_prob - access the problem object
  168.53 +*
  168.54 +*  SYNOPSIS
  168.55 +*
  168.56 +*  glp_prob *glp_ios_get_prob(glp_tree *tree);
  168.57 +*
  168.58 +*  DESCRIPTION
  168.59 +*
  168.60 +*  The routine glp_ios_get_prob can be called from the user-defined
  168.61 +*  callback routine to access the problem object, which is used by the
  168.62 +*  MIP solver. It is the original problem object passed to the routine
  168.63 +*  glp_intopt if the MIP presolver is not used; otherwise it is an
  168.64 +*  internal problem object built by the presolver. If the current
  168.65 +*  subproblem exists, LP segment of the problem object corresponds to
  168.66 +*  its LP relaxation.
  168.67 +*
  168.68 +*  RETURNS
  168.69 +*
  168.70 +*  The routine glp_ios_get_prob returns a pointer to the problem object
  168.71 +*  used by the MIP solver. */
  168.72 +
  168.73 +glp_prob *glp_ios_get_prob(glp_tree *tree)
  168.74 +{     return
  168.75 +         tree->mip;
  168.76 +}
  168.77 +
  168.78 +/***********************************************************************
  168.79 +*  NAME
  168.80 +*
  168.81 +*  glp_ios_tree_size - determine size of the branch-and-bound tree
  168.82 +*
  168.83 +*  SYNOPSIS
  168.84 +*
  168.85 +*  void glp_ios_tree_size(glp_tree *tree, int *a_cnt, int *n_cnt,
  168.86 +*     int *t_cnt);
  168.87 +*
  168.88 +*  DESCRIPTION
  168.89 +*
  168.90 +*  The routine glp_ios_tree_size stores the following three counts which
  168.91 +*  characterize the current size of the branch-and-bound tree:
  168.92 +*
  168.93 +*  a_cnt is the current number of active nodes, i.e. the current size of
  168.94 +*        the active list;
  168.95 +*
  168.96 +*  n_cnt is the current number of all (active and inactive) nodes;
  168.97 +*
  168.98 +*  t_cnt is the total number of nodes including those which have been
  168.99 +*        already removed from the tree. This count is increased whenever
 168.100 +*        a new node appears in the tree and never decreased.
 168.101 +*
 168.102 +*  If some of the parameters a_cnt, n_cnt, t_cnt is a null pointer, the
 168.103 +*  corresponding count is not stored. */
 168.104 +
 168.105 +void glp_ios_tree_size(glp_tree *tree, int *a_cnt, int *n_cnt,
 168.106 +      int *t_cnt)
 168.107 +{     if (a_cnt != NULL) *a_cnt = tree->a_cnt;
 168.108 +      if (n_cnt != NULL) *n_cnt = tree->n_cnt;
 168.109 +      if (t_cnt != NULL) *t_cnt = tree->t_cnt;
 168.110 +      return;
 168.111 +}
 168.112 +
 168.113 +/***********************************************************************
 168.114 +*  NAME
 168.115 +*
 168.116 +*  glp_ios_curr_node - determine current active subproblem
 168.117 +*
 168.118 +*  SYNOPSIS
 168.119 +*
 168.120 +*  int glp_ios_curr_node(glp_tree *tree);
 168.121 +*
 168.122 +*  RETURNS
 168.123 +*
 168.124 +*  The routine glp_ios_curr_node returns the reference number of the
 168.125 +*  current active subproblem. However, if the current subproblem does
 168.126 +*  not exist, the routine returns zero. */
 168.127 +
 168.128 +int glp_ios_curr_node(glp_tree *tree)
 168.129 +{     IOSNPD *node;
 168.130 +      /* obtain pointer to the current subproblem */
 168.131 +      node = tree->curr;
 168.132 +      /* return its reference number */
 168.133 +      return node == NULL ? 0 : node->p;
 168.134 +}
 168.135 +
 168.136 +/***********************************************************************
 168.137 +*  NAME
 168.138 +*
 168.139 +*  glp_ios_next_node - determine next active subproblem
 168.140 +*
 168.141 +*  SYNOPSIS
 168.142 +*
 168.143 +*  int glp_ios_next_node(glp_tree *tree, int p);
 168.144 +*
 168.145 +*  RETURNS
 168.146 +*
 168.147 +*  If the parameter p is zero, the routine glp_ios_next_node returns
 168.148 +*  the reference number of the first active subproblem. However, if the
 168.149 +*  tree is empty, zero is returned.
 168.150 +*
 168.151 +*  If the parameter p is not zero, it must specify the reference number
 168.152 +*  of some active subproblem, in which case the routine returns the
 168.153 +*  reference number of the next active subproblem. However, if there is
 168.154 +*  no next active subproblem in the list, zero is returned.
 168.155 +*
 168.156 +*  All subproblems in the active list are ordered chronologically, i.e.
 168.157 +*  subproblem A precedes subproblem B if A was created before B. */
 168.158 +
 168.159 +int glp_ios_next_node(glp_tree *tree, int p)
 168.160 +{     IOSNPD *node;
 168.161 +      if (p == 0)
 168.162 +      {  /* obtain pointer to the first active subproblem */
 168.163 +         node = tree->head;
 168.164 +      }
 168.165 +      else
 168.166 +      {  /* obtain pointer to the specified subproblem */
 168.167 +         if (!(1 <= p && p <= tree->nslots))
 168.168 +err:        xerror("glp_ios_next_node: p = %d; invalid subproblem refer"
 168.169 +               "ence number\n", p);
 168.170 +         node = tree->slot[p].node;
 168.171 +         if (node == NULL) goto err;
 168.172 +         /* the specified subproblem must be active */
 168.173 +         if (node->count != 0)
 168.174 +            xerror("glp_ios_next_node: p = %d; subproblem not in the ac"
 168.175 +               "tive list\n", p);
 168.176 +         /* obtain pointer to the next active subproblem */
 168.177 +         node = node->next;
 168.178 +      }
 168.179 +      /* return the reference number */
 168.180 +      return node == NULL ? 0 : node->p;
 168.181 +}
 168.182 +
 168.183 +/***********************************************************************
 168.184 +*  NAME
 168.185 +*
 168.186 +*  glp_ios_prev_node - determine previous active subproblem
 168.187 +*
 168.188 +*  SYNOPSIS
 168.189 +*
 168.190 +*  int glp_ios_prev_node(glp_tree *tree, int p);
 168.191 +*
 168.192 +*  RETURNS
 168.193 +*
 168.194 +*  If the parameter p is zero, the routine glp_ios_prev_node returns
 168.195 +*  the reference number of the last active subproblem. However, if the
 168.196 +*  tree is empty, zero is returned.
 168.197 +*
 168.198 +*  If the parameter p is not zero, it must specify the reference number
 168.199 +*  of some active subproblem, in which case the routine returns the
 168.200 +*  reference number of the previous active subproblem. However, if there
 168.201 +*  is no previous active subproblem in the list, zero is returned.
 168.202 +*
 168.203 +*  All subproblems in the active list are ordered chronologically, i.e.
 168.204 +*  subproblem A precedes subproblem B if A was created before B. */
 168.205 +
 168.206 +int glp_ios_prev_node(glp_tree *tree, int p)
 168.207 +{     IOSNPD *node;
 168.208 +      if (p == 0)
 168.209 +      {  /* obtain pointer to the last active subproblem */
 168.210 +         node = tree->tail;
 168.211 +      }
 168.212 +      else
 168.213 +      {  /* obtain pointer to the specified subproblem */
 168.214 +         if (!(1 <= p && p <= tree->nslots))
 168.215 +err:        xerror("glp_ios_prev_node: p = %d; invalid subproblem refer"
 168.216 +               "ence number\n", p);
 168.217 +         node = tree->slot[p].node;
 168.218 +         if (node == NULL) goto err;
 168.219 +         /* the specified subproblem must be active */
 168.220 +         if (node->count != 0)
 168.221 +            xerror("glp_ios_prev_node: p = %d; subproblem not in the ac"
 168.222 +               "tive list\n", p);
 168.223 +         /* obtain pointer to the previous active subproblem */
 168.224 +         node = node->prev;
 168.225 +      }
 168.226 +      /* return the reference number */
 168.227 +      return node == NULL ? 0 : node->p;
 168.228 +}
 168.229 +
 168.230 +/***********************************************************************
 168.231 +*  NAME
 168.232 +*
 168.233 +*  glp_ios_up_node - determine parent subproblem
 168.234 +*
 168.235 +*  SYNOPSIS
 168.236 +*
 168.237 +*  int glp_ios_up_node(glp_tree *tree, int p);
 168.238 +*
 168.239 +*  RETURNS
 168.240 +*
 168.241 +*  The parameter p must specify the reference number of some (active or
 168.242 +*  inactive) subproblem, in which case the routine iet_get_up_node
 168.243 +*  returns the reference number of its parent subproblem. However, if
 168.244 +*  the specified subproblem is the root of the tree and, therefore, has
 168.245 +*  no parent, the routine returns zero. */
 168.246 +
 168.247 +int glp_ios_up_node(glp_tree *tree, int p)
 168.248 +{     IOSNPD *node;
 168.249 +      /* obtain pointer to the specified subproblem */
 168.250 +      if (!(1 <= p && p <= tree->nslots))
 168.251 +err:     xerror("glp_ios_up_node: p = %d; invalid subproblem reference "
 168.252 +            "number\n", p);
 168.253 +      node = tree->slot[p].node;
 168.254 +      if (node == NULL) goto err;
 168.255 +      /* obtain pointer to the parent subproblem */
 168.256 +      node = node->up;
 168.257 +      /* return the reference number */
 168.258 +      return node == NULL ? 0 : node->p;
 168.259 +}
 168.260 +
 168.261 +/***********************************************************************
 168.262 +*  NAME
 168.263 +*
 168.264 +*  glp_ios_node_level - determine subproblem level
 168.265 +*
 168.266 +*  SYNOPSIS
 168.267 +*
 168.268 +*  int glp_ios_node_level(glp_tree *tree, int p);
 168.269 +*
 168.270 +*  RETURNS
 168.271 +*
 168.272 +*  The routine glp_ios_node_level returns the level of the subproblem,
 168.273 +*  whose reference number is p, in the branch-and-bound tree. (The root
 168.274 +*  subproblem has level 0, and the level of any other subproblem is the
 168.275 +*  level of its parent plus one.) */
 168.276 +
 168.277 +int glp_ios_node_level(glp_tree *tree, int p)
 168.278 +{     IOSNPD *node;
 168.279 +      /* obtain pointer to the specified subproblem */
 168.280 +      if (!(1 <= p && p <= tree->nslots))
 168.281 +err:     xerror("glp_ios_node_level: p = %d; invalid subproblem referen"
 168.282 +            "ce number\n", p);
 168.283 +      node = tree->slot[p].node;
 168.284 +      if (node == NULL) goto err;
 168.285 +      /* return the node level */
 168.286 +      return node->level;
 168.287 +}
 168.288 +
 168.289 +/***********************************************************************
 168.290 +*  NAME
 168.291 +*
 168.292 +*  glp_ios_node_bound - determine subproblem local bound
 168.293 +*
 168.294 +*  SYNOPSIS
 168.295 +*
 168.296 +*  double glp_ios_node_bound(glp_tree *tree, int p);
 168.297 +*
 168.298 +*  RETURNS
 168.299 +*
 168.300 +*  The routine glp_ios_node_bound returns the local bound for (active or
 168.301 +*  inactive) subproblem, whose reference number is p.
 168.302 +*
 168.303 +*  COMMENTS
 168.304 +*
 168.305 +*  The local bound for subproblem p is an lower (minimization) or upper
 168.306 +*  (maximization) bound for integer optimal solution to this subproblem
 168.307 +*  (not to the original problem). This bound is local in the sense that
 168.308 +*  only subproblems in the subtree rooted at node p cannot have better
 168.309 +*  integer feasible solutions.
 168.310 +*
 168.311 +*  On creating a subproblem (due to the branching step) its local bound
 168.312 +*  is inherited from its parent and then may get only stronger (never
 168.313 +*  weaker). For the root subproblem its local bound is initially set to
 168.314 +*  -DBL_MAX (minimization) or +DBL_MAX (maximization) and then improved
 168.315 +*  as the root LP relaxation has been solved.
 168.316 +*
 168.317 +*  Note that the local bound is not necessarily the optimal objective
 168.318 +*  value to corresponding LP relaxation; it may be stronger. */
 168.319 +
 168.320 +double glp_ios_node_bound(glp_tree *tree, int p)
 168.321 +{     IOSNPD *node;
 168.322 +      /* obtain pointer to the specified subproblem */
 168.323 +      if (!(1 <= p && p <= tree->nslots))
 168.324 +err:     xerror("glp_ios_node_bound: p = %d; invalid subproblem referen"
 168.325 +            "ce number\n", p);
 168.326 +      node = tree->slot[p].node;
 168.327 +      if (node == NULL) goto err;
 168.328 +      /* return the node local bound */
 168.329 +      return node->bound;
 168.330 +}
 168.331 +
 168.332 +/***********************************************************************
 168.333 +*  NAME
 168.334 +*
 168.335 +*  glp_ios_best_node - find active subproblem with best local bound
 168.336 +*
 168.337 +*  SYNOPSIS
 168.338 +*
 168.339 +*  int glp_ios_best_node(glp_tree *tree);
 168.340 +*
 168.341 +*  RETURNS
 168.342 +*
 168.343 +*  The routine glp_ios_best_node returns the reference number of the
 168.344 +*  active subproblem, whose local bound is best (i.e. smallest in case
 168.345 +*  of minimization or largest in case of maximization). However, if the
 168.346 +*  tree is empty, the routine returns zero.
 168.347 +*
 168.348 +*  COMMENTS
 168.349 +*
 168.350 +*  The best local bound is an lower (minimization) or upper
 168.351 +*  (maximization) bound for integer optimal solution to the original
 168.352 +*  MIP problem. */
 168.353 +
 168.354 +int glp_ios_best_node(glp_tree *tree)
 168.355 +{     return
 168.356 +         ios_best_node(tree);
 168.357 +}
 168.358 +
 168.359 +/***********************************************************************
 168.360 +*  NAME
 168.361 +*
 168.362 +*  glp_ios_mip_gap - compute relative MIP gap
 168.363 +*
 168.364 +*  SYNOPSIS
 168.365 +*
 168.366 +*  double glp_ios_mip_gap(glp_tree *tree);
 168.367 +*
 168.368 +*  DESCRIPTION
 168.369 +*
 168.370 +*  The routine glp_ios_mip_gap computes the relative MIP gap with the
 168.371 +*  following formula:
 168.372 +*
 168.373 +*     gap = |best_mip - best_bnd| / (|best_mip| + DBL_EPSILON),
 168.374 +*
 168.375 +*  where best_mip is the best integer feasible solution found so far,
 168.376 +*  best_bnd is the best (global) bound. If no integer feasible solution
 168.377 +*  has been found yet, gap is set to DBL_MAX.
 168.378 +*
 168.379 +*  RETURNS
 168.380 +*
 168.381 +*  The routine glp_ios_mip_gap returns the relative MIP gap. */
 168.382 +
 168.383 +double glp_ios_mip_gap(glp_tree *tree)
 168.384 +{     return
 168.385 +         ios_relative_gap(tree);
 168.386 +}
 168.387 +
 168.388 +/***********************************************************************
 168.389 +*  NAME
 168.390 +*
 168.391 +*  glp_ios_node_data - access subproblem application-specific data
 168.392 +*
 168.393 +*  SYNOPSIS
 168.394 +*
 168.395 +*  void *glp_ios_node_data(glp_tree *tree, int p);
 168.396 +*
 168.397 +*  DESCRIPTION
 168.398 +*
 168.399 +*  The routine glp_ios_node_data allows the application accessing a
 168.400 +*  memory block allocated for the subproblem (which may be active or
 168.401 +*  inactive), whose reference number is p.
 168.402 +*
 168.403 +*  The size of the block is defined by the control parameter cb_size
 168.404 +*  passed to the routine glp_intopt. The block is initialized by binary
 168.405 +*  zeros on creating corresponding subproblem, and its contents is kept
 168.406 +*  until the subproblem will be removed from the tree.
 168.407 +*
 168.408 +*  The application may use these memory blocks to store specific data
 168.409 +*  for each subproblem.
 168.410 +*
 168.411 +*  RETURNS
 168.412 +*
 168.413 +*  The routine glp_ios_node_data returns a pointer to the memory block
 168.414 +*  for the specified subproblem. Note that if cb_size = 0, the routine
 168.415 +*  returns a null pointer. */
 168.416 +
 168.417 +void *glp_ios_node_data(glp_tree *tree, int p)
 168.418 +{     IOSNPD *node;
 168.419 +      /* obtain pointer to the specified subproblem */
 168.420 +      if (!(1 <= p && p <= tree->nslots))
 168.421 +err:     xerror("glp_ios_node_level: p = %d; invalid subproblem referen"
 168.422 +            "ce number\n", p);
 168.423 +      node = tree->slot[p].node;
 168.424 +      if (node == NULL) goto err;
 168.425 +      /* return pointer to the application-specific data */
 168.426 +      return node->data;
 168.427 +}
 168.428 +
 168.429 +/***********************************************************************
 168.430 +*  NAME
 168.431 +*
 168.432 +*  glp_ios_row_attr - retrieve additional row attributes
 168.433 +*
 168.434 +*  SYNOPSIS
 168.435 +*
 168.436 +*  void glp_ios_row_attr(glp_tree *tree, int i, glp_attr *attr);
 168.437 +*
 168.438 +*  DESCRIPTION
 168.439 +*
 168.440 +*  The routine glp_ios_row_attr retrieves additional attributes of row
 168.441 +*  i and stores them in the structure glp_attr. */
 168.442 +
 168.443 +void glp_ios_row_attr(glp_tree *tree, int i, glp_attr *attr)
 168.444 +{     GLPROW *row;
 168.445 +      if (!(1 <= i && i <= tree->mip->m))
 168.446 +         xerror("glp_ios_row_attr: i = %d; row number out of range\n",
 168.447 +            i);
 168.448 +      row = tree->mip->row[i];
 168.449 +      attr->level = row->level;
 168.450 +      attr->origin = row->origin;
 168.451 +      attr->klass = row->klass;
 168.452 +      return;
 168.453 +}
 168.454 +
 168.455 +/**********************************************************************/
 168.456 +
 168.457 +int glp_ios_pool_size(glp_tree *tree)
 168.458 +{     /* determine current size of the cut pool */
 168.459 +      if (tree->reason != GLP_ICUTGEN)
 168.460 +         xerror("glp_ios_pool_size: operation not allowed\n");
 168.461 +      xassert(tree->local != NULL);
 168.462 +      return tree->local->size;
 168.463 +}
 168.464 +
 168.465 +/**********************************************************************/
 168.466 +
 168.467 +int glp_ios_add_row(glp_tree *tree,
 168.468 +      const char *name, int klass, int flags, int len, const int ind[],
 168.469 +      const double val[], int type, double rhs)
 168.470 +{     /* add row (constraint) to the cut pool */
 168.471 +      int num;
 168.472 +      if (tree->reason != GLP_ICUTGEN)
 168.473 +         xerror("glp_ios_add_row: operation not allowed\n");
 168.474 +      xassert(tree->local != NULL);
 168.475 +      num = ios_add_row(tree, tree->local, name, klass, flags, len,
 168.476 +         ind, val, type, rhs);
 168.477 +      return num;
 168.478 +}
 168.479 +
 168.480 +/**********************************************************************/
 168.481 +
 168.482 +void glp_ios_del_row(glp_tree *tree, int i)
 168.483 +{     /* remove row (constraint) from the cut pool */
 168.484 +      if (tree->reason != GLP_ICUTGEN)
 168.485 +         xerror("glp_ios_del_row: operation not allowed\n");
 168.486 +      ios_del_row(tree, tree->local, i);
 168.487 +      return;
 168.488 +}
 168.489 +
 168.490 +/**********************************************************************/
 168.491 +
 168.492 +void glp_ios_clear_pool(glp_tree *tree)
 168.493 +{     /* remove all rows (constraints) from the cut pool */
 168.494 +      if (tree->reason != GLP_ICUTGEN)
 168.495 +         xerror("glp_ios_clear_pool: operation not allowed\n");
 168.496 +      ios_clear_pool(tree, tree->local);
 168.497 +      return;
 168.498 +}
 168.499 +
 168.500 +/***********************************************************************
 168.501 +*  NAME
 168.502 +*
 168.503 +*  glp_ios_can_branch - check if can branch upon specified variable
 168.504 +*
 168.505 +*  SYNOPSIS
 168.506 +*
 168.507 +*  int glp_ios_can_branch(glp_tree *tree, int j);
 168.508 +*
 168.509 +*  RETURNS
 168.510 +*
 168.511 +*  If j-th variable (column) can be used to branch upon, the routine
 168.512 +*  glp_ios_can_branch returns non-zero, otherwise zero. */
 168.513 +
 168.514 +int glp_ios_can_branch(glp_tree *tree, int j)
 168.515 +{     if (!(1 <= j && j <= tree->mip->n))
 168.516 +         xerror("glp_ios_can_branch: j = %d; column number out of range"
 168.517 +            "\n", j);
 168.518 +      return tree->non_int[j];
 168.519 +}
 168.520 +
 168.521 +/***********************************************************************
 168.522 +*  NAME
 168.523 +*
 168.524 +*  glp_ios_branch_upon - choose variable to branch upon
 168.525 +*
 168.526 +*  SYNOPSIS
 168.527 +*
 168.528 +*  void glp_ios_branch_upon(glp_tree *tree, int j, int sel);
 168.529 +*
 168.530 +*  DESCRIPTION
 168.531 +*
 168.532 +*  The routine glp_ios_branch_upon can be called from the user-defined
 168.533 +*  callback routine in response to the reason GLP_IBRANCH to choose a
 168.534 +*  branching variable, whose ordinal number is j. Should note that only
 168.535 +*  variables, for which the routine glp_ios_can_branch returns non-zero,
 168.536 +*  can be used to branch upon.
 168.537 +*
 168.538 +*  The parameter sel is a flag that indicates which branch (subproblem)
 168.539 +*  should be selected next to continue the search:
 168.540 +*
 168.541 +*  GLP_DN_BRNCH - select down-branch;
 168.542 +*  GLP_UP_BRNCH - select up-branch;
 168.543 +*  GLP_NO_BRNCH - use general selection technique. */
 168.544 +
 168.545 +void glp_ios_branch_upon(glp_tree *tree, int j, int sel)
 168.546 +{     if (!(1 <= j && j <= tree->mip->n))
 168.547 +         xerror("glp_ios_branch_upon: j = %d; column number out of rang"
 168.548 +            "e\n", j);
 168.549 +      if (!(sel == GLP_DN_BRNCH || sel == GLP_UP_BRNCH ||
 168.550 +            sel == GLP_NO_BRNCH))
 168.551 +         xerror("glp_ios_branch_upon: sel = %d: invalid branch selectio"
 168.552 +            "n flag\n", sel);
 168.553 +      if (!(tree->non_int[j]))
 168.554 +         xerror("glp_ios_branch_upon: j = %d; variable cannot be used t"
 168.555 +            "o branch upon\n", j);
 168.556 +      if (tree->br_var != 0)
 168.557 +         xerror("glp_ios_branch_upon: branching variable already chosen"
 168.558 +            "\n");
 168.559 +      tree->br_var = j;
 168.560 +      tree->br_sel = sel;
 168.561 +      return;
 168.562 +}
 168.563 +
 168.564 +/***********************************************************************
 168.565 +*  NAME
 168.566 +*
 168.567 +*  glp_ios_select_node - select subproblem to continue the search
 168.568 +*
 168.569 +*  SYNOPSIS
 168.570 +*
 168.571 +*  void glp_ios_select_node(glp_tree *tree, int p);
 168.572 +*
 168.573 +*  DESCRIPTION
 168.574 +*
 168.575 +*  The routine glp_ios_select_node can be called from the user-defined
 168.576 +*  callback routine in response to the reason GLP_ISELECT to select an
 168.577 +*  active subproblem, whose reference number is p. The search will be
 168.578 +*  continued from the subproblem selected. */
 168.579 +
 168.580 +void glp_ios_select_node(glp_tree *tree, int p)
 168.581 +{     IOSNPD *node;
 168.582 +      /* obtain pointer to the specified subproblem */
 168.583 +      if (!(1 <= p && p <= tree->nslots))
 168.584 +err:     xerror("glp_ios_select_node: p = %d; invalid subproblem refere"
 168.585 +            "nce number\n", p);
 168.586 +      node = tree->slot[p].node;
 168.587 +      if (node == NULL) goto err;
 168.588 +      /* the specified subproblem must be active */
 168.589 +      if (node->count != 0)
 168.590 +         xerror("glp_ios_select_node: p = %d; subproblem not in the act"
 168.591 +            "ive list\n", p);
 168.592 +      /* no subproblem must be selected yet */
 168.593 +      if (tree->next_p != 0)
 168.594 +         xerror("glp_ios_select_node: subproblem already selected\n");
 168.595 +      /* select the specified subproblem to continue the search */
 168.596 +      tree->next_p = p;
 168.597 +      return;
 168.598 +}
 168.599 +
 168.600 +/***********************************************************************
 168.601 +*  NAME
 168.602 +*
 168.603 +*  glp_ios_heur_sol - provide solution found by heuristic
 168.604 +*
 168.605 +*  SYNOPSIS
 168.606 +*
 168.607 +*  int glp_ios_heur_sol(glp_tree *tree, const double x[]);
 168.608 +*
 168.609 +*  DESCRIPTION
 168.610 +*
 168.611 +*  The routine glp_ios_heur_sol can be called from the user-defined
 168.612 +*  callback routine in response to the reason GLP_IHEUR to provide an
 168.613 +*  integer feasible solution found by a primal heuristic.
 168.614 +*
 168.615 +*  Primal values of *all* variables (columns) found by the heuristic
 168.616 +*  should be placed in locations x[1], ..., x[n], where n is the number
 168.617 +*  of columns in the original problem object. Note that the routine
 168.618 +*  glp_ios_heur_sol *does not* check primal feasibility of the solution
 168.619 +*  provided.
 168.620 +*
 168.621 +*  Using the solution passed in the array x the routine computes value
 168.622 +*  of the objective function. If the objective value is better than the
 168.623 +*  best known integer feasible solution, the routine computes values of
 168.624 +*  auxiliary variables (rows) and stores all solution components in the
 168.625 +*  problem object.
 168.626 +*
 168.627 +*  RETURNS
 168.628 +*
 168.629 +*  If the provided solution is accepted, the routine glp_ios_heur_sol
 168.630 +*  returns zero. Otherwise, if the provided solution is rejected, the
 168.631 +*  routine returns non-zero. */
 168.632 +
 168.633 +int glp_ios_heur_sol(glp_tree *tree, const double x[])
 168.634 +{     glp_prob *mip = tree->mip;
 168.635 +      int m = tree->orig_m;
 168.636 +      int n = tree->n;
 168.637 +      int i, j;
 168.638 +      double obj;
 168.639 +      xassert(mip->m >= m);
 168.640 +      xassert(mip->n == n);
 168.641 +      /* check values of integer variables and compute value of the
 168.642 +         objective function */
 168.643 +      obj = mip->c0;
 168.644 +      for (j = 1; j <= n; j++)
 168.645 +      {  GLPCOL *col = mip->col[j];
 168.646 +         if (col->kind == GLP_IV)
 168.647 +         {  /* provided value must be integral */
 168.648 +            if (x[j] != floor(x[j])) return 1;
 168.649 +         }
 168.650 +         obj += col->coef * x[j];
 168.651 +      }
 168.652 +      /* check if the provided solution is better than the best known
 168.653 +         integer feasible solution */
 168.654 +      if (mip->mip_stat == GLP_FEAS)
 168.655 +      {  switch (mip->dir)
 168.656 +         {  case GLP_MIN:
 168.657 +               if (obj >= tree->mip->mip_obj) return 1;
 168.658 +               break;
 168.659 +            case GLP_MAX:
 168.660 +               if (obj <= tree->mip->mip_obj) return 1;
 168.661 +               break;
 168.662 +            default:
 168.663 +               xassert(mip != mip);
 168.664 +         }
 168.665 +      }
 168.666 +      /* it is better; store it in the problem object */
 168.667 +      if (tree->parm->msg_lev >= GLP_MSG_ON)
 168.668 +         xprintf("Solution found by heuristic: %.12g\n", obj);
 168.669 +      mip->mip_stat = GLP_FEAS;
 168.670 +      mip->mip_obj = obj;
 168.671 +      for (j = 1; j <= n; j++)
 168.672 +         mip->col[j]->mipx = x[j];
 168.673 +      for (i = 1; i <= m; i++)
 168.674 +      {  GLPROW *row = mip->row[i];
 168.675 +         GLPAIJ *aij;
 168.676 +         row->mipx = 0.0;
 168.677 +         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
 168.678 +            row->mipx += aij->val * aij->col->mipx;
 168.679 +      }
 168.680 +      return 0;
 168.681 +}
 168.682 +
 168.683 +/***********************************************************************
 168.684 +*  NAME
 168.685 +*
 168.686 +*  glp_ios_terminate - terminate the solution process.
 168.687 +*
 168.688 +*  SYNOPSIS
 168.689 +*
 168.690 +*  void glp_ios_terminate(glp_tree *tree);
 168.691 +*
 168.692 +*  DESCRIPTION
 168.693 +*
 168.694 +*  The routine glp_ios_terminate sets a flag indicating that the MIP
 168.695 +*  solver should prematurely terminate the search. */
 168.696 +
 168.697 +void glp_ios_terminate(glp_tree *tree)
 168.698 +{     if (tree->parm->msg_lev >= GLP_MSG_DBG)
 168.699 +         xprintf("The search is prematurely terminated due to applicati"
 168.700 +            "on request\n");
 168.701 +      tree->stop = 1;
 168.702 +      return;
 168.703 +}
 168.704 +
 168.705 +/* eof */
   169.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   169.2 +++ b/src/glpapi14.c	Mon Dec 06 13:09:21 2010 +0100
   169.3 @@ -0,0 +1,274 @@
   169.4 +/* glpapi14.c (processing models in GNU MathProg language) */
   169.5 +
   169.6 +/***********************************************************************
   169.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   169.8 +*
   169.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  169.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  169.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  169.12 +*  E-mail: <mao@gnu.org>.
  169.13 +*
  169.14 +*  GLPK is free software: you can redistribute it and/or modify it
  169.15 +*  under the terms of the GNU General Public License as published by
  169.16 +*  the Free Software Foundation, either version 3 of the License, or
  169.17 +*  (at your option) any later version.
  169.18 +*
  169.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  169.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  169.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  169.22 +*  License for more details.
  169.23 +*
  169.24 +*  You should have received a copy of the GNU General Public License
  169.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  169.26 +***********************************************************************/
  169.27 +
  169.28 +#define GLP_TRAN_DEFINED
  169.29 +typedef struct MPL glp_tran;
  169.30 +
  169.31 +#include "glpmpl.h"
  169.32 +#include "glpapi.h"
  169.33 +
  169.34 +glp_tran *glp_mpl_alloc_wksp(void)
  169.35 +{     /* allocate the MathProg translator workspace */
  169.36 +      glp_tran *tran;
  169.37 +      tran = mpl_initialize();
  169.38 +      return tran;
  169.39 +}
  169.40 +
  169.41 +#if 1 /* 08/XII-2009 */
  169.42 +void _glp_mpl_init_rand(glp_tran *tran, int seed)
  169.43 +{     if (tran->phase != 0)
  169.44 +         xerror("glp_mpl_init_rand: invalid call sequence\n");
  169.45 +      rng_init_rand(tran->rand, seed);
  169.46 +      return;
  169.47 +}
  169.48 +#endif
  169.49 +
  169.50 +int glp_mpl_read_model(glp_tran *tran, const char *fname, int skip)
  169.51 +{     /* read and translate model section */
  169.52 +      int ret;
  169.53 +      if (tran->phase != 0)
  169.54 +         xerror("glp_mpl_read_model: invalid call sequence\n");
  169.55 +      ret = mpl_read_model(tran, (char *)fname, skip);
  169.56 +      if (ret == 1 || ret == 2)
  169.57 +         ret = 0;
  169.58 +      else if (ret == 4)
  169.59 +         ret = 1;
  169.60 +      else
  169.61 +         xassert(ret != ret);
  169.62 +      return ret;
  169.63 +}
  169.64 +
  169.65 +int glp_mpl_read_data(glp_tran *tran, const char *fname)
  169.66 +{     /* read and translate data section */
  169.67 +      int ret;
  169.68 +      if (!(tran->phase == 1 || tran->phase == 2))
  169.69 +         xerror("glp_mpl_read_data: invalid call sequence\n");
  169.70 +      ret = mpl_read_data(tran, (char *)fname);
  169.71 +      if (ret == 2)
  169.72 +         ret = 0;
  169.73 +      else if (ret == 4)
  169.74 +         ret = 1;
  169.75 +      else
  169.76 +         xassert(ret != ret);
  169.77 +      return ret;
  169.78 +}
  169.79 +
  169.80 +int glp_mpl_generate(glp_tran *tran, const char *fname)
  169.81 +{     /* generate the model */
  169.82 +      int ret;
  169.83 +      if (!(tran->phase == 1 || tran->phase == 2))
  169.84 +         xerror("glp_mpl_generate: invalid call sequence\n");
  169.85 +      ret = mpl_generate(tran, (char *)fname);
  169.86 +      if (ret == 3)
  169.87 +         ret = 0;
  169.88 +      else if (ret == 4)
  169.89 +         ret = 1;
  169.90 +      return ret;
  169.91 +}
  169.92 +
  169.93 +void glp_mpl_build_prob(glp_tran *tran, glp_prob *prob)
  169.94 +{     /* build LP/MIP problem instance from the model */
  169.95 +      int m, n, i, j, t, kind, type, len, *ind;
  169.96 +      double lb, ub, *val;
  169.97 +      if (tran->phase != 3)
  169.98 +         xerror("glp_mpl_build_prob: invalid call sequence\n");
  169.99 +      /* erase the problem object */
 169.100 +      glp_erase_prob(prob);
 169.101 +      /* set problem name */
 169.102 +      glp_set_prob_name(prob, mpl_get_prob_name(tran));
 169.103 +      /* build rows (constraints) */
 169.104 +      m = mpl_get_num_rows(tran);
 169.105 +      if (m > 0)
 169.106 +         glp_add_rows(prob, m);
 169.107 +      for (i = 1; i <= m; i++)
 169.108 +      {  /* set row name */
 169.109 +         glp_set_row_name(prob, i, mpl_get_row_name(tran, i));
 169.110 +         /* set row bounds */
 169.111 +         type = mpl_get_row_bnds(tran, i, &lb, &ub);
 169.112 +         switch (type)
 169.113 +         {  case MPL_FR: type = GLP_FR; break;
 169.114 +            case MPL_LO: type = GLP_LO; break;
 169.115 +            case MPL_UP: type = GLP_UP; break;
 169.116 +            case MPL_DB: type = GLP_DB; break;
 169.117 +            case MPL_FX: type = GLP_FX; break;
 169.118 +            default: xassert(type != type);
 169.119 +         }
 169.120 +         if (type == GLP_DB && fabs(lb - ub) < 1e-9 * (1.0 + fabs(lb)))
 169.121 +         {  type = GLP_FX;
 169.122 +            if (fabs(lb) <= fabs(ub)) ub = lb; else lb = ub;
 169.123 +         }
 169.124 +         glp_set_row_bnds(prob, i, type, lb, ub);
 169.125 +         /* warn about non-zero constant term */
 169.126 +         if (mpl_get_row_c0(tran, i) != 0.0)
 169.127 +            xprintf("glp_mpl_build_prob: row %s; constant term %.12g ig"
 169.128 +               "nored\n",
 169.129 +               mpl_get_row_name(tran, i), mpl_get_row_c0(tran, i));
 169.130 +      }
 169.131 +      /* build columns (variables) */
 169.132 +      n = mpl_get_num_cols(tran);
 169.133 +      if (n > 0)
 169.134 +         glp_add_cols(prob, n);
 169.135 +      for (j = 1; j <= n; j++)
 169.136 +      {  /* set column name */
 169.137 +         glp_set_col_name(prob, j, mpl_get_col_name(tran, j));
 169.138 +         /* set column kind */
 169.139 +         kind = mpl_get_col_kind(tran, j);
 169.140 +         switch (kind)
 169.141 +         {  case MPL_NUM:
 169.142 +               break;
 169.143 +            case MPL_INT:
 169.144 +            case MPL_BIN:
 169.145 +               glp_set_col_kind(prob, j, GLP_IV);
 169.146 +               break;
 169.147 +            default:
 169.148 +               xassert(kind != kind);
 169.149 +         }
 169.150 +         /* set column bounds */
 169.151 +         type = mpl_get_col_bnds(tran, j, &lb, &ub);
 169.152 +         switch (type)
 169.153 +         {  case MPL_FR: type = GLP_FR; break;
 169.154 +            case MPL_LO: type = GLP_LO; break;
 169.155 +            case MPL_UP: type = GLP_UP; break;
 169.156 +            case MPL_DB: type = GLP_DB; break;
 169.157 +            case MPL_FX: type = GLP_FX; break;
 169.158 +            default: xassert(type != type);
 169.159 +         }
 169.160 +         if (kind == MPL_BIN)
 169.161 +         {  if (type == GLP_FR || type == GLP_UP || lb < 0.0) lb = 0.0;
 169.162 +            if (type == GLP_FR || type == GLP_LO || ub > 1.0) ub = 1.0;
 169.163 +            type = GLP_DB;
 169.164 +         }
 169.165 +         if (type == GLP_DB && fabs(lb - ub) < 1e-9 * (1.0 + fabs(lb)))
 169.166 +         {  type = GLP_FX;
 169.167 +            if (fabs(lb) <= fabs(ub)) ub = lb; else lb = ub;
 169.168 +         }
 169.169 +         glp_set_col_bnds(prob, j, type, lb, ub);
 169.170 +      }
 169.171 +      /* load the constraint matrix */
 169.172 +      ind = xcalloc(1+n, sizeof(int));
 169.173 +      val = xcalloc(1+n, sizeof(double));
 169.174 +      for (i = 1; i <= m; i++)
 169.175 +      {  len = mpl_get_mat_row(tran, i, ind, val);
 169.176 +         glp_set_mat_row(prob, i, len, ind, val);
 169.177 +      }
 169.178 +      /* build objective function (the first objective is used) */
 169.179 +      for (i = 1; i <= m; i++)
 169.180 +      {  kind = mpl_get_row_kind(tran, i);
 169.181 +         if (kind == MPL_MIN || kind == MPL_MAX)
 169.182 +         {  /* set objective name */
 169.183 +            glp_set_obj_name(prob, mpl_get_row_name(tran, i));
 169.184 +            /* set optimization direction */
 169.185 +            glp_set_obj_dir(prob, kind == MPL_MIN ? GLP_MIN : GLP_MAX);
 169.186 +            /* set constant term */
 169.187 +            glp_set_obj_coef(prob, 0, mpl_get_row_c0(tran, i));
 169.188 +            /* set objective coefficients */
 169.189 +            len = mpl_get_mat_row(tran, i, ind, val);
 169.190 +            for (t = 1; t <= len; t++)
 169.191 +               glp_set_obj_coef(prob, ind[t], val[t]);
 169.192 +            break;
 169.193 +         }
 169.194 +      }
 169.195 +      /* free working arrays */
 169.196 +      xfree(ind);
 169.197 +      xfree(val);
 169.198 +      return;
 169.199 +}
 169.200 +
 169.201 +int glp_mpl_postsolve(glp_tran *tran, glp_prob *prob, int sol)
 169.202 +{     /* postsolve the model */
 169.203 +      int i, j, m, n, stat, ret;
 169.204 +      double prim, dual;
 169.205 +      if (!(tran->phase == 3 && !tran->flag_p))
 169.206 +         xerror("glp_mpl_postsolve: invalid call sequence\n");
 169.207 +      if (!(sol == GLP_SOL || sol == GLP_IPT || sol == GLP_MIP))
 169.208 +         xerror("glp_mpl_postsolve: sol = %d; invalid parameter\n",
 169.209 +            sol);
 169.210 +      m = mpl_get_num_rows(tran);
 169.211 +      n = mpl_get_num_cols(tran);
 169.212 +      if (!(m == glp_get_num_rows(prob) &&
 169.213 +            n == glp_get_num_cols(prob)))
 169.214 +         xerror("glp_mpl_postsolve: wrong problem object\n");
 169.215 +      if (!mpl_has_solve_stmt(tran))
 169.216 +      {  ret = 0;
 169.217 +         goto done;
 169.218 +      }
 169.219 +      for (i = 1; i <= m; i++)
 169.220 +      {  if (sol == GLP_SOL)
 169.221 +         {  stat = glp_get_row_stat(prob, i);
 169.222 +            prim = glp_get_row_prim(prob, i);
 169.223 +            dual = glp_get_row_dual(prob, i);
 169.224 +         }
 169.225 +         else if (sol == GLP_IPT)
 169.226 +         {  stat = 0;
 169.227 +            prim = glp_ipt_row_prim(prob, i);
 169.228 +            dual = glp_ipt_row_dual(prob, i);
 169.229 +         }
 169.230 +         else if (sol == GLP_MIP)
 169.231 +         {  stat = 0;
 169.232 +            prim = glp_mip_row_val(prob, i);
 169.233 +            dual = 0.0;
 169.234 +         }
 169.235 +         else
 169.236 +            xassert(sol != sol);
 169.237 +         if (fabs(prim) < 1e-9) prim = 0.0;
 169.238 +         if (fabs(dual) < 1e-9) dual = 0.0;
 169.239 +         mpl_put_row_soln(tran, i, stat, prim, dual);
 169.240 +      }
 169.241 +      for (j = 1; j <= n; j++)
 169.242 +      {  if (sol == GLP_SOL)
 169.243 +         {  stat = glp_get_col_stat(prob, j);
 169.244 +            prim = glp_get_col_prim(prob, j);
 169.245 +            dual = glp_get_col_dual(prob, j);
 169.246 +         }
 169.247 +         else if (sol == GLP_IPT)
 169.248 +         {  stat = 0;
 169.249 +            prim = glp_ipt_col_prim(prob, j);
 169.250 +            dual = glp_ipt_col_dual(prob, j);
 169.251 +         }
 169.252 +         else if (sol == GLP_MIP)
 169.253 +         {  stat = 0;
 169.254 +            prim = glp_mip_col_val(prob, j);
 169.255 +            dual = 0.0;
 169.256 +         }
 169.257 +         else
 169.258 +            xassert(sol != sol);
 169.259 +         if (fabs(prim) < 1e-9) prim = 0.0;
 169.260 +         if (fabs(dual) < 1e-9) dual = 0.0;
 169.261 +         mpl_put_col_soln(tran, j, stat, prim, dual);
 169.262 +      }
 169.263 +      ret = mpl_postsolve(tran);
 169.264 +      if (ret == 3)
 169.265 +         ret = 0;
 169.266 +      else if (ret == 4)
 169.267 +         ret = 1;
 169.268 +done: return ret;
 169.269 +}
 169.270 +
 169.271 +void glp_mpl_free_wksp(glp_tran *tran)
 169.272 +{     /* free the MathProg translator workspace */
 169.273 +      mpl_terminate(tran);
 169.274 +      return;
 169.275 +}
 169.276 +
 169.277 +/* eof */
   170.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   170.2 +++ b/src/glpapi15.c	Mon Dec 06 13:09:21 2010 +0100
   170.3 @@ -0,0 +1,609 @@
   170.4 +/* glpapi15.c (basic graph and network routines) */
   170.5 +
   170.6 +/***********************************************************************
   170.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   170.8 +*
   170.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  170.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  170.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  170.12 +*  E-mail: <mao@gnu.org>.
  170.13 +*
  170.14 +*  GLPK is free software: you can redistribute it and/or modify it
  170.15 +*  under the terms of the GNU General Public License as published by
  170.16 +*  the Free Software Foundation, either version 3 of the License, or
  170.17 +*  (at your option) any later version.
  170.18 +*
  170.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  170.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  170.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  170.22 +*  License for more details.
  170.23 +*
  170.24 +*  You should have received a copy of the GNU General Public License
  170.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  170.26 +***********************************************************************/
  170.27 +
  170.28 +#include "glpapi.h"
  170.29 +
  170.30 +/* CAUTION: DO NOT CHANGE THE LIMITS BELOW */
  170.31 +
  170.32 +#define NV_MAX 100000000 /* = 100*10^6 */
  170.33 +/* maximal number of vertices in the graph */
  170.34 +
  170.35 +#define NA_MAX 500000000 /* = 500*10^6 */
  170.36 +/* maximal number of arcs in the graph */
  170.37 +
  170.38 +/***********************************************************************
  170.39 +*  NAME
  170.40 +*
  170.41 +*  glp_create_graph - create graph
  170.42 +*
  170.43 +*  SYNOPSIS
  170.44 +*
  170.45 +*  glp_graph *glp_create_graph(int v_size, int a_size);
  170.46 +*
  170.47 +*  DESCRIPTION
  170.48 +*
  170.49 +*  The routine creates a new graph, which initially is empty, i.e. has
  170.50 +*  no vertices and arcs.
  170.51 +*
  170.52 +*  The parameter v_size specifies the size of data associated with each
  170.53 +*  vertex of the graph (0 to 256 bytes).
  170.54 +*
  170.55 +*  The parameter a_size specifies the size of data associated with each
  170.56 +*  arc of the graph (0 to 256 bytes).
  170.57 +*
  170.58 +*  RETURNS
  170.59 +*
  170.60 +*  The routine returns a pointer to the graph created. */
  170.61 +
  170.62 +static void create_graph(glp_graph *G, int v_size, int a_size)
  170.63 +{     G->pool = dmp_create_pool();
  170.64 +      G->name = NULL;
  170.65 +      G->nv_max = 50;
  170.66 +      G->nv = G->na = 0;
  170.67 +      G->v = xcalloc(1+G->nv_max, sizeof(glp_vertex *));
  170.68 +      G->index = NULL;
  170.69 +      G->v_size = v_size;
  170.70 +      G->a_size = a_size;
  170.71 +      return;
  170.72 +}
  170.73 +
  170.74 +glp_graph *glp_create_graph(int v_size, int a_size)
  170.75 +{     glp_graph *G;
  170.76 +      if (!(0 <= v_size && v_size <= 256))
  170.77 +         xerror("glp_create_graph: v_size = %d; invalid size of vertex "
  170.78 +            "data\n", v_size);
  170.79 +      if (!(0 <= a_size && a_size <= 256))
  170.80 +         xerror("glp_create_graph: a_size = %d; invalid size of arc dat"
  170.81 +            "a\n", a_size);
  170.82 +      G = xmalloc(sizeof(glp_graph));
  170.83 +      create_graph(G, v_size, a_size);
  170.84 +      return G;
  170.85 +}
  170.86 +
  170.87 +/***********************************************************************
  170.88 +*  NAME
  170.89 +*
  170.90 +*  glp_set_graph_name - assign (change) graph name
  170.91 +*
  170.92 +*  SYNOPSIS
  170.93 +*
  170.94 +*  void glp_set_graph_name(glp_graph *G, const char *name);
  170.95 +*
  170.96 +*  DESCRIPTION
  170.97 +*
  170.98 +*  The routine glp_set_graph_name assigns a symbolic name specified by
  170.99 +*  the character string name (1 to 255 chars) to the graph.
 170.100 +*
 170.101 +*  If the parameter name is NULL or an empty string, the routine erases
 170.102 +*  the existing symbolic name of the graph. */
 170.103 +
 170.104 +void glp_set_graph_name(glp_graph *G, const char *name)
 170.105 +{     if (G->name != NULL)
 170.106 +      {  dmp_free_atom(G->pool, G->name, strlen(G->name)+1);
 170.107 +         G->name = NULL;
 170.108 +      }
 170.109 +      if (!(name == NULL || name[0] == '\0'))
 170.110 +      {  int j;
 170.111 +         for (j = 0; name[j] != '\0'; j++)
 170.112 +         {  if (j == 256)
 170.113 +               xerror("glp_set_graph_name: graph name too long\n");
 170.114 +            if (iscntrl((unsigned char)name[j]))
 170.115 +               xerror("glp_set_graph_name: graph name contains invalid "
 170.116 +                  "character(s)\n");
 170.117 +         }
 170.118 +         G->name = dmp_get_atom(G->pool, strlen(name)+1);
 170.119 +         strcpy(G->name, name);
 170.120 +      }
 170.121 +      return;
 170.122 +}
 170.123 +
 170.124 +/***********************************************************************
 170.125 +*  NAME
 170.126 +*
 170.127 +*  glp_add_vertices - add new vertices to graph
 170.128 +*
 170.129 +*  SYNOPSIS
 170.130 +*
 170.131 +*  int glp_add_vertices(glp_graph *G, int nadd);
 170.132 +*
 170.133 +*  DESCRIPTION
 170.134 +*
 170.135 +*  The routine glp_add_vertices adds nadd vertices to the specified
 170.136 +*  graph. New vertices are always added to the end of the vertex list,
 170.137 +*  so ordinal numbers of existing vertices remain unchanged.
 170.138 +*
 170.139 +*  Being added each new vertex is isolated (has no incident arcs).
 170.140 +*
 170.141 +*  RETURNS
 170.142 +*
 170.143 +*  The routine glp_add_vertices returns an ordinal number of the first
 170.144 +*  new vertex added to the graph. */
 170.145 +
 170.146 +int glp_add_vertices(glp_graph *G, int nadd)
 170.147 +{     int i, nv_new;
 170.148 +      if (nadd < 1)
 170.149 +         xerror("glp_add_vertices: nadd = %d; invalid number of vertice"
 170.150 +            "s\n", nadd);
 170.151 +      if (nadd > NV_MAX - G->nv)
 170.152 +         xerror("glp_add_vertices: nadd = %d; too many vertices\n",
 170.153 +            nadd);
 170.154 +      /* determine new number of vertices */
 170.155 +      nv_new = G->nv + nadd;
 170.156 +      /* increase the room, if necessary */
 170.157 +      if (G->nv_max < nv_new)
 170.158 +      {  glp_vertex **save = G->v;
 170.159 +         while (G->nv_max < nv_new)
 170.160 +         {  G->nv_max += G->nv_max;
 170.161 +            xassert(G->nv_max > 0);
 170.162 +         }
 170.163 +         G->v = xcalloc(1+G->nv_max, sizeof(glp_vertex *));
 170.164 +         memcpy(&G->v[1], &save[1], G->nv * sizeof(glp_vertex *));
 170.165 +         xfree(save);
 170.166 +      }
 170.167 +      /* add new vertices to the end of the vertex list */
 170.168 +      for (i = G->nv+1; i <= nv_new; i++)
 170.169 +      {  glp_vertex *v;
 170.170 +         G->v[i] = v = dmp_get_atom(G->pool, sizeof(glp_vertex));
 170.171 +         v->i = i;
 170.172 +         v->name = NULL;
 170.173 +         v->entry = NULL;
 170.174 +         if (G->v_size == 0)
 170.175 +            v->data = NULL;
 170.176 +         else
 170.177 +         {  v->data = dmp_get_atom(G->pool, G->v_size);
 170.178 +            memset(v->data, 0, G->v_size);
 170.179 +         }
 170.180 +         v->temp = NULL;
 170.181 +         v->in = v->out = NULL;
 170.182 +      }
 170.183 +      /* set new number of vertices */
 170.184 +      G->nv = nv_new;
 170.185 +      /* return the ordinal number of the first vertex added */
 170.186 +      return nv_new - nadd + 1;
 170.187 +}
 170.188 +
 170.189 +/**********************************************************************/
 170.190 +
 170.191 +void glp_set_vertex_name(glp_graph *G, int i, const char *name)
 170.192 +{     /* assign (change) vertex name */
 170.193 +      glp_vertex *v;
 170.194 +      if (!(1 <= i && i <= G->nv))
 170.195 +         xerror("glp_set_vertex_name: i = %d; vertex number out of rang"
 170.196 +            "e\n", i);
 170.197 +      v = G->v[i];
 170.198 +      if (v->name != NULL)
 170.199 +      {  if (v->entry != NULL)
 170.200 +         {  xassert(G->index != NULL);
 170.201 +            avl_delete_node(G->index, v->entry);
 170.202 +            v->entry = NULL;
 170.203 +         }
 170.204 +         dmp_free_atom(G->pool, v->name, strlen(v->name)+1);
 170.205 +         v->name = NULL;
 170.206 +      }
 170.207 +      if (!(name == NULL || name[0] == '\0'))
 170.208 +      {  int k;
 170.209 +         for (k = 0; name[k] != '\0'; k++)
 170.210 +         {  if (k == 256)
 170.211 +               xerror("glp_set_vertex_name: i = %d; vertex name too lon"
 170.212 +                  "g\n", i);
 170.213 +            if (iscntrl((unsigned char)name[k]))
 170.214 +               xerror("glp_set_vertex_name: i = %d; vertex name contain"
 170.215 +                  "s invalid character(s)\n", i);
 170.216 +         }
 170.217 +         v->name = dmp_get_atom(G->pool, strlen(name)+1);
 170.218 +         strcpy(v->name, name);
 170.219 +         if (G->index != NULL)
 170.220 +         {  xassert(v->entry == NULL);
 170.221 +            v->entry = avl_insert_node(G->index, v->name);
 170.222 +            avl_set_node_link(v->entry, v);
 170.223 +         }
 170.224 +      }
 170.225 +      return;
 170.226 +}
 170.227 +
 170.228 +/***********************************************************************
 170.229 +*  NAME
 170.230 +*
 170.231 +*  glp_add_arc - add new arc to graph
 170.232 +*
 170.233 +*  SYNOPSIS
 170.234 +*
 170.235 +*  glp_arc *glp_add_arc(glp_graph *G, int i, int j);
 170.236 +*
 170.237 +*  DESCRIPTION
 170.238 +*
 170.239 +*  The routine glp_add_arc adds a new arc to the specified graph.
 170.240 +*
 170.241 +*  The parameters i and j specify the ordinal numbers of, resp., tail
 170.242 +*  and head vertices of the arc. Note that self-loops and multiple arcs
 170.243 +*  are allowed.
 170.244 +*
 170.245 +*  RETURNS
 170.246 +*
 170.247 +*  The routine glp_add_arc returns a pointer to the arc added. */
 170.248 +
 170.249 +glp_arc *glp_add_arc(glp_graph *G, int i, int j)
 170.250 +{     glp_arc *a;
 170.251 +      if (!(1 <= i && i <= G->nv))
 170.252 +         xerror("glp_add_arc: i = %d; tail vertex number out of range\n"
 170.253 +            , i);
 170.254 +      if (!(1 <= j && j <= G->nv))
 170.255 +         xerror("glp_add_arc: j = %d; head vertex number out of range\n"
 170.256 +            , j);
 170.257 +      if (G->na == NA_MAX)
 170.258 +         xerror("glp_add_arc: too many arcs\n");
 170.259 +      a = dmp_get_atom(G->pool, sizeof(glp_arc));
 170.260 +      a->tail = G->v[i];
 170.261 +      a->head = G->v[j];
 170.262 +      if (G->a_size == 0)
 170.263 +         a->data = NULL;
 170.264 +      else
 170.265 +      {  a->data = dmp_get_atom(G->pool, G->a_size);
 170.266 +         memset(a->data, 0, G->a_size);
 170.267 +      }
 170.268 +      a->temp = NULL;
 170.269 +      a->t_prev = NULL;
 170.270 +      a->t_next = G->v[i]->out;
 170.271 +      if (a->t_next != NULL) a->t_next->t_prev = a;
 170.272 +      a->h_prev = NULL;
 170.273 +      a->h_next = G->v[j]->in;
 170.274 +      if (a->h_next != NULL) a->h_next->h_prev = a;
 170.275 +      G->v[i]->out = G->v[j]->in = a;
 170.276 +      G->na++;
 170.277 +      return a;
 170.278 +}
 170.279 +
 170.280 +/***********************************************************************
 170.281 +*  NAME
 170.282 +*
 170.283 +*  glp_del_vertices - delete vertices from graph
 170.284 +*
 170.285 +*  SYNOPSIS
 170.286 +*
 170.287 +*  void glp_del_vertices(glp_graph *G, int ndel, const int num[]);
 170.288 +*
 170.289 +*  DESCRIPTION
 170.290 +*
 170.291 +*  The routine glp_del_vertices deletes vertices along with all
 170.292 +*  incident arcs from the specified graph. Ordinal numbers of vertices
 170.293 +*  to be deleted should be placed in locations num[1], ..., num[ndel],
 170.294 +*  ndel > 0.
 170.295 +*
 170.296 +*  Note that deleting vertices involves changing ordinal numbers of
 170.297 +*  other vertices remaining in the graph. New ordinal numbers of the
 170.298 +*  remaining vertices are assigned under the assumption that the
 170.299 +*  original order of vertices is not changed. */
 170.300 +
 170.301 +void glp_del_vertices(glp_graph *G, int ndel, const int num[])
 170.302 +{     glp_vertex *v;
 170.303 +      int i, k, nv_new;
 170.304 +      /* scan the list of vertices to be deleted */
 170.305 +      if (!(1 <= ndel && ndel <= G->nv))
 170.306 +         xerror("glp_del_vertices: ndel = %d; invalid number of vertice"
 170.307 +            "s\n", ndel);
 170.308 +      for (k = 1; k <= ndel; k++)
 170.309 +      {  /* take the number of vertex to be deleted */
 170.310 +         i = num[k];
 170.311 +         /* obtain pointer to i-th vertex */
 170.312 +         if (!(1 <= i && i <= G->nv))
 170.313 +            xerror("glp_del_vertices: num[%d] = %d; vertex number out o"
 170.314 +               "f range\n", k, i);
 170.315 +         v = G->v[i];
 170.316 +         /* check that the vertex is not marked yet */
 170.317 +         if (v->i == 0)
 170.318 +            xerror("glp_del_vertices: num[%d] = %d; duplicate vertex nu"
 170.319 +               "mbers not allowed\n", k, i);
 170.320 +         /* erase symbolic name assigned to the vertex */
 170.321 +         glp_set_vertex_name(G, i, NULL);
 170.322 +         xassert(v->name == NULL);
 170.323 +         xassert(v->entry == NULL);
 170.324 +         /* free vertex data, if allocated */
 170.325 +         if (v->data != NULL)
 170.326 +            dmp_free_atom(G->pool, v->data, G->v_size);
 170.327 +         /* delete all incoming arcs */
 170.328 +         while (v->in != NULL)
 170.329 +            glp_del_arc(G, v->in);
 170.330 +         /* delete all outgoing arcs */
 170.331 +         while (v->out != NULL)
 170.332 +            glp_del_arc(G, v->out);
 170.333 +         /* mark the vertex to be deleted */
 170.334 +         v->i = 0;
 170.335 +      }
 170.336 +      /* delete all marked vertices from the vertex list */
 170.337 +      nv_new = 0;
 170.338 +      for (i = 1; i <= G->nv; i++)
 170.339 +      {  /* obtain pointer to i-th vertex */
 170.340 +         v = G->v[i];
 170.341 +         /* check if the vertex is marked */
 170.342 +         if (v->i == 0)
 170.343 +         {  /* it is marked, delete it */
 170.344 +            dmp_free_atom(G->pool, v, sizeof(glp_vertex));
 170.345 +         }
 170.346 +         else
 170.347 +         {  /* it is not marked, keep it */
 170.348 +            v->i = ++nv_new;
 170.349 +            G->v[v->i] = v;
 170.350 +         }
 170.351 +      }
 170.352 +      /* set new number of vertices in the graph */
 170.353 +      G->nv = nv_new;
 170.354 +      return;
 170.355 +}
 170.356 +
 170.357 +/***********************************************************************
 170.358 +*  NAME
 170.359 +*
 170.360 +*  glp_del_arc - delete arc from graph
 170.361 +*
 170.362 +*  SYNOPSIS
 170.363 +*
 170.364 +*  void glp_del_arc(glp_graph *G, glp_arc *a);
 170.365 +*
 170.366 +*  DESCRIPTION
 170.367 +*
 170.368 +*  The routine glp_del_arc deletes an arc from the specified graph.
 170.369 +*  The arc to be deleted must exist. */
 170.370 +
 170.371 +void glp_del_arc(glp_graph *G, glp_arc *a)
 170.372 +{     /* some sanity checks */
 170.373 +      xassert(G->na > 0);
 170.374 +      xassert(1 <= a->tail->i && a->tail->i <= G->nv);
 170.375 +      xassert(a->tail == G->v[a->tail->i]);
 170.376 +      xassert(1 <= a->head->i && a->head->i <= G->nv);
 170.377 +      xassert(a->head == G->v[a->head->i]);
 170.378 +      /* remove the arc from the list of incoming arcs */
 170.379 +      if (a->h_prev == NULL)
 170.380 +         a->head->in = a->h_next;
 170.381 +      else
 170.382 +         a->h_prev->h_next = a->h_next;
 170.383 +      if (a->h_next == NULL)
 170.384 +         ;
 170.385 +      else
 170.386 +         a->h_next->h_prev = a->h_prev;
 170.387 +      /* remove the arc from the list of outgoing arcs */
 170.388 +      if (a->t_prev == NULL)
 170.389 +         a->tail->out = a->t_next;
 170.390 +      else
 170.391 +         a->t_prev->t_next = a->t_next;
 170.392 +      if (a->t_next == NULL)
 170.393 +         ;
 170.394 +      else
 170.395 +         a->t_next->t_prev = a->t_prev;
 170.396 +      /* free arc data, if allocated */
 170.397 +      if (a->data != NULL)
 170.398 +         dmp_free_atom(G->pool, a->data, G->a_size);
 170.399 +      /* delete the arc from the graph */
 170.400 +      dmp_free_atom(G->pool, a, sizeof(glp_arc));
 170.401 +      G->na--;
 170.402 +      return;
 170.403 +}
 170.404 +
 170.405 +/***********************************************************************
 170.406 +*  NAME
 170.407 +*
 170.408 +*  glp_erase_graph - erase graph content
 170.409 +*
 170.410 +*  SYNOPSIS
 170.411 +*
 170.412 +*  void glp_erase_graph(glp_graph *G, int v_size, int a_size);
 170.413 +*
 170.414 +*  DESCRIPTION
 170.415 +*
 170.416 +*  The routine glp_erase_graph erases the content of the specified
 170.417 +*  graph. The effect of this operation is the same as if the graph
 170.418 +*  would be deleted with the routine glp_delete_graph and then created
 170.419 +*  anew with the routine glp_create_graph, with exception that the
 170.420 +*  handle (pointer) to the graph remains valid. */
 170.421 +
 170.422 +static void delete_graph(glp_graph *G)
 170.423 +{     dmp_delete_pool(G->pool);
 170.424 +      xfree(G->v);
 170.425 +      if (G->index != NULL) avl_delete_tree(G->index);
 170.426 +      return;
 170.427 +}
 170.428 +
 170.429 +void glp_erase_graph(glp_graph *G, int v_size, int a_size)
 170.430 +{     if (!(0 <= v_size && v_size <= 256))
 170.431 +         xerror("glp_erase_graph: v_size = %d; invalid size of vertex d"
 170.432 +            "ata\n", v_size);
 170.433 +      if (!(0 <= a_size && a_size <= 256))
 170.434 +         xerror("glp_erase_graph: a_size = %d; invalid size of arc data"
 170.435 +            "\n", a_size);
 170.436 +      delete_graph(G);
 170.437 +      create_graph(G, v_size, a_size);
 170.438 +      return;
 170.439 +}
 170.440 +
 170.441 +/***********************************************************************
 170.442 +*  NAME
 170.443 +*
 170.444 +*  glp_delete_graph - delete graph
 170.445 +*
 170.446 +*  SYNOPSIS
 170.447 +*
 170.448 +*  void glp_delete_graph(glp_graph *G);
 170.449 +*
 170.450 +*  DESCRIPTION
 170.451 +*
 170.452 +*  The routine glp_delete_graph deletes the specified graph and frees
 170.453 +*  all the memory allocated to this program object. */
 170.454 +
 170.455 +void glp_delete_graph(glp_graph *G)
 170.456 +{     delete_graph(G);
 170.457 +      xfree(G);
 170.458 +      return;
 170.459 +}
 170.460 +
 170.461 +/**********************************************************************/
 170.462 +
 170.463 +void glp_create_v_index(glp_graph *G)
 170.464 +{     /* create vertex name index */
 170.465 +      glp_vertex *v;
 170.466 +      int i;
 170.467 +      if (G->index == NULL)
 170.468 +      {  G->index = avl_create_tree(avl_strcmp, NULL);
 170.469 +         for (i = 1; i <= G->nv; i++)
 170.470 +         {  v = G->v[i];
 170.471 +            xassert(v->entry == NULL);
 170.472 +            if (v->name != NULL)
 170.473 +            {  v->entry = avl_insert_node(G->index, v->name);
 170.474 +               avl_set_node_link(v->entry, v);
 170.475 +            }
 170.476 +         }
 170.477 +      }
 170.478 +      return;
 170.479 +}
 170.480 +
 170.481 +int glp_find_vertex(glp_graph *G, const char *name)
 170.482 +{     /* find vertex by its name */
 170.483 +      AVLNODE *node;
 170.484 +      int i = 0;
 170.485 +      if (G->index == NULL)
 170.486 +         xerror("glp_find_vertex: vertex name index does not exist\n");
 170.487 +      if (!(name == NULL || name[0] == '\0' || strlen(name) > 255))
 170.488 +      {  node = avl_find_node(G->index, name);
 170.489 +         if (node != NULL)
 170.490 +            i = ((glp_vertex *)avl_get_node_link(node))->i;
 170.491 +      }
 170.492 +      return i;
 170.493 +}
 170.494 +
 170.495 +void glp_delete_v_index(glp_graph *G)
 170.496 +{     /* delete vertex name index */
 170.497 +      int i;
 170.498 +      if (G->index != NULL)
 170.499 +      {  avl_delete_tree(G->index), G->index = NULL;
 170.500 +         for (i = 1; i <= G->nv; i++) G->v[i]->entry = NULL;
 170.501 +      }
 170.502 +      return;
 170.503 +}
 170.504 +
 170.505 +/***********************************************************************
 170.506 +*  NAME
 170.507 +*
 170.508 +*  glp_read_graph - read graph from plain text file
 170.509 +*
 170.510 +*  SYNOPSIS
 170.511 +*
 170.512 +*  int glp_read_graph(glp_graph *G, const char *fname);
 170.513 +*
 170.514 +*  DESCRIPTION
 170.515 +*
 170.516 +*  The routine glp_read_graph reads a graph from a plain text file.
 170.517 +*
 170.518 +*  RETURNS
 170.519 +*
 170.520 +*  If the operation was successful, the routine returns zero. Otherwise
 170.521 +*  it prints an error message and returns non-zero. */
 170.522 +
 170.523 +int glp_read_graph(glp_graph *G, const char *fname)
 170.524 +{     glp_data *data;
 170.525 +      jmp_buf jump;
 170.526 +      int nv, na, i, j, k, ret;
 170.527 +      glp_erase_graph(G, G->v_size, G->a_size);
 170.528 +      xprintf("Reading graph from `%s'...\n", fname);
 170.529 +      data = glp_sdf_open_file(fname);
 170.530 +      if (data == NULL)
 170.531 +      {  ret = 1;
 170.532 +         goto done;
 170.533 +      }
 170.534 +      if (setjmp(jump))
 170.535 +      {  ret = 1;
 170.536 +         goto done;
 170.537 +      }
 170.538 +      glp_sdf_set_jump(data, jump);
 170.539 +      nv = glp_sdf_read_int(data);
 170.540 +      if (nv < 0)
 170.541 +         glp_sdf_error(data, "invalid number of vertices\n");
 170.542 +      na = glp_sdf_read_int(data);
 170.543 +      if (na < 0)
 170.544 +         glp_sdf_error(data, "invalid number of arcs\n");
 170.545 +      xprintf("Graph has %d vert%s and %d arc%s\n",
 170.546 +         nv, nv == 1 ? "ex" : "ices", na, na == 1 ? "" : "s");
 170.547 +      if (nv > 0) glp_add_vertices(G, nv);
 170.548 +      for (k = 1; k <= na; k++)
 170.549 +      {  i = glp_sdf_read_int(data);
 170.550 +         if (!(1 <= i && i <= nv))
 170.551 +            glp_sdf_error(data, "tail vertex number out of range\n");
 170.552 +         j = glp_sdf_read_int(data);
 170.553 +         if (!(1 <= j && j <= nv))
 170.554 +            glp_sdf_error(data, "head vertex number out of range\n");
 170.555 +         glp_add_arc(G, i, j);
 170.556 +      }
 170.557 +      xprintf("%d lines were read\n", glp_sdf_line(data));
 170.558 +      ret = 0;
 170.559 +done: if (data != NULL) glp_sdf_close_file(data);
 170.560 +      return ret;
 170.561 +}
 170.562 +
 170.563 +/***********************************************************************
 170.564 +*  NAME
 170.565 +*
 170.566 +*  glp_write_graph - write graph to plain text file
 170.567 +*
 170.568 +*  SYNOPSIS
 170.569 +*
 170.570 +*  int glp_write_graph(glp_graph *G, const char *fname).
 170.571 +*
 170.572 +*  DESCRIPTION
 170.573 +*
 170.574 +*  The routine glp_write_graph writes the specified graph to a plain
 170.575 +*  text file.
 170.576 +*
 170.577 +*  RETURNS
 170.578 +*
 170.579 +*  If the operation was successful, the routine returns zero. Otherwise
 170.580 +*  it prints an error message and returns non-zero. */
 170.581 +
 170.582 +int glp_write_graph(glp_graph *G, const char *fname)
 170.583 +{     XFILE *fp;
 170.584 +      glp_vertex *v;
 170.585 +      glp_arc *a;
 170.586 +      int i, count, ret;
 170.587 +      xprintf("Writing graph to `%s'...\n", fname);
 170.588 +      fp = xfopen(fname, "w"), count = 0;
 170.589 +      if (fp == NULL)
 170.590 +      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
 170.591 +         ret = 1;
 170.592 +         goto done;
 170.593 +      }
 170.594 +      xfprintf(fp, "%d %d\n", G->nv, G->na), count++;
 170.595 +      for (i = 1; i <= G->nv; i++)
 170.596 +      {  v = G->v[i];
 170.597 +         for (a = v->out; a != NULL; a = a->t_next)
 170.598 +            xfprintf(fp, "%d %d\n", a->tail->i, a->head->i), count++;
 170.599 +      }
 170.600 +      xfflush(fp);
 170.601 +      if (xferror(fp))
 170.602 +      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
 170.603 +         ret = 1;
 170.604 +         goto done;
 170.605 +      }
 170.606 +      xprintf("%d lines were written\n", count);
 170.607 +      ret = 0;
 170.608 +done: if (fp != NULL) xfclose(fp);
 170.609 +      return ret;
 170.610 +}
 170.611 +
 170.612 +/* eof */
   171.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   171.2 +++ b/src/glpapi16.c	Mon Dec 06 13:09:21 2010 +0100
   171.3 @@ -0,0 +1,329 @@
   171.4 +/* glpapi16.c (graph and network analysis routines) */
   171.5 +
   171.6 +/***********************************************************************
   171.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   171.8 +*
   171.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  171.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  171.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  171.12 +*  E-mail: <mao@gnu.org>.
  171.13 +*
  171.14 +*  GLPK is free software: you can redistribute it and/or modify it
  171.15 +*  under the terms of the GNU General Public License as published by
  171.16 +*  the Free Software Foundation, either version 3 of the License, or
  171.17 +*  (at your option) any later version.
  171.18 +*
  171.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  171.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  171.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  171.22 +*  License for more details.
  171.23 +*
  171.24 +*  You should have received a copy of the GNU General Public License
  171.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  171.26 +***********************************************************************/
  171.27 +
  171.28 +#include "glpapi.h"
  171.29 +#include "glpnet.h"
  171.30 +
  171.31 +/***********************************************************************
  171.32 +*  NAME
  171.33 +*
  171.34 +*  glp_weak_comp - find all weakly connected components of graph
  171.35 +*
  171.36 +*  SYNOPSIS
  171.37 +*
  171.38 +*  int glp_weak_comp(glp_graph *G, int v_num);
  171.39 +*
  171.40 +*  DESCRIPTION
  171.41 +*
  171.42 +*  The routine glp_weak_comp finds all weakly connected components of
  171.43 +*  the specified graph.
  171.44 +*
  171.45 +*  The parameter v_num specifies an offset of the field of type int
  171.46 +*  in the vertex data block, to which the routine stores the number of
  171.47 +*  a (weakly) connected component containing that vertex. If v_num < 0,
  171.48 +*  no component numbers are stored.
  171.49 +*
  171.50 +*  The components are numbered in arbitrary order from 1 to nc, where
  171.51 +*  nc is the total number of components found, 0 <= nc <= |V|.
  171.52 +*
  171.53 +*  RETURNS
  171.54 +*
  171.55 +*  The routine returns nc, the total number of components found. */
  171.56 +
  171.57 +int glp_weak_comp(glp_graph *G, int v_num)
  171.58 +{     glp_vertex *v;
  171.59 +      glp_arc *a;
  171.60 +      int f, i, j, nc, nv, pos1, pos2, *prev, *next, *list;
  171.61 +      if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int))
  171.62 +         xerror("glp_weak_comp: v_num = %d; invalid offset\n", v_num);
  171.63 +      nv = G->nv;
  171.64 +      if (nv == 0)
  171.65 +      {  nc = 0;
  171.66 +         goto done;
  171.67 +      }
  171.68 +      /* allocate working arrays */
  171.69 +      prev = xcalloc(1+nv, sizeof(int));
  171.70 +      next = xcalloc(1+nv, sizeof(int));
  171.71 +      list = xcalloc(1+nv, sizeof(int));
  171.72 +      /* if vertex i is unlabelled, prev[i] is the index of previous
  171.73 +         unlabelled vertex, and next[i] is the index of next unlabelled
  171.74 +         vertex; if vertex i is labelled, then prev[i] < 0, and next[i]
  171.75 +         is the connected component number */
  171.76 +      /* initially all vertices are unlabelled */
  171.77 +      f = 1;
  171.78 +      for (i = 1; i <= nv; i++)
  171.79 +         prev[i] = i - 1, next[i] = i + 1;
  171.80 +      next[nv] = 0;
  171.81 +      /* main loop (until all vertices have been labelled) */
  171.82 +      nc = 0;
  171.83 +      while (f != 0)
  171.84 +      {  /* take an unlabelled vertex */
  171.85 +         i = f;
  171.86 +         /* and remove it from the list of unlabelled vertices */
  171.87 +         f = next[i];
  171.88 +         if (f != 0) prev[f] = 0;
  171.89 +         /* label the vertex; it begins a new component */
  171.90 +         prev[i] = -1, next[i] = ++nc;
  171.91 +         /* breadth first search */
  171.92 +         list[1] = i, pos1 = pos2 = 1;
  171.93 +         while (pos1 <= pos2)
  171.94 +         {  /* dequeue vertex i */
  171.95 +            i = list[pos1++];
  171.96 +            /* consider all arcs incoming to vertex i */
  171.97 +            for (a = G->v[i]->in; a != NULL; a = a->h_next)
  171.98 +            {  /* vertex j is adjacent to vertex i */
  171.99 +               j = a->tail->i;
 171.100 +               if (prev[j] >= 0)
 171.101 +               {  /* vertex j is unlabelled */
 171.102 +                  /* remove it from the list of unlabelled vertices */
 171.103 +                  if (prev[j] == 0)
 171.104 +                     f = next[j];
 171.105 +                  else
 171.106 +                     next[prev[j]] = next[j];
 171.107 +                  if (next[j] == 0)
 171.108 +                     ;
 171.109 +                  else
 171.110 +                     prev[next[j]] = prev[j];
 171.111 +                  /* label the vertex */
 171.112 +                  prev[j] = -1, next[j] = nc;
 171.113 +                  /* and enqueue it for further consideration */
 171.114 +                  list[++pos2] = j;
 171.115 +               }
 171.116 +            }
 171.117 +            /* consider all arcs outgoing from vertex i */
 171.118 +            for (a = G->v[i]->out; a != NULL; a = a->t_next)
 171.119 +            {  /* vertex j is adjacent to vertex i */
 171.120 +               j = a->head->i;
 171.121 +               if (prev[j] >= 0)
 171.122 +               {  /* vertex j is unlabelled */
 171.123 +                  /* remove it from the list of unlabelled vertices */
 171.124 +                  if (prev[j] == 0)
 171.125 +                     f = next[j];
 171.126 +                  else
 171.127 +                     next[prev[j]] = next[j];
 171.128 +                  if (next[j] == 0)
 171.129 +                     ;
 171.130 +                  else
 171.131 +                     prev[next[j]] = prev[j];
 171.132 +                  /* label the vertex */
 171.133 +                  prev[j] = -1, next[j] = nc;
 171.134 +                  /* and enqueue it for further consideration */
 171.135 +                  list[++pos2] = j;
 171.136 +               }
 171.137 +            }
 171.138 +         }
 171.139 +      }
 171.140 +      /* store component numbers */
 171.141 +      if (v_num >= 0)
 171.142 +      {  for (i = 1; i <= nv; i++)
 171.143 +         {  v = G->v[i];
 171.144 +            memcpy((char *)v->data + v_num, &next[i], sizeof(int));
 171.145 +         }
 171.146 +      }
 171.147 +      /* free working arrays */
 171.148 +      xfree(prev);
 171.149 +      xfree(next);
 171.150 +      xfree(list);
 171.151 +done: return nc;
 171.152 +}
 171.153 +
 171.154 +/***********************************************************************
 171.155 +*  NAME
 171.156 +*
 171.157 +*  glp_strong_comp - find all strongly connected components of graph
 171.158 +*
 171.159 +*  SYNOPSIS
 171.160 +*
 171.161 +*  int glp_strong_comp(glp_graph *G, int v_num);
 171.162 +*
 171.163 +*  DESCRIPTION
 171.164 +*
 171.165 +*  The routine glp_strong_comp finds all strongly connected components
 171.166 +*  of the specified graph.
 171.167 +*
 171.168 +*  The parameter v_num specifies an offset of the field of type int
 171.169 +*  in the vertex data block, to which the routine stores the number of
 171.170 +*  a strongly connected component containing that vertex. If v_num < 0,
 171.171 +*  no component numbers are stored.
 171.172 +*
 171.173 +*  The components are numbered in arbitrary order from 1 to nc, where
 171.174 +*  nc is the total number of components found, 0 <= nc <= |V|. However,
 171.175 +*  the component numbering has the property that for every arc (i->j)
 171.176 +*  in the graph the condition num(i) >= num(j) holds.
 171.177 +*
 171.178 +*  RETURNS
 171.179 +*
 171.180 +*  The routine returns nc, the total number of components found. */
 171.181 +
 171.182 +int glp_strong_comp(glp_graph *G, int v_num)
 171.183 +{     glp_vertex *v;
 171.184 +      glp_arc *a;
 171.185 +      int i, k, last, n, na, nc, *icn, *ip, *lenr, *ior, *ib, *lowl,
 171.186 +         *numb, *prev;
 171.187 +      if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int))
 171.188 +         xerror("glp_strong_comp: v_num = %d; invalid offset\n",
 171.189 +            v_num);
 171.190 +      n = G->nv;
 171.191 +      if (n == 0)
 171.192 +      {  nc = 0;
 171.193 +         goto done;
 171.194 +      }
 171.195 +      na = G->na;
 171.196 +      icn = xcalloc(1+na, sizeof(int));
 171.197 +      ip = xcalloc(1+n, sizeof(int));
 171.198 +      lenr = xcalloc(1+n, sizeof(int));
 171.199 +      ior = xcalloc(1+n, sizeof(int));
 171.200 +      ib = xcalloc(1+n, sizeof(int));
 171.201 +      lowl = xcalloc(1+n, sizeof(int));
 171.202 +      numb = xcalloc(1+n, sizeof(int));
 171.203 +      prev = xcalloc(1+n, sizeof(int));
 171.204 +      k = 1;
 171.205 +      for (i = 1; i <= n; i++)
 171.206 +      {  v = G->v[i];
 171.207 +         ip[i] = k;
 171.208 +         for (a = v->out; a != NULL; a = a->t_next)
 171.209 +            icn[k++] = a->head->i;
 171.210 +         lenr[i] = k - ip[i];
 171.211 +      }
 171.212 +      xassert(na == k-1);
 171.213 +      nc = mc13d(n, icn, ip, lenr, ior, ib, lowl, numb, prev);
 171.214 +      if (v_num >= 0)
 171.215 +      {  xassert(ib[1] == 1);
 171.216 +         for (k = 1; k <= nc; k++)
 171.217 +         {  last = (k < nc ? ib[k+1] : n+1);
 171.218 +            xassert(ib[k] < last);
 171.219 +            for (i = ib[k]; i < last; i++)
 171.220 +            {  v = G->v[ior[i]];
 171.221 +               memcpy((char *)v->data + v_num, &k, sizeof(int));
 171.222 +            }
 171.223 +         }
 171.224 +      }
 171.225 +      xfree(icn);
 171.226 +      xfree(ip);
 171.227 +      xfree(lenr);
 171.228 +      xfree(ior);
 171.229 +      xfree(ib);
 171.230 +      xfree(lowl);
 171.231 +      xfree(numb);
 171.232 +      xfree(prev);
 171.233 +done: return nc;
 171.234 +}
 171.235 +
 171.236 +/***********************************************************************
 171.237 +*  NAME
 171.238 +*
 171.239 +*  glp_top_sort - topological sorting of acyclic digraph
 171.240 +*
 171.241 +*  SYNOPSIS
 171.242 +*
 171.243 +*  int glp_top_sort(glp_graph *G, int v_num);
 171.244 +*
 171.245 +*  DESCRIPTION
 171.246 +*
 171.247 +*  The routine glp_top_sort performs topological sorting of vertices of
 171.248 +*  the specified acyclic digraph.
 171.249 +*
 171.250 +*  The parameter v_num specifies an offset of the field of type int in
 171.251 +*  the vertex data block, to which the routine stores the vertex number
 171.252 +*  assigned. If v_num < 0, vertex numbers are not stored.
 171.253 +*
 171.254 +*  The vertices are numbered from 1 to n, where n is the total number
 171.255 +*  of vertices in the graph. The vertex numbering has the property that
 171.256 +*  for every arc (i->j) in the graph the condition num(i) < num(j)
 171.257 +*  holds. Special case num(i) = 0 means that vertex i is not assigned a
 171.258 +*  number, because the graph is *not* acyclic.
 171.259 +*
 171.260 +*  RETURNS
 171.261 +*
 171.262 +*  If the graph is acyclic and therefore all the vertices have been
 171.263 +*  assigned numbers, the routine glp_top_sort returns zero. Otherwise,
 171.264 +*  if the graph is not acyclic, the routine returns the number of
 171.265 +*  vertices which have not been numbered, i.e. for which num(i) = 0. */
 171.266 +
 171.267 +static int top_sort(glp_graph *G, int num[])
 171.268 +{     glp_arc *a;
 171.269 +      int i, j, cnt, top, *stack, *indeg;
 171.270 +      /* allocate working arrays */
 171.271 +      indeg = xcalloc(1+G->nv, sizeof(int));
 171.272 +      stack = xcalloc(1+G->nv, sizeof(int));
 171.273 +      /* determine initial indegree of each vertex; push into the stack
 171.274 +         the vertices having zero indegree */
 171.275 +      top = 0;
 171.276 +      for (i = 1; i <= G->nv; i++)
 171.277 +      {  num[i] = indeg[i] = 0;
 171.278 +         for (a = G->v[i]->in; a != NULL; a = a->h_next)
 171.279 +            indeg[i]++;
 171.280 +         if (indeg[i] == 0)
 171.281 +            stack[++top] = i;
 171.282 +      }
 171.283 +      /* assign numbers to vertices in the sorted order */
 171.284 +      cnt = 0;
 171.285 +      while (top > 0)
 171.286 +      {  /* pull vertex i from the stack */
 171.287 +         i = stack[top--];
 171.288 +         /* it has zero indegree in the current graph */
 171.289 +         xassert(indeg[i] == 0);
 171.290 +         /* so assign it a next number */
 171.291 +         xassert(num[i] == 0);
 171.292 +         num[i] = ++cnt;
 171.293 +         /* remove vertex i from the current graph, update indegree of
 171.294 +            its adjacent vertices, and push into the stack new vertices
 171.295 +            whose indegree becomes zero */
 171.296 +         for (a = G->v[i]->out; a != NULL; a = a->t_next)
 171.297 +         {  j = a->head->i;
 171.298 +            /* there exists arc (i->j) in the graph */
 171.299 +            xassert(indeg[j] > 0);
 171.300 +            indeg[j]--;
 171.301 +            if (indeg[j] == 0)
 171.302 +               stack[++top] = j;
 171.303 +         }
 171.304 +      }
 171.305 +      /* free working arrays */
 171.306 +      xfree(indeg);
 171.307 +      xfree(stack);
 171.308 +      return G->nv - cnt;
 171.309 +}
 171.310 +
 171.311 +int glp_top_sort(glp_graph *G, int v_num)
 171.312 +{     glp_vertex *v;
 171.313 +      int i, cnt, *num;
 171.314 +      if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int))
 171.315 +         xerror("glp_top_sort: v_num = %d; invalid offset\n", v_num);
 171.316 +      if (G->nv == 0)
 171.317 +      {  cnt = 0;
 171.318 +         goto done;
 171.319 +      }
 171.320 +      num = xcalloc(1+G->nv, sizeof(int));
 171.321 +      cnt = top_sort(G, num);
 171.322 +      if (v_num >= 0)
 171.323 +      {  for (i = 1; i <= G->nv; i++)
 171.324 +         {  v = G->v[i];
 171.325 +            memcpy((char *)v->data + v_num, &num[i], sizeof(int));
 171.326 +         }
 171.327 +      }
 171.328 +      xfree(num);
 171.329 +done: return cnt;
 171.330 +}
 171.331 +
 171.332 +/* eof */
   172.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   172.2 +++ b/src/glpapi17.c	Mon Dec 06 13:09:21 2010 +0100
   172.3 @@ -0,0 +1,1048 @@
   172.4 +/* glpapi17.c (flow network problems) */
   172.5 +
   172.6 +/***********************************************************************
   172.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   172.8 +*
   172.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  172.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  172.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  172.12 +*  E-mail: <mao@gnu.org>.
  172.13 +*
  172.14 +*  GLPK is free software: you can redistribute it and/or modify it
  172.15 +*  under the terms of the GNU General Public License as published by
  172.16 +*  the Free Software Foundation, either version 3 of the License, or
  172.17 +*  (at your option) any later version.
  172.18 +*
  172.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  172.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  172.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  172.22 +*  License for more details.
  172.23 +*
  172.24 +*  You should have received a copy of the GNU General Public License
  172.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  172.26 +***********************************************************************/
  172.27 +
  172.28 +#include "glpapi.h"
  172.29 +#include "glpnet.h"
  172.30 +
  172.31 +/***********************************************************************
  172.32 +*  NAME
  172.33 +*
  172.34 +*  glp_mincost_lp - convert minimum cost flow problem to LP
  172.35 +*
  172.36 +*  SYNOPSIS
  172.37 +*
  172.38 +*  void glp_mincost_lp(glp_prob *lp, glp_graph *G, int names,
  172.39 +*     int v_rhs, int a_low, int a_cap, int a_cost);
  172.40 +*
  172.41 +*  DESCRIPTION
  172.42 +*
  172.43 +*  The routine glp_mincost_lp builds an LP problem, which corresponds
  172.44 +*  to the minimum cost flow problem on the specified network G. */
  172.45 +
  172.46 +void glp_mincost_lp(glp_prob *lp, glp_graph *G, int names, int v_rhs,
  172.47 +      int a_low, int a_cap, int a_cost)
  172.48 +{     glp_vertex *v;
  172.49 +      glp_arc *a;
  172.50 +      int i, j, type, ind[1+2];
  172.51 +      double rhs, low, cap, cost, val[1+2];
  172.52 +      if (!(names == GLP_ON || names == GLP_OFF))
  172.53 +         xerror("glp_mincost_lp: names = %d; invalid parameter\n",
  172.54 +            names);
  172.55 +      if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
  172.56 +         xerror("glp_mincost_lp: v_rhs = %d; invalid offset\n", v_rhs);
  172.57 +      if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
  172.58 +         xerror("glp_mincost_lp: a_low = %d; invalid offset\n", a_low);
  172.59 +      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
  172.60 +         xerror("glp_mincost_lp: a_cap = %d; invalid offset\n", a_cap);
  172.61 +      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
  172.62 +         xerror("glp_mincost_lp: a_cost = %d; invalid offset\n", a_cost)
  172.63 +            ;
  172.64 +      glp_erase_prob(lp);
  172.65 +      if (names) glp_set_prob_name(lp, G->name);
  172.66 +      if (G->nv > 0) glp_add_rows(lp, G->nv);
  172.67 +      for (i = 1; i <= G->nv; i++)
  172.68 +      {  v = G->v[i];
  172.69 +         if (names) glp_set_row_name(lp, i, v->name);
  172.70 +         if (v_rhs >= 0)
  172.71 +            memcpy(&rhs, (char *)v->data + v_rhs, sizeof(double));
  172.72 +         else
  172.73 +            rhs = 0.0;
  172.74 +         glp_set_row_bnds(lp, i, GLP_FX, rhs, rhs);
  172.75 +      }
  172.76 +      if (G->na > 0) glp_add_cols(lp, G->na);
  172.77 +      for (i = 1, j = 0; i <= G->nv; i++)
  172.78 +      {  v = G->v[i];
  172.79 +         for (a = v->out; a != NULL; a = a->t_next)
  172.80 +         {  j++;
  172.81 +            if (names)
  172.82 +            {  char name[50+1];
  172.83 +               sprintf(name, "x[%d,%d]", a->tail->i, a->head->i);
  172.84 +               xassert(strlen(name) < sizeof(name));
  172.85 +               glp_set_col_name(lp, j, name);
  172.86 +            }
  172.87 +            if (a->tail->i != a->head->i)
  172.88 +            {  ind[1] = a->tail->i, val[1] = +1.0;
  172.89 +               ind[2] = a->head->i, val[2] = -1.0;
  172.90 +               glp_set_mat_col(lp, j, 2, ind, val);
  172.91 +            }
  172.92 +            if (a_low >= 0)
  172.93 +               memcpy(&low, (char *)a->data + a_low, sizeof(double));
  172.94 +            else
  172.95 +               low = 0.0;
  172.96 +            if (a_cap >= 0)
  172.97 +               memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
  172.98 +            else
  172.99 +               cap = 1.0;
 172.100 +            if (cap == DBL_MAX)
 172.101 +               type = GLP_LO;
 172.102 +            else if (low != cap)
 172.103 +               type = GLP_DB;
 172.104 +            else
 172.105 +               type = GLP_FX;
 172.106 +            glp_set_col_bnds(lp, j, type, low, cap);
 172.107 +            if (a_cost >= 0)
 172.108 +               memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
 172.109 +            else
 172.110 +               cost = 0.0;
 172.111 +            glp_set_obj_coef(lp, j, cost);
 172.112 +         }
 172.113 +      }
 172.114 +      xassert(j == G->na);
 172.115 +      return;
 172.116 +}
 172.117 +
 172.118 +/**********************************************************************/
 172.119 +
 172.120 +int glp_mincost_okalg(glp_graph *G, int v_rhs, int a_low, int a_cap,
 172.121 +      int a_cost, double *sol, int a_x, int v_pi)
 172.122 +{     /* find minimum-cost flow with out-of-kilter algorithm */
 172.123 +      glp_vertex *v;
 172.124 +      glp_arc *a;
 172.125 +      int nv, na, i, k, s, t, *tail, *head, *low, *cap, *cost, *x, *pi,
 172.126 +         ret;
 172.127 +      double sum, temp;
 172.128 +      if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
 172.129 +         xerror("glp_mincost_okalg: v_rhs = %d; invalid offset\n",
 172.130 +            v_rhs);
 172.131 +      if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
 172.132 +         xerror("glp_mincost_okalg: a_low = %d; invalid offset\n",
 172.133 +            a_low);
 172.134 +      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
 172.135 +         xerror("glp_mincost_okalg: a_cap = %d; invalid offset\n",
 172.136 +            a_cap);
 172.137 +      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
 172.138 +         xerror("glp_mincost_okalg: a_cost = %d; invalid offset\n",
 172.139 +            a_cost);
 172.140 +      if (a_x >= 0 && a_x > G->a_size - (int)sizeof(double))
 172.141 +         xerror("glp_mincost_okalg: a_x = %d; invalid offset\n", a_x);
 172.142 +      if (v_pi >= 0 && v_pi > G->v_size - (int)sizeof(double))
 172.143 +         xerror("glp_mincost_okalg: v_pi = %d; invalid offset\n", v_pi);
 172.144 +      /* s is artificial source node */
 172.145 +      s = G->nv + 1;
 172.146 +      /* t is artificial sink node */
 172.147 +      t = s + 1;
 172.148 +      /* nv is the total number of nodes in the resulting network */
 172.149 +      nv = t;
 172.150 +      /* na is the total number of arcs in the resulting network */
 172.151 +      na = G->na + 1;
 172.152 +      for (i = 1; i <= G->nv; i++)
 172.153 +      {  v = G->v[i];
 172.154 +         if (v_rhs >= 0)
 172.155 +            memcpy(&temp, (char *)v->data + v_rhs, sizeof(double));
 172.156 +         else
 172.157 +            temp = 0.0;
 172.158 +         if (temp != 0.0) na++;
 172.159 +      }
 172.160 +      /* allocate working arrays */
 172.161 +      tail = xcalloc(1+na, sizeof(int));
 172.162 +      head = xcalloc(1+na, sizeof(int));
 172.163 +      low = xcalloc(1+na, sizeof(int));
 172.164 +      cap = xcalloc(1+na, sizeof(int));
 172.165 +      cost = xcalloc(1+na, sizeof(int));
 172.166 +      x = xcalloc(1+na, sizeof(int));
 172.167 +      pi = xcalloc(1+nv, sizeof(int));
 172.168 +      /* construct the resulting network */
 172.169 +      k = 0;
 172.170 +      /* (original arcs) */
 172.171 +      for (i = 1; i <= G->nv; i++)
 172.172 +      {  v = G->v[i];
 172.173 +         for (a = v->out; a != NULL; a = a->t_next)
 172.174 +         {  k++;
 172.175 +            tail[k] = a->tail->i;
 172.176 +            head[k] = a->head->i;
 172.177 +            if (tail[k] == head[k])
 172.178 +            {  ret = GLP_EDATA;
 172.179 +               goto done;
 172.180 +            }
 172.181 +            if (a_low >= 0)
 172.182 +               memcpy(&temp, (char *)a->data + a_low, sizeof(double));
 172.183 +            else
 172.184 +               temp = 0.0;
 172.185 +            if (!(0.0 <= temp && temp <= (double)INT_MAX &&
 172.186 +                  temp == floor(temp)))
 172.187 +            {  ret = GLP_EDATA;
 172.188 +               goto done;
 172.189 +            }
 172.190 +            low[k] = (int)temp;
 172.191 +            if (a_cap >= 0)
 172.192 +               memcpy(&temp, (char *)a->data + a_cap, sizeof(double));
 172.193 +            else
 172.194 +               temp = 1.0;
 172.195 +            if (!((double)low[k] <= temp && temp <= (double)INT_MAX &&
 172.196 +                  temp == floor(temp)))
 172.197 +            {  ret = GLP_EDATA;
 172.198 +               goto done;
 172.199 +            }
 172.200 +            cap[k] = (int)temp;
 172.201 +            if (a_cost >= 0)
 172.202 +               memcpy(&temp, (char *)a->data + a_cost, sizeof(double));
 172.203 +            else
 172.204 +               temp = 0.0;
 172.205 +            if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp)))
 172.206 +            {  ret = GLP_EDATA;
 172.207 +               goto done;
 172.208 +            }
 172.209 +            cost[k] = (int)temp;
 172.210 +         }
 172.211 +      }
 172.212 +      /* (artificial arcs) */
 172.213 +      sum = 0.0;
 172.214 +      for (i = 1; i <= G->nv; i++)
 172.215 +      {  v = G->v[i];
 172.216 +         if (v_rhs >= 0)
 172.217 +            memcpy(&temp, (char *)v->data + v_rhs, sizeof(double));
 172.218 +         else
 172.219 +            temp = 0.0;
 172.220 +         if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp)))
 172.221 +         {  ret = GLP_EDATA;
 172.222 +            goto done;
 172.223 +         }
 172.224 +         if (temp > 0.0)
 172.225 +         {  /* artificial arc from s to original source i */
 172.226 +            k++;
 172.227 +            tail[k] = s;
 172.228 +            head[k] = i;
 172.229 +            low[k] = cap[k] = (int)(+temp); /* supply */
 172.230 +            cost[k] = 0;
 172.231 +            sum += (double)temp;
 172.232 +         }
 172.233 +         else if (temp < 0.0)
 172.234 +         {  /* artificial arc from original sink i to t */
 172.235 +            k++;
 172.236 +            tail[k] = i;
 172.237 +            head[k] = t;
 172.238 +            low[k] = cap[k] = (int)(-temp); /* demand */
 172.239 +            cost[k] = 0;
 172.240 +         }
 172.241 +      }
 172.242 +      /* (feedback arc from t to s) */
 172.243 +      k++;
 172.244 +      xassert(k == na);
 172.245 +      tail[k] = t;
 172.246 +      head[k] = s;
 172.247 +      if (sum > (double)INT_MAX)
 172.248 +      {  ret = GLP_EDATA;
 172.249 +         goto done;
 172.250 +      }
 172.251 +      low[k] = cap[k] = (int)sum; /* total supply/demand */
 172.252 +      cost[k] = 0;
 172.253 +      /* find minimal-cost circulation in the resulting network */
 172.254 +      ret = okalg(nv, na, tail, head, low, cap, cost, x, pi);
 172.255 +      switch (ret)
 172.256 +      {  case 0:
 172.257 +            /* optimal circulation found */
 172.258 +            ret = 0;
 172.259 +            break;
 172.260 +         case 1:
 172.261 +            /* no feasible circulation exists */
 172.262 +            ret = GLP_ENOPFS;
 172.263 +            break;
 172.264 +         case 2:
 172.265 +            /* integer overflow occured */
 172.266 +            ret = GLP_ERANGE;
 172.267 +            goto done;
 172.268 +         case 3:
 172.269 +            /* optimality test failed (logic error) */
 172.270 +            ret = GLP_EFAIL;
 172.271 +            goto done;
 172.272 +         default:
 172.273 +            xassert(ret != ret);
 172.274 +      }
 172.275 +      /* store solution components */
 172.276 +      /* (objective function = the total cost) */
 172.277 +      if (sol != NULL)
 172.278 +      {  temp = 0.0;
 172.279 +         for (k = 1; k <= na; k++)
 172.280 +            temp += (double)cost[k] * (double)x[k];
 172.281 +         *sol = temp;
 172.282 +      }
 172.283 +      /* (arc flows) */
 172.284 +      if (a_x >= 0)
 172.285 +      {  k = 0;
 172.286 +         for (i = 1; i <= G->nv; i++)
 172.287 +         {  v = G->v[i];
 172.288 +            for (a = v->out; a != NULL; a = a->t_next)
 172.289 +            {  temp = (double)x[++k];
 172.290 +               memcpy((char *)a->data + a_x, &temp, sizeof(double));
 172.291 +            }
 172.292 +         }
 172.293 +      }
 172.294 +      /* (node potentials = Lagrange multipliers) */
 172.295 +      if (v_pi >= 0)
 172.296 +      {  for (i = 1; i <= G->nv; i++)
 172.297 +         {  v = G->v[i];
 172.298 +            temp = - (double)pi[i];
 172.299 +            memcpy((char *)v->data + v_pi, &temp, sizeof(double));
 172.300 +         }
 172.301 +      }
 172.302 +done: /* free working arrays */
 172.303 +      xfree(tail);
 172.304 +      xfree(head);
 172.305 +      xfree(low);
 172.306 +      xfree(cap);
 172.307 +      xfree(cost);
 172.308 +      xfree(x);
 172.309 +      xfree(pi);
 172.310 +      return ret;
 172.311 +}
 172.312 +
 172.313 +/***********************************************************************
 172.314 +*  NAME
 172.315 +*
 172.316 +*  glp_maxflow_lp - convert maximum flow problem to LP
 172.317 +*
 172.318 +*  SYNOPSIS
 172.319 +*
 172.320 +*  void glp_maxflow_lp(glp_prob *lp, glp_graph *G, int names, int s,
 172.321 +*     int t, int a_cap);
 172.322 +*
 172.323 +*  DESCRIPTION
 172.324 +*
 172.325 +*  The routine glp_maxflow_lp builds an LP problem, which corresponds
 172.326 +*  to the maximum flow problem on the specified network G. */
 172.327 +
 172.328 +void glp_maxflow_lp(glp_prob *lp, glp_graph *G, int names, int s,
 172.329 +      int t, int a_cap)
 172.330 +{     glp_vertex *v;
 172.331 +      glp_arc *a;
 172.332 +      int i, j, type, ind[1+2];
 172.333 +      double cap, val[1+2];
 172.334 +      if (!(names == GLP_ON || names == GLP_OFF))
 172.335 +         xerror("glp_maxflow_lp: names = %d; invalid parameter\n",
 172.336 +            names);
 172.337 +      if (!(1 <= s && s <= G->nv))
 172.338 +         xerror("glp_maxflow_lp: s = %d; source node number out of rang"
 172.339 +            "e\n", s);
 172.340 +      if (!(1 <= t && t <= G->nv))
 172.341 +         xerror("glp_maxflow_lp: t = %d: sink node number out of range "
 172.342 +            "\n", t);
 172.343 +      if (s == t)
 172.344 +         xerror("glp_maxflow_lp: s = t = %d; source and sink nodes must"
 172.345 +            " be distinct\n", s);
 172.346 +      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
 172.347 +         xerror("glp_maxflow_lp: a_cap = %d; invalid offset\n", a_cap);
 172.348 +      glp_erase_prob(lp);
 172.349 +      if (names) glp_set_prob_name(lp, G->name);
 172.350 +      glp_set_obj_dir(lp, GLP_MAX);
 172.351 +      glp_add_rows(lp, G->nv);
 172.352 +      for (i = 1; i <= G->nv; i++)
 172.353 +      {  v = G->v[i];
 172.354 +         if (names) glp_set_row_name(lp, i, v->name);
 172.355 +         if (i == s)
 172.356 +            type = GLP_LO;
 172.357 +         else if (i == t)
 172.358 +            type = GLP_UP;
 172.359 +         else
 172.360 +            type = GLP_FX;
 172.361 +         glp_set_row_bnds(lp, i, type, 0.0, 0.0);
 172.362 +      }
 172.363 +      if (G->na > 0) glp_add_cols(lp, G->na);
 172.364 +      for (i = 1, j = 0; i <= G->nv; i++)
 172.365 +      {  v = G->v[i];
 172.366 +         for (a = v->out; a != NULL; a = a->t_next)
 172.367 +         {  j++;
 172.368 +            if (names)
 172.369 +            {  char name[50+1];
 172.370 +               sprintf(name, "x[%d,%d]", a->tail->i, a->head->i);
 172.371 +               xassert(strlen(name) < sizeof(name));
 172.372 +               glp_set_col_name(lp, j, name);
 172.373 +            }
 172.374 +            if (a->tail->i != a->head->i)
 172.375 +            {  ind[1] = a->tail->i, val[1] = +1.0;
 172.376 +               ind[2] = a->head->i, val[2] = -1.0;
 172.377 +               glp_set_mat_col(lp, j, 2, ind, val);
 172.378 +            }
 172.379 +            if (a_cap >= 0)
 172.380 +               memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
 172.381 +            else
 172.382 +               cap = 1.0;
 172.383 +            if (cap == DBL_MAX)
 172.384 +               type = GLP_LO;
 172.385 +            else if (cap != 0.0)
 172.386 +               type = GLP_DB;
 172.387 +            else
 172.388 +               type = GLP_FX;
 172.389 +            glp_set_col_bnds(lp, j, type, 0.0, cap);
 172.390 +            if (a->tail->i == s)
 172.391 +               glp_set_obj_coef(lp, j, +1.0);
 172.392 +            else if (a->head->i == s)
 172.393 +               glp_set_obj_coef(lp, j, -1.0);
 172.394 +         }
 172.395 +      }
 172.396 +      xassert(j == G->na);
 172.397 +      return;
 172.398 +}
 172.399 +
 172.400 +int glp_maxflow_ffalg(glp_graph *G, int s, int t, int a_cap,
 172.401 +      double *sol, int a_x, int v_cut)
 172.402 +{     /* find maximal flow with Ford-Fulkerson algorithm */
 172.403 +      glp_vertex *v;
 172.404 +      glp_arc *a;
 172.405 +      int nv, na, i, k, flag, *tail, *head, *cap, *x, ret;
 172.406 +      char *cut;
 172.407 +      double temp;
 172.408 +      if (!(1 <= s && s <= G->nv))
 172.409 +         xerror("glp_maxflow_ffalg: s = %d; source node number out of r"
 172.410 +            "ange\n", s);
 172.411 +      if (!(1 <= t && t <= G->nv))
 172.412 +         xerror("glp_maxflow_ffalg: t = %d: sink node number out of ran"
 172.413 +            "ge\n", t);
 172.414 +      if (s == t)
 172.415 +         xerror("glp_maxflow_ffalg: s = t = %d; source and sink nodes m"
 172.416 +            "ust be distinct\n", s);
 172.417 +      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
 172.418 +         xerror("glp_maxflow_ffalg: a_cap = %d; invalid offset\n",
 172.419 +            a_cap);
 172.420 +      if (v_cut >= 0 && v_cut > G->v_size - (int)sizeof(int))
 172.421 +         xerror("glp_maxflow_ffalg: v_cut = %d; invalid offset\n",
 172.422 +            v_cut);
 172.423 +      /* allocate working arrays */
 172.424 +      nv = G->nv;
 172.425 +      na = G->na;
 172.426 +      tail = xcalloc(1+na, sizeof(int));
 172.427 +      head = xcalloc(1+na, sizeof(int));
 172.428 +      cap = xcalloc(1+na, sizeof(int));
 172.429 +      x = xcalloc(1+na, sizeof(int));
 172.430 +      if (v_cut < 0)
 172.431 +         cut = NULL;
 172.432 +      else
 172.433 +         cut = xcalloc(1+nv, sizeof(char));
 172.434 +      /* copy the flow network */
 172.435 +      k = 0;
 172.436 +      for (i = 1; i <= G->nv; i++)
 172.437 +      {  v = G->v[i];
 172.438 +         for (a = v->out; a != NULL; a = a->t_next)
 172.439 +         {  k++;
 172.440 +            tail[k] = a->tail->i;
 172.441 +            head[k] = a->head->i;
 172.442 +            if (tail[k] == head[k])
 172.443 +            {  ret = GLP_EDATA;
 172.444 +               goto done;
 172.445 +            }
 172.446 +            if (a_cap >= 0)
 172.447 +               memcpy(&temp, (char *)a->data + a_cap, sizeof(double));
 172.448 +            else
 172.449 +               temp = 1.0;
 172.450 +            if (!(0.0 <= temp && temp <= (double)INT_MAX &&
 172.451 +                  temp == floor(temp)))
 172.452 +            {  ret = GLP_EDATA;
 172.453 +               goto done;
 172.454 +            }
 172.455 +            cap[k] = (int)temp;
 172.456 +         }
 172.457 +      }
 172.458 +      xassert(k == na);
 172.459 +      /* find maximal flow in the flow network */
 172.460 +      ffalg(nv, na, tail, head, s, t, cap, x, cut);
 172.461 +      ret = 0;
 172.462 +      /* store solution components */
 172.463 +      /* (objective function = total flow through the network) */
 172.464 +      if (sol != NULL)
 172.465 +      {  temp = 0.0;
 172.466 +         for (k = 1; k <= na; k++)
 172.467 +         {  if (tail[k] == s)
 172.468 +               temp += (double)x[k];
 172.469 +            else if (head[k] == s)
 172.470 +               temp -= (double)x[k];
 172.471 +         }
 172.472 +         *sol = temp;
 172.473 +      }
 172.474 +      /* (arc flows) */
 172.475 +      if (a_x >= 0)
 172.476 +      {  k = 0;
 172.477 +         for (i = 1; i <= G->nv; i++)
 172.478 +         {  v = G->v[i];
 172.479 +            for (a = v->out; a != NULL; a = a->t_next)
 172.480 +            {  temp = (double)x[++k];
 172.481 +               memcpy((char *)a->data + a_x, &temp, sizeof(double));
 172.482 +            }
 172.483 +         }
 172.484 +      }
 172.485 +      /* (node flags) */
 172.486 +      if (v_cut >= 0)
 172.487 +      {  for (i = 1; i <= G->nv; i++)
 172.488 +         {  v = G->v[i];
 172.489 +            flag = cut[i];
 172.490 +            memcpy((char *)v->data + v_cut, &flag, sizeof(int));
 172.491 +         }
 172.492 +      }
 172.493 +done: /* free working arrays */
 172.494 +      xfree(tail);
 172.495 +      xfree(head);
 172.496 +      xfree(cap);
 172.497 +      xfree(x);
 172.498 +      if (cut != NULL) xfree(cut);
 172.499 +      return ret;
 172.500 +}
 172.501 +
 172.502 +/***********************************************************************
 172.503 +*  NAME
 172.504 +*
 172.505 +*  glp_check_asnprob - check correctness of assignment problem data
 172.506 +*
 172.507 +*  SYNOPSIS
 172.508 +*
 172.509 +*  int glp_check_asnprob(glp_graph *G, int v_set);
 172.510 +*
 172.511 +*  RETURNS
 172.512 +*
 172.513 +*  If the specified assignment problem data are correct, the routine
 172.514 +*  glp_check_asnprob returns zero, otherwise, non-zero. */
 172.515 +
 172.516 +int glp_check_asnprob(glp_graph *G, int v_set)
 172.517 +{     glp_vertex *v;
 172.518 +      int i, k, ret = 0;
 172.519 +      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
 172.520 +         xerror("glp_check_asnprob: v_set = %d; invalid offset\n",
 172.521 +            v_set);
 172.522 +      for (i = 1; i <= G->nv; i++)
 172.523 +      {  v = G->v[i];
 172.524 +         if (v_set >= 0)
 172.525 +         {  memcpy(&k, (char *)v->data + v_set, sizeof(int));
 172.526 +            if (k == 0)
 172.527 +            {  if (v->in != NULL)
 172.528 +               {  ret = 1;
 172.529 +                  break;
 172.530 +               }
 172.531 +            }
 172.532 +            else if (k == 1)
 172.533 +            {  if (v->out != NULL)
 172.534 +               {  ret = 2;
 172.535 +                  break;
 172.536 +               }
 172.537 +            }
 172.538 +            else
 172.539 +            {  ret = 3;
 172.540 +               break;
 172.541 +            }
 172.542 +         }
 172.543 +         else
 172.544 +         {  if (v->in != NULL && v->out != NULL)
 172.545 +            {  ret = 4;
 172.546 +               break;
 172.547 +            }
 172.548 +         }
 172.549 +      }
 172.550 +      return ret;
 172.551 +}
 172.552 +
 172.553 +/***********************************************************************
 172.554 +*  NAME
 172.555 +*
 172.556 +*  glp_asnprob_lp - convert assignment problem to LP
 172.557 +*
 172.558 +*  SYNOPSIS
 172.559 +*
 172.560 +*  int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G, int names,
 172.561 +*     int v_set, int a_cost);
 172.562 +*
 172.563 +*  DESCRIPTION
 172.564 +*
 172.565 +*  The routine glp_asnprob_lp builds an LP problem, which corresponds
 172.566 +*  to the assignment problem on the specified graph G.
 172.567 +*
 172.568 +*  RETURNS
 172.569 +*
 172.570 +*  If the LP problem has been successfully built, the routine returns
 172.571 +*  zero, otherwise, non-zero. */
 172.572 +
 172.573 +int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G, int names,
 172.574 +      int v_set, int a_cost)
 172.575 +{     glp_vertex *v;
 172.576 +      glp_arc *a;
 172.577 +      int i, j, ret, ind[1+2];
 172.578 +      double cost, val[1+2];
 172.579 +      if (!(form == GLP_ASN_MIN || form == GLP_ASN_MAX ||
 172.580 +            form == GLP_ASN_MMP))
 172.581 +         xerror("glp_asnprob_lp: form = %d; invalid parameter\n",
 172.582 +            form);
 172.583 +      if (!(names == GLP_ON || names == GLP_OFF))
 172.584 +         xerror("glp_asnprob_lp: names = %d; invalid parameter\n",
 172.585 +            names);
 172.586 +      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
 172.587 +         xerror("glp_asnprob_lp: v_set = %d; invalid offset\n",
 172.588 +            v_set);
 172.589 +      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
 172.590 +         xerror("glp_asnprob_lp: a_cost = %d; invalid offset\n",
 172.591 +            a_cost);
 172.592 +      ret = glp_check_asnprob(G, v_set);
 172.593 +      if (ret != 0) goto done;
 172.594 +      glp_erase_prob(P);
 172.595 +      if (names) glp_set_prob_name(P, G->name);
 172.596 +      glp_set_obj_dir(P, form == GLP_ASN_MIN ? GLP_MIN : GLP_MAX);
 172.597 +      if (G->nv > 0) glp_add_rows(P, G->nv);
 172.598 +      for (i = 1; i <= G->nv; i++)
 172.599 +      {  v = G->v[i];
 172.600 +         if (names) glp_set_row_name(P, i, v->name);
 172.601 +         glp_set_row_bnds(P, i, form == GLP_ASN_MMP ? GLP_UP : GLP_FX,
 172.602 +            1.0, 1.0);
 172.603 +      }
 172.604 +      if (G->na > 0) glp_add_cols(P, G->na);
 172.605 +      for (i = 1, j = 0; i <= G->nv; i++)
 172.606 +      {  v = G->v[i];
 172.607 +         for (a = v->out; a != NULL; a = a->t_next)
 172.608 +         {  j++;
 172.609 +            if (names)
 172.610 +            {  char name[50+1];
 172.611 +               sprintf(name, "x[%d,%d]", a->tail->i, a->head->i);
 172.612 +               xassert(strlen(name) < sizeof(name));
 172.613 +               glp_set_col_name(P, j, name);
 172.614 +            }
 172.615 +            ind[1] = a->tail->i, val[1] = +1.0;
 172.616 +            ind[2] = a->head->i, val[2] = +1.0;
 172.617 +            glp_set_mat_col(P, j, 2, ind, val);
 172.618 +            glp_set_col_bnds(P, j, GLP_DB, 0.0, 1.0);
 172.619 +            if (a_cost >= 0)
 172.620 +               memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
 172.621 +            else
 172.622 +               cost = 1.0;
 172.623 +            glp_set_obj_coef(P, j, cost);
 172.624 +         }
 172.625 +      }
 172.626 +      xassert(j == G->na);
 172.627 +done: return ret;
 172.628 +}
 172.629 +
 172.630 +/**********************************************************************/
 172.631 +
 172.632 +int glp_asnprob_okalg(int form, glp_graph *G, int v_set, int a_cost,
 172.633 +      double *sol, int a_x)
 172.634 +{     /* solve assignment problem with out-of-kilter algorithm */
 172.635 +      glp_vertex *v;
 172.636 +      glp_arc *a;
 172.637 +      int nv, na, i, k, *tail, *head, *low, *cap, *cost, *x, *pi, ret;
 172.638 +      double temp;
 172.639 +      if (!(form == GLP_ASN_MIN || form == GLP_ASN_MAX ||
 172.640 +            form == GLP_ASN_MMP))
 172.641 +         xerror("glp_asnprob_okalg: form = %d; invalid parameter\n",
 172.642 +            form);
 172.643 +      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
 172.644 +         xerror("glp_asnprob_okalg: v_set = %d; invalid offset\n",
 172.645 +            v_set);
 172.646 +      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
 172.647 +         xerror("glp_asnprob_okalg: a_cost = %d; invalid offset\n",
 172.648 +            a_cost);
 172.649 +      if (a_x >= 0 && a_x > G->a_size - (int)sizeof(int))
 172.650 +         xerror("glp_asnprob_okalg: a_x = %d; invalid offset\n", a_x);
 172.651 +      if (glp_check_asnprob(G, v_set))
 172.652 +         return GLP_EDATA;
 172.653 +      /* nv is the total number of nodes in the resulting network */
 172.654 +      nv = G->nv + 1;
 172.655 +      /* na is the total number of arcs in the resulting network */
 172.656 +      na = G->na + G->nv;
 172.657 +      /* allocate working arrays */
 172.658 +      tail = xcalloc(1+na, sizeof(int));
 172.659 +      head = xcalloc(1+na, sizeof(int));
 172.660 +      low = xcalloc(1+na, sizeof(int));
 172.661 +      cap = xcalloc(1+na, sizeof(int));
 172.662 +      cost = xcalloc(1+na, sizeof(int));
 172.663 +      x = xcalloc(1+na, sizeof(int));
 172.664 +      pi = xcalloc(1+nv, sizeof(int));
 172.665 +      /* construct the resulting network */
 172.666 +      k = 0;
 172.667 +      /* (original arcs) */
 172.668 +      for (i = 1; i <= G->nv; i++)
 172.669 +      {  v = G->v[i];
 172.670 +         for (a = v->out; a != NULL; a = a->t_next)
 172.671 +         {  k++;
 172.672 +            tail[k] = a->tail->i;
 172.673 +            head[k] = a->head->i;
 172.674 +            low[k] = 0;
 172.675 +            cap[k] = 1;
 172.676 +            if (a_cost >= 0)
 172.677 +               memcpy(&temp, (char *)a->data + a_cost, sizeof(double));
 172.678 +            else
 172.679 +               temp = 1.0;
 172.680 +            if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp)))
 172.681 +            {  ret = GLP_EDATA;
 172.682 +               goto done;
 172.683 +            }
 172.684 +            cost[k] = (int)temp;
 172.685 +            if (form != GLP_ASN_MIN) cost[k] = - cost[k];
 172.686 +         }
 172.687 +      }
 172.688 +      /* (artificial arcs) */
 172.689 +      for (i = 1; i <= G->nv; i++)
 172.690 +      {  v = G->v[i];
 172.691 +         k++;
 172.692 +         if (v->out == NULL)
 172.693 +            tail[k] = i, head[k] = nv;
 172.694 +         else if (v->in == NULL)
 172.695 +            tail[k] = nv, head[k] = i;
 172.696 +         else
 172.697 +            xassert(v != v);
 172.698 +         low[k] = (form == GLP_ASN_MMP ? 0 : 1);
 172.699 +         cap[k] = 1;
 172.700 +         cost[k] = 0;
 172.701 +      }
 172.702 +      xassert(k == na);
 172.703 +      /* find minimal-cost circulation in the resulting network */
 172.704 +      ret = okalg(nv, na, tail, head, low, cap, cost, x, pi);
 172.705 +      switch (ret)
 172.706 +      {  case 0:
 172.707 +            /* optimal circulation found */
 172.708 +            ret = 0;
 172.709 +            break;
 172.710 +         case 1:
 172.711 +            /* no feasible circulation exists */
 172.712 +            ret = GLP_ENOPFS;
 172.713 +            break;
 172.714 +         case 2:
 172.715 +            /* integer overflow occured */
 172.716 +            ret = GLP_ERANGE;
 172.717 +            goto done;
 172.718 +         case 3:
 172.719 +            /* optimality test failed (logic error) */
 172.720 +            ret = GLP_EFAIL;
 172.721 +            goto done;
 172.722 +         default:
 172.723 +            xassert(ret != ret);
 172.724 +      }
 172.725 +      /* store solution components */
 172.726 +      /* (objective function = the total cost) */
 172.727 +      if (sol != NULL)
 172.728 +      {  temp = 0.0;
 172.729 +         for (k = 1; k <= na; k++)
 172.730 +            temp += (double)cost[k] * (double)x[k];
 172.731 +         if (form != GLP_ASN_MIN) temp = - temp;
 172.732 +         *sol = temp;
 172.733 +      }
 172.734 +      /* (arc flows) */
 172.735 +      if (a_x >= 0)
 172.736 +      {  k = 0;
 172.737 +         for (i = 1; i <= G->nv; i++)
 172.738 +         {  v = G->v[i];
 172.739 +            for (a = v->out; a != NULL; a = a->t_next)
 172.740 +            {  k++;
 172.741 +               if (ret == 0)
 172.742 +                  xassert(x[k] == 0 || x[k] == 1);
 172.743 +               memcpy((char *)a->data + a_x, &x[k], sizeof(int));
 172.744 +            }
 172.745 +         }
 172.746 +      }
 172.747 +done: /* free working arrays */
 172.748 +      xfree(tail);
 172.749 +      xfree(head);
 172.750 +      xfree(low);
 172.751 +      xfree(cap);
 172.752 +      xfree(cost);
 172.753 +      xfree(x);
 172.754 +      xfree(pi);
 172.755 +      return ret;
 172.756 +}
 172.757 +
 172.758 +/***********************************************************************
 172.759 +*  NAME
 172.760 +*
 172.761 +*  glp_asnprob_hall - find bipartite matching of maximum cardinality
 172.762 +*
 172.763 +*  SYNOPSIS
 172.764 +*
 172.765 +*  int glp_asnprob_hall(glp_graph *G, int v_set, int a_x);
 172.766 +*
 172.767 +*  DESCRIPTION
 172.768 +*
 172.769 +*  The routine glp_asnprob_hall finds a matching of maximal cardinality
 172.770 +*  in the specified bipartite graph G. It uses a version of the Fortran
 172.771 +*  routine MC21A developed by I.S.Duff [1], which implements Hall's
 172.772 +*  algorithm [2].
 172.773 +*
 172.774 +*  RETURNS
 172.775 +*
 172.776 +*  The routine glp_asnprob_hall returns the cardinality of the matching
 172.777 +*  found. However, if the specified graph is incorrect (as detected by
 172.778 +*  the routine glp_check_asnprob), the routine returns negative value.
 172.779 +*
 172.780 +*  REFERENCES
 172.781 +*
 172.782 +*  1. I.S.Duff, Algorithm 575: Permutations for zero-free diagonal, ACM
 172.783 +*     Trans. on Math. Softw. 7 (1981), 387-390.
 172.784 +*
 172.785 +*  2. M.Hall, "An Algorithm for distinct representatives," Amer. Math.
 172.786 +*     Monthly 63 (1956), 716-717. */
 172.787 +
 172.788 +int glp_asnprob_hall(glp_graph *G, int v_set, int a_x)
 172.789 +{     glp_vertex *v;
 172.790 +      glp_arc *a;
 172.791 +      int card, i, k, loc, n, n1, n2, xij;
 172.792 +      int *num, *icn, *ip, *lenr, *iperm, *pr, *arp, *cv, *out;
 172.793 +      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
 172.794 +         xerror("glp_asnprob_hall: v_set = %d; invalid offset\n",
 172.795 +            v_set);
 172.796 +      if (a_x >= 0 && a_x > G->a_size - (int)sizeof(int))
 172.797 +         xerror("glp_asnprob_hall: a_x = %d; invalid offset\n", a_x);
 172.798 +      if (glp_check_asnprob(G, v_set))
 172.799 +         return -1;
 172.800 +      /* determine the number of vertices in sets R and S and renumber
 172.801 +         vertices in S which correspond to columns of the matrix; skip
 172.802 +         all isolated vertices */
 172.803 +      num = xcalloc(1+G->nv, sizeof(int));
 172.804 +      n1 = n2 = 0;
 172.805 +      for (i = 1; i <= G->nv; i++)
 172.806 +      {  v = G->v[i];
 172.807 +         if (v->in == NULL && v->out != NULL)
 172.808 +            n1++, num[i] = 0; /* vertex in R */
 172.809 +         else if (v->in != NULL && v->out == NULL)
 172.810 +            n2++, num[i] = n2; /* vertex in S */
 172.811 +         else
 172.812 +         {  xassert(v->in == NULL && v->out == NULL);
 172.813 +            num[i] = -1; /* isolated vertex */
 172.814 +         }
 172.815 +      }
 172.816 +      /* the matrix must be square, thus, if it has more columns than
 172.817 +         rows, extra rows will be just empty, and vice versa */
 172.818 +      n = (n1 >= n2 ? n1 : n2);
 172.819 +      /* allocate working arrays */
 172.820 +      icn = xcalloc(1+G->na, sizeof(int));
 172.821 +      ip = xcalloc(1+n, sizeof(int));
 172.822 +      lenr = xcalloc(1+n, sizeof(int));
 172.823 +      iperm = xcalloc(1+n, sizeof(int));
 172.824 +      pr = xcalloc(1+n, sizeof(int));
 172.825 +      arp = xcalloc(1+n, sizeof(int));
 172.826 +      cv = xcalloc(1+n, sizeof(int));
 172.827 +      out = xcalloc(1+n, sizeof(int));
 172.828 +      /* build the adjacency matrix of the bipartite graph in row-wise
 172.829 +         format (rows are vertices in R, columns are vertices in S) */
 172.830 +      k = 0, loc = 1;
 172.831 +      for (i = 1; i <= G->nv; i++)
 172.832 +      {  if (num[i] != 0) continue;
 172.833 +         /* vertex i in R */
 172.834 +         ip[++k] = loc;
 172.835 +         v = G->v[i];
 172.836 +         for (a = v->out; a != NULL; a = a->t_next)
 172.837 +         {  xassert(num[a->head->i] != 0);
 172.838 +            icn[loc++] = num[a->head->i];
 172.839 +         }
 172.840 +         lenr[k] = loc - ip[k];
 172.841 +      }
 172.842 +      xassert(loc-1 == G->na);
 172.843 +      /* make all extra rows empty (all extra columns are empty due to
 172.844 +         the row-wise format used) */
 172.845 +      for (k++; k <= n; k++)
 172.846 +         ip[k] = loc, lenr[k] = 0;
 172.847 +      /* find a row permutation that maximizes the number of non-zeros
 172.848 +         on the main diagonal */
 172.849 +      card = mc21a(n, icn, ip, lenr, iperm, pr, arp, cv, out);
 172.850 +#if 1 /* 18/II-2010 */
 172.851 +      /* FIXED: if card = n, arp remains clobbered on exit */
 172.852 +      for (i = 1; i <= n; i++)
 172.853 +         arp[i] = 0;
 172.854 +      for (i = 1; i <= card; i++)
 172.855 +      {  k = iperm[i];
 172.856 +         xassert(1 <= k && k <= n);
 172.857 +         xassert(arp[k] == 0);
 172.858 +         arp[k] = i;
 172.859 +      }
 172.860 +#endif
 172.861 +      /* store solution, if necessary */
 172.862 +      if (a_x < 0) goto skip;
 172.863 +      k = 0;
 172.864 +      for (i = 1; i <= G->nv; i++)
 172.865 +      {  if (num[i] != 0) continue;
 172.866 +         /* vertex i in R */
 172.867 +         k++;
 172.868 +         v = G->v[i];
 172.869 +         for (a = v->out; a != NULL; a = a->t_next)
 172.870 +         {  /* arp[k] is the number of matched column or zero */
 172.871 +            if (arp[k] == num[a->head->i])
 172.872 +            {  xassert(arp[k] != 0);
 172.873 +               xij = 1;
 172.874 +            }
 172.875 +            else
 172.876 +               xij = 0;
 172.877 +            memcpy((char *)a->data + a_x, &xij, sizeof(int));
 172.878 +         }
 172.879 +      }
 172.880 +skip: /* free working arrays */
 172.881 +      xfree(num);
 172.882 +      xfree(icn);
 172.883 +      xfree(ip);
 172.884 +      xfree(lenr);
 172.885 +      xfree(iperm);
 172.886 +      xfree(pr);
 172.887 +      xfree(arp);
 172.888 +      xfree(cv);
 172.889 +      xfree(out);
 172.890 +      return card;
 172.891 +}
 172.892 +
 172.893 +/***********************************************************************
 172.894 +*  NAME
 172.895 +*
 172.896 +*  glp_cpp - solve critical path problem
 172.897 +*
 172.898 +*  SYNOPSIS
 172.899 +*
 172.900 +*  double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls);
 172.901 +*
 172.902 +*  DESCRIPTION
 172.903 +*
 172.904 +*  The routine glp_cpp solves the critical path problem represented in
 172.905 +*  the form of the project network.
 172.906 +*
 172.907 +*  The parameter G is a pointer to the graph object, which specifies
 172.908 +*  the project network. This graph must be acyclic. Multiple arcs are
 172.909 +*  allowed being considered as single arcs.
 172.910 +*
 172.911 +*  The parameter v_t specifies an offset of the field of type double
 172.912 +*  in the vertex data block, which contains time t[i] >= 0 needed to
 172.913 +*  perform corresponding job j. If v_t < 0, it is assumed that t[i] = 1
 172.914 +*  for all jobs.
 172.915 +*
 172.916 +*  The parameter v_es specifies an offset of the field of type double
 172.917 +*  in the vertex data block, to which the routine stores earliest start
 172.918 +*  time for corresponding job. If v_es < 0, this time is not stored.
 172.919 +*
 172.920 +*  The parameter v_ls specifies an offset of the field of type double
 172.921 +*  in the vertex data block, to which the routine stores latest start
 172.922 +*  time for corresponding job. If v_ls < 0, this time is not stored.
 172.923 +*
 172.924 +*  RETURNS
 172.925 +*
 172.926 +*  The routine glp_cpp returns the minimal project duration, that is,
 172.927 +*  minimal time needed to perform all jobs in the project. */
 172.928 +
 172.929 +static void sorting(glp_graph *G, int list[]);
 172.930 +
 172.931 +double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls)
 172.932 +{     glp_vertex *v;
 172.933 +      glp_arc *a;
 172.934 +      int i, j, k, nv, *list;
 172.935 +      double temp, total, *t, *es, *ls;
 172.936 +      if (v_t >= 0 && v_t > G->v_size - (int)sizeof(double))
 172.937 +         xerror("glp_cpp: v_t = %d; invalid offset\n", v_t);
 172.938 +      if (v_es >= 0 && v_es > G->v_size - (int)sizeof(double))
 172.939 +         xerror("glp_cpp: v_es = %d; invalid offset\n", v_es);
 172.940 +      if (v_ls >= 0 && v_ls > G->v_size - (int)sizeof(double))
 172.941 +         xerror("glp_cpp: v_ls = %d; invalid offset\n", v_ls);
 172.942 +      nv = G->nv;
 172.943 +      if (nv == 0)
 172.944 +      {  total = 0.0;
 172.945 +         goto done;
 172.946 +      }
 172.947 +      /* allocate working arrays */
 172.948 +      t = xcalloc(1+nv, sizeof(double));
 172.949 +      es = xcalloc(1+nv, sizeof(double));
 172.950 +      ls = xcalloc(1+nv, sizeof(double));
 172.951 +      list = xcalloc(1+nv, sizeof(int));
 172.952 +      /* retrieve job times */
 172.953 +      for (i = 1; i <= nv; i++)
 172.954 +      {  v = G->v[i];
 172.955 +         if (v_t >= 0)
 172.956 +         {  memcpy(&t[i], (char *)v->data + v_t, sizeof(double));
 172.957 +            if (t[i] < 0.0)
 172.958 +               xerror("glp_cpp: t[%d] = %g; invalid time\n", i, t[i]);
 172.959 +         }
 172.960 +         else
 172.961 +            t[i] = 1.0;
 172.962 +      }
 172.963 +      /* perform topological sorting to determine the list of nodes
 172.964 +         (jobs) such that if list[k] = i and list[kk] = j and there
 172.965 +         exists arc (i->j), then k < kk */
 172.966 +      sorting(G, list);
 172.967 +      /* FORWARD PASS */
 172.968 +      /* determine earliest start times */
 172.969 +      for (k = 1; k <= nv; k++)
 172.970 +      {  j = list[k];
 172.971 +         es[j] = 0.0;
 172.972 +         for (a = G->v[j]->in; a != NULL; a = a->h_next)
 172.973 +         {  i = a->tail->i;
 172.974 +            /* there exists arc (i->j) in the project network */
 172.975 +            temp = es[i] + t[i];
 172.976 +            if (es[j] < temp) es[j] = temp;
 172.977 +         }
 172.978 +      }
 172.979 +      /* determine the minimal project duration */
 172.980 +      total = 0.0;
 172.981 +      for (i = 1; i <= nv; i++)
 172.982 +      {  temp = es[i] + t[i];
 172.983 +         if (total < temp) total = temp;
 172.984 +      }
 172.985 +      /* BACKWARD PASS */
 172.986 +      /* determine latest start times */
 172.987 +      for (k = nv; k >= 1; k--)
 172.988 +      {  i = list[k];
 172.989 +         ls[i] = total - t[i];
 172.990 +         for (a = G->v[i]->out; a != NULL; a = a->t_next)
 172.991 +         {  j = a->head->i;
 172.992 +            /* there exists arc (i->j) in the project network */
 172.993 +            temp = ls[j] - t[i];
 172.994 +            if (ls[i] > temp) ls[i] = temp;
 172.995 +         }
 172.996 +         /* avoid possible round-off errors */
 172.997 +         if (ls[i] < es[i]) ls[i] = es[i];
 172.998 +      }
 172.999 +      /* store results, if necessary */
172.1000 +      if (v_es >= 0)
172.1001 +      {  for (i = 1; i <= nv; i++)
172.1002 +         {  v = G->v[i];
172.1003 +            memcpy((char *)v->data + v_es, &es[i], sizeof(double));
172.1004 +         }
172.1005 +      }
172.1006 +      if (v_ls >= 0)
172.1007 +      {  for (i = 1; i <= nv; i++)
172.1008 +         {  v = G->v[i];
172.1009 +            memcpy((char *)v->data + v_ls, &ls[i], sizeof(double));
172.1010 +         }
172.1011 +      }
172.1012 +      /* free working arrays */
172.1013 +      xfree(t);
172.1014 +      xfree(es);
172.1015 +      xfree(ls);
172.1016 +      xfree(list);
172.1017 +done: return total;
172.1018 +}
172.1019 +
172.1020 +static void sorting(glp_graph *G, int list[])
172.1021 +{     /* perform topological sorting to determine the list of nodes
172.1022 +         (jobs) such that if list[k] = i and list[kk] = j and there
172.1023 +         exists arc (i->j), then k < kk */
172.1024 +      int i, k, nv, v_size, *num;
172.1025 +      void **save;
172.1026 +      nv = G->nv;
172.1027 +      v_size = G->v_size;
172.1028 +      save = xcalloc(1+nv, sizeof(void *));
172.1029 +      num = xcalloc(1+nv, sizeof(int));
172.1030 +      G->v_size = sizeof(int);
172.1031 +      for (i = 1; i <= nv; i++)
172.1032 +      {  save[i] = G->v[i]->data;
172.1033 +         G->v[i]->data = &num[i];
172.1034 +         list[i] = 0;
172.1035 +      }
172.1036 +      if (glp_top_sort(G, 0) != 0)
172.1037 +         xerror("glp_cpp: project network is not acyclic\n");
172.1038 +      G->v_size = v_size;
172.1039 +      for (i = 1; i <= nv; i++)
172.1040 +      {  G->v[i]->data = save[i];
172.1041 +         k = num[i];
172.1042 +         xassert(1 <= k && k <= nv);
172.1043 +         xassert(list[k] == 0);
172.1044 +         list[k] = i;
172.1045 +      }
172.1046 +      xfree(save);
172.1047 +      xfree(num);
172.1048 +      return;
172.1049 +}
172.1050 +
172.1051 +/* eof */
   173.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   173.2 +++ b/src/glpapi18.c	Mon Dec 06 13:09:21 2010 +0100
   173.3 @@ -0,0 +1,122 @@
   173.4 +/* glpapi18.c (maximum clique problem) */
   173.5 +
   173.6 +/***********************************************************************
   173.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   173.8 +*
   173.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  173.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  173.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  173.12 +*  E-mail: <mao@gnu.org>.
  173.13 +*
  173.14 +*  GLPK is free software: you can redistribute it and/or modify it
  173.15 +*  under the terms of the GNU General Public License as published by
  173.16 +*  the Free Software Foundation, either version 3 of the License, or
  173.17 +*  (at your option) any later version.
  173.18 +*
  173.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  173.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  173.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  173.22 +*  License for more details.
  173.23 +*
  173.24 +*  You should have received a copy of the GNU General Public License
  173.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  173.26 +***********************************************************************/
  173.27 +
  173.28 +#include "glpapi.h"
  173.29 +#include "glpnet.h"
  173.30 +
  173.31 +static void set_edge(int nv, unsigned char a[], int i, int j)
  173.32 +{     int k;
  173.33 +      xassert(1 <= j && j < i && i <= nv);
  173.34 +      k = ((i - 1) * (i - 2)) / 2 + (j - 1);
  173.35 +      a[k / CHAR_BIT] |=
  173.36 +         (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT));
  173.37 +      return;
  173.38 +}
  173.39 +
  173.40 +int glp_wclique_exact(glp_graph *G, int v_wgt, double *sol, int v_set)
  173.41 +{     /* find maximum weight clique with exact algorithm */
  173.42 +      glp_arc *e;
  173.43 +      int i, j, k, len, x, *w, *ind, ret = 0;
  173.44 +      unsigned char *a;
  173.45 +      double s, t;
  173.46 +      if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double))
  173.47 +         xerror("glp_wclique_exact: v_wgt = %d; invalid parameter\n",
  173.48 +            v_wgt);
  173.49 +      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
  173.50 +         xerror("glp_wclique_exact: v_set = %d; invalid parameter\n",
  173.51 +            v_set);
  173.52 +      if (G->nv == 0)
  173.53 +      {  /* empty graph has only empty clique */
  173.54 +         if (sol != NULL) *sol = 0.0;
  173.55 +         return 0;
  173.56 +      }
  173.57 +      /* allocate working arrays */
  173.58 +      w = xcalloc(1+G->nv, sizeof(int));
  173.59 +      ind = xcalloc(1+G->nv, sizeof(int));
  173.60 +      len = G->nv; /* # vertices */
  173.61 +      len = len * (len - 1) / 2; /* # entries in lower triangle */
  173.62 +      len = (len + (CHAR_BIT - 1)) / CHAR_BIT; /* # bytes needed */
  173.63 +      a = xcalloc(len, sizeof(char));
  173.64 +      memset(a, 0, len * sizeof(char));
  173.65 +      /* determine vertex weights */
  173.66 +      s = 0.0;
  173.67 +      for (i = 1; i <= G->nv; i++)
  173.68 +      {  if (v_wgt >= 0)
  173.69 +         {  memcpy(&t, (char *)G->v[i]->data + v_wgt, sizeof(double));
  173.70 +            if (!(0.0 <= t && t <= (double)INT_MAX && t == floor(t)))
  173.71 +            {  ret = GLP_EDATA;
  173.72 +               goto done;
  173.73 +            }
  173.74 +            w[i] = (int)t;
  173.75 +         }
  173.76 +         else
  173.77 +            w[i] = 1;
  173.78 +         s += (double)w[i];
  173.79 +      }
  173.80 +      if (s > (double)INT_MAX)
  173.81 +      {  ret = GLP_EDATA;
  173.82 +         goto done;
  173.83 +      }
  173.84 +      /* build the adjacency matrix */
  173.85 +      for (i = 1; i <= G->nv; i++)
  173.86 +      {  for (e = G->v[i]->in; e != NULL; e = e->h_next)
  173.87 +         {  j = e->tail->i;
  173.88 +            /* there exists edge (j,i) in the graph */
  173.89 +            if (i > j) set_edge(G->nv, a, i, j);
  173.90 +         }
  173.91 +         for (e = G->v[i]->out; e != NULL; e = e->t_next)
  173.92 +         {  j = e->head->i;
  173.93 +            /* there exists edge (i,j) in the graph */
  173.94 +            if (i > j) set_edge(G->nv, a, i, j);
  173.95 +         }
  173.96 +      }
  173.97 +      /* find maximum weight clique in the graph */
  173.98 +      len = wclique(G->nv, w, a, ind);
  173.99 +      /* compute the clique weight */
 173.100 +      s = 0.0;
 173.101 +      for (k = 1; k <= len; k++)
 173.102 +      {  i = ind[k];
 173.103 +         xassert(1 <= i && i <= G->nv);
 173.104 +         s += (double)w[i];
 173.105 +      }
 173.106 +      if (sol != NULL) *sol = s;
 173.107 +      /* mark vertices included in the clique */
 173.108 +      if (v_set >= 0)
 173.109 +      {  x = 0;
 173.110 +         for (i = 1; i <= G->nv; i++)
 173.111 +            memcpy((char *)G->v[i]->data + v_set, &x, sizeof(int));
 173.112 +         x = 1;
 173.113 +         for (k = 1; k <= len; k++)
 173.114 +         {  i = ind[k];
 173.115 +            memcpy((char *)G->v[i]->data + v_set, &x, sizeof(int));
 173.116 +         }
 173.117 +      }
 173.118 +done: /* free working arrays */
 173.119 +      xfree(w);
 173.120 +      xfree(ind);
 173.121 +      xfree(a);
 173.122 +      return ret;
 173.123 +}
 173.124 +
 173.125 +/* eof */
   174.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   174.2 +++ b/src/glpapi19.c	Mon Dec 06 13:09:21 2010 +0100
   174.3 @@ -0,0 +1,1196 @@
   174.4 +/* glpapi19.c (stand-alone LP/MIP solver) */
   174.5 +
   174.6 +/***********************************************************************
   174.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   174.8 +*
   174.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  174.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  174.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  174.12 +*  E-mail: <mao@gnu.org>.
  174.13 +*
  174.14 +*  GLPK is free software: you can redistribute it and/or modify it
  174.15 +*  under the terms of the GNU General Public License as published by
  174.16 +*  the Free Software Foundation, either version 3 of the License, or
  174.17 +*  (at your option) any later version.
  174.18 +*
  174.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  174.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  174.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  174.22 +*  License for more details.
  174.23 +*
  174.24 +*  You should have received a copy of the GNU General Public License
  174.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  174.26 +***********************************************************************/
  174.27 +
  174.28 +#include "glpapi.h"
  174.29 +#include "glpgmp.h"
  174.30 +
  174.31 +struct csa
  174.32 +{     /* common storage area */
  174.33 +      glp_prob *prob;
  174.34 +      /* LP/MIP problem object */
  174.35 +      glp_bfcp bfcp;
  174.36 +      /* basis factorization control parameters */
  174.37 +      glp_smcp smcp;
  174.38 +      /* simplex method control parameters */
  174.39 +      glp_iptcp iptcp;
  174.40 +      /* interior-point method control parameters */
  174.41 +      glp_iocp iocp;
  174.42 +      /* integer optimizer control parameters */
  174.43 +      glp_tran *tran;
  174.44 +      /* model translator workspace */
  174.45 +      glp_graph *graph;
  174.46 +      /* network problem object */
  174.47 +      int format;
  174.48 +      /* problem file format: */
  174.49 +#define FMT_MPS_DECK    1  /* fixed MPS */
  174.50 +#define FMT_MPS_FILE    2  /* free MPS */
  174.51 +#define FMT_LP          3  /* CPLEX LP */
  174.52 +#define FMT_GLP         4  /* GLPK LP/MIP */
  174.53 +#define FMT_MATHPROG    5  /* MathProg */
  174.54 +#define FMT_MIN_COST    6  /* DIMACS min-cost flow */
  174.55 +#define FMT_MAX_FLOW    7  /* DIMACS maximum flow */
  174.56 +      const char *in_file;
  174.57 +      /* name of input problem file */
  174.58 +#define DATA_MAX 10
  174.59 +      /* maximal number of input data files */
  174.60 +      int ndf;
  174.61 +      /* number of input data files specified */
  174.62 +      const char *in_data[1+DATA_MAX];
  174.63 +      /* name(s) of input data file(s) */
  174.64 +      const char *out_dpy;
  174.65 +      /* name of output file to send display output; NULL means the
  174.66 +         display output is sent to the terminal */
  174.67 +      int seed;
  174.68 +      /* seed value to be passed to the MathProg translator; initially
  174.69 +         set to 1; 0x80000000 means the value is omitted */
  174.70 +      int solution;
  174.71 +      /* solution type flag: */
  174.72 +#define SOL_BASIC       1  /* basic */
  174.73 +#define SOL_INTERIOR    2  /* interior-point */
  174.74 +#define SOL_INTEGER     3  /* mixed integer */
  174.75 +      const char *in_res;
  174.76 +      /* name of input solution file in raw format */
  174.77 +      int dir;
  174.78 +      /* optimization direction flag:
  174.79 +         0       - not specified
  174.80 +         GLP_MIN - minimization
  174.81 +         GLP_MAX - maximization */
  174.82 +      int scale;
  174.83 +      /* automatic problem scaling flag */
  174.84 +      const char *out_sol;
  174.85 +      /* name of output solution file in printable format */
  174.86 +      const char *out_res;
  174.87 +      /* name of output solution file in raw format */
  174.88 +      const char *out_ranges;
  174.89 +      /* name of output file to write sensitivity analysis report */
  174.90 +      int check;
  174.91 +      /* input data checking flag; no solution is performed */
  174.92 +      const char *new_name;
  174.93 +      /* new name to be assigned to the problem */
  174.94 +      const char *out_mps;
  174.95 +      /* name of output problem file in fixed MPS format */
  174.96 +      const char *out_freemps;
  174.97 +      /* name of output problem file in free MPS format */
  174.98 +      const char *out_cpxlp;
  174.99 +      /* name of output problem file in CPLEX LP format */
 174.100 +      const char *out_glp;
 174.101 +      /* name of output problem file in GLPK format */
 174.102 +      const char *out_pb;
 174.103 +      /* name of output problem file in OPB format */
 174.104 +      const char *out_npb;
 174.105 +      /* name of output problem file in normalized OPB format */
 174.106 +      const char *log_file;
 174.107 +      /* name of output file to hardcopy terminal output */
 174.108 +      int crash;
 174.109 +      /* initial basis option: */
 174.110 +#define USE_STD_BASIS   1  /* use standard basis */
 174.111 +#define USE_ADV_BASIS   2  /* use advanced basis */
 174.112 +#define USE_CPX_BASIS   3  /* use Bixby's basis */
 174.113 +#define USE_INI_BASIS   4  /* use initial basis from ini_file */
 174.114 +      const char *ini_file;
 174.115 +      /* name of input file containing initial basis */
 174.116 +      int exact;
 174.117 +      /* flag to use glp_exact rather than glp_simplex */
 174.118 +      int xcheck;
 174.119 +      /* flag to check final basis with glp_exact */
 174.120 +      int nomip;
 174.121 +      /* flag to consider MIP as pure LP */
 174.122 +};
 174.123 +
 174.124 +static void print_help(const char *my_name)
 174.125 +{     /* print help information */
 174.126 +      xprintf("Usage: %s [options...] filename\n", my_name);
 174.127 +      xprintf("\n");
 174.128 +      xprintf("General options:\n");
 174.129 +      xprintf("   --mps             read LP/MIP problem in fixed MPS fo"
 174.130 +         "rmat\n");
 174.131 +      xprintf("   --freemps         read LP/MIP problem in free MPS for"
 174.132 +         "mat (default)\n");
 174.133 +      xprintf("   --lp              read LP/MIP problem in CPLEX LP for"
 174.134 +         "mat\n");
 174.135 +      xprintf("   --glp             read LP/MIP problem in GLPK format "
 174.136 +         "\n");
 174.137 +      xprintf("   --math            read LP/MIP model written in GNU Ma"
 174.138 +         "thProg modeling\n");
 174.139 +      xprintf("                     language\n");
 174.140 +      xprintf("   -m filename, --model filename\n");
 174.141 +      xprintf("                     read model section and optional dat"
 174.142 +         "a section from\n");
 174.143 +      xprintf("                     filename (same as --math)\n");
 174.144 +      xprintf("   -d filename, --data filename\n");
 174.145 +      xprintf("                     read data section from filename (fo"
 174.146 +         "r --math only);\n");
 174.147 +      xprintf("                     if model file also has data section"
 174.148 +         ", it is ignored\n");
 174.149 +      xprintf("   -y filename, --display filename\n");
 174.150 +      xprintf("                     send display output to filename (fo"
 174.151 +         "r --math only);\n");
 174.152 +      xprintf("                     by default the output is sent to te"
 174.153 +         "rminal\n");
 174.154 +      xprintf("   --seed value      initialize pseudo-random number gen"
 174.155 +         "erator used in\n");
 174.156 +      xprintf("                     MathProg model with specified seed "
 174.157 +         "(any integer);\n");
 174.158 +      xprintf("                     if seed value is ?, some random see"
 174.159 +         "d will be used\n");
 174.160 +      xprintf("   --mincost         read min-cost flow problem in DIMAC"
 174.161 +         "S format\n");
 174.162 +      xprintf("   --maxflow         read maximum flow problem in DIMACS"
 174.163 +         " format\n");
 174.164 +      xprintf("   --simplex         use simplex method (default)\n");
 174.165 +      xprintf("   --interior        use interior point method (LP only)"
 174.166 +         "\n");
 174.167 +      xprintf("   -r filename, --read filename\n");
 174.168 +      xprintf("                     read solution from filename rather "
 174.169 +         "to find it with\n");
 174.170 +      xprintf("                     the solver\n");
 174.171 +      xprintf("   --min             minimization\n");
 174.172 +      xprintf("   --max             maximization\n");
 174.173 +      xprintf("   --scale           scale problem (default)\n");
 174.174 +      xprintf("   --noscale         do not scale problem\n");
 174.175 +      xprintf("   -o filename, --output filename\n");
 174.176 +      xprintf("                     write solution to filename in print"
 174.177 +         "able format\n");
 174.178 +      xprintf("   -w filename, --write filename\n");
 174.179 +      xprintf("                     write solution to filename in plain"
 174.180 +         " text format\n");
 174.181 +      xprintf("   --ranges filename\n");
 174.182 +      xprintf("                     write sensitivity analysis report t"
 174.183 +         "o filename in\n");
 174.184 +      xprintf("                     printable format (simplex only)\n");
 174.185 +      xprintf("   --tmlim nnn       limit solution time to nnn seconds "
 174.186 +         "\n");
 174.187 +      xprintf("   --memlim nnn      limit available memory to nnn megab"
 174.188 +         "ytes\n");
 174.189 +      xprintf("   --check           do not solve problem, check input d"
 174.190 +         "ata only\n");
 174.191 +      xprintf("   --name probname   change problem name to probname\n");
 174.192 +      xprintf("   --wmps filename   write problem to filename in fixed "
 174.193 +         "MPS format\n");
 174.194 +      xprintf("   --wfreemps filename\n");
 174.195 +      xprintf("                     write problem to filename in free M"
 174.196 +         "PS format\n");
 174.197 +      xprintf("   --wlp filename    write problem to filename in CPLEX "
 174.198 +         "LP format\n");
 174.199 +      xprintf("   --wglp filename   write problem to filename in GLPK f"
 174.200 +         "ormat\n");
 174.201 +#if 0
 174.202 +      xprintf("   --wpb filename    write problem to filename in OPB fo"
 174.203 +         "rmat\n");
 174.204 +      xprintf("   --wnpb filename   write problem to filename in normal"
 174.205 +         "ized OPB format\n");
 174.206 +#endif
 174.207 +      xprintf("   --log filename    write copy of terminal output to fi"
 174.208 +         "lename\n");
 174.209 +      xprintf("   -h, --help        display this help information and e"
 174.210 +         "xit\n");
 174.211 +      xprintf("   -v, --version     display program version and exit\n")
 174.212 +         ;
 174.213 +      xprintf("\n");
 174.214 +      xprintf("LP basis factorization options:\n");
 174.215 +      xprintf("   --luf             LU + Forrest-Tomlin update\n");
 174.216 +      xprintf("                     (faster, less stable; default)\n");
 174.217 +      xprintf("   --cbg             LU + Schur complement + Bartels-Gol"
 174.218 +         "ub update\n");
 174.219 +      xprintf("                     (slower, more stable)\n");
 174.220 +      xprintf("   --cgr             LU + Schur complement + Givens rota"
 174.221 +         "tion update\n");
 174.222 +      xprintf("                     (slower, more stable)\n");
 174.223 +      xprintf("\n");
 174.224 +      xprintf("Options specific to simplex solver:\n");
 174.225 +      xprintf("   --primal          use primal simplex (default)\n");
 174.226 +      xprintf("   --dual            use dual simplex\n");
 174.227 +      xprintf("   --std             use standard initial basis of all s"
 174.228 +         "lacks\n");
 174.229 +      xprintf("   --adv             use advanced initial basis (default"
 174.230 +         ")\n");
 174.231 +      xprintf("   --bib             use Bixby's initial basis\n");
 174.232 +      xprintf("   --ini filename    use as initial basis previously sav"
 174.233 +         "ed with -w\n");
 174.234 +      xprintf("                     (disables LP presolver)\n");
 174.235 +      xprintf("   --steep           use steepest edge technique (defaul"
 174.236 +         "t)\n");
 174.237 +      xprintf("   --nosteep         use standard \"textbook\" pricing\n"
 174.238 +         );
 174.239 +      xprintf("   --relax           use Harris' two-pass ratio test (de"
 174.240 +         "fault)\n");
 174.241 +      xprintf("   --norelax         use standard \"textbook\" ratio tes"
 174.242 +         "t\n");
 174.243 +      xprintf("   --presol          use presolver (default; assumes --s"
 174.244 +         "cale and --adv)\n");
 174.245 +      xprintf("   --nopresol        do not use presolver\n");
 174.246 +      xprintf("   --exact           use simplex method based on exact a"
 174.247 +         "rithmetic\n");
 174.248 +      xprintf("   --xcheck          check final basis using exact arith"
 174.249 +         "metic\n");
 174.250 +      xprintf("\n");
 174.251 +      xprintf("Options specific to interior-point solver:\n");
 174.252 +      xprintf("   --nord            use natural (original) ordering\n");
 174.253 +      xprintf("   --qmd             use quotient minimum degree orderin"
 174.254 +         "g\n");
 174.255 +      xprintf("   --amd             use approximate minimum degree orde"
 174.256 +         "ring (default)\n");
 174.257 +      xprintf("   --symamd          use approximate minimum degree orde"
 174.258 +         "ring\n");
 174.259 +      xprintf("\n");
 174.260 +      xprintf("Options specific to MIP solver:\n");
 174.261 +      xprintf("   --nomip           consider all integer variables as c"
 174.262 +         "ontinuous\n");
 174.263 +      xprintf("                     (allows solving MIP as pure LP)\n");
 174.264 +      xprintf("   --first           branch on first integer variable\n")
 174.265 +         ;
 174.266 +      xprintf("   --last            branch on last integer variable\n");
 174.267 +      xprintf("   --mostf           branch on most fractional variable "
 174.268 +         "\n");
 174.269 +      xprintf("   --drtom           branch using heuristic by Driebeck "
 174.270 +         "and Tomlin\n");
 174.271 +      xprintf("                     (default)\n");
 174.272 +      xprintf("   --pcost           branch using hybrid pseudocost heur"
 174.273 +         "istic (may be\n");
 174.274 +      xprintf("                     useful for hard instances)\n");
 174.275 +      xprintf("   --dfs             backtrack using depth first search "
 174.276 +         "\n");
 174.277 +      xprintf("   --bfs             backtrack using breadth first searc"
 174.278 +         "h\n");
 174.279 +      xprintf("   --bestp           backtrack using the best projection"
 174.280 +         " heuristic\n");
 174.281 +      xprintf("   --bestb           backtrack using node with best loca"
 174.282 +         "l bound\n");
 174.283 +      xprintf("                     (default)\n");
 174.284 +      xprintf("   --intopt          use MIP presolver (default)\n");
 174.285 +      xprintf("   --nointopt        do not use MIP presolver\n");
 174.286 +      xprintf("   --binarize        replace general integer variables b"
 174.287 +         "y binary ones\n");
 174.288 +      xprintf("                     (assumes --intopt)\n");
 174.289 +      xprintf("   --fpump           apply feasibility pump heuristic\n")
 174.290 +         ;
 174.291 +      xprintf("   --gomory          generate Gomory's mixed integer cut"
 174.292 +         "s\n");
 174.293 +      xprintf("   --mir             generate MIR (mixed integer roundin"
 174.294 +         "g) cuts\n");
 174.295 +      xprintf("   --cover           generate mixed cover cuts\n");
 174.296 +      xprintf("   --clique          generate clique cuts\n");
 174.297 +      xprintf("   --cuts            generate all cuts above\n");
 174.298 +      xprintf("   --mipgap tol      set relative mip gap tolerance to t"
 174.299 +         "ol\n");
 174.300 +      xprintf("\n");
 174.301 +      xprintf("For description of the MPS and CPLEX LP formats see Refe"
 174.302 +         "rence Manual.\n");
 174.303 +      xprintf("For description of the modeling language see \"GLPK: Mod"
 174.304 +         "eling Language\n");
 174.305 +      xprintf("GNU MathProg\". Both documents are included in the GLPK "
 174.306 +         "distribution.\n");
 174.307 +      xprintf("\n");
 174.308 +      xprintf("See GLPK web page at <http://www.gnu.org/software/glpk/g"
 174.309 +         "lpk.html>.\n");
 174.310 +      xprintf("\n");
 174.311 +      xprintf("Please report bugs to <bug-glpk@gnu.org>.\n");
 174.312 +      return;
 174.313 +}
 174.314 +
 174.315 +static void print_version(int briefly)
 174.316 +{     /* print version information */
 174.317 +      xprintf("GLPSOL: GLPK LP/MIP Solver, v%s\n", glp_version());
 174.318 +      if (briefly) goto done;
 174.319 +      xprintf("\n");
 174.320 +      xprintf("Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, "
 174.321 +         "2007, 2008,\n");
 174.322 +      xprintf("2009, 2010 Andrew Makhorin, Department for Applied Infor"
 174.323 +         "matics, Moscow\n");
 174.324 +      xprintf("Aviation Institute, Moscow, Russia. All rights reserved."
 174.325 +         "\n");
 174.326 +      xprintf("\n");
 174.327 +      xprintf("This program has ABSOLUTELY NO WARRANTY.\n");
 174.328 +      xprintf("\n");
 174.329 +      xprintf("This program is free software; you may re-distribute it "
 174.330 +         "under the terms\n");
 174.331 +      xprintf("of the GNU General Public License version 3 or later.\n")
 174.332 +         ;
 174.333 +done: return;
 174.334 +}
 174.335 +
 174.336 +static int parse_cmdline(struct csa *csa, int argc, const char *argv[])
 174.337 +{     /* parse command-line parameters */
 174.338 +      int k;
 174.339 +#define p(str) (strcmp(argv[k], str) == 0)
 174.340 +      for (k = 1; k < argc; k++)
 174.341 +      {  if (p("--mps"))
 174.342 +            csa->format = FMT_MPS_DECK;
 174.343 +         else if (p("--freemps"))
 174.344 +            csa->format = FMT_MPS_FILE;
 174.345 +         else if (p("--lp") || p("--cpxlp"))
 174.346 +            csa->format = FMT_LP;
 174.347 +         else if (p("--glp"))
 174.348 +            csa->format = FMT_GLP;
 174.349 +         else if (p("--math") || p("-m") || p("--model"))
 174.350 +            csa->format = FMT_MATHPROG;
 174.351 +         else if (p("-d") || p("--data"))
 174.352 +         {  k++;
 174.353 +            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
 174.354 +            {  xprintf("No input data file specified\n");
 174.355 +               return 1;
 174.356 +            }
 174.357 +            if (csa->ndf == DATA_MAX)
 174.358 +            {  xprintf("Too many input data files\n");
 174.359 +               return 1;
 174.360 +            }
 174.361 +            csa->in_data[++(csa->ndf)] = argv[k];
 174.362 +         }
 174.363 +         else if (p("-y") || p("--display"))
 174.364 +         {  k++;
 174.365 +            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
 174.366 +            {  xprintf("No display output file specified\n");
 174.367 +               return 1;
 174.368 +            }
 174.369 +            if (csa->out_dpy != NULL)
 174.370 +            {  xprintf("Only one display output file allowed\n");
 174.371 +               return 1;
 174.372 +            }
 174.373 +            csa->out_dpy = argv[k];
 174.374 +         }
 174.375 +         else if (p("--seed"))
 174.376 +         {  k++;
 174.377 +            if (k == argc || argv[k][0] == '\0' ||
 174.378 +               argv[k][0] == '-' && !isdigit((unsigned char)argv[k][1]))
 174.379 +            {  xprintf("No seed value specified\n");
 174.380 +               return 1;
 174.381 +            }
 174.382 +            if (strcmp(argv[k], "?") == 0)
 174.383 +               csa->seed = 0x80000000;
 174.384 +            else if (str2int(argv[k], &csa->seed))
 174.385 +            {  xprintf("Invalid seed value `%s'\n", argv[k]);
 174.386 +               return 1;
 174.387 +            }
 174.388 +         }
 174.389 +         else if (p("--mincost"))
 174.390 +            csa->format = FMT_MIN_COST;
 174.391 +         else if (p("--maxflow"))
 174.392 +            csa->format = FMT_MAX_FLOW;
 174.393 +         else if (p("--simplex"))
 174.394 +            csa->solution = SOL_BASIC;
 174.395 +         else if (p("--interior"))
 174.396 +            csa->solution = SOL_INTERIOR;
 174.397 +#if 1 /* 28/V-2010 */
 174.398 +         else if (p("--alien"))
 174.399 +            csa->iocp.alien = GLP_ON;
 174.400 +#endif
 174.401 +         else if (p("-r") || p("--read"))
 174.402 +         {  k++;
 174.403 +            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
 174.404 +            {  xprintf("No input solution file specified\n");
 174.405 +               return 1;
 174.406 +            }
 174.407 +            if (csa->in_res != NULL)
 174.408 +            {  xprintf("Only one input solution file allowed\n");
 174.409 +               return 1;
 174.410 +            }
 174.411 +            csa->in_res = argv[k];
 174.412 +         }
 174.413 +         else if (p("--min"))
 174.414 +            csa->dir = GLP_MIN;
 174.415 +         else if (p("--max"))
 174.416 +            csa->dir = GLP_MAX;
 174.417 +         else if (p("--scale"))
 174.418 +            csa->scale = 1;
 174.419 +         else if (p("--noscale"))
 174.420 +            csa->scale = 0;
 174.421 +         else if (p("-o") || p("--output"))
 174.422 +         {  k++;
 174.423 +            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
 174.424 +            {  xprintf("No output solution file specified\n");
 174.425 +               return 1;
 174.426 +            }
 174.427 +            if (csa->out_sol != NULL)
 174.428 +            {  xprintf("Only one output solution file allowed\n");
 174.429 +               return 1;
 174.430 +            }
 174.431 +            csa->out_sol = argv[k];
 174.432 +         }
 174.433 +         else if (p("-w") || p("--write"))
 174.434 +         {  k++;
 174.435 +            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
 174.436 +            {  xprintf("No output solution file specified\n");
 174.437 +               return 1;
 174.438 +            }
 174.439 +            if (csa->out_res != NULL)
 174.440 +            {  xprintf("Only one output solution file allowed\n");
 174.441 +               return 1;
 174.442 +            }
 174.443 +            csa->out_res = argv[k];
 174.444 +         }
 174.445 +         else if (p("--ranges") || p("--bounds"))
 174.446 +         {  k++;
 174.447 +            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
 174.448 +            {  xprintf("No output file specified to write sensitivity a"
 174.449 +                  "nalysis report\n");
 174.450 +               return 1;
 174.451 +            }
 174.452 +            if (csa->out_ranges != NULL)
 174.453 +            {  xprintf("Only one output file allowed to write sensitivi"
 174.454 +                  "ty analysis report\n");
 174.455 +               return 1;
 174.456 +            }
 174.457 +            csa->out_ranges = argv[k];
 174.458 +         }
 174.459 +         else if (p("--tmlim"))
 174.460 +         {  int tm_lim;
 174.461 +            k++;
 174.462 +            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
 174.463 +            {  xprintf("No time limit specified\n");
 174.464 +               return 1;
 174.465 +            }
 174.466 +            if (str2int(argv[k], &tm_lim) || tm_lim < 0)
 174.467 +            {  xprintf("Invalid time limit `%s'\n", argv[k]);
 174.468 +               return 1;
 174.469 +            }
 174.470 +            if (tm_lim <= INT_MAX / 1000)
 174.471 +               csa->smcp.tm_lim = csa->iocp.tm_lim = 1000 * tm_lim;
 174.472 +            else
 174.473 +               csa->smcp.tm_lim = csa->iocp.tm_lim = INT_MAX;
 174.474 +         }
 174.475 +         else if (p("--memlim"))
 174.476 +         {  int mem_lim;
 174.477 +            k++;
 174.478 +            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
 174.479 +            {  xprintf("No memory limit specified\n");
 174.480 +               return 1;
 174.481 +            }
 174.482 +            if (str2int(argv[k], &mem_lim) || mem_lim < 1)
 174.483 +            {  xprintf("Invalid memory limit `%s'\n", argv[k]);
 174.484 +               return 1;
 174.485 +            }
 174.486 +            glp_mem_limit(mem_lim);
 174.487 +         }
 174.488 +         else if (p("--check"))
 174.489 +            csa->check = 1;
 174.490 +         else if (p("--name"))
 174.491 +         {  k++;
 174.492 +            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
 174.493 +            {  xprintf("No problem name specified\n");
 174.494 +               return 1;
 174.495 +            }
 174.496 +            if (csa->new_name != NULL)
 174.497 +            {  xprintf("Only one problem name allowed\n");
 174.498 +               return 1;
 174.499 +            }
 174.500 +            csa->new_name = argv[k];
 174.501 +         }
 174.502 +         else if (p("--wmps"))
 174.503 +         {  k++;
 174.504 +            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
 174.505 +            {  xprintf("No fixed MPS output file specified\n");
 174.506 +               return 1;
 174.507 +            }
 174.508 +            if (csa->out_mps != NULL)
 174.509 +            {  xprintf("Only one fixed MPS output file allowed\n");
 174.510 +               return 1;
 174.511 +            }
 174.512 +            csa->out_mps = argv[k];
 174.513 +         }
 174.514 +         else if (p("--wfreemps"))
 174.515 +         {  k++;
 174.516 +            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
 174.517 +            {  xprintf("No free MPS output file specified\n");
 174.518 +               return 1;
 174.519 +            }
 174.520 +            if (csa->out_freemps != NULL)
 174.521 +            {  xprintf("Only one free MPS output file allowed\n");
 174.522 +               return 1;
 174.523 +            }
 174.524 +            csa->out_freemps = argv[k];
 174.525 +         }
 174.526 +         else if (p("--wlp") || p("--wcpxlp") || p("--wlpt"))
 174.527 +         {  k++;
 174.528 +            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
 174.529 +            {  xprintf("No CPLEX LP output file specified\n");
 174.530 +               return 1;
 174.531 +            }
 174.532 +            if (csa->out_cpxlp != NULL)
 174.533 +            {  xprintf("Only one CPLEX LP output file allowed\n");
 174.534 +               return 1;
 174.535 +            }
 174.536 +            csa->out_cpxlp = argv[k];
 174.537 +         }
 174.538 +         else if (p("--wglp"))
 174.539 +         {  k++;
 174.540 +            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
 174.541 +            {  xprintf("No GLPK LP/MIP output file specified\n");
 174.542 +               return 1;
 174.543 +            }
 174.544 +            if (csa->out_glp != NULL)
 174.545 +            {  xprintf("Only one GLPK LP/MIP output file allowed\n");
 174.546 +               return 1;
 174.547 +            }
 174.548 +            csa->out_glp = argv[k];
 174.549 +         }
 174.550 +         else if (p("--wpb"))
 174.551 +         {  k++;
 174.552 +            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
 174.553 +            {  xprintf("No problem output file specified\n");
 174.554 +               return 1;
 174.555 +            }
 174.556 +            if (csa->out_pb != NULL)
 174.557 +            {  xprintf("Only one OPB output file allowed\n");
 174.558 +               return 1;
 174.559 +            }
 174.560 +            csa->out_pb = argv[k];
 174.561 +         }
 174.562 +         else if (p("--wnpb"))
 174.563 +         {  k++;
 174.564 +            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
 174.565 +            {  xprintf("No problem output file specified\n");
 174.566 +               return 1;
 174.567 +            }
 174.568 +            if (csa->out_npb != NULL)
 174.569 +            {  xprintf("Only one normalized OPB output file allowed\n");
 174.570 +               return 1;
 174.571 +            }
 174.572 +            csa->out_npb = argv[k];
 174.573 +         }
 174.574 +         else if (p("--log"))
 174.575 +         {  k++;
 174.576 +            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
 174.577 +            {  xprintf("No log file specified\n");
 174.578 +               return 1;
 174.579 +            }
 174.580 +            if (csa->log_file != NULL)
 174.581 +            {  xprintf("Only one log file allowed\n");
 174.582 +               return 1;
 174.583 +            }
 174.584 +            csa->log_file = argv[k];
 174.585 +         }
 174.586 +         else if (p("-h") || p("--help"))
 174.587 +         {  print_help(argv[0]);
 174.588 +            return -1;
 174.589 +         }
 174.590 +         else if (p("-v") || p("--version"))
 174.591 +         {  print_version(0);
 174.592 +            return -1;
 174.593 +         }
 174.594 +         else if (p("--luf"))
 174.595 +            csa->bfcp.type = GLP_BF_FT;
 174.596 +         else if (p("--cbg"))
 174.597 +            csa->bfcp.type = GLP_BF_BG;
 174.598 +         else if (p("--cgr"))
 174.599 +            csa->bfcp.type = GLP_BF_GR;
 174.600 +         else if (p("--primal"))
 174.601 +            csa->smcp.meth = GLP_PRIMAL;
 174.602 +         else if (p("--dual"))
 174.603 +            csa->smcp.meth = GLP_DUAL;
 174.604 +         else if (p("--std"))
 174.605 +            csa->crash = USE_STD_BASIS;
 174.606 +         else if (p("--adv"))
 174.607 +            csa->crash = USE_ADV_BASIS;
 174.608 +         else if (p("--bib"))
 174.609 +            csa->crash = USE_CPX_BASIS;
 174.610 +         else if (p("--ini"))
 174.611 +         {  csa->crash = USE_INI_BASIS;
 174.612 +            csa->smcp.presolve = GLP_OFF;
 174.613 +            k++;
 174.614 +            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
 174.615 +            {  xprintf("No initial basis file specified\n");
 174.616 +               return 1;
 174.617 +            }
 174.618 +            if (csa->ini_file != NULL)
 174.619 +            {  xprintf("Only one initial basis file allowed\n");
 174.620 +               return 1;
 174.621 +            }
 174.622 +            csa->ini_file = argv[k];
 174.623 +         }
 174.624 +         else if (p("--steep"))
 174.625 +            csa->smcp.pricing = GLP_PT_PSE;
 174.626 +         else if (p("--nosteep"))
 174.627 +            csa->smcp.pricing = GLP_PT_STD;
 174.628 +         else if (p("--relax"))
 174.629 +            csa->smcp.r_test = GLP_RT_HAR;
 174.630 +         else if (p("--norelax"))
 174.631 +            csa->smcp.r_test = GLP_RT_STD;
 174.632 +         else if (p("--presol"))
 174.633 +            csa->smcp.presolve = GLP_ON;
 174.634 +         else if (p("--nopresol"))
 174.635 +            csa->smcp.presolve = GLP_OFF;
 174.636 +         else if (p("--exact"))
 174.637 +            csa->exact = 1;
 174.638 +         else if (p("--xcheck"))
 174.639 +            csa->xcheck = 1;
 174.640 +         else if (p("--nord"))
 174.641 +            csa->iptcp.ord_alg = GLP_ORD_NONE;
 174.642 +         else if (p("--qmd"))
 174.643 +            csa->iptcp.ord_alg = GLP_ORD_QMD;
 174.644 +         else if (p("--amd"))
 174.645 +            csa->iptcp.ord_alg = GLP_ORD_AMD;
 174.646 +         else if (p("--symamd"))
 174.647 +            csa->iptcp.ord_alg = GLP_ORD_SYMAMD;
 174.648 +         else if (p("--nomip"))
 174.649 +            csa->nomip = 1;
 174.650 +         else if (p("--first"))
 174.651 +            csa->iocp.br_tech = GLP_BR_FFV;
 174.652 +         else if (p("--last"))
 174.653 +            csa->iocp.br_tech = GLP_BR_LFV;
 174.654 +         else if (p("--drtom"))
 174.655 +            csa->iocp.br_tech = GLP_BR_DTH;
 174.656 +         else if (p("--mostf"))
 174.657 +            csa->iocp.br_tech = GLP_BR_MFV;
 174.658 +         else if (p("--pcost"))
 174.659 +            csa->iocp.br_tech = GLP_BR_PCH;
 174.660 +         else if (p("--dfs"))
 174.661 +            csa->iocp.bt_tech = GLP_BT_DFS;
 174.662 +         else if (p("--bfs"))
 174.663 +            csa->iocp.bt_tech = GLP_BT_BFS;
 174.664 +         else if (p("--bestp"))
 174.665 +            csa->iocp.bt_tech = GLP_BT_BPH;
 174.666 +         else if (p("--bestb"))
 174.667 +            csa->iocp.bt_tech = GLP_BT_BLB;
 174.668 +         else if (p("--intopt"))
 174.669 +            csa->iocp.presolve = GLP_ON;
 174.670 +         else if (p("--nointopt"))
 174.671 +            csa->iocp.presolve = GLP_OFF;
 174.672 +         else if (p("--binarize"))
 174.673 +            csa->iocp.presolve = csa->iocp.binarize = GLP_ON;
 174.674 +         else if (p("--fpump"))
 174.675 +            csa->iocp.fp_heur = GLP_ON;
 174.676 +         else if (p("--gomory"))
 174.677 +            csa->iocp.gmi_cuts = GLP_ON;
 174.678 +         else if (p("--mir"))
 174.679 +            csa->iocp.mir_cuts = GLP_ON;
 174.680 +         else if (p("--cover"))
 174.681 +            csa->iocp.cov_cuts = GLP_ON;
 174.682 +         else if (p("--clique"))
 174.683 +            csa->iocp.clq_cuts = GLP_ON;
 174.684 +         else if (p("--cuts"))
 174.685 +            csa->iocp.gmi_cuts = csa->iocp.mir_cuts =
 174.686 +            csa->iocp.cov_cuts = csa->iocp.clq_cuts = GLP_ON;
 174.687 +         else if (p("--mipgap"))
 174.688 +         {  double mip_gap;
 174.689 +            k++;
 174.690 +            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
 174.691 +            {  xprintf("No relative gap tolerance specified\n");
 174.692 +               return 1;
 174.693 +            }
 174.694 +            if (str2num(argv[k], &mip_gap) || mip_gap < 0.0)
 174.695 +            {  xprintf("Invalid relative mip gap tolerance `%s'\n",
 174.696 +                  argv[k]);
 174.697 +               return 1;
 174.698 +            }
 174.699 +            csa->iocp.mip_gap = mip_gap;
 174.700 +         }
 174.701 +         else if (argv[k][0] == '-' ||
 174.702 +                 (argv[k][0] == '-' && argv[k][1] == '-'))
 174.703 +         {  xprintf("Invalid option `%s'; try %s --help\n",
 174.704 +               argv[k], argv[0]);
 174.705 +            return 1;
 174.706 +         }
 174.707 +         else
 174.708 +         {  if (csa->in_file != NULL)
 174.709 +            {  xprintf("Only one input problem file allowed\n");
 174.710 +               return 1;
 174.711 +            }
 174.712 +            csa->in_file = argv[k];
 174.713 +         }
 174.714 +      }
 174.715 +#undef p
 174.716 +      return 0;
 174.717 +}
 174.718 +
 174.719 +typedef struct { double rhs, pi; } v_data;
 174.720 +typedef struct { double low, cap, cost, x; } a_data;
 174.721 +
 174.722 +int glp_main(int argc, const char *argv[])
 174.723 +{     /* stand-alone LP/MIP solver */
 174.724 +      struct csa _csa, *csa = &_csa;
 174.725 +      int ret;
 174.726 +      glp_long start;
 174.727 +      /* perform initialization */
 174.728 +      csa->prob = glp_create_prob();
 174.729 +      glp_get_bfcp(csa->prob, &csa->bfcp);
 174.730 +      glp_init_smcp(&csa->smcp);
 174.731 +      csa->smcp.presolve = GLP_ON;
 174.732 +      glp_init_iptcp(&csa->iptcp);
 174.733 +      glp_init_iocp(&csa->iocp);
 174.734 +      csa->iocp.presolve = GLP_ON;
 174.735 +      csa->tran = NULL;
 174.736 +      csa->graph = NULL;
 174.737 +      csa->format = FMT_MPS_FILE;
 174.738 +      csa->in_file = NULL;
 174.739 +      csa->ndf = 0;
 174.740 +      csa->out_dpy = NULL;
 174.741 +      csa->seed = 1;
 174.742 +      csa->solution = SOL_BASIC;
 174.743 +      csa->in_res = NULL;
 174.744 +      csa->dir = 0;
 174.745 +      csa->scale = 1;
 174.746 +      csa->out_sol = NULL;
 174.747 +      csa->out_res = NULL;
 174.748 +      csa->out_ranges = NULL;
 174.749 +      csa->check = 0;
 174.750 +      csa->new_name = NULL;
 174.751 +      csa->out_mps = NULL;
 174.752 +      csa->out_freemps = NULL;
 174.753 +      csa->out_cpxlp = NULL;
 174.754 +      csa->out_glp = NULL;
 174.755 +      csa->out_pb = NULL;
 174.756 +      csa->out_npb = NULL;
 174.757 +      csa->log_file = NULL;
 174.758 +      csa->crash = USE_ADV_BASIS;
 174.759 +      csa->ini_file = NULL;
 174.760 +      csa->exact = 0;
 174.761 +      csa->xcheck = 0;
 174.762 +      csa->nomip = 0;
 174.763 +      /* parse command-line parameters */
 174.764 +      ret = parse_cmdline(csa, argc, argv);
 174.765 +      if (ret < 0)
 174.766 +      {  ret = EXIT_SUCCESS;
 174.767 +         goto done;
 174.768 +      }
 174.769 +      if (ret > 0)
 174.770 +      {  ret = EXIT_FAILURE;
 174.771 +         goto done;
 174.772 +      }
 174.773 +      /*--------------------------------------------------------------*/
 174.774 +      /* remove all output files specified in the command line */
 174.775 +      if (csa->out_dpy != NULL) remove(csa->out_dpy);
 174.776 +      if (csa->out_sol != NULL) remove(csa->out_sol);
 174.777 +      if (csa->out_res != NULL) remove(csa->out_res);
 174.778 +      if (csa->out_ranges != NULL) remove(csa->out_ranges);
 174.779 +      if (csa->out_mps != NULL) remove(csa->out_mps);
 174.780 +      if (csa->out_freemps != NULL) remove(csa->out_freemps);
 174.781 +      if (csa->out_cpxlp != NULL) remove(csa->out_cpxlp);
 174.782 +      if (csa->out_glp != NULL) remove(csa->out_glp);
 174.783 +      if (csa->out_pb != NULL) remove(csa->out_pb);
 174.784 +      if (csa->out_npb != NULL) remove(csa->out_npb);
 174.785 +      if (csa->log_file != NULL) remove(csa->log_file);
 174.786 +      /*--------------------------------------------------------------*/
 174.787 +      /* open log file, if required */
 174.788 +      if (csa->log_file != NULL)
 174.789 +      {  if (glp_open_tee(csa->log_file))
 174.790 +         {  xprintf("Unable to create log file\n");
 174.791 +            ret = EXIT_FAILURE;
 174.792 +            goto done;
 174.793 +         }
 174.794 +      }
 174.795 +      /*--------------------------------------------------------------*/
 174.796 +      /* print version information */
 174.797 +      print_version(1);
 174.798 +      /*--------------------------------------------------------------*/
 174.799 +      /* print parameters specified in the command line */
 174.800 +      if (argc > 1)
 174.801 +      {  int k, len = INT_MAX;
 174.802 +         xprintf("Parameter(s) specified in the command line:");
 174.803 +         for (k = 1; k < argc; k++)
 174.804 +         {  if (len > 72)
 174.805 +               xprintf("\n"), len = 0;
 174.806 +            xprintf(" %s", argv[k]);
 174.807 +            len += 1 + strlen(argv[k]);
 174.808 +         }
 174.809 +         xprintf("\n");
 174.810 +      }
 174.811 +      /*--------------------------------------------------------------*/
 174.812 +      /* read problem data from the input file */
 174.813 +      if (csa->in_file == NULL)
 174.814 +      {  xprintf("No input problem file specified; try %s --help\n",
 174.815 +            argv[0]);
 174.816 +         ret = EXIT_FAILURE;
 174.817 +         goto done;
 174.818 +      }
 174.819 +      if (csa->format == FMT_MPS_DECK)
 174.820 +      {  ret = glp_read_mps(csa->prob, GLP_MPS_DECK, NULL,
 174.821 +            csa->in_file);
 174.822 +         if (ret != 0)
 174.823 +err1:    {  xprintf("MPS file processing error\n");
 174.824 +            ret = EXIT_FAILURE;
 174.825 +            goto done;
 174.826 +         }
 174.827 +      }
 174.828 +      else if (csa->format == FMT_MPS_FILE)
 174.829 +      {  ret = glp_read_mps(csa->prob, GLP_MPS_FILE, NULL,
 174.830 +            csa->in_file);
 174.831 +         if (ret != 0) goto err1;
 174.832 +      }
 174.833 +      else if (csa->format == FMT_LP)
 174.834 +      {  ret = glp_read_lp(csa->prob, NULL, csa->in_file);
 174.835 +         if (ret != 0)
 174.836 +         {  xprintf("CPLEX LP file processing error\n");
 174.837 +            ret = EXIT_FAILURE;
 174.838 +            goto done;
 174.839 +         }
 174.840 +      }
 174.841 +      else if (csa->format == FMT_GLP)
 174.842 +      {  ret = glp_read_prob(csa->prob, 0, csa->in_file);
 174.843 +         if (ret != 0)
 174.844 +         {  xprintf("GLPK LP/MIP file processing error\n");
 174.845 +            ret = EXIT_FAILURE;
 174.846 +            goto done;
 174.847 +         }
 174.848 +      }
 174.849 +      else if (csa->format == FMT_MATHPROG)
 174.850 +      {  int k;
 174.851 +         /* allocate the translator workspace */
 174.852 +         csa->tran = glp_mpl_alloc_wksp();
 174.853 +         /* set seed value */
 174.854 +         if (csa->seed == 0x80000000)
 174.855 +         {  csa->seed = glp_time().lo;
 174.856 +            xprintf("Seed value %d will be used\n", csa->seed);
 174.857 +         }
 174.858 +         _glp_mpl_init_rand(csa->tran, csa->seed);
 174.859 +         /* read model section and optional data section */
 174.860 +         if (glp_mpl_read_model(csa->tran, csa->in_file, csa->ndf > 0))
 174.861 +err2:    {  xprintf("MathProg model processing error\n");
 174.862 +            ret = EXIT_FAILURE;
 174.863 +            goto done;
 174.864 +         }
 174.865 +         /* read optional data section(s), if necessary */
 174.866 +         for (k = 1; k <= csa->ndf; k++)
 174.867 +         {  if (glp_mpl_read_data(csa->tran, csa->in_data[k]))
 174.868 +               goto err2;
 174.869 +         }
 174.870 +         /* generate the model */
 174.871 +         if (glp_mpl_generate(csa->tran, csa->out_dpy)) goto err2;
 174.872 +         /* build the problem instance from the model */
 174.873 +         glp_mpl_build_prob(csa->tran, csa->prob);
 174.874 +      }
 174.875 +      else if (csa->format == FMT_MIN_COST)
 174.876 +      {  csa->graph = glp_create_graph(sizeof(v_data), sizeof(a_data));
 174.877 +         ret = glp_read_mincost(csa->graph, offsetof(v_data, rhs),
 174.878 +            offsetof(a_data, low), offsetof(a_data, cap),
 174.879 +            offsetof(a_data, cost), csa->in_file);
 174.880 +         if (ret != 0)
 174.881 +         {  xprintf("DIMACS file processing error\n");
 174.882 +            ret = EXIT_FAILURE;
 174.883 +            goto done;
 174.884 +         }
 174.885 +         glp_mincost_lp(csa->prob, csa->graph, GLP_ON,
 174.886 +            offsetof(v_data, rhs), offsetof(a_data, low),
 174.887 +            offsetof(a_data, cap), offsetof(a_data, cost));
 174.888 +         glp_set_prob_name(csa->prob, csa->in_file);
 174.889 +      }
 174.890 +      else if (csa->format == FMT_MAX_FLOW)
 174.891 +      {  int s, t;
 174.892 +         csa->graph = glp_create_graph(sizeof(v_data), sizeof(a_data));
 174.893 +         ret = glp_read_maxflow(csa->graph, &s, &t,
 174.894 +            offsetof(a_data, cap), csa->in_file);
 174.895 +         if (ret != 0)
 174.896 +         {  xprintf("DIMACS file processing error\n");
 174.897 +            ret = EXIT_FAILURE;
 174.898 +            goto done;
 174.899 +         }
 174.900 +         glp_maxflow_lp(csa->prob, csa->graph, GLP_ON, s, t,
 174.901 +            offsetof(a_data, cap));
 174.902 +         glp_set_prob_name(csa->prob, csa->in_file);
 174.903 +      }
 174.904 +      else
 174.905 +         xassert(csa != csa);
 174.906 +      /*--------------------------------------------------------------*/
 174.907 +      /* change problem name, if required */
 174.908 +      if (csa->new_name != NULL)
 174.909 +         glp_set_prob_name(csa->prob, csa->new_name);
 174.910 +      /* change optimization direction, if required */
 174.911 +      if (csa->dir != 0)
 174.912 +         glp_set_obj_dir(csa->prob, csa->dir);
 174.913 +      /* sort elements of the constraint matrix */
 174.914 +      glp_sort_matrix(csa->prob);
 174.915 +      /*--------------------------------------------------------------*/
 174.916 +      /* write problem data in fixed MPS format, if required */
 174.917 +      if (csa->out_mps != NULL)
 174.918 +      {  ret = glp_write_mps(csa->prob, GLP_MPS_DECK, NULL,
 174.919 +            csa->out_mps);
 174.920 +         if (ret != 0)
 174.921 +         {  xprintf("Unable to write problem in fixed MPS format\n");
 174.922 +            ret = EXIT_FAILURE;
 174.923 +            goto done;
 174.924 +         }
 174.925 +      }
 174.926 +      /* write problem data in free MPS format, if required */
 174.927 +      if (csa->out_freemps != NULL)
 174.928 +      {  ret = glp_write_mps(csa->prob, GLP_MPS_FILE, NULL,
 174.929 +            csa->out_freemps);
 174.930 +         if (ret != 0)
 174.931 +         {  xprintf("Unable to write problem in free MPS format\n");
 174.932 +            ret = EXIT_FAILURE;
 174.933 +            goto done;
 174.934 +         }
 174.935 +      }
 174.936 +      /* write problem data in CPLEX LP format, if required */
 174.937 +      if (csa->out_cpxlp != NULL)
 174.938 +      {  ret = glp_write_lp(csa->prob, NULL, csa->out_cpxlp);
 174.939 +         if (ret != 0)
 174.940 +         {  xprintf("Unable to write problem in CPLEX LP format\n");
 174.941 +            ret = EXIT_FAILURE;
 174.942 +            goto done;
 174.943 +         }
 174.944 +      }
 174.945 +      /* write problem data in GLPK format, if required */
 174.946 +      if (csa->out_glp != NULL)
 174.947 +      {  ret = glp_write_prob(csa->prob, 0, csa->out_glp);
 174.948 +         if (ret != 0)
 174.949 +         {  xprintf("Unable to write problem in GLPK format\n");
 174.950 +            ret = EXIT_FAILURE;
 174.951 +            goto done;
 174.952 +         }
 174.953 +      }
 174.954 +      /* write problem data in OPB format, if required */
 174.955 +      if (csa->out_pb != NULL)
 174.956 +      {  ret = lpx_write_pb(csa->prob, csa->out_pb, 0, 0);
 174.957 +         if (ret != 0)
 174.958 +         {  xprintf("Unable to write problem in OPB format\n");
 174.959 +            ret = EXIT_FAILURE;
 174.960 +            goto done;
 174.961 +         }
 174.962 +      }
 174.963 +      /* write problem data in normalized OPB format, if required */
 174.964 +      if (csa->out_npb != NULL)
 174.965 +      {  ret = lpx_write_pb(csa->prob, csa->out_npb, 1, 1);
 174.966 +         if (ret != 0)
 174.967 +         {  xprintf(
 174.968 +               "Unable to write problem in normalized OPB format\n");
 174.969 +            ret = EXIT_FAILURE;
 174.970 +            goto done;
 174.971 +         }
 174.972 +      }
 174.973 +      /*--------------------------------------------------------------*/
 174.974 +      /* if only problem data check is required, skip computations */
 174.975 +      if (csa->check)
 174.976 +      {  ret = EXIT_SUCCESS;
 174.977 +         goto done;
 174.978 +      }
 174.979 +      /*--------------------------------------------------------------*/
 174.980 +      /* determine the solution type */
 174.981 +      if (!csa->nomip &&
 174.982 +          glp_get_num_int(csa->prob) + glp_get_num_bin(csa->prob) > 0)
 174.983 +      {  if (csa->solution == SOL_INTERIOR)
 174.984 +         {  xprintf("Interior-point method is not able to solve MIP pro"
 174.985 +               "blem; use --simplex\n");
 174.986 +            ret = EXIT_FAILURE;
 174.987 +            goto done;
 174.988 +         }
 174.989 +         csa->solution = SOL_INTEGER;
 174.990 +      }
 174.991 +      /*--------------------------------------------------------------*/
 174.992 +      /* if solution is provided, read it and skip computations */
 174.993 +      if (csa->in_res != NULL)
 174.994 +      {  if (csa->solution == SOL_BASIC)
 174.995 +            ret = glp_read_sol(csa->prob, csa->in_res);
 174.996 +         else if (csa->solution == SOL_INTERIOR)
 174.997 +            ret = glp_read_ipt(csa->prob, csa->in_res);
 174.998 +         else if (csa->solution == SOL_INTEGER)
 174.999 +            ret = glp_read_mip(csa->prob, csa->in_res);
174.1000 +         else
174.1001 +            xassert(csa != csa);
174.1002 +         if (ret != 0)
174.1003 +         {  xprintf("Unable to read problem solution\n");
174.1004 +            ret = EXIT_FAILURE;
174.1005 +            goto done;
174.1006 +         }
174.1007 +         goto skip;
174.1008 +      }
174.1009 +      /*--------------------------------------------------------------*/
174.1010 +      /* scale the problem data, if required */
174.1011 +      if (csa->scale)
174.1012 +      {  if (csa->solution == SOL_BASIC && !csa->smcp.presolve ||
174.1013 +             csa->solution == SOL_INTERIOR ||
174.1014 +             csa->solution == SOL_INTEGER && !csa->iocp.presolve)
174.1015 +            glp_scale_prob(csa->prob, GLP_SF_AUTO);
174.1016 +      }
174.1017 +      /*--------------------------------------------------------------*/
174.1018 +      /* construct starting LP basis */
174.1019 +      if (csa->solution == SOL_BASIC && !csa->smcp.presolve ||
174.1020 +          csa->solution == SOL_INTEGER && !csa->iocp.presolve)
174.1021 +      {  if (csa->crash == USE_STD_BASIS)
174.1022 +            glp_std_basis(csa->prob);
174.1023 +         else if (csa->crash == USE_ADV_BASIS)
174.1024 +            glp_adv_basis(csa->prob, 0);
174.1025 +         else if (csa->crash == USE_CPX_BASIS)
174.1026 +            glp_cpx_basis(csa->prob);
174.1027 +         else if (csa->crash == USE_INI_BASIS)
174.1028 +         {  ret = glp_read_sol(csa->prob, csa->ini_file);
174.1029 +            if (ret != 0)
174.1030 +            {  xprintf("Unable to read initial basis\n");
174.1031 +               ret = EXIT_FAILURE;
174.1032 +               goto done;
174.1033 +            }
174.1034 +         }
174.1035 +         else
174.1036 +            xassert(csa != csa);
174.1037 +      }
174.1038 +      /*--------------------------------------------------------------*/
174.1039 +      /* solve the problem */
174.1040 +      start = xtime();
174.1041 +      if (csa->solution == SOL_BASIC)
174.1042 +      {  if (!csa->exact)
174.1043 +         {  glp_set_bfcp(csa->prob, &csa->bfcp);
174.1044 +            glp_simplex(csa->prob, &csa->smcp);
174.1045 +            if (csa->xcheck)
174.1046 +            {  if (csa->smcp.presolve &&
174.1047 +                   glp_get_status(csa->prob) != GLP_OPT)
174.1048 +                  xprintf("If you need to check final basis for non-opt"
174.1049 +                     "imal solution, use --nopresol\n");
174.1050 +               else
174.1051 +                  glp_exact(csa->prob, &csa->smcp);
174.1052 +            }
174.1053 +            if (csa->out_sol != NULL || csa->out_res != NULL)
174.1054 +            {  if (csa->smcp.presolve &&
174.1055 +                   glp_get_status(csa->prob) != GLP_OPT)
174.1056 +               xprintf("If you need actual output for non-optimal solut"
174.1057 +                  "ion, use --nopresol\n");
174.1058 +            }
174.1059 +         }
174.1060 +         else
174.1061 +            glp_exact(csa->prob, &csa->smcp);
174.1062 +      }
174.1063 +      else if (csa->solution == SOL_INTERIOR)
174.1064 +         glp_interior(csa->prob, &csa->iptcp);
174.1065 +      else if (csa->solution == SOL_INTEGER)
174.1066 +      {  if (!csa->iocp.presolve)
174.1067 +         {  glp_set_bfcp(csa->prob, &csa->bfcp);
174.1068 +            glp_simplex(csa->prob, &csa->smcp);
174.1069 +         }
174.1070 +#if 0
174.1071 +         csa->iocp.msg_lev = GLP_MSG_DBG;
174.1072 +         csa->iocp.pp_tech = GLP_PP_NONE;
174.1073 +#endif
174.1074 +         glp_intopt(csa->prob, &csa->iocp);
174.1075 +      }
174.1076 +      else
174.1077 +         xassert(csa != csa);
174.1078 +      /*--------------------------------------------------------------*/
174.1079 +      /* display statistics */
174.1080 +      xprintf("Time used:   %.1f secs\n", xdifftime(xtime(), start));
174.1081 +      {  glp_long tpeak;
174.1082 +         char buf[50];
174.1083 +         glp_mem_usage(NULL, NULL, NULL, &tpeak);
174.1084 +         xprintf("Memory used: %.1f Mb (%s bytes)\n",
174.1085 +            xltod(tpeak) / 1048576.0, xltoa(tpeak, buf));
174.1086 +      }
174.1087 +      /*--------------------------------------------------------------*/
174.1088 +skip: /* postsolve the model, if necessary */
174.1089 +      if (csa->tran != NULL)
174.1090 +      {  if (csa->solution == SOL_BASIC)
174.1091 +            ret = glp_mpl_postsolve(csa->tran, csa->prob, GLP_SOL);
174.1092 +         else if (csa->solution == SOL_INTERIOR)
174.1093 +            ret = glp_mpl_postsolve(csa->tran, csa->prob, GLP_IPT);
174.1094 +         else if (csa->solution == SOL_INTEGER)
174.1095 +            ret = glp_mpl_postsolve(csa->tran, csa->prob, GLP_MIP);
174.1096 +         else
174.1097 +            xassert(csa != csa);
174.1098 +         if (ret != 0)
174.1099 +         {  xprintf("Model postsolving error\n");
174.1100 +            ret = EXIT_FAILURE;
174.1101 +            goto done;
174.1102 +         }
174.1103 +      }
174.1104 +      /*--------------------------------------------------------------*/
174.1105 +      /* write problem solution in printable format, if required */
174.1106 +      if (csa->out_sol != NULL)
174.1107 +      {  if (csa->solution == SOL_BASIC)
174.1108 +            ret = lpx_print_sol(csa->prob, csa->out_sol);
174.1109 +         else if (csa->solution == SOL_INTERIOR)
174.1110 +            ret = lpx_print_ips(csa->prob, csa->out_sol);
174.1111 +         else if (csa->solution == SOL_INTEGER)
174.1112 +            ret = lpx_print_mip(csa->prob, csa->out_sol);
174.1113 +         else
174.1114 +            xassert(csa != csa);
174.1115 +         if (ret != 0)
174.1116 +         {  xprintf("Unable to write problem solution\n");
174.1117 +            ret = EXIT_FAILURE;
174.1118 +            goto done;
174.1119 +         }
174.1120 +      }
174.1121 +      /* write problem solution in printable format, if required */
174.1122 +      if (csa->out_res != NULL)
174.1123 +      {  if (csa->solution == SOL_BASIC)
174.1124 +            ret = glp_write_sol(csa->prob, csa->out_res);
174.1125 +         else if (csa->solution == SOL_INTERIOR)
174.1126 +            ret = glp_write_ipt(csa->prob, csa->out_res);
174.1127 +         else if (csa->solution == SOL_INTEGER)
174.1128 +            ret = glp_write_mip(csa->prob, csa->out_res);
174.1129 +         else
174.1130 +            xassert(csa != csa);
174.1131 +         if (ret != 0)
174.1132 +         {  xprintf("Unable to write problem solution\n");
174.1133 +            ret = EXIT_FAILURE;
174.1134 +            goto done;
174.1135 +         }
174.1136 +      }
174.1137 +      /* write sensitivity analysis report, if required */
174.1138 +      if (csa->out_ranges != NULL)
174.1139 +      {  if (csa->solution == SOL_BASIC)
174.1140 +         {  if (glp_get_status(csa->prob) == GLP_OPT)
174.1141 +            {  if (glp_bf_exists(csa->prob))
174.1142 +ranges:        {  ret = glp_print_ranges(csa->prob, 0, NULL, 0,
174.1143 +                     csa->out_ranges);
174.1144 +                  if (ret != 0)
174.1145 +                  {  xprintf("Unable to write sensitivity analysis repo"
174.1146 +                        "rt\n");
174.1147 +                     ret = EXIT_FAILURE;
174.1148 +                     goto done;
174.1149 +                  }
174.1150 +               }
174.1151 +               else
174.1152 +               {  ret = glp_factorize(csa->prob);
174.1153 +                  if (ret == 0) goto ranges;
174.1154 +                  xprintf("Cannot produce sensitivity analysis report d"
174.1155 +                     "ue to error in basis factorization (glp_factorize"
174.1156 +                     " returned %d); try --nopresol\n", ret);
174.1157 +               }
174.1158 +            }
174.1159 +            else
174.1160 +               xprintf("Cannot produce sensitivity analysis report for "
174.1161 +                  "non-optimal basic solution\n");
174.1162 +         }
174.1163 +         else
174.1164 +            xprintf("Cannot produce sensitivity analysis report for int"
174.1165 +               "erior-point or MIP solution\n");
174.1166 +      }
174.1167 +      /*--------------------------------------------------------------*/
174.1168 +      /* all seems to be ok */
174.1169 +      ret = EXIT_SUCCESS;
174.1170 +      /*--------------------------------------------------------------*/
174.1171 +done: /* delete the LP/MIP problem object */
174.1172 +      if (csa->prob != NULL)
174.1173 +         glp_delete_prob(csa->prob);
174.1174 +      /* free the translator workspace, if necessary */
174.1175 +      if (csa->tran != NULL)
174.1176 +         glp_mpl_free_wksp(csa->tran);
174.1177 +      /* delete the network problem object, if necessary */
174.1178 +      if (csa->graph != NULL)
174.1179 +         glp_delete_graph(csa->graph);
174.1180 +      xassert(gmp_pool_count() == 0);
174.1181 +      gmp_free_mem();
174.1182 +      /* close log file, if necessary */
174.1183 +      if (csa->log_file != NULL) glp_close_tee();
174.1184 +      /* check that no memory blocks are still allocated */
174.1185 +      {  int count;
174.1186 +         glp_long total;
174.1187 +         glp_mem_usage(&count, NULL, &total, NULL);
174.1188 +         if (count != 0)
174.1189 +            xerror("Error: %d memory block(s) were lost\n", count);
174.1190 +         xassert(count == 0);
174.1191 +         xassert(total.lo == 0 && total.hi == 0);
174.1192 +      }
174.1193 +      /* free the GLPK environment */
174.1194 +      glp_free_env();
174.1195 +      /* return to the control program */
174.1196 +      return ret;
174.1197 +}
174.1198 +
174.1199 +/* eof */
   175.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   175.2 +++ b/src/glpavl.c	Mon Dec 06 13:09:21 2010 +0100
   175.3 @@ -0,0 +1,357 @@
   175.4 +/* glpavl.c (binary search tree) */
   175.5 +
   175.6 +/***********************************************************************
   175.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   175.8 +*
   175.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  175.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  175.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  175.12 +*  E-mail: <mao@gnu.org>.
  175.13 +*
  175.14 +*  GLPK is free software: you can redistribute it and/or modify it
  175.15 +*  under the terms of the GNU General Public License as published by
  175.16 +*  the Free Software Foundation, either version 3 of the License, or
  175.17 +*  (at your option) any later version.
  175.18 +*
  175.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  175.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  175.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  175.22 +*  License for more details.
  175.23 +*
  175.24 +*  You should have received a copy of the GNU General Public License
  175.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  175.26 +***********************************************************************/
  175.27 +
  175.28 +#include "glpavl.h"
  175.29 +
  175.30 +AVL *avl_create_tree(int (*fcmp)(void *info, const void *key1,
  175.31 +      const void *key2), void *info)
  175.32 +{     /* create AVL tree */
  175.33 +      AVL *tree;
  175.34 +      tree = xmalloc(sizeof(AVL));
  175.35 +      tree->pool = dmp_create_pool();
  175.36 +      tree->root = NULL;
  175.37 +      tree->fcmp = fcmp;
  175.38 +      tree->info = info;
  175.39 +      tree->size = 0;
  175.40 +      tree->height = 0;
  175.41 +      return tree;
  175.42 +}
  175.43 +
  175.44 +int avl_strcmp(void *info, const void *key1, const void *key2)
  175.45 +{     /* compare character string keys */
  175.46 +      xassert(info == info);
  175.47 +      return strcmp(key1, key2);
  175.48 +}
  175.49 +
  175.50 +static AVLNODE *rotate_subtree(AVL *tree, AVLNODE *node);
  175.51 +
  175.52 +AVLNODE *avl_insert_node(AVL *tree, const void *key)
  175.53 +{     /* insert new node into AVL tree */
  175.54 +      AVLNODE *p, *q, *r;
  175.55 +      short int flag;
  175.56 +      /* find an appropriate point for insertion */
  175.57 +      p = NULL; q = tree->root;
  175.58 +      while (q != NULL)
  175.59 +      {  p = q;
  175.60 +         if (tree->fcmp(tree->info, key, p->key) <= 0)
  175.61 +         {  flag = 0;
  175.62 +            q = p->left;
  175.63 +            p->rank++;
  175.64 +         }
  175.65 +         else
  175.66 +         {  flag = 1;
  175.67 +            q = p->right;
  175.68 +         }
  175.69 +      }
  175.70 +      /* create new node and insert it into the tree */
  175.71 +      r = dmp_get_atom(tree->pool, sizeof(AVLNODE));
  175.72 +      r->key = key; r->type = 0; r->link = NULL;
  175.73 +      r->rank = 1; r->up = p;
  175.74 +      r->flag = (short int)(p == NULL ? 0 : flag);
  175.75 +      r->bal = 0; r->left = NULL; r->right = NULL;
  175.76 +      tree->size++;
  175.77 +      if (p == NULL)
  175.78 +         tree->root = r;
  175.79 +      else
  175.80 +         if (flag == 0) p->left = r; else p->right = r;
  175.81 +      /* go upstairs to the root and correct all subtrees affected by
  175.82 +         insertion */
  175.83 +      while (p != NULL)
  175.84 +      {  if (flag == 0)
  175.85 +         {  /* the height of the left subtree of [p] is increased */
  175.86 +            if (p->bal > 0)
  175.87 +            {  p->bal = 0;
  175.88 +               break;
  175.89 +            }
  175.90 +            if (p->bal < 0)
  175.91 +            {  rotate_subtree(tree, p);
  175.92 +               break;
  175.93 +            }
  175.94 +            p->bal = -1; flag = p->flag; p = p->up;
  175.95 +         }
  175.96 +         else
  175.97 +         {  /* the height of the right subtree of [p] is increased */
  175.98 +            if (p->bal < 0)
  175.99 +            {  p->bal = 0;
 175.100 +               break;
 175.101 +            }
 175.102 +            if (p->bal > 0)
 175.103 +            {  rotate_subtree(tree, p);
 175.104 +               break;
 175.105 +            }
 175.106 +            p->bal = +1; flag = p->flag; p = p->up;
 175.107 +         }
 175.108 +      }
 175.109 +      /* if the root has been reached, the height of the entire tree is
 175.110 +         increased */
 175.111 +      if (p == NULL) tree->height++;
 175.112 +      return r;
 175.113 +}
 175.114 +
 175.115 +void avl_set_node_type(AVLNODE *node, int type)
 175.116 +{     /* assign the type field of specified node */
 175.117 +      node->type = type;
 175.118 +      return;
 175.119 +}
 175.120 +
 175.121 +void avl_set_node_link(AVLNODE *node, void *link)
 175.122 +{     /* assign the link field of specified node */
 175.123 +      node->link = link;
 175.124 +      return;
 175.125 +}
 175.126 +
 175.127 +AVLNODE *avl_find_node(AVL *tree, const void *key)
 175.128 +{     /* find node in AVL tree */
 175.129 +      AVLNODE *p;
 175.130 +      int c;
 175.131 +      p = tree->root;
 175.132 +      while (p != NULL)
 175.133 +      {  c = tree->fcmp(tree->info, key, p->key);
 175.134 +         if (c == 0) break;
 175.135 +         p = (c < 0 ? p->left : p->right);
 175.136 +      }
 175.137 +      return p;
 175.138 +}
 175.139 +
 175.140 +int avl_get_node_type(AVLNODE *node)
 175.141 +{     /* retrieve the type field of specified node */
 175.142 +      return node->type;
 175.143 +}
 175.144 +
 175.145 +void *avl_get_node_link(AVLNODE *node)
 175.146 +{     /* retrieve the link field of specified node */
 175.147 +      return node->link;
 175.148 +}
 175.149 +
 175.150 +static AVLNODE *find_next_node(AVL *tree, AVLNODE *node)
 175.151 +{     /* find next node in AVL tree */
 175.152 +      AVLNODE *p, *q;
 175.153 +      if (tree->root == NULL) return NULL;
 175.154 +      p = node;
 175.155 +      q = (p == NULL ? tree->root : p->right);
 175.156 +      if (q == NULL)
 175.157 +      {  /* go upstairs from the left subtree */
 175.158 +         for (;;)
 175.159 +         {  q = p->up;
 175.160 +            if (q == NULL) break;
 175.161 +            if (p->flag == 0) break;
 175.162 +            p = q;
 175.163 +         }
 175.164 +      }
 175.165 +      else
 175.166 +      {  /* go downstairs into the right subtree */
 175.167 +         for (;;)
 175.168 +         {  p = q->left;
 175.169 +            if (p == NULL) break;
 175.170 +            q = p;
 175.171 +         }
 175.172 +      }
 175.173 +      return q;
 175.174 +}
 175.175 +
 175.176 +void avl_delete_node(AVL *tree, AVLNODE *node)
 175.177 +{     /* delete specified node from AVL tree */
 175.178 +      AVLNODE *f, *p, *q, *r, *s, *x, *y;
 175.179 +      short int flag;
 175.180 +      p = node;
 175.181 +      /* if both subtrees of the specified node are non-empty, the node
 175.182 +         should be interchanged with the next one, at least one subtree
 175.183 +         of which is always empty */
 175.184 +      if (p->left == NULL || p->right == NULL) goto skip;
 175.185 +      f = p->up; q = p->left;
 175.186 +      r = find_next_node(tree, p); s = r->right;
 175.187 +      if (p->right == r)
 175.188 +      {  if (f == NULL)
 175.189 +            tree->root = r;
 175.190 +         else
 175.191 +            if (p->flag == 0) f->left = r; else f->right = r;
 175.192 +         r->rank = p->rank; r->up = f;
 175.193 +         r->flag = p->flag; r->bal = p->bal;
 175.194 +         r->left = q; r->right = p;
 175.195 +         q->up = r;
 175.196 +         p->rank = 1; p->up = r; p->flag = 1;
 175.197 +         p->bal = (short int)(s == NULL ? 0 : +1);
 175.198 +         p->left = NULL; p->right = s;
 175.199 +         if (s != NULL) s->up = p;
 175.200 +      }
 175.201 +      else
 175.202 +      {  x = p->right; y = r->up;
 175.203 +         if (f == NULL)
 175.204 +            tree->root = r;
 175.205 +         else
 175.206 +            if (p->flag == 0) f->left = r; else f->right = r;
 175.207 +         r->rank = p->rank; r->up = f;
 175.208 +         r->flag = p->flag; r->bal = p->bal;
 175.209 +         r->left = q; r->right = x;
 175.210 +         q->up = r; x->up = r; y->left = p;
 175.211 +         p->rank = 1; p->up = y; p->flag = 0;
 175.212 +         p->bal = (short int)(s == NULL ? 0 : +1);
 175.213 +         p->left = NULL; p->right = s;
 175.214 +         if (s != NULL) s->up = p;
 175.215 +      }
 175.216 +skip: /* now the specified node [p] has at least one empty subtree;
 175.217 +         go upstairs to the root and adjust the rank field of all nodes
 175.218 +         affected by deletion */
 175.219 +      q = p; f = q->up;
 175.220 +      while (f != NULL)
 175.221 +      {  if (q->flag == 0) f->rank--;
 175.222 +         q = f; f = q->up;
 175.223 +      }
 175.224 +      /* delete the specified node from the tree */
 175.225 +      f = p->up; flag = p->flag;
 175.226 +      q = p->left != NULL ? p->left : p->right;
 175.227 +      if (f == NULL)
 175.228 +         tree->root = q;
 175.229 +      else
 175.230 +         if (flag == 0) f->left = q; else f->right = q;
 175.231 +      if (q != NULL) q->up = f, q->flag = flag;
 175.232 +      tree->size--;
 175.233 +      /* go upstairs to the root and correct all subtrees affected by
 175.234 +         deletion */
 175.235 +      while (f != NULL)
 175.236 +      {  if (flag == 0)
 175.237 +         {  /* the height of the left subtree of [f] is decreased */
 175.238 +            if (f->bal == 0)
 175.239 +            {  f->bal = +1;
 175.240 +               break;
 175.241 +            }
 175.242 +            if (f->bal < 0)
 175.243 +               f->bal = 0;
 175.244 +            else
 175.245 +            {  f = rotate_subtree(tree, f);
 175.246 +               if (f->bal < 0) break;
 175.247 +            }
 175.248 +            flag = f->flag; f = f->up;
 175.249 +         }
 175.250 +         else
 175.251 +         {  /* the height of the right subtree of [f] is decreased */
 175.252 +            if (f->bal == 0)
 175.253 +            {  f->bal = -1;
 175.254 +               break;
 175.255 +            }
 175.256 +            if (f->bal > 0)
 175.257 +               f->bal = 0;
 175.258 +            else
 175.259 +            {  f = rotate_subtree(tree, f);
 175.260 +               if (f->bal > 0) break;
 175.261 +            }
 175.262 +            flag = f->flag; f = f->up;
 175.263 +         }
 175.264 +      }
 175.265 +      /* if the root has been reached, the height of the entire tree is
 175.266 +         decreased */
 175.267 +      if (f == NULL) tree->height--;
 175.268 +      /* returns the deleted node to the memory pool */
 175.269 +      dmp_free_atom(tree->pool, p, sizeof(AVLNODE));
 175.270 +      return;
 175.271 +}
 175.272 +
 175.273 +static AVLNODE *rotate_subtree(AVL *tree, AVLNODE *node)
 175.274 +{     /* restore balance of AVL subtree */
 175.275 +      AVLNODE *f, *p, *q, *r, *x, *y;
 175.276 +      xassert(node != NULL);
 175.277 +      p = node;
 175.278 +      if (p->bal < 0)
 175.279 +      {  /* perform negative (left) rotation */
 175.280 +         f = p->up; q = p->left; r = q->right;
 175.281 +         if (q->bal <= 0)
 175.282 +         {  /* perform single negative rotation */
 175.283 +            if (f == NULL)
 175.284 +               tree->root = q;
 175.285 +            else
 175.286 +               if (p->flag == 0) f->left = q; else f->right = q;
 175.287 +            p->rank -= q->rank;
 175.288 +            q->up = f; q->flag = p->flag; q->bal++; q->right = p;
 175.289 +            p->up = q; p->flag = 1;
 175.290 +            p->bal = (short int)(-q->bal); p->left = r;
 175.291 +            if (r != NULL) r->up = p, r->flag = 0;
 175.292 +            node = q;
 175.293 +         }
 175.294 +         else
 175.295 +         {  /* perform double negative rotation */
 175.296 +            x = r->left; y = r->right;
 175.297 +            if (f == NULL)
 175.298 +               tree->root = r;
 175.299 +            else
 175.300 +               if (p->flag == 0) f->left = r; else f->right = r;
 175.301 +            p->rank -= (q->rank + r->rank);
 175.302 +            r->rank += q->rank;
 175.303 +            p->bal = (short int)(r->bal >= 0 ? 0 : +1);
 175.304 +            q->bal = (short int)(r->bal <= 0 ? 0 : -1);
 175.305 +            r->up = f; r->flag = p->flag; r->bal = 0;
 175.306 +            r->left = q; r->right = p;
 175.307 +            p->up = r; p->flag = 1; p->left = y;
 175.308 +            q->up = r; q->flag = 0; q->right = x;
 175.309 +            if (x != NULL) x->up = q, x->flag = 1;
 175.310 +            if (y != NULL) y->up = p, y->flag = 0;
 175.311 +            node = r;
 175.312 +         }
 175.313 +      }
 175.314 +      else
 175.315 +      {  /* perform positive (right) rotation */
 175.316 +         f = p->up; q = p->right; r = q->left;
 175.317 +         if (q->bal >= 0)
 175.318 +         {  /* perform single positive rotation */
 175.319 +            if (f == NULL)
 175.320 +               tree->root = q;
 175.321 +            else
 175.322 +               if (p->flag == 0) f->left = q; else f->right = q;
 175.323 +            q->rank += p->rank;
 175.324 +            q->up = f; q->flag = p->flag; q->bal--; q->left = p;
 175.325 +            p->up = q; p->flag = 0;
 175.326 +            p->bal = (short int)(-q->bal); p->right = r;
 175.327 +            if (r != NULL) r->up = p, r->flag = 1;
 175.328 +            node = q;
 175.329 +         }
 175.330 +         else
 175.331 +         {  /* perform double positive rotation */
 175.332 +            x = r->left; y = r->right;
 175.333 +            if (f == NULL)
 175.334 +               tree->root = r;
 175.335 +            else
 175.336 +               if (p->flag == 0) f->left = r; else f->right = r;
 175.337 +            q->rank -= r->rank;
 175.338 +            r->rank += p->rank;
 175.339 +            p->bal = (short int)(r->bal <= 0 ? 0 : -1);
 175.340 +            q->bal = (short int)(r->bal >= 0 ? 0 : +1);
 175.341 +            r->up = f; r->flag = p->flag; r->bal = 0;
 175.342 +            r->left = p; r->right = q;
 175.343 +            p->up = r; p->flag = 0; p->right = x;
 175.344 +            q->up = r; q->flag = 1; q->left = y;
 175.345 +            if (x != NULL) x->up = p, x->flag = 1;
 175.346 +            if (y != NULL) y->up = q, y->flag = 0;
 175.347 +            node = r;
 175.348 +         }
 175.349 +      }
 175.350 +      return node;
 175.351 +}
 175.352 +
 175.353 +void avl_delete_tree(AVL *tree)
 175.354 +{     /* delete AVL tree */
 175.355 +      dmp_delete_pool(tree->pool);
 175.356 +      xfree(tree);
 175.357 +      return;
 175.358 +}
 175.359 +
 175.360 +/* eof */
   176.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   176.2 +++ b/src/glpavl.h	Mon Dec 06 13:09:21 2010 +0100
   176.3 @@ -0,0 +1,123 @@
   176.4 +/* glpavl.h (binary search tree) */
   176.5 +
   176.6 +/***********************************************************************
   176.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   176.8 +*
   176.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  176.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  176.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  176.12 +*  E-mail: <mao@gnu.org>.
  176.13 +*
  176.14 +*  GLPK is free software: you can redistribute it and/or modify it
  176.15 +*  under the terms of the GNU General Public License as published by
  176.16 +*  the Free Software Foundation, either version 3 of the License, or
  176.17 +*  (at your option) any later version.
  176.18 +*
  176.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  176.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  176.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  176.22 +*  License for more details.
  176.23 +*
  176.24 +*  You should have received a copy of the GNU General Public License
  176.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  176.26 +***********************************************************************/
  176.27 +
  176.28 +#ifndef GLPAVL_H
  176.29 +#define GLPAVL_H
  176.30 +
  176.31 +#include "glpdmp.h"
  176.32 +
  176.33 +typedef struct AVL AVL;
  176.34 +typedef struct AVLNODE AVLNODE;
  176.35 +
  176.36 +struct AVL
  176.37 +{     /* AVL tree (Adelson-Velsky & Landis binary search tree) */
  176.38 +      DMP *pool;
  176.39 +      /* memory pool for allocating nodes */
  176.40 +      AVLNODE *root;
  176.41 +      /* pointer to the root node */
  176.42 +      int (*fcmp)(void *info, const void *key1, const void *key2);
  176.43 +      /* application-defined key comparison routine */
  176.44 +      void *info;
  176.45 +      /* transit pointer passed to the routine fcmp */
  176.46 +      int size;
  176.47 +      /* the tree size (the total number of nodes) */
  176.48 +      int height;
  176.49 +      /* the tree height */
  176.50 +};
  176.51 +
  176.52 +struct AVLNODE
  176.53 +{     /* node of AVL tree */
  176.54 +      const void *key;
  176.55 +      /* pointer to the node key (data structure for representing keys
  176.56 +         is supplied by the application) */
  176.57 +      int rank;
  176.58 +      /* node rank = relative position of the node in its own subtree =
  176.59 +         the number of nodes in the left subtree plus one */
  176.60 +      int type;
  176.61 +      /* reserved for the application specific information */
  176.62 +      void *link;
  176.63 +      /* reserved for the application specific information */
  176.64 +      AVLNODE *up;
  176.65 +      /* pointer to the parent node */
  176.66 +      short int flag;
  176.67 +      /* node flag:
  176.68 +         0 - this node is the left child of its parent (or this node is
  176.69 +             the root of the tree and has no parent)
  176.70 +         1 - this node is the right child of its parent */
  176.71 +      short int bal;
  176.72 +      /* node balance = the difference between heights of the right and
  176.73 +         left subtrees:
  176.74 +         -1 - the left subtree is higher than the right one;
  176.75 +          0 - the left and right subtrees have the same height;
  176.76 +         +1 - the left subtree is lower than the right one */
  176.77 +      AVLNODE *left;
  176.78 +      /* pointer to the root of the left subtree */
  176.79 +      AVLNODE *right;
  176.80 +      /* pointer to the root of the right subtree */
  176.81 +};
  176.82 +
  176.83 +#define avl_create_tree _glp_avl_create_tree
  176.84 +AVL *avl_create_tree(int (*fcmp)(void *info, const void *key1,
  176.85 +      const void *key2), void *info);
  176.86 +/* create AVL tree */
  176.87 +
  176.88 +#define avl_strcmp _glp_avl_strcmp
  176.89 +int avl_strcmp(void *info, const void *key1, const void *key2);
  176.90 +/* compare character string keys */
  176.91 +
  176.92 +#define avl_insert_node _glp_avl_insert_node
  176.93 +AVLNODE *avl_insert_node(AVL *tree, const void *key);
  176.94 +/* insert new node into AVL tree */
  176.95 +
  176.96 +#define avl_set_node_type _glp_avl_set_node_type
  176.97 +void avl_set_node_type(AVLNODE *node, int type);
  176.98 +/* assign the type field of specified node */
  176.99 +
 176.100 +#define avl_set_node_link _glp_avl_set_node_link
 176.101 +void avl_set_node_link(AVLNODE *node, void *link);
 176.102 +/* assign the link field of specified node */
 176.103 +
 176.104 +#define avl_find_node _glp_avl_find_node
 176.105 +AVLNODE *avl_find_node(AVL *tree, const void *key);
 176.106 +/* find node in AVL tree */
 176.107 +
 176.108 +#define avl_get_node_type _glp_avl_get_node_type
 176.109 +int avl_get_node_type(AVLNODE *node);
 176.110 +/* retrieve the type field of specified node */
 176.111 +
 176.112 +#define avl_get_node_link _glp_avl_get_node_link
 176.113 +void *avl_get_node_link(AVLNODE *node);
 176.114 +/* retrieve the link field of specified node */
 176.115 +
 176.116 +#define avl_delete_node _glp_avl_delete_node
 176.117 +void avl_delete_node(AVL *tree, AVLNODE *node);
 176.118 +/* delete specified node from AVL tree */
 176.119 +
 176.120 +#define avl_delete_tree _glp_avl_delete_tree
 176.121 +void avl_delete_tree(AVL *tree);
 176.122 +/* delete AVL tree */
 176.123 +
 176.124 +#endif
 176.125 +
 176.126 +/* eof */
   177.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   177.2 +++ b/src/glpbfd.c	Mon Dec 06 13:09:21 2010 +0100
   177.3 @@ -0,0 +1,481 @@
   177.4 +/* glpbfd.c (LP basis factorization driver) */
   177.5 +
   177.6 +/***********************************************************************
   177.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   177.8 +*
   177.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  177.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  177.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  177.12 +*  E-mail: <mao@gnu.org>.
  177.13 +*
  177.14 +*  GLPK is free software: you can redistribute it and/or modify it
  177.15 +*  under the terms of the GNU General Public License as published by
  177.16 +*  the Free Software Foundation, either version 3 of the License, or
  177.17 +*  (at your option) any later version.
  177.18 +*
  177.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  177.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  177.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  177.22 +*  License for more details.
  177.23 +*
  177.24 +*  You should have received a copy of the GNU General Public License
  177.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  177.26 +***********************************************************************/
  177.27 +
  177.28 +typedef struct BFD BFD;
  177.29 +
  177.30 +#define GLPBFD_PRIVATE
  177.31 +#include "glpapi.h"
  177.32 +#include "glpfhv.h"
  177.33 +#include "glplpf.h"
  177.34 +
  177.35 +/* CAUTION: DO NOT CHANGE THE LIMIT BELOW */
  177.36 +
  177.37 +#define M_MAX 100000000 /* = 100*10^6 */
  177.38 +/* maximal order of the basis matrix */
  177.39 +
  177.40 +struct BFD
  177.41 +{     /* LP basis factorization */
  177.42 +      int valid;
  177.43 +      /* factorization is valid only if this flag is set */
  177.44 +      int type;
  177.45 +      /* factorization type:
  177.46 +         GLP_BF_FT - LUF + Forrest-Tomlin
  177.47 +         GLP_BF_BG - LUF + Schur compl. + Bartels-Golub
  177.48 +         GLP_BF_GR - LUF + Schur compl. + Givens rotation */
  177.49 +      FHV *fhv;
  177.50 +      /* LP basis factorization (GLP_BF_FT) */
  177.51 +      LPF *lpf;
  177.52 +      /* LP basis factorization (GLP_BF_BG, GLP_BF_GR) */
  177.53 +      int lu_size;      /* luf.sv_size */
  177.54 +      double piv_tol;   /* luf.piv_tol */
  177.55 +      int piv_lim;      /* luf.piv_lim */
  177.56 +      int suhl;         /* luf.suhl */
  177.57 +      double eps_tol;   /* luf.eps_tol */
  177.58 +      double max_gro;   /* luf.max_gro */
  177.59 +      int nfs_max;      /* fhv.hh_max */
  177.60 +      double upd_tol;   /* fhv.upd_tol */
  177.61 +      int nrs_max;      /* lpf.n_max */
  177.62 +      int rs_size;      /* lpf.v_size */
  177.63 +      /* internal control parameters */
  177.64 +      int upd_lim;
  177.65 +      /* the factorization update limit */
  177.66 +      int upd_cnt;
  177.67 +      /* the factorization update count */
  177.68 +};
  177.69 +
  177.70 +/***********************************************************************
  177.71 +*  NAME
  177.72 +*
  177.73 +*  bfd_create_it - create LP basis factorization
  177.74 +*
  177.75 +*  SYNOPSIS
  177.76 +*
  177.77 +*  #include "glpbfd.h"
  177.78 +*  BFD *bfd_create_it(void);
  177.79 +*
  177.80 +*  DESCRIPTION
  177.81 +*
  177.82 +*  The routine bfd_create_it creates a program object, which represents
  177.83 +*  a factorization of LP basis.
  177.84 +*
  177.85 +*  RETURNS
  177.86 +*
  177.87 +*  The routine bfd_create_it returns a pointer to the object created. */
  177.88 +
  177.89 +BFD *bfd_create_it(void)
  177.90 +{     BFD *bfd;
  177.91 +      bfd = xmalloc(sizeof(BFD));
  177.92 +      bfd->valid = 0;
  177.93 +      bfd->type = GLP_BF_FT;
  177.94 +      bfd->fhv = NULL;
  177.95 +      bfd->lpf = NULL;
  177.96 +      bfd->lu_size = 0;
  177.97 +      bfd->piv_tol = 0.10;
  177.98 +      bfd->piv_lim = 4;
  177.99 +      bfd->suhl = 1;
 177.100 +      bfd->eps_tol = 1e-15;
 177.101 +      bfd->max_gro = 1e+10;
 177.102 +      bfd->nfs_max = 100;
 177.103 +      bfd->upd_tol = 1e-6;
 177.104 +      bfd->nrs_max = 100;
 177.105 +      bfd->rs_size = 1000;
 177.106 +      bfd->upd_lim = -1;
 177.107 +      bfd->upd_cnt = 0;
 177.108 +      return bfd;
 177.109 +}
 177.110 +
 177.111 +/**********************************************************************/
 177.112 +
 177.113 +void bfd_set_parm(BFD *bfd, const void *_parm)
 177.114 +{     /* change LP basis factorization control parameters */
 177.115 +      const glp_bfcp *parm = _parm;
 177.116 +      xassert(bfd != NULL);
 177.117 +      bfd->type = parm->type;
 177.118 +      bfd->lu_size = parm->lu_size;
 177.119 +      bfd->piv_tol = parm->piv_tol;
 177.120 +      bfd->piv_lim = parm->piv_lim;
 177.121 +      bfd->suhl = parm->suhl;
 177.122 +      bfd->eps_tol = parm->eps_tol;
 177.123 +      bfd->max_gro = parm->max_gro;
 177.124 +      bfd->nfs_max = parm->nfs_max;
 177.125 +      bfd->upd_tol = parm->upd_tol;
 177.126 +      bfd->nrs_max = parm->nrs_max;
 177.127 +      bfd->rs_size = parm->rs_size;
 177.128 +      return;
 177.129 +}
 177.130 +
 177.131 +/***********************************************************************
 177.132 +*  NAME
 177.133 +*
 177.134 +*  bfd_factorize - compute LP basis factorization
 177.135 +*
 177.136 +*  SYNOPSIS
 177.137 +*
 177.138 +*  #include "glpbfd.h"
 177.139 +*  int bfd_factorize(BFD *bfd, int m, int bh[], int (*col)(void *info,
 177.140 +*     int j, int ind[], double val[]), void *info);
 177.141 +*
 177.142 +*  DESCRIPTION
 177.143 +*
 177.144 +*  The routine bfd_factorize computes the factorization of the basis
 177.145 +*  matrix B specified by the routine col.
 177.146 +*
 177.147 +*  The parameter bfd specified the basis factorization data structure
 177.148 +*  created with the routine bfd_create_it.
 177.149 +*
 177.150 +*  The parameter m specifies the order of B, m > 0.
 177.151 +*
 177.152 +*  The array bh specifies the basis header: bh[j], 1 <= j <= m, is the
 177.153 +*  number of j-th column of B in some original matrix. The array bh is
 177.154 +*  optional and can be specified as NULL.
 177.155 +*
 177.156 +*  The formal routine col specifies the matrix B to be factorized. To
 177.157 +*  obtain j-th column of A the routine bfd_factorize calls the routine
 177.158 +*  col with the parameter j (1 <= j <= n). In response the routine col
 177.159 +*  should store row indices and numerical values of non-zero elements
 177.160 +*  of j-th column of B to locations ind[1,...,len] and val[1,...,len],
 177.161 +*  respectively, where len is the number of non-zeros in j-th column
 177.162 +*  returned on exit. Neither zero nor duplicate elements are allowed.
 177.163 +*
 177.164 +*  The parameter info is a transit pointer passed to the routine col.
 177.165 +*
 177.166 +*  RETURNS
 177.167 +*
 177.168 +*  0  The factorization has been successfully computed.
 177.169 +*
 177.170 +*  BFD_ESING
 177.171 +*     The specified matrix is singular within the working precision.
 177.172 +*
 177.173 +*  BFD_ECOND
 177.174 +*     The specified matrix is ill-conditioned.
 177.175 +*
 177.176 +*  For more details see comments to the routine luf_factorize. */
 177.177 +
 177.178 +int bfd_factorize(BFD *bfd, int m, const int bh[], int (*col)
 177.179 +      (void *info, int j, int ind[], double val[]), void *info)
 177.180 +{     LUF *luf;
 177.181 +      int nov, ret;
 177.182 +      xassert(bfd != NULL);
 177.183 +      xassert(1 <= m && m <= M_MAX);
 177.184 +      /* invalidate the factorization */
 177.185 +      bfd->valid = 0;
 177.186 +      /* create the factorization, if necessary */
 177.187 +      nov = 0;
 177.188 +      switch (bfd->type)
 177.189 +      {  case GLP_BF_FT:
 177.190 +            if (bfd->lpf != NULL)
 177.191 +               lpf_delete_it(bfd->lpf), bfd->lpf = NULL;
 177.192 +            if (bfd->fhv == NULL)
 177.193 +               bfd->fhv = fhv_create_it(), nov = 1;
 177.194 +            break;
 177.195 +         case GLP_BF_BG:
 177.196 +         case GLP_BF_GR:
 177.197 +            if (bfd->fhv != NULL)
 177.198 +               fhv_delete_it(bfd->fhv), bfd->fhv = NULL;
 177.199 +            if (bfd->lpf == NULL)
 177.200 +               bfd->lpf = lpf_create_it(), nov = 1;
 177.201 +            break;
 177.202 +         default:
 177.203 +            xassert(bfd != bfd);
 177.204 +      }
 177.205 +      /* set control parameters specific to LUF */
 177.206 +      if (bfd->fhv != NULL)
 177.207 +         luf = bfd->fhv->luf;
 177.208 +      else if (bfd->lpf != NULL)
 177.209 +         luf = bfd->lpf->luf;
 177.210 +      else
 177.211 +         xassert(bfd != bfd);
 177.212 +      if (nov) luf->new_sva = bfd->lu_size;
 177.213 +      luf->piv_tol = bfd->piv_tol;
 177.214 +      luf->piv_lim = bfd->piv_lim;
 177.215 +      luf->suhl = bfd->suhl;
 177.216 +      luf->eps_tol = bfd->eps_tol;
 177.217 +      luf->max_gro = bfd->max_gro;
 177.218 +      /* set control parameters specific to FHV */
 177.219 +      if (bfd->fhv != NULL)
 177.220 +      {  if (nov) bfd->fhv->hh_max = bfd->nfs_max;
 177.221 +         bfd->fhv->upd_tol = bfd->upd_tol;
 177.222 +      }
 177.223 +      /* set control parameters specific to LPF */
 177.224 +      if (bfd->lpf != NULL)
 177.225 +      {  if (nov) bfd->lpf->n_max = bfd->nrs_max;
 177.226 +         if (nov) bfd->lpf->v_size = bfd->rs_size;
 177.227 +      }
 177.228 +      /* try to factorize the basis matrix */
 177.229 +      if (bfd->fhv != NULL)
 177.230 +      {  switch (fhv_factorize(bfd->fhv, m, col, info))
 177.231 +         {  case 0:
 177.232 +               break;
 177.233 +            case FHV_ESING:
 177.234 +               ret = BFD_ESING;
 177.235 +               goto done;
 177.236 +            case FHV_ECOND:
 177.237 +               ret = BFD_ECOND;
 177.238 +               goto done;
 177.239 +            default:
 177.240 +               xassert(bfd != bfd);
 177.241 +         }
 177.242 +      }
 177.243 +      else if (bfd->lpf != NULL)
 177.244 +      {  switch (lpf_factorize(bfd->lpf, m, bh, col, info))
 177.245 +         {  case 0:
 177.246 +               /* set the Schur complement update type */
 177.247 +               switch (bfd->type)
 177.248 +               {  case GLP_BF_BG:
 177.249 +                     /* Bartels-Golub update */
 177.250 +                     bfd->lpf->scf->t_opt = SCF_TBG;
 177.251 +                     break;
 177.252 +                  case GLP_BF_GR:
 177.253 +                     /* Givens rotation update */
 177.254 +                     bfd->lpf->scf->t_opt = SCF_TGR;
 177.255 +                     break;
 177.256 +                  default:
 177.257 +                     xassert(bfd != bfd);
 177.258 +               }
 177.259 +               break;
 177.260 +            case LPF_ESING:
 177.261 +               ret = BFD_ESING;
 177.262 +               goto done;
 177.263 +            case LPF_ECOND:
 177.264 +               ret = BFD_ECOND;
 177.265 +               goto done;
 177.266 +            default:
 177.267 +               xassert(bfd != bfd);
 177.268 +         }
 177.269 +      }
 177.270 +      else
 177.271 +         xassert(bfd != bfd);
 177.272 +      /* the basis matrix has been successfully factorized */
 177.273 +      bfd->valid = 1;
 177.274 +      bfd->upd_cnt = 0;
 177.275 +      ret = 0;
 177.276 +done: /* return to the calling program */
 177.277 +      return ret;
 177.278 +}
 177.279 +
 177.280 +/***********************************************************************
 177.281 +*  NAME
 177.282 +*
 177.283 +*  bfd_ftran - perform forward transformation (solve system B*x = b)
 177.284 +*
 177.285 +*  SYNOPSIS
 177.286 +*
 177.287 +*  #include "glpbfd.h"
 177.288 +*  void bfd_ftran(BFD *bfd, double x[]);
 177.289 +*
 177.290 +*  DESCRIPTION
 177.291 +*
 177.292 +*  The routine bfd_ftran performs forward transformation, i.e. solves
 177.293 +*  the system B*x = b, where B is the basis matrix, x is the vector of
 177.294 +*  unknowns to be computed, b is the vector of right-hand sides.
 177.295 +*
 177.296 +*  On entry elements of the vector b should be stored in dense format
 177.297 +*  in locations x[1], ..., x[m], where m is the number of rows. On exit
 177.298 +*  the routine stores elements of the vector x in the same locations. */
 177.299 +
 177.300 +void bfd_ftran(BFD *bfd, double x[])
 177.301 +{     xassert(bfd != NULL);
 177.302 +      xassert(bfd->valid);
 177.303 +      if (bfd->fhv != NULL)
 177.304 +         fhv_ftran(bfd->fhv, x);
 177.305 +      else if (bfd->lpf != NULL)
 177.306 +         lpf_ftran(bfd->lpf, x);
 177.307 +      else
 177.308 +         xassert(bfd != bfd);
 177.309 +      return;
 177.310 +}
 177.311 +
 177.312 +/***********************************************************************
 177.313 +*  NAME
 177.314 +*
 177.315 +*  bfd_btran - perform backward transformation (solve system B'*x = b)
 177.316 +*
 177.317 +*  SYNOPSIS
 177.318 +*
 177.319 +*  #include "glpbfd.h"
 177.320 +*  void bfd_btran(BFD *bfd, double x[]);
 177.321 +*
 177.322 +*  DESCRIPTION
 177.323 +*
 177.324 +*  The routine bfd_btran performs backward transformation, i.e. solves
 177.325 +*  the system B'*x = b, where B' is a matrix transposed to the basis
 177.326 +*  matrix B, x is the vector of unknowns to be computed, b is the vector
 177.327 +*  of right-hand sides.
 177.328 +*
 177.329 +*  On entry elements of the vector b should be stored in dense format
 177.330 +*  in locations x[1], ..., x[m], where m is the number of rows. On exit
 177.331 +*  the routine stores elements of the vector x in the same locations. */
 177.332 +
 177.333 +void bfd_btran(BFD *bfd, double x[])
 177.334 +{     xassert(bfd != NULL);
 177.335 +      xassert(bfd->valid);
 177.336 +      if (bfd->fhv != NULL)
 177.337 +         fhv_btran(bfd->fhv, x);
 177.338 +      else if (bfd->lpf != NULL)
 177.339 +         lpf_btran(bfd->lpf, x);
 177.340 +      else
 177.341 +         xassert(bfd != bfd);
 177.342 +      return;
 177.343 +}
 177.344 +
 177.345 +/***********************************************************************
 177.346 +*  NAME
 177.347 +*
 177.348 +*  bfd_update_it - update LP basis factorization
 177.349 +*
 177.350 +*  SYNOPSIS
 177.351 +*
 177.352 +*  #include "glpbfd.h"
 177.353 +*  int bfd_update_it(BFD *bfd, int j, int bh, int len, const int ind[],
 177.354 +*     const double val[]);
 177.355 +*
 177.356 +*  DESCRIPTION
 177.357 +*
 177.358 +*  The routine bfd_update_it updates the factorization of the basis
 177.359 +*  matrix B after replacing its j-th column by a new vector.
 177.360 +*
 177.361 +*  The parameter j specifies the number of column of B, which has been
 177.362 +*  replaced, 1 <= j <= m, where m is the order of B.
 177.363 +*
 177.364 +*  The parameter bh specifies the basis header entry for the new column
 177.365 +*  of B, which is the number of the new column in some original matrix.
 177.366 +*  This parameter is optional and can be specified as 0.
 177.367 +*
 177.368 +*  Row indices and numerical values of non-zero elements of the new
 177.369 +*  column of B should be placed in locations ind[1], ..., ind[len] and
 177.370 +*  val[1], ..., val[len], resp., where len is the number of non-zeros
 177.371 +*  in the column. Neither zero nor duplicate elements are allowed.
 177.372 +*
 177.373 +*  RETURNS
 177.374 +*
 177.375 +*  0  The factorization has been successfully updated.
 177.376 +*
 177.377 +*  BFD_ESING
 177.378 +*     New basis matrix is singular within the working precision.
 177.379 +*
 177.380 +*  BFD_ECHECK
 177.381 +*     The factorization is inaccurate.
 177.382 +*
 177.383 +*  BFD_ELIMIT
 177.384 +*     Factorization update limit has been reached.
 177.385 +*
 177.386 +*  BFD_EROOM
 177.387 +*     Overflow of the sparse vector area.
 177.388 +*
 177.389 +*  In case of non-zero return code the factorization becomes invalid.
 177.390 +*  It should not be used until it has been recomputed with the routine
 177.391 +*  bfd_factorize. */
 177.392 +
 177.393 +int bfd_update_it(BFD *bfd, int j, int bh, int len, const int ind[],
 177.394 +      const double val[])
 177.395 +{     int ret;
 177.396 +      xassert(bfd != NULL);
 177.397 +      xassert(bfd->valid);
 177.398 +      /* try to update the factorization */
 177.399 +      if (bfd->fhv != NULL)
 177.400 +      {  switch (fhv_update_it(bfd->fhv, j, len, ind, val))
 177.401 +         {  case 0:
 177.402 +               break;
 177.403 +            case FHV_ESING:
 177.404 +               bfd->valid = 0;
 177.405 +               ret = BFD_ESING;
 177.406 +               goto done;
 177.407 +            case FHV_ECHECK:
 177.408 +               bfd->valid = 0;
 177.409 +               ret = BFD_ECHECK;
 177.410 +               goto done;
 177.411 +            case FHV_ELIMIT:
 177.412 +               bfd->valid = 0;
 177.413 +               ret = BFD_ELIMIT;
 177.414 +               goto done;
 177.415 +            case FHV_EROOM:
 177.416 +               bfd->valid = 0;
 177.417 +               ret = BFD_EROOM;
 177.418 +               goto done;
 177.419 +            default:
 177.420 +               xassert(bfd != bfd);
 177.421 +         }
 177.422 +      }
 177.423 +      else if (bfd->lpf != NULL)
 177.424 +      {  switch (lpf_update_it(bfd->lpf, j, bh, len, ind, val))
 177.425 +         {  case 0:
 177.426 +               break;
 177.427 +            case LPF_ESING:
 177.428 +               bfd->valid = 0;
 177.429 +               ret = BFD_ESING;
 177.430 +               goto done;
 177.431 +            case LPF_ELIMIT:
 177.432 +               bfd->valid = 0;
 177.433 +               ret = BFD_ELIMIT;
 177.434 +               goto done;
 177.435 +            default:
 177.436 +               xassert(bfd != bfd);
 177.437 +         }
 177.438 +      }
 177.439 +      else
 177.440 +         xassert(bfd != bfd);
 177.441 +      /* the factorization has been successfully updated */
 177.442 +      /* increase the update count */
 177.443 +      bfd->upd_cnt++;
 177.444 +      ret = 0;
 177.445 +done: /* return to the calling program */
 177.446 +      return ret;
 177.447 +}
 177.448 +
 177.449 +/**********************************************************************/
 177.450 +
 177.451 +int bfd_get_count(BFD *bfd)
 177.452 +{     /* determine factorization update count */
 177.453 +      xassert(bfd != NULL);
 177.454 +      xassert(bfd->valid);
 177.455 +      return bfd->upd_cnt;
 177.456 +}
 177.457 +
 177.458 +/***********************************************************************
 177.459 +*  NAME
 177.460 +*
 177.461 +*  bfd_delete_it - delete LP basis factorization
 177.462 +*
 177.463 +*  SYNOPSIS
 177.464 +*
 177.465 +*  #include "glpbfd.h"
 177.466 +*  void bfd_delete_it(BFD *bfd);
 177.467 +*
 177.468 +*  DESCRIPTION
 177.469 +*
 177.470 +*  The routine bfd_delete_it deletes LP basis factorization specified
 177.471 +*  by the parameter fhv and frees all memory allocated to this program
 177.472 +*  object. */
 177.473 +
 177.474 +void bfd_delete_it(BFD *bfd)
 177.475 +{     xassert(bfd != NULL);
 177.476 +      if (bfd->fhv != NULL)
 177.477 +         fhv_delete_it(bfd->fhv);
 177.478 +      if (bfd->lpf != NULL)
 177.479 +         lpf_delete_it(bfd->lpf);
 177.480 +      xfree(bfd);
 177.481 +      return;
 177.482 +}
 177.483 +
 177.484 +/* eof */
   178.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   178.2 +++ b/src/glpbfd.h	Mon Dec 06 13:09:21 2010 +0100
   178.3 @@ -0,0 +1,75 @@
   178.4 +/* glpbfd.h (LP basis factorization driver) */
   178.5 +
   178.6 +/***********************************************************************
   178.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   178.8 +*
   178.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  178.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  178.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  178.12 +*  E-mail: <mao@gnu.org>.
  178.13 +*
  178.14 +*  GLPK is free software: you can redistribute it and/or modify it
  178.15 +*  under the terms of the GNU General Public License as published by
  178.16 +*  the Free Software Foundation, either version 3 of the License, or
  178.17 +*  (at your option) any later version.
  178.18 +*
  178.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  178.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  178.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  178.22 +*  License for more details.
  178.23 +*
  178.24 +*  You should have received a copy of the GNU General Public License
  178.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  178.26 +***********************************************************************/
  178.27 +
  178.28 +#ifndef GLPBFD_H
  178.29 +#define GLPBFD_H
  178.30 +
  178.31 +#ifndef GLPBFD_PRIVATE
  178.32 +typedef struct { double _opaque_bfd[100]; } BFD;
  178.33 +#endif
  178.34 +
  178.35 +/* return codes: */
  178.36 +#define BFD_ESING    1  /* singular matrix */
  178.37 +#define BFD_ECOND    2  /* ill-conditioned matrix */
  178.38 +#define BFD_ECHECK   3  /* insufficient accuracy */
  178.39 +#define BFD_ELIMIT   4  /* update limit reached */
  178.40 +#define BFD_EROOM    5  /* SVA overflow */
  178.41 +
  178.42 +#define bfd_create_it _glp_bfd_create_it
  178.43 +BFD *bfd_create_it(void);
  178.44 +/* create LP basis factorization */
  178.45 +
  178.46 +#define bfd_set_parm _glp_bfd_set_parm
  178.47 +void bfd_set_parm(BFD *bfd, const void *parm);
  178.48 +/* change LP basis factorization control parameters */
  178.49 +
  178.50 +#define bfd_factorize _glp_bfd_factorize
  178.51 +int bfd_factorize(BFD *bfd, int m, const int bh[], int (*col)
  178.52 +      (void *info, int j, int ind[], double val[]), void *info);
  178.53 +/* compute LP basis factorization */
  178.54 +
  178.55 +#define bfd_ftran _glp_bfd_ftran
  178.56 +void bfd_ftran(BFD *bfd, double x[]);
  178.57 +/* perform forward transformation (solve system B*x = b) */
  178.58 +
  178.59 +#define bfd_btran _glp_bfd_btran
  178.60 +void bfd_btran(BFD *bfd, double x[]);
  178.61 +/* perform backward transformation (solve system B'*x = b) */
  178.62 +
  178.63 +#define bfd_update_it _glp_bfd_update_it
  178.64 +int bfd_update_it(BFD *bfd, int j, int bh, int len, const int ind[],
  178.65 +      const double val[]);
  178.66 +/* update LP basis factorization */
  178.67 +
  178.68 +#define bfd_get_count _glp_bfd_get_count
  178.69 +int bfd_get_count(BFD *bfd);
  178.70 +/* determine factorization update count */
  178.71 +
  178.72 +#define bfd_delete_it _glp_bfd_delete_it
  178.73 +void bfd_delete_it(BFD *bfd);
  178.74 +/* delete LP basis factorization */
  178.75 +
  178.76 +#endif
  178.77 +
  178.78 +/* eof */
   179.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   179.2 +++ b/src/glpbfx.c	Mon Dec 06 13:09:21 2010 +0100
   179.3 @@ -0,0 +1,91 @@
   179.4 +/* glpbfx.c */
   179.5 +
   179.6 +/***********************************************************************
   179.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   179.8 +*
   179.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  179.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  179.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  179.12 +*  E-mail: <mao@gnu.org>.
  179.13 +*
  179.14 +*  GLPK is free software: you can redistribute it and/or modify it
  179.15 +*  under the terms of the GNU General Public License as published by
  179.16 +*  the Free Software Foundation, either version 3 of the License, or
  179.17 +*  (at your option) any later version.
  179.18 +*
  179.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  179.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  179.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  179.22 +*  License for more details.
  179.23 +*
  179.24 +*  You should have received a copy of the GNU General Public License
  179.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  179.26 +***********************************************************************/
  179.27 +
  179.28 +typedef struct BFX BFX;
  179.29 +#define GLPBFX_DEFINED
  179.30 +#include "glpbfx.h"
  179.31 +#include "glpenv.h"
  179.32 +#include "glplux.h"
  179.33 +
  179.34 +struct BFX
  179.35 +{     int valid;
  179.36 +      LUX *lux;
  179.37 +};
  179.38 +
  179.39 +BFX *bfx_create_binv(void)
  179.40 +{     /* create factorization of the basis matrix */
  179.41 +      BFX *bfx;
  179.42 +      bfx = xmalloc(sizeof(BFX));
  179.43 +      bfx->valid = 0;
  179.44 +      bfx->lux = NULL;
  179.45 +      return bfx;
  179.46 +}
  179.47 +
  179.48 +int bfx_factorize(BFX *binv, int m, int (*col)(void *info, int j,
  179.49 +      int ind[], mpq_t val[]), void *info)
  179.50 +{     /* compute factorization of the basis matrix */
  179.51 +      int ret;
  179.52 +      xassert(m > 0);
  179.53 +      if (binv->lux != NULL && binv->lux->n != m)
  179.54 +      {  lux_delete(binv->lux);
  179.55 +         binv->lux = NULL;
  179.56 +      }
  179.57 +      if (binv->lux == NULL)
  179.58 +         binv->lux = lux_create(m);
  179.59 +      ret = lux_decomp(binv->lux, col, info);
  179.60 +      binv->valid = (ret == 0);
  179.61 +      return ret;
  179.62 +}
  179.63 +
  179.64 +void bfx_ftran(BFX *binv, mpq_t x[], int save)
  179.65 +{     /* perform forward transformation (FTRAN) */
  179.66 +      xassert(binv->valid);
  179.67 +      lux_solve(binv->lux, 0, x);
  179.68 +      xassert(save == save);
  179.69 +      return;
  179.70 +}
  179.71 +
  179.72 +void bfx_btran(BFX *binv, mpq_t x[])
  179.73 +{     /* perform backward transformation (BTRAN) */
  179.74 +      xassert(binv->valid);
  179.75 +      lux_solve(binv->lux, 1, x);
  179.76 +      return;
  179.77 +}
  179.78 +
  179.79 +int bfx_update(BFX *binv, int j)
  179.80 +{     /* update factorization of the basis matrix */
  179.81 +      xassert(binv->valid);
  179.82 +      xassert(1 <= j && j <= binv->lux->n);
  179.83 +      return 1;
  179.84 +}
  179.85 +
  179.86 +void bfx_delete_binv(BFX *binv)
  179.87 +{     /* delete factorization of the basis matrix */
  179.88 +      if (binv->lux != NULL)
  179.89 +         lux_delete(binv->lux);
  179.90 +      xfree(binv);
  179.91 +      return;
  179.92 +}
  179.93 +
  179.94 +/* eof */
   180.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   180.2 +++ b/src/glpbfx.h	Mon Dec 06 13:09:21 2010 +0100
   180.3 @@ -0,0 +1,71 @@
   180.4 +/* glpbfx.h (basis factorization interface, bignum arithmetic) */
   180.5 +
   180.6 +/***********************************************************************
   180.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   180.8 +*
   180.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  180.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  180.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  180.12 +*  E-mail: <mao@gnu.org>.
  180.13 +*
  180.14 +*  GLPK is free software: you can redistribute it and/or modify it
  180.15 +*  under the terms of the GNU General Public License as published by
  180.16 +*  the Free Software Foundation, either version 3 of the License, or
  180.17 +*  (at your option) any later version.
  180.18 +*
  180.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  180.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  180.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  180.22 +*  License for more details.
  180.23 +*
  180.24 +*  You should have received a copy of the GNU General Public License
  180.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  180.26 +***********************************************************************/
  180.27 +
  180.28 +#ifndef GLPBFX_H
  180.29 +#define GLPBFX_H
  180.30 +
  180.31 +#include "glpgmp.h"
  180.32 +
  180.33 +#ifndef GLPBFX_DEFINED
  180.34 +#define GLPBFX_DEFINED
  180.35 +typedef struct { double _opaque_bfx; } BFX;
  180.36 +#endif
  180.37 +
  180.38 +#define bfx_create_binv       _glp_bfx_create_binv
  180.39 +#define bfx_is_valid          _glp_bfx_is_valid
  180.40 +#define bfx_invalidate        _glp_bfx_invalidate
  180.41 +#define bfx_factorize         _glp_bfx_factorize
  180.42 +#define bfx_ftran             _glp_bfx_ftran
  180.43 +#define bfx_btran             _glp_bfx_btran
  180.44 +#define bfx_update            _glp_bfx_update
  180.45 +#define bfx_delete_binv       _glp_bfx_delete_binv
  180.46 +
  180.47 +BFX *bfx_create_binv(void);
  180.48 +/* create factorization of the basis matrix */
  180.49 +
  180.50 +int bfx_is_valid(BFX *binv);
  180.51 +/* check if factorization is valid */
  180.52 +
  180.53 +void bfx_invalidate(BFX *binv);
  180.54 +/* invalidate factorization of the basis matrix */
  180.55 +
  180.56 +int bfx_factorize(BFX *binv, int m, int (*col)(void *info, int j,
  180.57 +      int ind[], mpq_t val[]), void *info);
  180.58 +/* compute factorization of the basis matrix */
  180.59 +
  180.60 +void bfx_ftran(BFX *binv, mpq_t x[], int save);
  180.61 +/* perform forward transformation (FTRAN) */
  180.62 +
  180.63 +void bfx_btran(BFX *binv, mpq_t x[]);
  180.64 +/* perform backward transformation (BTRAN) */
  180.65 +
  180.66 +int bfx_update(BFX *binv, int j);
  180.67 +/* update factorization of the basis matrix */
  180.68 +
  180.69 +void bfx_delete_binv(BFX *binv);
  180.70 +/* delete factorization of the basis matrix */
  180.71 +
  180.72 +#endif
  180.73 +
  180.74 +/* eof */
   181.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   181.2 +++ b/src/glpcpx.c	Mon Dec 06 13:09:21 2010 +0100
   181.3 @@ -0,0 +1,1239 @@
   181.4 +/* glpcpx.c (CPLEX LP format routines) */
   181.5 +
   181.6 +/***********************************************************************
   181.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   181.8 +*
   181.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  181.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  181.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  181.12 +*  E-mail: <mao@gnu.org>.
  181.13 +*
  181.14 +*  GLPK is free software: you can redistribute it and/or modify it
  181.15 +*  under the terms of the GNU General Public License as published by
  181.16 +*  the Free Software Foundation, either version 3 of the License, or
  181.17 +*  (at your option) any later version.
  181.18 +*
  181.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  181.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  181.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  181.22 +*  License for more details.
  181.23 +*
  181.24 +*  You should have received a copy of the GNU General Public License
  181.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  181.26 +***********************************************************************/
  181.27 +
  181.28 +#include "glpapi.h"
  181.29 +
  181.30 +/***********************************************************************
  181.31 +*  NAME
  181.32 +*
  181.33 +*  glp_init_cpxcp - initialize CPLEX LP format control parameters
  181.34 +*
  181.35 +*  SYNOPSIS
  181.36 +*
  181.37 +*  void glp_init_cpxcp(glp_cpxcp *parm):
  181.38 +*
  181.39 +*  The routine glp_init_cpxcp initializes control parameters used by
  181.40 +*  the CPLEX LP input/output routines glp_read_lp and glp_write_lp with
  181.41 +*  default values.
  181.42 +*
  181.43 +*  Default values of the control parameters are stored in the glp_cpxcp
  181.44 +*  structure, which the parameter parm points to. */
  181.45 +
  181.46 +void glp_init_cpxcp(glp_cpxcp *parm)
  181.47 +{     xassert(parm != NULL);
  181.48 +      return;
  181.49 +}
  181.50 +
  181.51 +static void check_parm(const char *func, const glp_cpxcp *parm)
  181.52 +{     /* check control parameters */
  181.53 +      xassert(func != NULL);
  181.54 +      xassert(parm != NULL);
  181.55 +      return;
  181.56 +}
  181.57 +
  181.58 +/***********************************************************************
  181.59 +*  NAME
  181.60 +*
  181.61 +*  glp_read_lp - read problem data in CPLEX LP format
  181.62 +*
  181.63 +*  SYNOPSIS
  181.64 +*
  181.65 +*  int glp_read_lp(glp_prob *P, const glp_cpxcp *parm, const char
  181.66 +*     *fname);
  181.67 +*
  181.68 +*  DESCRIPTION
  181.69 +*
  181.70 +*  The routine glp_read_lp reads problem data in CPLEX LP format from
  181.71 +*  a text file.
  181.72 +*
  181.73 +*  The parameter parm is a pointer to the structure glp_cpxcp, which
  181.74 +*  specifies control parameters used by the routine. If parm is NULL,
  181.75 +*  the routine uses default settings.
  181.76 +*
  181.77 +*  The character string fname specifies a name of the text file to be
  181.78 +*  read.
  181.79 +*
  181.80 +*  Note that before reading data the current content of the problem
  181.81 +*  object is completely erased with the routine glp_erase_prob.
  181.82 +*
  181.83 +*  RETURNS
  181.84 +*
  181.85 +*  If the operation was successful, the routine glp_read_lp returns
  181.86 +*  zero. Otherwise, it prints an error message and returns non-zero. */
  181.87 +
  181.88 +struct csa
  181.89 +{     /* common storage area */
  181.90 +      glp_prob *P;
  181.91 +      /* LP/MIP problem object */
  181.92 +      const glp_cpxcp *parm;
  181.93 +      /* pointer to control parameters */
  181.94 +      const char *fname;
  181.95 +      /* name of input CPLEX LP file */
  181.96 +      XFILE *fp;
  181.97 +      /* stream assigned to input CPLEX LP file */
  181.98 +      jmp_buf jump;
  181.99 +      /* label for go to in case of error */
 181.100 +      int count;
 181.101 +      /* line count */
 181.102 +      int c;
 181.103 +      /* current character or XEOF */
 181.104 +      int token;
 181.105 +      /* current token: */
 181.106 +#define T_EOF        0x00  /* end of file */
 181.107 +#define T_MINIMIZE   0x01  /* keyword 'minimize' */
 181.108 +#define T_MAXIMIZE   0x02  /* keyword 'maximize' */
 181.109 +#define T_SUBJECT_TO 0x03  /* keyword 'subject to' */
 181.110 +#define T_BOUNDS     0x04  /* keyword 'bounds' */
 181.111 +#define T_GENERAL    0x05  /* keyword 'general' */
 181.112 +#define T_INTEGER    0x06  /* keyword 'integer' */
 181.113 +#define T_BINARY     0x07  /* keyword 'binary' */
 181.114 +#define T_END        0x08  /* keyword 'end' */
 181.115 +#define T_NAME       0x09  /* symbolic name */
 181.116 +#define T_NUMBER     0x0A  /* numeric constant */
 181.117 +#define T_PLUS       0x0B  /* delimiter '+' */
 181.118 +#define T_MINUS      0x0C  /* delimiter '-' */
 181.119 +#define T_COLON      0x0D  /* delimiter ':' */
 181.120 +#define T_LE         0x0E  /* delimiter '<=' */
 181.121 +#define T_GE         0x0F  /* delimiter '>=' */
 181.122 +#define T_EQ         0x10  /* delimiter '=' */
 181.123 +      char image[255+1];
 181.124 +      /* image of current token */
 181.125 +      int imlen;
 181.126 +      /* length of token image */
 181.127 +      double value;
 181.128 +      /* value of numeric constant */
 181.129 +      int n_max;
 181.130 +      /* length of the following five arrays (enlarged automatically,
 181.131 +         if necessary) */
 181.132 +      int *ind; /* int ind[1+n_max]; */
 181.133 +      double *val; /* double val[1+n_max]; */
 181.134 +      char *flag; /* char flag[1+n_max]; */
 181.135 +      /* working arrays used to construct linear forms */
 181.136 +      double *lb; /* double lb[1+n_max]; */
 181.137 +      double *ub; /* double ub[1+n_max]; */
 181.138 +      /* lower and upper bounds of variables (columns) */
 181.139 +};
 181.140 +
 181.141 +#define CHAR_SET "!\"#$%&()/,.;?@_`'{}|~"
 181.142 +/* characters, which may appear in symbolic names */
 181.143 +
 181.144 +static void error(struct csa *csa, const char *fmt, ...)
 181.145 +{     /* print error message and terminate processing */
 181.146 +      va_list arg;
 181.147 +      xprintf("%s:%d: ", csa->fname, csa->count);
 181.148 +      va_start(arg, fmt);
 181.149 +      xvprintf(fmt, arg);
 181.150 +      va_end(arg);
 181.151 +      longjmp(csa->jump, 1);
 181.152 +      /* no return */
 181.153 +}
 181.154 +
 181.155 +static void warning(struct csa *csa, const char *fmt, ...)
 181.156 +{     /* print warning message and continue processing */
 181.157 +      va_list arg;
 181.158 +      xprintf("%s:%d: warning: ", csa->fname, csa->count);
 181.159 +      va_start(arg, fmt);
 181.160 +      xvprintf(fmt, arg);
 181.161 +      va_end(arg);
 181.162 +      return;
 181.163 +}
 181.164 +
 181.165 +static void read_char(struct csa *csa)
 181.166 +{     /* read next character from input file */
 181.167 +      int c;
 181.168 +      xassert(csa->c != XEOF);
 181.169 +      if (csa->c == '\n') csa->count++;
 181.170 +      c = xfgetc(csa->fp);
 181.171 +      if (c < 0)
 181.172 +      {  if (xferror(csa->fp))
 181.173 +            error(csa, "read error - %s\n", xerrmsg());
 181.174 +         else if (csa->c == '\n')
 181.175 +         {  csa->count--;
 181.176 +            c = XEOF;
 181.177 +         }
 181.178 +         else
 181.179 +         {  warning(csa, "missing final end of line\n");
 181.180 +            c = '\n';
 181.181 +         }
 181.182 +      }
 181.183 +      else if (c == '\n')
 181.184 +         ;
 181.185 +      else if (isspace(c))
 181.186 +         c = ' ';
 181.187 +      else if (iscntrl(c))
 181.188 +         error(csa, "invalid control character 0x%02X\n", c);
 181.189 +      csa->c = c;
 181.190 +      return;
 181.191 +}
 181.192 +
 181.193 +static void add_char(struct csa *csa)
 181.194 +{     /* append current character to current token */
 181.195 +      if (csa->imlen == sizeof(csa->image)-1)
 181.196 +         error(csa, "token `%.15s...' too long\n", csa->image);
 181.197 +      csa->image[csa->imlen++] = (char)csa->c;
 181.198 +      csa->image[csa->imlen] = '\0';
 181.199 +      read_char(csa);
 181.200 +      return;
 181.201 +}
 181.202 +
 181.203 +static int the_same(char *s1, char *s2)
 181.204 +{     /* compare two character strings ignoring case sensitivity */
 181.205 +      for (; *s1 != '\0'; s1++, s2++)
 181.206 +      {  if (tolower((unsigned char)*s1) != tolower((unsigned char)*s2))
 181.207 +            return 0;
 181.208 +      }
 181.209 +      return 1;
 181.210 +}
 181.211 +
 181.212 +static void scan_token(struct csa *csa)
 181.213 +{     /* scan next token */
 181.214 +      int flag;
 181.215 +      csa->token = -1;
 181.216 +      csa->image[0] = '\0';
 181.217 +      csa->imlen = 0;
 181.218 +      csa->value = 0.0;
 181.219 +loop: flag = 0;
 181.220 +      /* skip non-significant characters */
 181.221 +      while (csa->c == ' ') read_char(csa);
 181.222 +      /* recognize and scan current token */
 181.223 +      if (csa->c == XEOF)
 181.224 +         csa->token = T_EOF;
 181.225 +      else if (csa->c == '\n')
 181.226 +      {  read_char(csa);
 181.227 +         /* if the next character is letter, it may begin a keyword */
 181.228 +         if (isalpha(csa->c))
 181.229 +         {  flag = 1;
 181.230 +            goto name;
 181.231 +         }
 181.232 +         goto loop;
 181.233 +      }
 181.234 +      else if (csa->c == '\\')
 181.235 +      {  /* comment; ignore everything until end-of-line */
 181.236 +         while (csa->c != '\n') read_char(csa);
 181.237 +         goto loop;
 181.238 +      }
 181.239 +      else if (isalpha(csa->c) || csa->c != '.' && strchr(CHAR_SET,
 181.240 +         csa->c) != NULL)
 181.241 +name: {  /* symbolic name */
 181.242 +         csa->token = T_NAME;
 181.243 +         while (isalnum(csa->c) || strchr(CHAR_SET, csa->c) != NULL)
 181.244 +            add_char(csa);
 181.245 +         if (flag)
 181.246 +         {  /* check for keyword */
 181.247 +            if (the_same(csa->image, "minimize"))
 181.248 +               csa->token = T_MINIMIZE;
 181.249 +            else if (the_same(csa->image, "minimum"))
 181.250 +               csa->token = T_MINIMIZE;
 181.251 +            else if (the_same(csa->image, "min"))
 181.252 +               csa->token = T_MINIMIZE;
 181.253 +            else if (the_same(csa->image, "maximize"))
 181.254 +               csa->token = T_MAXIMIZE;
 181.255 +            else if (the_same(csa->image, "maximum"))
 181.256 +               csa->token = T_MAXIMIZE;
 181.257 +            else if (the_same(csa->image, "max"))
 181.258 +               csa->token = T_MAXIMIZE;
 181.259 +            else if (the_same(csa->image, "subject"))
 181.260 +            {  if (csa->c == ' ')
 181.261 +               {  read_char(csa);
 181.262 +                  if (tolower(csa->c) == 't')
 181.263 +                  {  csa->token = T_SUBJECT_TO;
 181.264 +                     csa->image[csa->imlen++] = ' ';
 181.265 +                     csa->image[csa->imlen] = '\0';
 181.266 +                     add_char(csa);
 181.267 +                     if (tolower(csa->c) != 'o')
 181.268 +                        error(csa, "keyword `subject to' incomplete\n");
 181.269 +                     add_char(csa);
 181.270 +                     if (isalpha(csa->c))
 181.271 +                        error(csa, "keyword `%s%c...' not recognized\n",
 181.272 +                           csa->image, csa->c);
 181.273 +                  }
 181.274 +               }
 181.275 +            }
 181.276 +            else if (the_same(csa->image, "such"))
 181.277 +            {  if (csa->c == ' ')
 181.278 +               {  read_char(csa);
 181.279 +                  if (tolower(csa->c) == 't')
 181.280 +                  {  csa->token = T_SUBJECT_TO;
 181.281 +                     csa->image[csa->imlen++] = ' ';
 181.282 +                     csa->image[csa->imlen] = '\0';
 181.283 +                     add_char(csa);
 181.284 +                     if (tolower(csa->c) != 'h')
 181.285 +err:                    error(csa, "keyword `such that' incomplete\n");
 181.286 +                     add_char(csa);
 181.287 +                     if (tolower(csa->c) != 'a') goto err;
 181.288 +                     add_char(csa);
 181.289 +                     if (tolower(csa->c) != 't') goto err;
 181.290 +                     add_char(csa);
 181.291 +                     if (isalpha(csa->c))
 181.292 +                        error(csa, "keyword `%s%c...' not recognized\n",
 181.293 +                           csa->image, csa->c);
 181.294 +                  }
 181.295 +               }
 181.296 +            }
 181.297 +            else if (the_same(csa->image, "st"))
 181.298 +               csa->token = T_SUBJECT_TO;
 181.299 +            else if (the_same(csa->image, "s.t."))
 181.300 +               csa->token = T_SUBJECT_TO;
 181.301 +            else if (the_same(csa->image, "st."))
 181.302 +               csa->token = T_SUBJECT_TO;
 181.303 +            else if (the_same(csa->image, "bounds"))
 181.304 +               csa->token = T_BOUNDS;
 181.305 +            else if (the_same(csa->image, "bound"))
 181.306 +               csa->token = T_BOUNDS;
 181.307 +            else if (the_same(csa->image, "general"))
 181.308 +               csa->token = T_GENERAL;
 181.309 +            else if (the_same(csa->image, "generals"))
 181.310 +               csa->token = T_GENERAL;
 181.311 +            else if (the_same(csa->image, "gen"))
 181.312 +               csa->token = T_GENERAL;
 181.313 +            else if (the_same(csa->image, "integer"))
 181.314 +               csa->token = T_INTEGER;
 181.315 +            else if (the_same(csa->image, "integers"))
 181.316 +               csa->token = T_INTEGER;
 181.317 +            else if (the_same(csa->image, "int"))
 181.318 +              csa->token = T_INTEGER;
 181.319 +            else if (the_same(csa->image, "binary"))
 181.320 +               csa->token = T_BINARY;
 181.321 +            else if (the_same(csa->image, "binaries"))
 181.322 +               csa->token = T_BINARY;
 181.323 +            else if (the_same(csa->image, "bin"))
 181.324 +               csa->token = T_BINARY;
 181.325 +            else if (the_same(csa->image, "end"))
 181.326 +               csa->token = T_END;
 181.327 +         }
 181.328 +      }
 181.329 +      else if (isdigit(csa->c) || csa->c == '.')
 181.330 +      {  /* numeric constant */
 181.331 +         csa->token = T_NUMBER;
 181.332 +         /* scan integer part */
 181.333 +         while (isdigit(csa->c)) add_char(csa);
 181.334 +         /* scan optional fractional part (it is mandatory, if there is
 181.335 +            no integer part) */
 181.336 +         if (csa->c == '.')
 181.337 +         {  add_char(csa);
 181.338 +            if (csa->imlen == 1 && !isdigit(csa->c))
 181.339 +               error(csa, "invalid use of decimal point\n");
 181.340 +            while (isdigit(csa->c)) add_char(csa);
 181.341 +         }
 181.342 +         /* scan optional decimal exponent */
 181.343 +         if (csa->c == 'e' || csa->c == 'E')
 181.344 +         {  add_char(csa);
 181.345 +            if (csa->c == '+' || csa->c == '-') add_char(csa);
 181.346 +            if (!isdigit(csa->c))
 181.347 +               error(csa, "numeric constant `%s' incomplete\n",
 181.348 +                  csa->image);
 181.349 +            while (isdigit(csa->c)) add_char(csa);
 181.350 +         }
 181.351 +         /* convert the numeric constant to floating-point */
 181.352 +         if (str2num(csa->image, &csa->value))
 181.353 +            error(csa, "numeric constant `%s' out of range\n",
 181.354 +               csa->image);
 181.355 +      }
 181.356 +      else if (csa->c == '+')
 181.357 +         csa->token = T_PLUS, add_char(csa);
 181.358 +      else if (csa->c == '-')
 181.359 +         csa->token = T_MINUS, add_char(csa);
 181.360 +      else if (csa->c == ':')
 181.361 +         csa->token = T_COLON, add_char(csa);
 181.362 +      else if (csa->c == '<')
 181.363 +      {  csa->token = T_LE, add_char(csa);
 181.364 +         if (csa->c == '=') add_char(csa);
 181.365 +      }
 181.366 +      else if (csa->c == '>')
 181.367 +      {  csa->token = T_GE, add_char(csa);
 181.368 +         if (csa->c == '=') add_char(csa);
 181.369 +      }
 181.370 +      else if (csa->c == '=')
 181.371 +      {  csa->token = T_EQ, add_char(csa);
 181.372 +         if (csa->c == '<')
 181.373 +            csa->token = T_LE, add_char(csa);
 181.374 +         else if (csa->c == '>')
 181.375 +            csa->token = T_GE, add_char(csa);
 181.376 +      }
 181.377 +      else
 181.378 +         error(csa, "character `%c' not recognized\n", csa->c);
 181.379 +      /* skip non-significant characters */
 181.380 +      while (csa->c == ' ') read_char(csa);
 181.381 +      return;
 181.382 +}
 181.383 +
 181.384 +static int find_col(struct csa *csa, char *name)
 181.385 +{     /* find column by its symbolic name */
 181.386 +      int j;
 181.387 +      j = glp_find_col(csa->P, name);
 181.388 +      if (j == 0)
 181.389 +      {  /* not found; create new column */
 181.390 +         j = glp_add_cols(csa->P, 1);
 181.391 +         glp_set_col_name(csa->P, j, name);
 181.392 +         /* enlarge working arrays, if necessary */
 181.393 +         if (csa->n_max < j)
 181.394 +         {  int n_max = csa->n_max;
 181.395 +            int *ind = csa->ind;
 181.396 +            double *val = csa->val;
 181.397 +            char *flag = csa->flag;
 181.398 +            double *lb = csa->lb;
 181.399 +            double *ub = csa->ub;
 181.400 +            csa->n_max += csa->n_max;
 181.401 +            csa->ind = xcalloc(1+csa->n_max, sizeof(int));
 181.402 +            memcpy(&csa->ind[1], &ind[1], n_max * sizeof(int));
 181.403 +            xfree(ind);
 181.404 +            csa->val = xcalloc(1+csa->n_max, sizeof(double));
 181.405 +            memcpy(&csa->val[1], &val[1], n_max * sizeof(double));
 181.406 +            xfree(val);
 181.407 +            csa->flag = xcalloc(1+csa->n_max, sizeof(char));
 181.408 +            memset(&csa->flag[1], 0, csa->n_max * sizeof(char));
 181.409 +            memcpy(&csa->flag[1], &flag[1], n_max * sizeof(char));
 181.410 +            xfree(flag);
 181.411 +            csa->lb = xcalloc(1+csa->n_max, sizeof(double));
 181.412 +            memcpy(&csa->lb[1], &lb[1], n_max * sizeof(double));
 181.413 +            xfree(lb);
 181.414 +            csa->ub = xcalloc(1+csa->n_max, sizeof(double));
 181.415 +            memcpy(&csa->ub[1], &ub[1], n_max * sizeof(double));
 181.416 +            xfree(ub);
 181.417 +         }
 181.418 +         csa->lb[j] = +DBL_MAX, csa->ub[j] = -DBL_MAX;
 181.419 +      }
 181.420 +      return j;
 181.421 +}
 181.422 +
 181.423 +/***********************************************************************
 181.424 +*  parse_linear_form - parse linear form
 181.425 +*
 181.426 +*  This routine parses the linear form using the following syntax:
 181.427 +*
 181.428 +*  <variable> ::= <symbolic name>
 181.429 +*  <coefficient> ::= <numeric constant>
 181.430 +*  <term> ::= <variable> | <numeric constant> <variable>
 181.431 +*  <linear form> ::= <term> | + <term> | - <term> |
 181.432 +*     <linear form> + <term> | <linear form> - <term>
 181.433 +*
 181.434 +*  The routine returns the number of terms in the linear form. */
 181.435 +
 181.436 +static int parse_linear_form(struct csa *csa)
 181.437 +{     int j, k, len = 0, newlen;
 181.438 +      double s, coef;
 181.439 +loop: /* parse an optional sign */
 181.440 +      if (csa->token == T_PLUS)
 181.441 +         s = +1.0, scan_token(csa);
 181.442 +      else if (csa->token == T_MINUS)
 181.443 +         s = -1.0, scan_token(csa);
 181.444 +      else
 181.445 +         s = +1.0;
 181.446 +      /* parse an optional coefficient */
 181.447 +      if (csa->token == T_NUMBER)
 181.448 +         coef = csa->value, scan_token(csa);
 181.449 +      else
 181.450 +         coef = 1.0;
 181.451 +      /* parse a variable name */
 181.452 +      if (csa->token != T_NAME)
 181.453 +         error(csa, "missing variable name\n");
 181.454 +      /* find the corresponding column */
 181.455 +      j = find_col(csa, csa->image);
 181.456 +      /* check if the variable is already used in the linear form */
 181.457 +      if (csa->flag[j])
 181.458 +         error(csa, "multiple use of variable `%s' not allowed\n",
 181.459 +            csa->image);
 181.460 +      /* add new term to the linear form */
 181.461 +      len++, csa->ind[len] = j, csa->val[len] = s * coef;
 181.462 +      /* and mark that the variable is used in the linear form */
 181.463 +      csa->flag[j] = 1;
 181.464 +      scan_token(csa);
 181.465 +      /* if the next token is a sign, there is another term */
 181.466 +      if (csa->token == T_PLUS || csa->token == T_MINUS) goto loop;
 181.467 +      /* clear marks of the variables used in the linear form */
 181.468 +      for (k = 1; k <= len; k++) csa->flag[csa->ind[k]] = 0;
 181.469 +      /* remove zero coefficients */
 181.470 +      newlen = 0;
 181.471 +      for (k = 1; k <= len; k++)
 181.472 +      {  if (csa->val[k] != 0.0)
 181.473 +         {  newlen++;
 181.474 +            csa->ind[newlen] = csa->ind[k];
 181.475 +            csa->val[newlen] = csa->val[k];
 181.476 +         }
 181.477 +      }
 181.478 +      return newlen;
 181.479 +}
 181.480 +
 181.481 +/***********************************************************************
 181.482 +*  parse_objective - parse objective function
 181.483 +*
 181.484 +*  This routine parses definition of the objective function using the
 181.485 +*  following syntax:
 181.486 +*
 181.487 +*  <obj sense> ::= minimize | minimum | min | maximize | maximum | max
 181.488 +*  <obj name> ::= <empty> | <symbolic name> :
 181.489 +*  <obj function> ::= <obj sense> <obj name> <linear form> */
 181.490 +
 181.491 +static void parse_objective(struct csa *csa)
 181.492 +{     /* parse objective sense */
 181.493 +      int k, len;
 181.494 +      /* parse the keyword 'minimize' or 'maximize' */
 181.495 +      if (csa->token == T_MINIMIZE)
 181.496 +         glp_set_obj_dir(csa->P, GLP_MIN);
 181.497 +      else if (csa->token == T_MAXIMIZE)
 181.498 +         glp_set_obj_dir(csa->P, GLP_MAX);
 181.499 +      else
 181.500 +         xassert(csa != csa);
 181.501 +      scan_token(csa);
 181.502 +      /* parse objective name */
 181.503 +      if (csa->token == T_NAME && csa->c == ':')
 181.504 +      {  /* objective name is followed by a colon */
 181.505 +         glp_set_obj_name(csa->P, csa->image);
 181.506 +         scan_token(csa);
 181.507 +         xassert(csa->token == T_COLON);
 181.508 +         scan_token(csa);
 181.509 +      }
 181.510 +      else
 181.511 +      {  /* objective name is not specified; use default */
 181.512 +         glp_set_obj_name(csa->P, "obj");
 181.513 +      }
 181.514 +      /* parse linear form */
 181.515 +      len = parse_linear_form(csa);
 181.516 +      for (k = 1; k <= len; k++)
 181.517 +         glp_set_obj_coef(csa->P, csa->ind[k], csa->val[k]);
 181.518 +      return;
 181.519 +}
 181.520 +
 181.521 +/***********************************************************************
 181.522 +*  parse_constraints - parse constraints section
 181.523 +*
 181.524 +*  This routine parses the constraints section using the following
 181.525 +*  syntax:
 181.526 +*
 181.527 +*  <row name> ::= <empty> | <symbolic name> :
 181.528 +*  <row sense> ::= < | <= | =< | > | >= | => | =
 181.529 +*  <right-hand side> ::= <numeric constant> | + <numeric constant> |
 181.530 +*     - <numeric constant>
 181.531 +*  <constraint> ::= <row name> <linear form> <row sense>
 181.532 +*     <right-hand side>
 181.533 +*  <subject to> ::= subject to | such that | st | s.t. | st.
 181.534 +*  <constraints section> ::= <subject to> <constraint> |
 181.535 +*     <constraints section> <constraint> */
 181.536 +
 181.537 +static void parse_constraints(struct csa *csa)
 181.538 +{     int i, len, type;
 181.539 +      double s;
 181.540 +      /* parse the keyword 'subject to' */
 181.541 +      xassert(csa->token == T_SUBJECT_TO);
 181.542 +      scan_token(csa);
 181.543 +loop: /* create new row (constraint) */
 181.544 +      i = glp_add_rows(csa->P, 1);
 181.545 +      /* parse row name */
 181.546 +      if (csa->token == T_NAME && csa->c == ':')
 181.547 +      {  /* row name is followed by a colon */
 181.548 +         if (glp_find_row(csa->P, csa->image) != 0)
 181.549 +            error(csa, "constraint `%s' multiply defined\n",
 181.550 +               csa->image);
 181.551 +         glp_set_row_name(csa->P, i, csa->image);
 181.552 +         scan_token(csa);
 181.553 +         xassert(csa->token == T_COLON);
 181.554 +         scan_token(csa);
 181.555 +      }
 181.556 +      else
 181.557 +      {  /* row name is not specified; use default */
 181.558 +         char name[50];
 181.559 +         sprintf(name, "r.%d", csa->count);
 181.560 +         glp_set_row_name(csa->P, i, name);
 181.561 +      }
 181.562 +      /* parse linear form */
 181.563 +      len = parse_linear_form(csa);
 181.564 +      glp_set_mat_row(csa->P, i, len, csa->ind, csa->val);
 181.565 +      /* parse constraint sense */
 181.566 +      if (csa->token == T_LE)
 181.567 +         type = GLP_UP, scan_token(csa);
 181.568 +      else if (csa->token == T_GE)
 181.569 +         type = GLP_LO, scan_token(csa);
 181.570 +      else if (csa->token == T_EQ)
 181.571 +         type = GLP_FX, scan_token(csa);
 181.572 +      else
 181.573 +         error(csa, "missing constraint sense\n");
 181.574 +      /* parse right-hand side */
 181.575 +      if (csa->token == T_PLUS)
 181.576 +         s = +1.0, scan_token(csa);
 181.577 +      else if (csa->token == T_MINUS)
 181.578 +         s = -1.0, scan_token(csa);
 181.579 +      else
 181.580 +         s = +1.0;
 181.581 +      if (csa->token != T_NUMBER)
 181.582 +         error(csa, "missing right-hand side\n");
 181.583 +      glp_set_row_bnds(csa->P, i, type, s * csa->value, s * csa->value);
 181.584 +      /* the rest of the current line must be empty */
 181.585 +      if (!(csa->c == '\n' || csa->c == XEOF))
 181.586 +         error(csa, "invalid symbol(s) beyond right-hand side\n");
 181.587 +      scan_token(csa);
 181.588 +      /* if the next token is a sign, numeric constant, or a symbolic
 181.589 +         name, here is another constraint */
 181.590 +      if (csa->token == T_PLUS || csa->token == T_MINUS ||
 181.591 +          csa->token == T_NUMBER || csa->token == T_NAME) goto loop;
 181.592 +      return;
 181.593 +}
 181.594 +
 181.595 +static void set_lower_bound(struct csa *csa, int j, double lb)
 181.596 +{     /* set lower bound of j-th variable */
 181.597 +      if (csa->lb[j] != +DBL_MAX)
 181.598 +      {  warning(csa, "lower bound of variable `%s' redefined\n",
 181.599 +            glp_get_col_name(csa->P, j));
 181.600 +      }
 181.601 +      csa->lb[j] = lb;
 181.602 +      return;
 181.603 +}
 181.604 +
 181.605 +static void set_upper_bound(struct csa *csa, int j, double ub)
 181.606 +{     /* set upper bound of j-th variable */
 181.607 +      if (csa->ub[j] != -DBL_MAX)
 181.608 +      {  warning(csa, "upper bound of variable `%s' redefined\n",
 181.609 +            glp_get_col_name(csa->P, j));
 181.610 +      }
 181.611 +      csa->ub[j] = ub;
 181.612 +      return;
 181.613 +}
 181.614 +
 181.615 +/***********************************************************************
 181.616 +*  parse_bounds - parse bounds section
 181.617 +*
 181.618 +*  This routine parses the bounds section using the following syntax:
 181.619 +*
 181.620 +*  <variable> ::= <symbolic name>
 181.621 +*  <infinity> ::= infinity | inf
 181.622 +*  <bound> ::= <numeric constant> | + <numeric constant> |
 181.623 +*     - <numeric constant> | + <infinity> | - <infinity>
 181.624 +*  <lt> ::= < | <= | =<
 181.625 +*  <gt> ::= > | >= | =>
 181.626 +*  <bound definition> ::= <bound> <lt> <variable> <lt> <bound> |
 181.627 +*     <bound> <lt> <variable> | <variable> <lt> <bound> |
 181.628 +*     <variable> <gt> <bound> | <variable> = <bound> | <variable> free
 181.629 +*  <bounds> ::= bounds | bound
 181.630 +*  <bounds section> ::= <bounds> |
 181.631 +*     <bounds section> <bound definition> */
 181.632 +
 181.633 +static void parse_bounds(struct csa *csa)
 181.634 +{     int j, lb_flag;
 181.635 +      double lb, s;
 181.636 +      /* parse the keyword 'bounds' */
 181.637 +      xassert(csa->token == T_BOUNDS);
 181.638 +      scan_token(csa);
 181.639 +loop: /* bound definition can start with a sign, numeric constant, or
 181.640 +         a symbolic name */
 181.641 +      if (!(csa->token == T_PLUS || csa->token == T_MINUS ||
 181.642 +            csa->token == T_NUMBER || csa->token == T_NAME)) goto done;
 181.643 +      /* parse bound definition */
 181.644 +      if (csa->token == T_PLUS || csa->token == T_MINUS)
 181.645 +      {  /* parse signed lower bound */
 181.646 +         lb_flag = 1;
 181.647 +         s = (csa->token == T_PLUS ? +1.0 : -1.0);
 181.648 +         scan_token(csa);
 181.649 +         if (csa->token == T_NUMBER)
 181.650 +            lb = s * csa->value, scan_token(csa);
 181.651 +         else if (the_same(csa->image, "infinity") ||
 181.652 +                  the_same(csa->image, "inf"))
 181.653 +         {  if (s > 0.0)
 181.654 +               error(csa, "invalid use of `+inf' as lower bound\n");
 181.655 +            lb = -DBL_MAX, scan_token(csa);
 181.656 +         }
 181.657 +         else
 181.658 +            error(csa, "missing lower bound\n");
 181.659 +      }
 181.660 +      else if (csa->token == T_NUMBER)
 181.661 +      {  /* parse unsigned lower bound */
 181.662 +         lb_flag = 1;
 181.663 +         lb = csa->value, scan_token(csa);
 181.664 +      }
 181.665 +      else
 181.666 +      {  /* lower bound is not specified */
 181.667 +         lb_flag = 0;
 181.668 +      }
 181.669 +      /* parse the token that should follow the lower bound */
 181.670 +      if (lb_flag)
 181.671 +      {  if (csa->token != T_LE)
 181.672 +            error(csa, "missing `<', `<=', or `=<' after lower bound\n")
 181.673 +               ;
 181.674 +         scan_token(csa);
 181.675 +      }
 181.676 +      /* parse variable name */
 181.677 +      if (csa->token != T_NAME)
 181.678 +         error(csa, "missing variable name\n");
 181.679 +      j = find_col(csa, csa->image);
 181.680 +      /* set lower bound */
 181.681 +      if (lb_flag) set_lower_bound(csa, j, lb);
 181.682 +      scan_token(csa);
 181.683 +      /* parse the context that follows the variable name */
 181.684 +      if (csa->token == T_LE)
 181.685 +      {  /* parse upper bound */
 181.686 +         scan_token(csa);
 181.687 +         if (csa->token == T_PLUS || csa->token == T_MINUS)
 181.688 +         {  /* parse signed upper bound */
 181.689 +            s = (csa->token == T_PLUS ? +1.0 : -1.0);
 181.690 +            scan_token(csa);
 181.691 +            if (csa->token == T_NUMBER)
 181.692 +            {  set_upper_bound(csa, j, s * csa->value);
 181.693 +               scan_token(csa);
 181.694 +            }
 181.695 +            else if (the_same(csa->image, "infinity") ||
 181.696 +                     the_same(csa->image, "inf"))
 181.697 +            {  if (s < 0.0)
 181.698 +                  error(csa, "invalid use of `-inf' as upper bound\n");
 181.699 +               set_upper_bound(csa, j, +DBL_MAX);
 181.700 +               scan_token(csa);
 181.701 +            }
 181.702 +            else
 181.703 +               error(csa, "missing upper bound\n");
 181.704 +         }
 181.705 +         else if (csa->token == T_NUMBER)
 181.706 +         {  /* parse unsigned upper bound */
 181.707 +            set_upper_bound(csa, j, csa->value);
 181.708 +            scan_token(csa);
 181.709 +         }
 181.710 +         else
 181.711 +            error(csa, "missing upper bound\n");
 181.712 +      }
 181.713 +      else if (csa->token == T_GE)
 181.714 +      {  /* parse lower bound */
 181.715 +         if (lb_flag)
 181.716 +         {  /* the context '... <= x >= ...' is invalid */
 181.717 +            error(csa, "invalid bound definition\n");
 181.718 +         }
 181.719 +         scan_token(csa);
 181.720 +         if (csa->token == T_PLUS || csa->token == T_MINUS)
 181.721 +         {  /* parse signed lower bound */
 181.722 +            s = (csa->token == T_PLUS ? +1.0 : -1.0);
 181.723 +            scan_token(csa);
 181.724 +            if (csa->token == T_NUMBER)
 181.725 +            {  set_lower_bound(csa, j, s * csa->value);
 181.726 +               scan_token(csa);
 181.727 +            }
 181.728 +            else if (the_same(csa->image, "infinity") ||
 181.729 +                     the_same(csa->image, "inf") == 0)
 181.730 +            {  if (s > 0.0)
 181.731 +                  error(csa, "invalid use of `+inf' as lower bound\n");
 181.732 +               set_lower_bound(csa, j, -DBL_MAX);
 181.733 +               scan_token(csa);
 181.734 +            }
 181.735 +            else
 181.736 +               error(csa, "missing lower bound\n");
 181.737 +         }
 181.738 +         else if (csa->token == T_NUMBER)
 181.739 +         {  /* parse unsigned lower bound */
 181.740 +            set_lower_bound(csa, j, csa->value);
 181.741 +            scan_token(csa);
 181.742 +         }
 181.743 +         else
 181.744 +            error(csa, "missing lower bound\n");
 181.745 +      }
 181.746 +      else if (csa->token == T_EQ)
 181.747 +      {  /* parse fixed value */
 181.748 +         if (lb_flag)
 181.749 +         {  /* the context '... <= x = ...' is invalid */
 181.750 +            error(csa, "invalid bound definition\n");
 181.751 +         }
 181.752 +         scan_token(csa);
 181.753 +         if (csa->token == T_PLUS || csa->token == T_MINUS)
 181.754 +         {  /* parse signed fixed value */
 181.755 +            s = (csa->token == T_PLUS ? +1.0 : -1.0);
 181.756 +            scan_token(csa);
 181.757 +            if (csa->token == T_NUMBER)
 181.758 +            {  set_lower_bound(csa, j, s * csa->value);
 181.759 +               set_upper_bound(csa, j, s * csa->value);
 181.760 +               scan_token(csa);
 181.761 +            }
 181.762 +            else
 181.763 +               error(csa, "missing fixed value\n");
 181.764 +         }
 181.765 +         else if (csa->token == T_NUMBER)
 181.766 +         {  /* parse unsigned fixed value */
 181.767 +            set_lower_bound(csa, j, csa->value);
 181.768 +            set_upper_bound(csa, j, csa->value);
 181.769 +            scan_token(csa);
 181.770 +         }
 181.771 +         else
 181.772 +            error(csa, "missing fixed value\n");
 181.773 +      }
 181.774 +      else if (the_same(csa->image, "free"))
 181.775 +      {  /* parse the keyword 'free' */
 181.776 +         if (lb_flag)
 181.777 +         {  /* the context '... <= x free ...' is invalid */
 181.778 +            error(csa, "invalid bound definition\n");
 181.779 +         }
 181.780 +         set_lower_bound(csa, j, -DBL_MAX);
 181.781 +         set_upper_bound(csa, j, +DBL_MAX);
 181.782 +         scan_token(csa);
 181.783 +      }
 181.784 +      else if (!lb_flag)
 181.785 +      {  /* neither lower nor upper bounds are specified */
 181.786 +         error(csa, "invalid bound definition\n");
 181.787 +      }
 181.788 +      goto loop;
 181.789 +done: return;
 181.790 +}
 181.791 +
 181.792 +/***********************************************************************
 181.793 +*  parse_integer - parse general, integer, or binary section
 181.794 +*
 181.795 +*  <variable> ::= <symbolic name>
 181.796 +*  <general> ::= general | generals | gen
 181.797 +*  <integer> ::= integer | integers | int
 181.798 +*  <binary> ::= binary | binaries | bin
 181.799 +*  <section head> ::= <general> <integer> <binary>
 181.800 +*  <additional section> ::= <section head> |
 181.801 +*     <additional section> <variable> */
 181.802 +
 181.803 +static void parse_integer(struct csa *csa)
 181.804 +{     int j, binary;
 181.805 +      /* parse the keyword 'general', 'integer', or 'binary' */
 181.806 +      if (csa->token == T_GENERAL)
 181.807 +         binary = 0, scan_token(csa);
 181.808 +      else if (csa->token == T_INTEGER)
 181.809 +         binary = 0, scan_token(csa);
 181.810 +      else if (csa->token == T_BINARY)
 181.811 +         binary = 1, scan_token(csa);
 181.812 +      else
 181.813 +         xassert(csa != csa);
 181.814 +      /* parse list of variables (may be empty) */
 181.815 +      while (csa->token == T_NAME)
 181.816 +      {  /* find the corresponding column */
 181.817 +         j = find_col(csa, csa->image);
 181.818 +         /* change kind of the variable */
 181.819 +         glp_set_col_kind(csa->P, j, GLP_IV);
 181.820 +         /* set 0-1 bounds for the binary variable */
 181.821 +         if (binary)
 181.822 +         {  set_lower_bound(csa, j, 0.0);
 181.823 +            set_upper_bound(csa, j, 1.0);
 181.824 +         }
 181.825 +         scan_token(csa);
 181.826 +      }
 181.827 +      return;
 181.828 +}
 181.829 +
 181.830 +int glp_read_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname)
 181.831 +{     /* read problem data in CPLEX LP format */
 181.832 +      glp_cpxcp _parm;
 181.833 +      struct csa _csa, *csa = &_csa;
 181.834 +      int ret;
 181.835 +      xprintf("Reading problem data from `%s'...\n", fname);
 181.836 +      if (parm == NULL)
 181.837 +         glp_init_cpxcp(&_parm), parm = &_parm;
 181.838 +      /* check control parameters */
 181.839 +      check_parm("glp_read_lp", parm);
 181.840 +      /* initialize common storage area */
 181.841 +      csa->P = P;
 181.842 +      csa->parm = parm;
 181.843 +      csa->fname = fname;
 181.844 +      csa->fp = NULL;
 181.845 +      if (setjmp(csa->jump))
 181.846 +      {  ret = 1;
 181.847 +         goto done;
 181.848 +      }
 181.849 +      csa->count = 0;
 181.850 +      csa->c = '\n';
 181.851 +      csa->token = T_EOF;
 181.852 +      csa->image[0] = '\0';
 181.853 +      csa->imlen = 0;
 181.854 +      csa->value = 0.0;
 181.855 +      csa->n_max = 100;
 181.856 +      csa->ind = xcalloc(1+csa->n_max, sizeof(int));
 181.857 +      csa->val = xcalloc(1+csa->n_max, sizeof(double));
 181.858 +      csa->flag = xcalloc(1+csa->n_max, sizeof(char));
 181.859 +      memset(&csa->flag[1], 0, csa->n_max * sizeof(char));
 181.860 +      csa->lb = xcalloc(1+csa->n_max, sizeof(double));
 181.861 +      csa->ub = xcalloc(1+csa->n_max, sizeof(double));
 181.862 +      /* erase problem object */
 181.863 +      glp_erase_prob(P);
 181.864 +      glp_create_index(P);
 181.865 +      /* open input CPLEX LP file */
 181.866 +      csa->fp = xfopen(fname, "r");
 181.867 +      if (csa->fp == NULL)
 181.868 +      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
 181.869 +         ret = 1;
 181.870 +         goto done;
 181.871 +      }
 181.872 +      /* scan very first token */
 181.873 +      scan_token(csa);
 181.874 +      /* parse definition of the objective function */
 181.875 +      if (!(csa->token == T_MINIMIZE || csa->token == T_MAXIMIZE))
 181.876 +         error(csa, "`minimize' or `maximize' keyword missing\n");
 181.877 +      parse_objective(csa);
 181.878 +      /* parse constraints section */
 181.879 +      if (csa->token != T_SUBJECT_TO)
 181.880 +         error(csa, "constraints section missing\n");
 181.881 +      parse_constraints(csa);
 181.882 +      /* parse optional bounds section */
 181.883 +      if (csa->token == T_BOUNDS) parse_bounds(csa);
 181.884 +      /* parse optional general, integer, and binary sections */
 181.885 +      while (csa->token == T_GENERAL ||
 181.886 +             csa->token == T_INTEGER ||
 181.887 +             csa->token == T_BINARY) parse_integer(csa);
 181.888 +      /* check for the keyword 'end' */
 181.889 +      if (csa->token == T_END)
 181.890 +         scan_token(csa);
 181.891 +      else if (csa->token == T_EOF)
 181.892 +         warning(csa, "keyword `end' missing\n");
 181.893 +      else
 181.894 +         error(csa, "symbol `%s' in wrong position\n", csa->image);
 181.895 +      /* nothing must follow the keyword 'end' (except comments) */
 181.896 +      if (csa->token != T_EOF)
 181.897 +         error(csa, "extra symbol(s) detected beyond `end'\n");
 181.898 +      /* set bounds of variables */
 181.899 +      {  int j, type;
 181.900 +         double lb, ub;
 181.901 +         for (j = 1; j <= P->n; j++)
 181.902 +         {  lb = csa->lb[j];
 181.903 +            ub = csa->ub[j];
 181.904 +            if (lb == +DBL_MAX) lb = 0.0;      /* default lb */
 181.905 +            if (ub == -DBL_MAX) ub = +DBL_MAX; /* default ub */
 181.906 +            if (lb == -DBL_MAX && ub == +DBL_MAX)
 181.907 +               type = GLP_FR;
 181.908 +            else if (ub == +DBL_MAX)
 181.909 +               type = GLP_LO;
 181.910 +            else if (lb == -DBL_MAX)
 181.911 +               type = GLP_UP;
 181.912 +            else if (lb != ub)
 181.913 +               type = GLP_DB;
 181.914 +            else
 181.915 +               type = GLP_FX;
 181.916 +            glp_set_col_bnds(csa->P, j, type, lb, ub);
 181.917 +         }
 181.918 +      }
 181.919 +      /* print some statistics */
 181.920 +      xprintf("%d row%s, %d column%s, %d non-zero%s\n",
 181.921 +         P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s",
 181.922 +         P->nnz, P->nnz == 1 ? "" : "s");
 181.923 +      if (glp_get_num_int(P) > 0)
 181.924 +      {  int ni = glp_get_num_int(P);
 181.925 +         int nb = glp_get_num_bin(P);
 181.926 +         if (ni == 1)
 181.927 +         {  if (nb == 0)
 181.928 +               xprintf("One variable is integer\n");
 181.929 +            else
 181.930 +               xprintf("One variable is binary\n");
 181.931 +         }
 181.932 +         else
 181.933 +         {  xprintf("%d integer variables, ", ni);
 181.934 +            if (nb == 0)
 181.935 +               xprintf("none");
 181.936 +            else if (nb == 1)
 181.937 +               xprintf("one");
 181.938 +            else if (nb == ni)
 181.939 +               xprintf("all");
 181.940 +            else
 181.941 +               xprintf("%d", nb);
 181.942 +            xprintf(" of which %s binary\n", nb == 1 ? "is" : "are");
 181.943 +         }
 181.944 +      }
 181.945 +      xprintf("%d lines were read\n", csa->count);
 181.946 +      /* problem data has been successfully read */
 181.947 +      glp_delete_index(P);
 181.948 +      glp_sort_matrix(P);
 181.949 +      ret = 0;
 181.950 +done: if (csa->fp != NULL) xfclose(csa->fp);
 181.951 +      xfree(csa->ind);
 181.952 +      xfree(csa->val);
 181.953 +      xfree(csa->flag);
 181.954 +      xfree(csa->lb);
 181.955 +      xfree(csa->ub);
 181.956 +      if (ret != 0) glp_erase_prob(P);
 181.957 +      return ret;
 181.958 +}
 181.959 +
 181.960 +/***********************************************************************
 181.961 +*  NAME
 181.962 +*
 181.963 +*  glp_write_lp - write problem data in CPLEX LP format
 181.964 +*
 181.965 +*  SYNOPSIS
 181.966 +*
 181.967 +*  int glp_write_lp(glp_prob *P, const glp_cpxcp *parm, const char
 181.968 +*     *fname);
 181.969 +*
 181.970 +*  DESCRIPTION
 181.971 +*
 181.972 +*  The routine glp_write_lp writes problem data in CPLEX LP format to
 181.973 +*  a text file.
 181.974 +*
 181.975 +*  The parameter parm is a pointer to the structure glp_cpxcp, which
 181.976 +*  specifies control parameters used by the routine. If parm is NULL,
 181.977 +*  the routine uses default settings.
 181.978 +*
 181.979 +*  The character string fname specifies a name of the text file to be
 181.980 +*  written.
 181.981 +*
 181.982 +*  RETURNS
 181.983 +*
 181.984 +*  If the operation was successful, the routine glp_write_lp returns
 181.985 +*  zero. Otherwise, it prints an error message and returns non-zero. */
 181.986 +
 181.987 +#define csa csa1
 181.988 +
 181.989 +struct csa
 181.990 +{     /* common storage area */
 181.991 +      glp_prob *P;
 181.992 +      /* pointer to problem object */
 181.993 +      const glp_cpxcp *parm;
 181.994 +      /* pointer to control parameters */
 181.995 +};
 181.996 +
 181.997 +static int check_name(char *name)
 181.998 +{     /* check if specified name is valid for CPLEX LP format */
 181.999 +      if (*name == '.') return 1;
181.1000 +      if (isdigit((unsigned char)*name)) return 1;
181.1001 +      for (; *name; name++)
181.1002 +      {  if (!isalnum((unsigned char)*name) &&
181.1003 +             strchr(CHAR_SET, (unsigned char)*name) == NULL) return 1;
181.1004 +      }
181.1005 +      return 0; /* name is ok */
181.1006 +}
181.1007 +
181.1008 +static void adjust_name(char *name)
181.1009 +{     /* attempt to adjust specified name to make it valid for CPLEX LP
181.1010 +         format */
181.1011 +      for (; *name; name++)
181.1012 +      {  if (*name == ' ')
181.1013 +            *name = '_';
181.1014 +         else if (*name == '-')
181.1015 +            *name = '~';
181.1016 +         else if (*name == '[')
181.1017 +            *name = '(';
181.1018 +         else if (*name == ']')
181.1019 +            *name = ')';
181.1020 +      }
181.1021 +      return;
181.1022 +}
181.1023 +
181.1024 +static char *row_name(struct csa *csa, int i, char rname[255+1])
181.1025 +{     /* construct symbolic name of i-th row (constraint) */
181.1026 +      const char *name;
181.1027 +      if (i == 0)
181.1028 +         name = glp_get_obj_name(csa->P);
181.1029 +      else
181.1030 +         name = glp_get_row_name(csa->P, i);
181.1031 +      if (name == NULL) goto fake;
181.1032 +      strcpy(rname, name);
181.1033 +      adjust_name(rname);
181.1034 +      if (check_name(rname)) goto fake;
181.1035 +      return rname;
181.1036 +fake: if (i == 0)
181.1037 +         strcpy(rname, "obj");
181.1038 +      else
181.1039 +         sprintf(rname, "r_%d", i);
181.1040 +      return rname;
181.1041 +}
181.1042 +
181.1043 +static char *col_name(struct csa *csa, int j, char cname[255+1])
181.1044 +{     /* construct symbolic name of j-th column (variable) */
181.1045 +      const char *name;
181.1046 +      name = glp_get_col_name(csa->P, j);
181.1047 +      if (name == NULL) goto fake;
181.1048 +      strcpy(cname, name);
181.1049 +      adjust_name(cname);
181.1050 +      if (check_name(cname)) goto fake;
181.1051 +      return cname;
181.1052 +fake: sprintf(cname, "x_%d", j);
181.1053 +      return cname;
181.1054 +}
181.1055 +
181.1056 +int glp_write_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname)
181.1057 +{     /* write problem data in CPLEX LP format */
181.1058 +      glp_cpxcp _parm;
181.1059 +      struct csa _csa, *csa = &_csa;
181.1060 +      XFILE *fp;
181.1061 +      GLPROW *row;
181.1062 +      GLPCOL *col;
181.1063 +      GLPAIJ *aij;
181.1064 +      int i, j, len, flag, count, ret;
181.1065 +      char line[1000+1], term[500+1], name[255+1];
181.1066 +      xprintf("Writing problem data to `%s'...\n", fname);
181.1067 +      if (parm == NULL)
181.1068 +         glp_init_cpxcp(&_parm), parm = &_parm;
181.1069 +      /* check control parameters */
181.1070 +      check_parm("glp_write_lp", parm);
181.1071 +      /* initialize common storage area */
181.1072 +      csa->P = P;
181.1073 +      csa->parm = parm;
181.1074 +      /* create output CPLEX LP file */
181.1075 +      fp = xfopen(fname, "w"), count = 0;
181.1076 +      if (fp == NULL)
181.1077 +      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
181.1078 +         ret = 1;
181.1079 +         goto done;
181.1080 +      }
181.1081 +      /* write problem name */
181.1082 +      xfprintf(fp, "\\* Problem: %s *\\\n",
181.1083 +         P->name == NULL ? "Unknown" : P->name), count++;
181.1084 +      xfprintf(fp, "\n"), count++;
181.1085 +      /* the problem should contain at least one row and one column */
181.1086 +      if (!(P->m > 0 && P->n > 0))
181.1087 +      {  xprintf("Warning: problem has no rows/columns\n");
181.1088 +         xfprintf(fp, "\\* WARNING: PROBLEM HAS NO ROWS/COLUMNS *\\\n"),
181.1089 +            count++;
181.1090 +         xfprintf(fp, "\n"), count++;
181.1091 +         goto skip;
181.1092 +      }
181.1093 +      /* write the objective function definition */
181.1094 +      if (P->dir == GLP_MIN)
181.1095 +         xfprintf(fp, "Minimize\n"), count++;
181.1096 +      else if (P->dir == GLP_MAX)
181.1097 +         xfprintf(fp, "Maximize\n"), count++;
181.1098 +      else
181.1099 +         xassert(P != P);
181.1100 +      row_name(csa, 0, name);
181.1101 +      sprintf(line, " %s:", name);
181.1102 +      len = 0;
181.1103 +      for (j = 1; j <= P->n; j++)
181.1104 +      {  col = P->col[j];
181.1105 +         if (col->coef != 0.0 || col->ptr == NULL)
181.1106 +         {  len++;
181.1107 +            col_name(csa, j, name);
181.1108 +            if (col->coef == 0.0)
181.1109 +               sprintf(term, " + 0 %s", name); /* empty column */
181.1110 +            else if (col->coef == +1.0)
181.1111 +               sprintf(term, " + %s", name);
181.1112 +            else if (col->coef == -1.0)
181.1113 +               sprintf(term, " - %s", name);
181.1114 +            else if (col->coef > 0.0)
181.1115 +               sprintf(term, " + %.*g %s", DBL_DIG, +col->coef, name);
181.1116 +            else
181.1117 +               sprintf(term, " - %.*g %s", DBL_DIG, -col->coef, name);
181.1118 +            if (strlen(line) + strlen(term) > 72)
181.1119 +               xfprintf(fp, "%s\n", line), line[0] = '\0', count++;
181.1120 +            strcat(line, term);
181.1121 +         }
181.1122 +      }
181.1123 +      if (len == 0)
181.1124 +      {  /* empty objective */
181.1125 +         sprintf(term, " 0 %s", col_name(csa, 1, name));
181.1126 +         strcat(line, term);
181.1127 +      }
181.1128 +      xfprintf(fp, "%s\n", line), count++;
181.1129 +      if (P->c0 != 0.0)
181.1130 +         xfprintf(fp, "\\* constant term = %.*g *\\\n", DBL_DIG, P->c0),
181.1131 +            count++;
181.1132 +      xfprintf(fp, "\n"), count++;
181.1133 +      /* write the constraints section */
181.1134 +      xfprintf(fp, "Subject To\n"), count++;
181.1135 +      for (i = 1; i <= P->m; i++)
181.1136 +      {  row = P->row[i];
181.1137 +         if (row->type == GLP_FR) continue; /* skip free row */
181.1138 +         row_name(csa, i, name);
181.1139 +         sprintf(line, " %s:", name);
181.1140 +         /* linear form */
181.1141 +         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
181.1142 +         {  col_name(csa, aij->col->j, name);
181.1143 +            if (aij->val == +1.0)
181.1144 +               sprintf(term, " + %s", name);
181.1145 +            else if (aij->val == -1.0)
181.1146 +               sprintf(term, " - %s", name);
181.1147 +            else if (aij->val > 0.0)
181.1148 +               sprintf(term, " + %.*g %s", DBL_DIG, +aij->val, name);
181.1149 +            else
181.1150 +               sprintf(term, " - %.*g %s", DBL_DIG, -aij->val, name);
181.1151 +            if (strlen(line) + strlen(term) > 72)
181.1152 +               xfprintf(fp, "%s\n", line), line[0] = '\0', count++;
181.1153 +            strcat(line, term);
181.1154 +         }
181.1155 +         if (row->type == GLP_DB)
181.1156 +         {  /* double-bounded (ranged) constraint */
181.1157 +            sprintf(term, " - ~r_%d", i);
181.1158 +            if (strlen(line) + strlen(term) > 72)
181.1159 +               xfprintf(fp, "%s\n", line), line[0] = '\0', count++;
181.1160 +            strcat(line, term);
181.1161 +         }
181.1162 +         else if (row->ptr == NULL)
181.1163 +         {  /* empty constraint */
181.1164 +            sprintf(term, " 0 %s", col_name(csa, 1, name));
181.1165 +            strcat(line, term);
181.1166 +         }
181.1167 +         /* right hand-side */
181.1168 +         if (row->type == GLP_LO)
181.1169 +            sprintf(term, " >= %.*g", DBL_DIG, row->lb);
181.1170 +         else if (row->type == GLP_UP)
181.1171 +            sprintf(term, " <= %.*g", DBL_DIG, row->ub);
181.1172 +         else if (row->type == GLP_DB || row->type == GLP_FX)
181.1173 +            sprintf(term, " = %.*g", DBL_DIG, row->lb);
181.1174 +         else
181.1175 +            xassert(row != row);
181.1176 +         if (strlen(line) + strlen(term) > 72)
181.1177 +            xfprintf(fp, "%s\n", line), line[0] = '\0', count++;
181.1178 +         strcat(line, term);
181.1179 +         xfprintf(fp, "%s\n", line), count++;
181.1180 +      }
181.1181 +      xfprintf(fp, "\n"), count++;
181.1182 +      /* write the bounds section */
181.1183 +      flag = 0;
181.1184 +      for (i = 1; i <= P->m; i++)
181.1185 +      {  row = P->row[i];
181.1186 +         if (row->type != GLP_DB) continue;
181.1187 +         if (!flag)
181.1188 +            xfprintf(fp, "Bounds\n"), flag = 1, count++;
181.1189 +         xfprintf(fp, " 0 <= ~r_%d <= %.*g\n",
181.1190 +            i, DBL_DIG, row->ub - row->lb), count++;
181.1191 +      }
181.1192 +      for (j = 1; j <= P->n; j++)
181.1193 +      {  col = P->col[j];
181.1194 +         if (col->type == GLP_LO && col->lb == 0.0) continue;
181.1195 +         if (!flag)
181.1196 +            xfprintf(fp, "Bounds\n"), flag = 1, count++;
181.1197 +         col_name(csa, j, name);
181.1198 +         if (col->type == GLP_FR)
181.1199 +            xfprintf(fp, " %s free\n", name), count++;
181.1200 +         else if (col->type == GLP_LO)
181.1201 +            xfprintf(fp, " %s >= %.*g\n",
181.1202 +               name, DBL_DIG, col->lb), count++;
181.1203 +         else if (col->type == GLP_UP)
181.1204 +            xfprintf(fp, " -Inf <= %s <= %.*g\n",
181.1205 +               name, DBL_DIG, col->ub), count++;
181.1206 +         else if (col->type == GLP_DB)
181.1207 +            xfprintf(fp, " %.*g <= %s <= %.*g\n",
181.1208 +               DBL_DIG, col->lb, name, DBL_DIG, col->ub), count++;
181.1209 +         else if (col->type == GLP_FX)
181.1210 +            xfprintf(fp, " %s = %.*g\n",
181.1211 +               name, DBL_DIG, col->lb), count++;
181.1212 +         else
181.1213 +            xassert(col != col);
181.1214 +      }
181.1215 +      if (flag) xfprintf(fp, "\n"), count++;
181.1216 +      /* write the integer section */
181.1217 +      flag = 0;
181.1218 +      for (j = 1; j <= P->n; j++)
181.1219 +      {  col = P->col[j];
181.1220 +         if (col->kind == GLP_CV) continue;
181.1221 +         xassert(col->kind == GLP_IV);
181.1222 +         if (!flag)
181.1223 +            xfprintf(fp, "Generals\n"), flag = 1, count++;
181.1224 +         xfprintf(fp, " %s\n", col_name(csa, j, name)), count++;
181.1225 +      }
181.1226 +      if (flag) xfprintf(fp, "\n"), count++;
181.1227 +skip: /* write the end keyword */
181.1228 +      xfprintf(fp, "End\n"), count++;
181.1229 +      xfflush(fp);
181.1230 +      if (xferror(fp))
181.1231 +      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
181.1232 +         ret = 1;
181.1233 +         goto done;
181.1234 +      }
181.1235 +      /* problem data has been successfully written */
181.1236 +      xprintf("%d lines were written\n", count);
181.1237 +      ret = 0;
181.1238 +done: if (fp != NULL) xfclose(fp);
181.1239 +      return ret;
181.1240 +}
181.1241 +
181.1242 +/* eof */
   182.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   182.2 +++ b/src/glpdmp.c	Mon Dec 06 13:09:21 2010 +0100
   182.3 @@ -0,0 +1,259 @@
   182.4 +/* glpdmp.c (dynamic memory pool) */
   182.5 +
   182.6 +/***********************************************************************
   182.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   182.8 +*
   182.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  182.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  182.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  182.12 +*  E-mail: <mao@gnu.org>.
  182.13 +*
  182.14 +*  GLPK is free software: you can redistribute it and/or modify it
  182.15 +*  under the terms of the GNU General Public License as published by
  182.16 +*  the Free Software Foundation, either version 3 of the License, or
  182.17 +*  (at your option) any later version.
  182.18 +*
  182.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  182.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  182.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  182.22 +*  License for more details.
  182.23 +*
  182.24 +*  You should have received a copy of the GNU General Public License
  182.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  182.26 +***********************************************************************/
  182.27 +
  182.28 +#include "glpdmp.h"
  182.29 +
  182.30 +#if 1 /* 29/VIII-2008 */
  182.31 +/* some processors need data to be properly aligned; the macro
  182.32 +   align_datasize enlarges the specified size of a data item to provide
  182.33 +   a proper alignment of immediately following data */
  182.34 +
  182.35 +#define align_datasize(size) ((((size) + 7) / 8) * 8)
  182.36 +/* 8 bytes is sufficient in both 32- and 64-bit environments */
  182.37 +#endif
  182.38 +
  182.39 +#ifdef GLP_DEBUG
  182.40 +struct info
  182.41 +{     DMP *pool;
  182.42 +      int size;
  182.43 +};
  182.44 +#endif
  182.45 +
  182.46 +/***********************************************************************
  182.47 +*  NAME
  182.48 +*
  182.49 +*  dmp_create_pool - create dynamic memory pool
  182.50 +*
  182.51 +*  SYNOPSIS
  182.52 +*
  182.53 +*  #include "glpdmp.h"
  182.54 +*  DMP *dmp_create_pool(void);
  182.55 +*
  182.56 +*  DESCRIPTION
  182.57 +*
  182.58 +*  The routine dmp_create_pool creates a dynamic memory pool.
  182.59 +*
  182.60 +*  RETURNS
  182.61 +*
  182.62 +*  The routine returns a pointer to the memory pool created. */
  182.63 +
  182.64 +DMP *dmp_create_pool(void)
  182.65 +{     DMP *pool;
  182.66 +      int k;
  182.67 +#ifdef GLP_DEBUG
  182.68 +      xprintf("dmp_create_pool: warning: debug mode enabled\n");
  182.69 +#endif
  182.70 +      pool = xmalloc(sizeof(DMP));
  182.71 +#if 0
  182.72 +      pool->size = 0;
  182.73 +#endif
  182.74 +      for (k = 0; k <= 31; k++) pool->avail[k] = NULL;
  182.75 +      pool->block = NULL;
  182.76 +      pool->used = DMP_BLK_SIZE;
  182.77 +      pool->count.lo = pool->count.hi = 0;
  182.78 +      return pool;
  182.79 +}
  182.80 +
  182.81 +/***********************************************************************
  182.82 +*  NAME
  182.83 +*
  182.84 +*  dmp_get_atom - get free atom from dynamic memory pool
  182.85 +*
  182.86 +*  SYNOPSIS
  182.87 +*
  182.88 +*  #include "glpdmp.h"
  182.89 +*  void *dmp_get_atom(DMP *pool, int size);
  182.90 +*
  182.91 +*  DESCRIPTION
  182.92 +*
  182.93 +*  The routine dmp_get_atom obtains a free atom (memory block) from the
  182.94 +*  specified memory pool.
  182.95 +*
  182.96 +*  The parameter size is the atom size, in bytes, 1 <= size <= 256.
  182.97 +*
  182.98 +*  Note that the free atom contains arbitrary data, not binary zeros.
  182.99 +*
 182.100 +*  RETURNS
 182.101 +*
 182.102 +*  The routine returns a pointer to the free atom obtained. */
 182.103 +
 182.104 +void *dmp_get_atom(DMP *pool, int size)
 182.105 +{     void *atom;
 182.106 +      int k;
 182.107 +#ifdef GLP_DEBUG
 182.108 +      int orig_size = size;
 182.109 +#endif
 182.110 +      if (!(1 <= size && size <= 256))
 182.111 +         xerror("dmp_get_atom: size = %d; invalid atom size\n", size);
 182.112 +#if 0
 182.113 +      if (!(pool->size == 0 || pool->size == size))
 182.114 +         xerror("dmp_get_atom: size = %d; wrong atom size\n", size);
 182.115 +#endif
 182.116 +      /* adjust the size to provide the proper data alignment */
 182.117 +      size = align_datasize(size);
 182.118 +#ifdef GLP_DEBUG
 182.119 +      size += align_datasize(sizeof(struct info));
 182.120 +#endif
 182.121 +      /* adjust the size to make it multiple of 8 bytes, if needed */
 182.122 +      size = ((size + 7) / 8) * 8;
 182.123 +      /* determine the corresponding list of free cells */
 182.124 +      k = size / 8 - 1;
 182.125 +      xassert(0 <= k && k <= 31);
 182.126 +      /* obtain a free atom */
 182.127 +      if (pool->avail[k] == NULL)
 182.128 +      {  /* the list of free cells is empty */
 182.129 +         if (pool->used + size > DMP_BLK_SIZE)
 182.130 +         {  /* allocate a new memory block */
 182.131 +            void *block = xmalloc(DMP_BLK_SIZE);
 182.132 +            *(void **)block = pool->block;
 182.133 +            pool->block = block;
 182.134 +            pool->used = align_datasize(sizeof(void *));
 182.135 +         }
 182.136 +         /* place the atom in the current memory block */
 182.137 +         atom = (char *)pool->block + pool->used;
 182.138 +         pool->used += size;
 182.139 +      }
 182.140 +      else
 182.141 +      {  /* obtain the atom from the list of free cells */
 182.142 +         atom = pool->avail[k];
 182.143 +         pool->avail[k] = *(void **)atom;
 182.144 +      }
 182.145 +      memset(atom, '?', size);
 182.146 +      /* increase the number of atoms which are currently in use */
 182.147 +      pool->count.lo++;
 182.148 +      if (pool->count.lo == 0) pool->count.hi++;
 182.149 +#ifdef GLP_DEBUG
 182.150 +      ((struct info *)atom)->pool = pool;
 182.151 +      ((struct info *)atom)->size = orig_size;
 182.152 +      atom = (char *)atom + align_datasize(sizeof(struct info));
 182.153 +#endif
 182.154 +      return atom;
 182.155 +}
 182.156 +
 182.157 +/***********************************************************************
 182.158 +*  NAME
 182.159 +*
 182.160 +*  dmp_free_atom - return atom to dynamic memory pool
 182.161 +*
 182.162 +*  SYNOPSIS
 182.163 +*
 182.164 +*  #include "glpdmp.h"
 182.165 +*  void dmp_free_atom(DMP *pool, void *atom, int size);
 182.166 +*
 182.167 +*  DESCRIPTION
 182.168 +*
 182.169 +*  The routine dmp_free_atom returns the specified atom (memory block)
 182.170 +*  to the specified memory pool, making it free.
 182.171 +*
 182.172 +*  The parameter size is the atom size, in bytes, 1 <= size <= 256.
 182.173 +*
 182.174 +*  Note that the atom can be returned only to the pool, from which it
 182.175 +*  was obtained, and its size must be exactly the same as on obtaining
 182.176 +*  it from the pool. */
 182.177 +
 182.178 +void dmp_free_atom(DMP *pool, void *atom, int size)
 182.179 +{     int k;
 182.180 +      if (!(1 <= size && size <= 256))
 182.181 +         xerror("dmp_free_atom: size = %d; invalid atom size\n", size);
 182.182 +#if 0
 182.183 +      if (!(pool->size == 0 || pool->size == size))
 182.184 +         xerror("dmp_free_atom: size = %d; wrong atom size\n", size);
 182.185 +#endif
 182.186 +      if (pool->count.lo == 0 && pool->count.hi == 0)
 182.187 +         xerror("dmp_free_atom: pool allocation error\n");
 182.188 +#ifdef GLP_DEBUG
 182.189 +      atom = (char *)atom - align_datasize(sizeof(struct info));
 182.190 +      xassert(((struct info *)atom)->pool == pool);
 182.191 +      xassert(((struct info *)atom)->size == size);
 182.192 +#endif
 182.193 +      /* adjust the size to provide the proper data alignment */
 182.194 +      size = align_datasize(size);
 182.195 +#ifdef GLP_DEBUG
 182.196 +      size += align_datasize(sizeof(struct info));
 182.197 +#endif
 182.198 +      /* adjust the size to make it multiple of 8 bytes, if needed */
 182.199 +      size = ((size + 7) / 8) * 8;
 182.200 +      /* determine the corresponding list of free cells */
 182.201 +      k = size / 8 - 1;
 182.202 +      xassert(0 <= k && k <= 31);
 182.203 +      /* return the atom to the list of free cells */
 182.204 +      *(void **)atom = pool->avail[k];
 182.205 +      pool->avail[k] = atom;
 182.206 +      /* decrease the number of atoms which are currently in use */
 182.207 +      pool->count.lo--;
 182.208 +      if (pool->count.lo == 0xFFFFFFFF) pool->count.hi--;
 182.209 +      return;
 182.210 +}
 182.211 +
 182.212 +/***********************************************************************
 182.213 +*  NAME
 182.214 +*
 182.215 +*  dmp_in_use - determine how many atoms are still in use
 182.216 +*
 182.217 +*  SYNOPSIS
 182.218 +*
 182.219 +*  #include "glpdmp.h"
 182.220 +*  glp_long dmp_in_use(DMP *pool);
 182.221 +*
 182.222 +*  DESCRIPTION
 182.223 +*
 182.224 +*  The routine dmp_in_use determines how many atoms allocated from the
 182.225 +*  specified memory pool with the routine dmp_get_atom are still in use,
 182.226 +*  i.e. not returned to the pool with the routine dmp_free_atom.
 182.227 +*
 182.228 +*  RETURNS
 182.229 +*
 182.230 +*  The routine returns the number of atoms which are still in use. */
 182.231 +
 182.232 +glp_long dmp_in_use(DMP *pool)
 182.233 +{     return
 182.234 +         pool->count;
 182.235 +}
 182.236 +
 182.237 +/***********************************************************************
 182.238 +*  NAME
 182.239 +*
 182.240 +*  dmp_delete_pool - delete dynamic memory pool
 182.241 +*
 182.242 +*  SYNOPSIS
 182.243 +*
 182.244 +*  #include "glpdmp.h"
 182.245 +*  void dmp_delete_pool(DMP *pool);
 182.246 +*
 182.247 +*  DESCRIPTION
 182.248 +*
 182.249 +*  The routine dmp_delete_pool deletes the specified dynamic memory
 182.250 +*  pool and frees all the memory allocated to this object. */
 182.251 +
 182.252 +void dmp_delete_pool(DMP *pool)
 182.253 +{     while (pool->block != NULL)
 182.254 +      {  void *block = pool->block;
 182.255 +         pool->block = *(void **)block;
 182.256 +         xfree(block);
 182.257 +      }
 182.258 +      xfree(pool);
 182.259 +      return;
 182.260 +}
 182.261 +
 182.262 +/* eof */
   183.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   183.2 +++ b/src/glpdmp.h	Mon Dec 06 13:09:21 2010 +0100
   183.3 @@ -0,0 +1,80 @@
   183.4 +/* glpdmp.h (dynamic memory pool) */
   183.5 +
   183.6 +/***********************************************************************
   183.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   183.8 +*
   183.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  183.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  183.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  183.12 +*  E-mail: <mao@gnu.org>.
  183.13 +*
  183.14 +*  GLPK is free software: you can redistribute it and/or modify it
  183.15 +*  under the terms of the GNU General Public License as published by
  183.16 +*  the Free Software Foundation, either version 3 of the License, or
  183.17 +*  (at your option) any later version.
  183.18 +*
  183.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  183.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  183.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  183.22 +*  License for more details.
  183.23 +*
  183.24 +*  You should have received a copy of the GNU General Public License
  183.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  183.26 +***********************************************************************/
  183.27 +
  183.28 +#ifndef GLPDMP_H
  183.29 +#define GLPDMP_H
  183.30 +
  183.31 +#include "glpenv.h"
  183.32 +
  183.33 +typedef struct DMP DMP;
  183.34 +
  183.35 +#define DMP_BLK_SIZE 8000
  183.36 +/* size of memory blocks, in bytes, allocated for memory pools */
  183.37 +
  183.38 +struct DMP
  183.39 +{     /* dynamic memory pool */
  183.40 +#if 0
  183.41 +      int size;
  183.42 +      /* size of atoms, in bytes, 1 <= size <= 256; if size = 0, atoms
  183.43 +         may have different sizes */
  183.44 +#endif
  183.45 +      void *avail[32];
  183.46 +      /* avail[k], 0 <= k <= 31, is a pointer to the first available
  183.47 +         (free) cell of (k+1)*8 bytes long; in the beginning of each
  183.48 +         free cell there is a pointer to another free cell of the same
  183.49 +         length */
  183.50 +      void *block;
  183.51 +      /* pointer to the most recently allocated memory block; in the
  183.52 +         beginning of each allocated memory block there is a pointer to
  183.53 +         the previously allocated memory block */
  183.54 +      int used;
  183.55 +      /* number of bytes used in the most recently allocated memory
  183.56 +         block */
  183.57 +      glp_long count;
  183.58 +      /* number of atoms which are currently in use */
  183.59 +};
  183.60 +
  183.61 +#define dmp_create_pool _glp_dmp_create_pool
  183.62 +DMP *dmp_create_pool(void);
  183.63 +/* create dynamic memory pool */
  183.64 +
  183.65 +#define dmp_get_atom _glp_dmp_get_atom
  183.66 +void *dmp_get_atom(DMP *pool, int size);
  183.67 +/* get free atom from dynamic memory pool */
  183.68 +
  183.69 +#define dmp_free_atom _glp_dmp_free_atom
  183.70 +void dmp_free_atom(DMP *pool, void *atom, int size);
  183.71 +/* return atom to dynamic memory pool */
  183.72 +
  183.73 +#define dmp_in_use _glp_dmp_in_use
  183.74 +glp_long dmp_in_use(DMP *pool);
  183.75 +/* determine how many atoms are still in use */
  183.76 +
  183.77 +#define dmp_delete_pool _glp_dmp_delete_pool
  183.78 +void dmp_delete_pool(DMP *pool);
  183.79 +/* delete dynamic memory pool */
  183.80 +
  183.81 +#endif
  183.82 +
  183.83 +/* eof */
   184.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   184.2 +++ b/src/glpdmx.c	Mon Dec 06 13:09:21 2010 +0100
   184.3 @@ -0,0 +1,1468 @@
   184.4 +/* glpdmx.c (reading/writing data in DIMACS format) */
   184.5 +
   184.6 +/***********************************************************************
   184.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   184.8 +*
   184.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  184.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  184.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  184.12 +*  E-mail: <mao@gnu.org>.
  184.13 +*
  184.14 +*  GLPK is free software: you can redistribute it and/or modify it
  184.15 +*  under the terms of the GNU General Public License as published by
  184.16 +*  the Free Software Foundation, either version 3 of the License, or
  184.17 +*  (at your option) any later version.
  184.18 +*
  184.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  184.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  184.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  184.22 +*  License for more details.
  184.23 +*
  184.24 +*  You should have received a copy of the GNU General Public License
  184.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  184.26 +***********************************************************************/
  184.27 +
  184.28 +#define _GLPSTD_STDIO
  184.29 +#include "glpapi.h"
  184.30 +
  184.31 +struct csa
  184.32 +{     /* common storage area */
  184.33 +      jmp_buf jump;
  184.34 +      /* label for go to in case of error */
  184.35 +      const char *fname;
  184.36 +      /* name of input text file */
  184.37 +      XFILE *fp;
  184.38 +      /* stream assigned to input text file */
  184.39 +      int count;
  184.40 +      /* line count */
  184.41 +      int c;
  184.42 +      /* current character */
  184.43 +      char field[255+1];
  184.44 +      /* data field */
  184.45 +      int empty;
  184.46 +      /* warning 'empty line ignored' was printed */
  184.47 +      int nonint;
  184.48 +      /* warning 'non-integer data detected' was printed */
  184.49 +};
  184.50 +
  184.51 +static void error(struct csa *csa, const char *fmt, ...)
  184.52 +{     /* print error message and terminate processing */
  184.53 +      va_list arg;
  184.54 +      xprintf("%s:%d: error: ", csa->fname, csa->count);
  184.55 +      va_start(arg, fmt);
  184.56 +      xvprintf(fmt, arg);
  184.57 +      va_end(arg);
  184.58 +      xprintf("\n");
  184.59 +      longjmp(csa->jump, 1);
  184.60 +      /* no return */
  184.61 +}
  184.62 +
  184.63 +static void warning(struct csa *csa, const char *fmt, ...)
  184.64 +{     /* print warning message and continue processing */
  184.65 +      va_list arg;
  184.66 +      xprintf("%s:%d: warning: ", csa->fname, csa->count);
  184.67 +      va_start(arg, fmt);
  184.68 +      xvprintf(fmt, arg);
  184.69 +      va_end(arg);
  184.70 +      xprintf("\n");
  184.71 +      return;
  184.72 +}
  184.73 +
  184.74 +static void read_char(struct csa *csa)
  184.75 +{     /* read character from input text file */
  184.76 +      int c;
  184.77 +      if (csa->c == '\n') csa->count++;
  184.78 +      c = xfgetc(csa->fp);
  184.79 +      if (c < 0)
  184.80 +      {  if (xferror(csa->fp))
  184.81 +            error(csa, "read error - %s", xerrmsg());
  184.82 +         else if (csa->c == '\n')
  184.83 +            error(csa, "unexpected end of file");
  184.84 +         else
  184.85 +         {  warning(csa, "missing final end of line");
  184.86 +            c = '\n';
  184.87 +         }
  184.88 +      }
  184.89 +      else if (c == '\n')
  184.90 +         ;
  184.91 +      else if (isspace(c))
  184.92 +         c = ' ';
  184.93 +      else if (iscntrl(c))
  184.94 +         error(csa, "invalid control character 0x%02X", c);
  184.95 +      csa->c = c;
  184.96 +      return;
  184.97 +}
  184.98 +
  184.99 +static void read_designator(struct csa *csa)
 184.100 +{     /* read one-character line designator */
 184.101 +      xassert(csa->c == '\n');
 184.102 +      read_char(csa);
 184.103 +      for (;;)
 184.104 +      {  /* skip preceding white-space characters */
 184.105 +         while (csa->c == ' ')
 184.106 +            read_char(csa);
 184.107 +         if (csa->c == '\n')
 184.108 +         {  /* ignore empty line */
 184.109 +            if (!csa->empty)
 184.110 +            {  warning(csa, "empty line ignored");
 184.111 +               csa->empty = 1;
 184.112 +            }
 184.113 +            read_char(csa);
 184.114 +         }
 184.115 +         else if (csa->c == 'c')
 184.116 +         {  /* skip comment line */
 184.117 +            while (csa->c != '\n')
 184.118 +               read_char(csa);
 184.119 +            read_char(csa);
 184.120 +         }
 184.121 +         else
 184.122 +         {  /* hmm... looks like a line designator */
 184.123 +            csa->field[0] = (char)csa->c, csa->field[1] = '\0';
 184.124 +            /* check that it is followed by a white-space character */
 184.125 +            read_char(csa);
 184.126 +            if (!(csa->c == ' ' || csa->c == '\n'))
 184.127 +               error(csa, "line designator missing or invalid");
 184.128 +            break;
 184.129 +         }
 184.130 +      }
 184.131 +      return;
 184.132 +}
 184.133 +
 184.134 +static void read_field(struct csa *csa)
 184.135 +{     /* read data field */
 184.136 +      int len = 0;
 184.137 +      /* skip preceding white-space characters */
 184.138 +      while (csa->c == ' ')
 184.139 +         read_char(csa);
 184.140 +      /* scan data field */
 184.141 +      if (csa->c == '\n')
 184.142 +         error(csa, "unexpected end of line");
 184.143 +      while (!(csa->c == ' ' || csa->c == '\n'))
 184.144 +      {  if (len == sizeof(csa->field)-1)
 184.145 +            error(csa, "data field `%.15s...' too long", csa->field);
 184.146 +         csa->field[len++] = (char)csa->c;
 184.147 +         read_char(csa);
 184.148 +      }
 184.149 +      csa->field[len] = '\0';
 184.150 +      return;
 184.151 +}
 184.152 +
 184.153 +static void end_of_line(struct csa *csa)
 184.154 +{     /* skip white-space characters until end of line */
 184.155 +      while (csa->c == ' ')
 184.156 +         read_char(csa);
 184.157 +      if (csa->c != '\n')
 184.158 +         error(csa, "too many data fields specified");
 184.159 +      return;
 184.160 +}
 184.161 +
 184.162 +static void check_int(struct csa *csa, double num)
 184.163 +{     /* print a warning if non-integer data are detected */
 184.164 +      if (!csa->nonint && num != floor(num))
 184.165 +      {  warning(csa, "non-integer data detected");
 184.166 +         csa->nonint = 1;
 184.167 +      }
 184.168 +      return;
 184.169 +}
 184.170 +
 184.171 +/***********************************************************************
 184.172 +*  NAME
 184.173 +*
 184.174 +*  glp_read_mincost - read min-cost flow problem data in DIMACS format
 184.175 +*
 184.176 +*  SYNOPSIS
 184.177 +*
 184.178 +*  int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
 184.179 +*     int a_cost, const char *fname);
 184.180 +*
 184.181 +*  DESCRIPTION
 184.182 +*
 184.183 +*  The routine glp_read_mincost reads minimum cost flow problem data in
 184.184 +*  DIMACS format from a text file.
 184.185 +*
 184.186 +*  RETURNS
 184.187 +*
 184.188 +*  If the operation was successful, the routine returns zero. Otherwise
 184.189 +*  it prints an error message and returns non-zero. */
 184.190 +
 184.191 +int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
 184.192 +      int a_cost, const char *fname)
 184.193 +{     struct csa _csa, *csa = &_csa;
 184.194 +      glp_vertex *v;
 184.195 +      glp_arc *a;
 184.196 +      int i, j, k, nv, na, ret = 0;
 184.197 +      double rhs, low, cap, cost;
 184.198 +      char *flag = NULL;
 184.199 +      if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
 184.200 +         xerror("glp_read_mincost: v_rhs = %d; invalid offset\n",
 184.201 +            v_rhs);
 184.202 +      if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
 184.203 +         xerror("glp_read_mincost: a_low = %d; invalid offset\n",
 184.204 +            a_low);
 184.205 +      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
 184.206 +         xerror("glp_read_mincost: a_cap = %d; invalid offset\n",
 184.207 +            a_cap);
 184.208 +      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
 184.209 +         xerror("glp_read_mincost: a_cost = %d; invalid offset\n",
 184.210 +            a_cost);
 184.211 +      glp_erase_graph(G, G->v_size, G->a_size);
 184.212 +      if (setjmp(csa->jump))
 184.213 +      {  ret = 1;
 184.214 +         goto done;
 184.215 +      }
 184.216 +      csa->fname = fname;
 184.217 +      csa->fp = NULL;
 184.218 +      csa->count = 0;
 184.219 +      csa->c = '\n';
 184.220 +      csa->field[0] = '\0';
 184.221 +      csa->empty = csa->nonint = 0;
 184.222 +      xprintf("Reading min-cost flow problem data from `%s'...\n",
 184.223 +         fname);
 184.224 +      csa->fp = xfopen(fname, "r");
 184.225 +      if (csa->fp == NULL)
 184.226 +      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
 184.227 +         longjmp(csa->jump, 1);
 184.228 +      }
 184.229 +      /* read problem line */
 184.230 +      read_designator(csa);
 184.231 +      if (strcmp(csa->field, "p") != 0)
 184.232 +         error(csa, "problem line missing or invalid");
 184.233 +      read_field(csa);
 184.234 +      if (strcmp(csa->field, "min") != 0)
 184.235 +         error(csa, "wrong problem designator; `min' expected");
 184.236 +      read_field(csa);
 184.237 +      if (!(str2int(csa->field, &nv) == 0 && nv >= 0))
 184.238 +         error(csa, "number of nodes missing or invalid");
 184.239 +      read_field(csa);
 184.240 +      if (!(str2int(csa->field, &na) == 0 && na >= 0))
 184.241 +         error(csa, "number of arcs missing or invalid");
 184.242 +      xprintf("Flow network has %d node%s and %d arc%s\n",
 184.243 +         nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s");
 184.244 +      if (nv > 0) glp_add_vertices(G, nv);
 184.245 +      end_of_line(csa);
 184.246 +      /* read node descriptor lines */
 184.247 +      flag = xcalloc(1+nv, sizeof(char));
 184.248 +      memset(&flag[1], 0, nv * sizeof(char));
 184.249 +      if (v_rhs >= 0)
 184.250 +      {  rhs = 0.0;
 184.251 +         for (i = 1; i <= nv; i++)
 184.252 +         {  v = G->v[i];
 184.253 +            memcpy((char *)v->data + v_rhs, &rhs, sizeof(double));
 184.254 +         }
 184.255 +      }
 184.256 +      for (;;)
 184.257 +      {  read_designator(csa);
 184.258 +         if (strcmp(csa->field, "n") != 0) break;
 184.259 +         read_field(csa);
 184.260 +         if (str2int(csa->field, &i) != 0)
 184.261 +            error(csa, "node number missing or invalid");
 184.262 +         if (!(1 <= i && i <= nv))
 184.263 +            error(csa, "node number %d out of range", i);
 184.264 +         if (flag[i])
 184.265 +            error(csa, "duplicate descriptor of node %d", i);
 184.266 +         read_field(csa);
 184.267 +         if (str2num(csa->field, &rhs) != 0)
 184.268 +            error(csa, "node supply/demand missing or invalid");
 184.269 +         check_int(csa, rhs);
 184.270 +         if (v_rhs >= 0)
 184.271 +         {  v = G->v[i];
 184.272 +            memcpy((char *)v->data + v_rhs, &rhs, sizeof(double));
 184.273 +         }
 184.274 +         flag[i] = 1;
 184.275 +         end_of_line(csa);
 184.276 +      }
 184.277 +      xfree(flag), flag = NULL;
 184.278 +      /* read arc descriptor lines */
 184.279 +      for (k = 1; k <= na; k++)
 184.280 +      {  if (k > 1) read_designator(csa);
 184.281 +         if (strcmp(csa->field, "a") != 0)
 184.282 +            error(csa, "wrong line designator; `a' expected");
 184.283 +         read_field(csa);
 184.284 +         if (str2int(csa->field, &i) != 0)
 184.285 +            error(csa, "starting node number missing or invalid");
 184.286 +         if (!(1 <= i && i <= nv))
 184.287 +            error(csa, "starting node number %d out of range", i);
 184.288 +         read_field(csa);
 184.289 +         if (str2int(csa->field, &j) != 0)
 184.290 +            error(csa, "ending node number missing or invalid");
 184.291 +         if (!(1 <= j && j <= nv))
 184.292 +            error(csa, "ending node number %d out of range", j);
 184.293 +         read_field(csa);
 184.294 +         if (!(str2num(csa->field, &low) == 0 && low >= 0.0))
 184.295 +            error(csa, "lower bound of arc flow missing or invalid");
 184.296 +         check_int(csa, low);
 184.297 +         read_field(csa);
 184.298 +         if (!(str2num(csa->field, &cap) == 0 && cap >= low))
 184.299 +            error(csa, "upper bound of arc flow missing or invalid");
 184.300 +         check_int(csa, cap);
 184.301 +         read_field(csa);
 184.302 +         if (str2num(csa->field, &cost) != 0)
 184.303 +            error(csa, "per-unit cost of arc flow missing or invalid");
 184.304 +         check_int(csa, cost);
 184.305 +         a = glp_add_arc(G, i, j);
 184.306 +         if (a_low >= 0)
 184.307 +            memcpy((char *)a->data + a_low, &low, sizeof(double));
 184.308 +         if (a_cap >= 0)
 184.309 +            memcpy((char *)a->data + a_cap, &cap, sizeof(double));
 184.310 +         if (a_cost >= 0)
 184.311 +            memcpy((char *)a->data + a_cost, &cost, sizeof(double));
 184.312 +         end_of_line(csa);
 184.313 +      }
 184.314 +      xprintf("%d lines were read\n", csa->count);
 184.315 +done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
 184.316 +      if (csa->fp != NULL) xfclose(csa->fp);
 184.317 +      if (flag != NULL) xfree(flag);
 184.318 +      return ret;
 184.319 +}
 184.320 +
 184.321 +/***********************************************************************
 184.322 +*  NAME
 184.323 +*
 184.324 +*  glp_write_mincost - write min-cost flow problem data in DIMACS format
 184.325 +*
 184.326 +*  SYNOPSIS
 184.327 +*
 184.328 +*  int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
 184.329 +*     int a_cost, const char *fname);
 184.330 +*
 184.331 +*  DESCRIPTION
 184.332 +*
 184.333 +*  The routine glp_write_mincost writes minimum cost flow problem data
 184.334 +*  in DIMACS format to a text file.
 184.335 +*
 184.336 +*  RETURNS
 184.337 +*
 184.338 +*  If the operation was successful, the routine returns zero. Otherwise
 184.339 +*  it prints an error message and returns non-zero. */
 184.340 +
 184.341 +int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
 184.342 +      int a_cost, const char *fname)
 184.343 +{     XFILE *fp;
 184.344 +      glp_vertex *v;
 184.345 +      glp_arc *a;
 184.346 +      int i, count = 0, ret;
 184.347 +      double rhs, low, cap, cost;
 184.348 +      if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
 184.349 +         xerror("glp_write_mincost: v_rhs = %d; invalid offset\n",
 184.350 +            v_rhs);
 184.351 +      if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
 184.352 +         xerror("glp_write_mincost: a_low = %d; invalid offset\n",
 184.353 +            a_low);
 184.354 +      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
 184.355 +         xerror("glp_write_mincost: a_cap = %d; invalid offset\n",
 184.356 +            a_cap);
 184.357 +      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
 184.358 +         xerror("glp_write_mincost: a_cost = %d; invalid offset\n",
 184.359 +            a_cost);
 184.360 +      xprintf("Writing min-cost flow problem data to `%s'...\n",
 184.361 +         fname);
 184.362 +      fp = xfopen(fname, "w");
 184.363 +      if (fp == NULL)
 184.364 +      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
 184.365 +         ret = 1;
 184.366 +         goto done;
 184.367 +      }
 184.368 +      xfprintf(fp, "c %s\n",
 184.369 +         G->name == NULL ? "unknown" : G->name), count++;
 184.370 +      xfprintf(fp, "p min %d %d\n", G->nv, G->na), count++;
 184.371 +      if (v_rhs >= 0)
 184.372 +      {  for (i = 1; i <= G->nv; i++)
 184.373 +         {  v = G->v[i];
 184.374 +            memcpy(&rhs, (char *)v->data + v_rhs, sizeof(double));
 184.375 +            if (rhs != 0.0)
 184.376 +               xfprintf(fp, "n %d %.*g\n", i, DBL_DIG, rhs), count++;
 184.377 +         }
 184.378 +      }
 184.379 +      for (i = 1; i <= G->nv; i++)
 184.380 +      {  v = G->v[i];
 184.381 +         for (a = v->out; a != NULL; a = a->t_next)
 184.382 +         {  if (a_low >= 0)
 184.383 +               memcpy(&low, (char *)a->data + a_low, sizeof(double));
 184.384 +            else
 184.385 +               low = 0.0;
 184.386 +            if (a_cap >= 0)
 184.387 +               memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
 184.388 +            else
 184.389 +               cap = 1.0;
 184.390 +            if (a_cost >= 0)
 184.391 +               memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
 184.392 +            else
 184.393 +               cost = 0.0;
 184.394 +            xfprintf(fp, "a %d %d %.*g %.*g %.*g\n",
 184.395 +               a->tail->i, a->head->i, DBL_DIG, low, DBL_DIG, cap,
 184.396 +               DBL_DIG, cost), count++;
 184.397 +         }
 184.398 +      }
 184.399 +      xfprintf(fp, "c eof\n"), count++;
 184.400 +      xfflush(fp);
 184.401 +      if (xferror(fp))
 184.402 +      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
 184.403 +         ret = 1;
 184.404 +         goto done;
 184.405 +      }
 184.406 +      xprintf("%d lines were written\n", count);
 184.407 +      ret = 0;
 184.408 +done: if (fp != NULL) xfclose(fp);
 184.409 +      return ret;
 184.410 +}
 184.411 +
 184.412 +/***********************************************************************
 184.413 +*  NAME
 184.414 +*
 184.415 +*  glp_read_maxflow - read maximum flow problem data in DIMACS format
 184.416 +*
 184.417 +*  SYNOPSIS
 184.418 +*
 184.419 +*  int glp_read_maxflow(glp_graph *G, int *s, int *t, int a_cap,
 184.420 +*     const char *fname);
 184.421 +*
 184.422 +*  DESCRIPTION
 184.423 +*
 184.424 +*  The routine glp_read_maxflow reads maximum flow problem data in
 184.425 +*  DIMACS format from a text file.
 184.426 +*
 184.427 +*  RETURNS
 184.428 +*
 184.429 +*  If the operation was successful, the routine returns zero. Otherwise
 184.430 +*  it prints an error message and returns non-zero. */
 184.431 +
 184.432 +int glp_read_maxflow(glp_graph *G, int *_s, int *_t, int a_cap,
 184.433 +      const char *fname)
 184.434 +{     struct csa _csa, *csa = &_csa;
 184.435 +      glp_arc *a;
 184.436 +      int i, j, k, s, t, nv, na, ret = 0;
 184.437 +      double cap;
 184.438 +      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
 184.439 +         xerror("glp_read_maxflow: a_cap = %d; invalid offset\n",
 184.440 +            a_cap);
 184.441 +      glp_erase_graph(G, G->v_size, G->a_size);
 184.442 +      if (setjmp(csa->jump))
 184.443 +      {  ret = 1;
 184.444 +         goto done;
 184.445 +      }
 184.446 +      csa->fname = fname;
 184.447 +      csa->fp = NULL;
 184.448 +      csa->count = 0;
 184.449 +      csa->c = '\n';
 184.450 +      csa->field[0] = '\0';
 184.451 +      csa->empty = csa->nonint = 0;
 184.452 +      xprintf("Reading maximum flow problem data from `%s'...\n",
 184.453 +         fname);
 184.454 +      csa->fp = xfopen(fname, "r");
 184.455 +      if (csa->fp == NULL)
 184.456 +      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
 184.457 +         longjmp(csa->jump, 1);
 184.458 +      }
 184.459 +      /* read problem line */
 184.460 +      read_designator(csa);
 184.461 +      if (strcmp(csa->field, "p") != 0)
 184.462 +         error(csa, "problem line missing or invalid");
 184.463 +      read_field(csa);
 184.464 +      if (strcmp(csa->field, "max") != 0)
 184.465 +         error(csa, "wrong problem designator; `max' expected");
 184.466 +      read_field(csa);
 184.467 +      if (!(str2int(csa->field, &nv) == 0 && nv >= 2))
 184.468 +         error(csa, "number of nodes missing or invalid");
 184.469 +      read_field(csa);
 184.470 +      if (!(str2int(csa->field, &na) == 0 && na >= 0))
 184.471 +         error(csa, "number of arcs missing or invalid");
 184.472 +      xprintf("Flow network has %d node%s and %d arc%s\n",
 184.473 +         nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s");
 184.474 +      if (nv > 0) glp_add_vertices(G, nv);
 184.475 +      end_of_line(csa);
 184.476 +      /* read node descriptor lines */
 184.477 +      s = t = 0;
 184.478 +      for (;;)
 184.479 +      {  read_designator(csa);
 184.480 +         if (strcmp(csa->field, "n") != 0) break;
 184.481 +         read_field(csa);
 184.482 +         if (str2int(csa->field, &i) != 0)
 184.483 +            error(csa, "node number missing or invalid");
 184.484 +         if (!(1 <= i && i <= nv))
 184.485 +            error(csa, "node number %d out of range", i);
 184.486 +         read_field(csa);
 184.487 +         if (strcmp(csa->field, "s") == 0)
 184.488 +         {  if (s > 0)
 184.489 +               error(csa, "only one source node allowed");
 184.490 +            s = i;
 184.491 +         }
 184.492 +         else if (strcmp(csa->field, "t") == 0)
 184.493 +         {  if (t > 0)
 184.494 +               error(csa, "only one sink node allowed");
 184.495 +            t = i;
 184.496 +         }
 184.497 +         else
 184.498 +            error(csa, "wrong node designator; `s' or `t' expected");
 184.499 +         if (s > 0 && s == t)
 184.500 +            error(csa, "source and sink nodes must be distinct");
 184.501 +         end_of_line(csa);
 184.502 +      }
 184.503 +      if (s == 0)
 184.504 +         error(csa, "source node descriptor missing\n");
 184.505 +      if (t == 0)
 184.506 +         error(csa, "sink node descriptor missing\n");
 184.507 +      if (_s != NULL) *_s = s;
 184.508 +      if (_t != NULL) *_t = t;
 184.509 +      /* read arc descriptor lines */
 184.510 +      for (k = 1; k <= na; k++)
 184.511 +      {  if (k > 1) read_designator(csa);
 184.512 +         if (strcmp(csa->field, "a") != 0)
 184.513 +            error(csa, "wrong line designator; `a' expected");
 184.514 +         read_field(csa);
 184.515 +         if (str2int(csa->field, &i) != 0)
 184.516 +            error(csa, "starting node number missing or invalid");
 184.517 +         if (!(1 <= i && i <= nv))
 184.518 +            error(csa, "starting node number %d out of range", i);
 184.519 +         read_field(csa);
 184.520 +         if (str2int(csa->field, &j) != 0)
 184.521 +            error(csa, "ending node number missing or invalid");
 184.522 +         if (!(1 <= j && j <= nv))
 184.523 +            error(csa, "ending node number %d out of range", j);
 184.524 +         read_field(csa);
 184.525 +         if (!(str2num(csa->field, &cap) == 0 && cap >= 0.0))
 184.526 +            error(csa, "arc capacity missing or invalid");
 184.527 +         check_int(csa, cap);
 184.528 +         a = glp_add_arc(G, i, j);
 184.529 +         if (a_cap >= 0)
 184.530 +            memcpy((char *)a->data + a_cap, &cap, sizeof(double));
 184.531 +         end_of_line(csa);
 184.532 +      }
 184.533 +      xprintf("%d lines were read\n", csa->count);
 184.534 +done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
 184.535 +      if (csa->fp != NULL) xfclose(csa->fp);
 184.536 +      return ret;
 184.537 +}
 184.538 +
 184.539 +/***********************************************************************
 184.540 +*  NAME
 184.541 +*
 184.542 +*  glp_write_maxflow - write maximum flow problem data in DIMACS format
 184.543 +*
 184.544 +*  SYNOPSIS
 184.545 +*
 184.546 +*  int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap,
 184.547 +*     const char *fname);
 184.548 +*
 184.549 +*  DESCRIPTION
 184.550 +*
 184.551 +*  The routine glp_write_maxflow writes maximum flow problem data in
 184.552 +*  DIMACS format to a text file.
 184.553 +*
 184.554 +*  RETURNS
 184.555 +*
 184.556 +*  If the operation was successful, the routine returns zero. Otherwise
 184.557 +*  it prints an error message and returns non-zero. */
 184.558 +
 184.559 +int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap,
 184.560 +      const char *fname)
 184.561 +{     XFILE *fp;
 184.562 +      glp_vertex *v;
 184.563 +      glp_arc *a;
 184.564 +      int i, count = 0, ret;
 184.565 +      double cap;
 184.566 +      if (!(1 <= s && s <= G->nv))
 184.567 +         xerror("glp_write_maxflow: s = %d; source node number out of r"
 184.568 +            "ange\n", s);
 184.569 +      if (!(1 <= t && t <= G->nv))
 184.570 +         xerror("glp_write_maxflow: t = %d: sink node number out of ran"
 184.571 +            "ge\n", t);
 184.572 +      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
 184.573 +         xerror("glp_write_mincost: a_cap = %d; invalid offset\n",
 184.574 +            a_cap);
 184.575 +      xprintf("Writing maximum flow problem data to `%s'...\n",
 184.576 +         fname);
 184.577 +      fp = xfopen(fname, "w");
 184.578 +      if (fp == NULL)
 184.579 +      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
 184.580 +         ret = 1;
 184.581 +         goto done;
 184.582 +      }
 184.583 +      xfprintf(fp, "c %s\n",
 184.584 +         G->name == NULL ? "unknown" : G->name), count++;
 184.585 +      xfprintf(fp, "p max %d %d\n", G->nv, G->na), count++;
 184.586 +      xfprintf(fp, "n %d s\n", s), count++;
 184.587 +      xfprintf(fp, "n %d t\n", t), count++;
 184.588 +      for (i = 1; i <= G->nv; i++)
 184.589 +      {  v = G->v[i];
 184.590 +         for (a = v->out; a != NULL; a = a->t_next)
 184.591 +         {  if (a_cap >= 0)
 184.592 +               memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
 184.593 +            else
 184.594 +               cap = 1.0;
 184.595 +            xfprintf(fp, "a %d %d %.*g\n",
 184.596 +               a->tail->i, a->head->i, DBL_DIG, cap), count++;
 184.597 +         }
 184.598 +      }
 184.599 +      xfprintf(fp, "c eof\n"), count++;
 184.600 +      xfflush(fp);
 184.601 +      if (xferror(fp))
 184.602 +      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
 184.603 +         ret = 1;
 184.604 +         goto done;
 184.605 +      }
 184.606 +      xprintf("%d lines were written\n", count);
 184.607 +      ret = 0;
 184.608 +done: if (fp != NULL) xfclose(fp);
 184.609 +      return ret;
 184.610 +}
 184.611 +
 184.612 +/***********************************************************************
 184.613 +*  NAME
 184.614 +*
 184.615 +*  glp_read_asnprob - read assignment problem data in DIMACS format
 184.616 +*
 184.617 +*  SYNOPSIS
 184.618 +*
 184.619 +*  int glp_read_asnprob(glp_graph *G, int v_set, int a_cost,
 184.620 +*     const char *fname);
 184.621 +*
 184.622 +*  DESCRIPTION
 184.623 +*
 184.624 +*  The routine glp_read_asnprob reads assignment problem data in DIMACS
 184.625 +*  format from a text file.
 184.626 +*
 184.627 +*  RETURNS
 184.628 +*
 184.629 +*  If the operation was successful, the routine returns zero. Otherwise
 184.630 +*  it prints an error message and returns non-zero. */
 184.631 +
 184.632 +int glp_read_asnprob(glp_graph *G, int v_set, int a_cost, const char
 184.633 +      *fname)
 184.634 +{     struct csa _csa, *csa = &_csa;
 184.635 +      glp_vertex *v;
 184.636 +      glp_arc *a;
 184.637 +      int nv, na, n1, i, j, k, ret = 0;
 184.638 +      double cost;
 184.639 +      char *flag = NULL;
 184.640 +      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
 184.641 +         xerror("glp_read_asnprob: v_set = %d; invalid offset\n",
 184.642 +            v_set);
 184.643 +      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
 184.644 +         xerror("glp_read_asnprob: a_cost = %d; invalid offset\n",
 184.645 +            a_cost);
 184.646 +      glp_erase_graph(G, G->v_size, G->a_size);
 184.647 +      if (setjmp(csa->jump))
 184.648 +      {  ret = 1;
 184.649 +         goto done;
 184.650 +      }
 184.651 +      csa->fname = fname;
 184.652 +      csa->fp = NULL;
 184.653 +      csa->count = 0;
 184.654 +      csa->c = '\n';
 184.655 +      csa->field[0] = '\0';
 184.656 +      csa->empty = csa->nonint = 0;
 184.657 +      xprintf("Reading assignment problem data from `%s'...\n", fname);
 184.658 +      csa->fp = xfopen(fname, "r");
 184.659 +      if (csa->fp == NULL)
 184.660 +      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
 184.661 +         longjmp(csa->jump, 1);
 184.662 +      }
 184.663 +      /* read problem line */
 184.664 +      read_designator(csa);
 184.665 +      if (strcmp(csa->field, "p") != 0)
 184.666 +         error(csa, "problem line missing or invalid");
 184.667 +      read_field(csa);
 184.668 +      if (strcmp(csa->field, "asn") != 0)
 184.669 +         error(csa, "wrong problem designator; `asn' expected");
 184.670 +      read_field(csa);
 184.671 +      if (!(str2int(csa->field, &nv) == 0 && nv >= 0))
 184.672 +         error(csa, "number of nodes missing or invalid");
 184.673 +      read_field(csa);
 184.674 +      if (!(str2int(csa->field, &na) == 0 && na >= 0))
 184.675 +         error(csa, "number of arcs missing or invalid");
 184.676 +      if (nv > 0) glp_add_vertices(G, nv);
 184.677 +      end_of_line(csa);
 184.678 +      /* read node descriptor lines */
 184.679 +      flag = xcalloc(1+nv, sizeof(char));
 184.680 +      memset(&flag[1], 0, nv * sizeof(char));
 184.681 +      n1 = 0;
 184.682 +      for (;;)
 184.683 +      {  read_designator(csa);
 184.684 +         if (strcmp(csa->field, "n") != 0) break;
 184.685 +         read_field(csa);
 184.686 +         if (str2int(csa->field, &i) != 0)
 184.687 +            error(csa, "node number missing or invalid");
 184.688 +         if (!(1 <= i && i <= nv))
 184.689 +            error(csa, "node number %d out of range", i);
 184.690 +         if (flag[i])
 184.691 +            error(csa, "duplicate descriptor of node %d", i);
 184.692 +         flag[i] = 1, n1++;
 184.693 +         end_of_line(csa);
 184.694 +      }
 184.695 +      xprintf(
 184.696 +         "Assignment problem has %d + %d = %d node%s and %d arc%s\n",
 184.697 +         n1, nv - n1, nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s");
 184.698 +      if (v_set >= 0)
 184.699 +      {  for (i = 1; i <= nv; i++)
 184.700 +         {  v = G->v[i];
 184.701 +            k = (flag[i] ? 0 : 1);
 184.702 +            memcpy((char *)v->data + v_set, &k, sizeof(int));
 184.703 +         }
 184.704 +      }
 184.705 +      /* read arc descriptor lines */
 184.706 +      for (k = 1; k <= na; k++)
 184.707 +      {  if (k > 1) read_designator(csa);
 184.708 +         if (strcmp(csa->field, "a") != 0)
 184.709 +            error(csa, "wrong line designator; `a' expected");
 184.710 +         read_field(csa);
 184.711 +         if (str2int(csa->field, &i) != 0)
 184.712 +            error(csa, "starting node number missing or invalid");
 184.713 +         if (!(1 <= i && i <= nv))
 184.714 +            error(csa, "starting node number %d out of range", i);
 184.715 +         if (!flag[i])
 184.716 +            error(csa, "node %d cannot be a starting node", i);
 184.717 +         read_field(csa);
 184.718 +         if (str2int(csa->field, &j) != 0)
 184.719 +            error(csa, "ending node number missing or invalid");
 184.720 +         if (!(1 <= j && j <= nv))
 184.721 +            error(csa, "ending node number %d out of range", j);
 184.722 +         if (flag[j])
 184.723 +            error(csa, "node %d cannot be an ending node", j);
 184.724 +         read_field(csa);
 184.725 +         if (str2num(csa->field, &cost) != 0)
 184.726 +            error(csa, "arc cost missing or invalid");
 184.727 +         check_int(csa, cost);
 184.728 +         a = glp_add_arc(G, i, j);
 184.729 +         if (a_cost >= 0)
 184.730 +            memcpy((char *)a->data + a_cost, &cost, sizeof(double));
 184.731 +         end_of_line(csa);
 184.732 +      }
 184.733 +      xprintf("%d lines were read\n", csa->count);
 184.734 +done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
 184.735 +      if (csa->fp != NULL) xfclose(csa->fp);
 184.736 +      if (flag != NULL) xfree(flag);
 184.737 +      return ret;
 184.738 +}
 184.739 +
 184.740 +/***********************************************************************
 184.741 +*  NAME
 184.742 +*
 184.743 +*  glp_write_asnprob - write assignment problem data in DIMACS format
 184.744 +*
 184.745 +*  SYNOPSIS
 184.746 +*
 184.747 +*  int glp_write_asnprob(glp_graph *G, int v_set, int a_cost,
 184.748 +*     const char *fname);
 184.749 +*
 184.750 +*  DESCRIPTION
 184.751 +*
 184.752 +*  The routine glp_write_asnprob writes assignment problem data in
 184.753 +*  DIMACS format to a text file.
 184.754 +*
 184.755 +*  RETURNS
 184.756 +*
 184.757 +*  If the operation was successful, the routine returns zero. Otherwise
 184.758 +*  it prints an error message and returns non-zero. */
 184.759 +
 184.760 +int glp_write_asnprob(glp_graph *G, int v_set, int a_cost, const char
 184.761 +      *fname)
 184.762 +{     XFILE *fp;
 184.763 +      glp_vertex *v;
 184.764 +      glp_arc *a;
 184.765 +      int i, k, count = 0, ret;
 184.766 +      double cost;
 184.767 +      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
 184.768 +         xerror("glp_write_asnprob: v_set = %d; invalid offset\n",
 184.769 +            v_set);
 184.770 +      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
 184.771 +         xerror("glp_write_asnprob: a_cost = %d; invalid offset\n",
 184.772 +            a_cost);
 184.773 +      xprintf("Writing assignment problem data to `%s'...\n", fname);
 184.774 +      fp = xfopen(fname, "w");
 184.775 +      if (fp == NULL)
 184.776 +      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
 184.777 +         ret = 1;
 184.778 +         goto done;
 184.779 +      }
 184.780 +      xfprintf(fp, "c %s\n",
 184.781 +         G->name == NULL ? "unknown" : G->name), count++;
 184.782 +      xfprintf(fp, "p asn %d %d\n", G->nv, G->na), count++;
 184.783 +      for (i = 1; i <= G->nv; i++)
 184.784 +      {  v = G->v[i];
 184.785 +         if (v_set >= 0)
 184.786 +            memcpy(&k, (char *)v->data + v_set, sizeof(int));
 184.787 +         else
 184.788 +            k = (v->out != NULL ? 0 : 1);
 184.789 +         if (k == 0)
 184.790 +            xfprintf(fp, "n %d\n", i), count++;
 184.791 +      }
 184.792 +      for (i = 1; i <= G->nv; i++)
 184.793 +      {  v = G->v[i];
 184.794 +         for (a = v->out; a != NULL; a = a->t_next)
 184.795 +         {  if (a_cost >= 0)
 184.796 +               memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
 184.797 +            else
 184.798 +               cost = 1.0;
 184.799 +            xfprintf(fp, "a %d %d %.*g\n",
 184.800 +               a->tail->i, a->head->i, DBL_DIG, cost), count++;
 184.801 +         }
 184.802 +      }
 184.803 +      xfprintf(fp, "c eof\n"), count++;
 184.804 +      xfflush(fp);
 184.805 +      if (xferror(fp))
 184.806 +      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
 184.807 +         ret = 1;
 184.808 +         goto done;
 184.809 +      }
 184.810 +      xprintf("%d lines were written\n", count);
 184.811 +      ret = 0;
 184.812 +done: if (fp != NULL) xfclose(fp);
 184.813 +      return ret;
 184.814 +}
 184.815 +
 184.816 +/***********************************************************************
 184.817 +*  NAME
 184.818 +*
 184.819 +*  glp_read_ccdata - read graph in DIMACS clique/coloring format
 184.820 +*
 184.821 +*  SYNOPSIS
 184.822 +*
 184.823 +*  int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname);
 184.824 +*
 184.825 +*  DESCRIPTION
 184.826 +*
 184.827 +*  The routine glp_read_ccdata reads an (undirected) graph in DIMACS
 184.828 +*  clique/coloring format from a text file.
 184.829 +*
 184.830 +*  RETURNS
 184.831 +*
 184.832 +*  If the operation was successful, the routine returns zero. Otherwise
 184.833 +*  it prints an error message and returns non-zero. */
 184.834 +
 184.835 +int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname)
 184.836 +{     struct csa _csa, *csa = &_csa;
 184.837 +      glp_vertex *v;
 184.838 +      int i, j, k, nv, ne, ret = 0;
 184.839 +      double w;
 184.840 +      char *flag = NULL;
 184.841 +      if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double))
 184.842 +         xerror("glp_read_ccdata: v_wgt = %d; invalid offset\n",
 184.843 +            v_wgt);
 184.844 +      glp_erase_graph(G, G->v_size, G->a_size);
 184.845 +      if (setjmp(csa->jump))
 184.846 +      {  ret = 1;
 184.847 +         goto done;
 184.848 +      }
 184.849 +      csa->fname = fname;
 184.850 +      csa->fp = NULL;
 184.851 +      csa->count = 0;
 184.852 +      csa->c = '\n';
 184.853 +      csa->field[0] = '\0';
 184.854 +      csa->empty = csa->nonint = 0;
 184.855 +      xprintf("Reading graph from `%s'...\n", fname);
 184.856 +      csa->fp = xfopen(fname, "r");
 184.857 +      if (csa->fp == NULL)
 184.858 +      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
 184.859 +         longjmp(csa->jump, 1);
 184.860 +      }
 184.861 +      /* read problem line */
 184.862 +      read_designator(csa);
 184.863 +      if (strcmp(csa->field, "p") != 0)
 184.864 +         error(csa, "problem line missing or invalid");
 184.865 +      read_field(csa);
 184.866 +      if (strcmp(csa->field, "edge") != 0)
 184.867 +         error(csa, "wrong problem designator; `edge' expected");
 184.868 +      read_field(csa);
 184.869 +      if (!(str2int(csa->field, &nv) == 0 && nv >= 0))
 184.870 +         error(csa, "number of vertices missing or invalid");
 184.871 +      read_field(csa);
 184.872 +      if (!(str2int(csa->field, &ne) == 0 && ne >= 0))
 184.873 +         error(csa, "number of edges missing or invalid");
 184.874 +      xprintf("Graph has %d vert%s and %d edge%s\n",
 184.875 +         nv, nv == 1 ? "ex" : "ices", ne, ne == 1 ? "" : "s");
 184.876 +      if (nv > 0) glp_add_vertices(G, nv);
 184.877 +      end_of_line(csa);
 184.878 +      /* read node descriptor lines */
 184.879 +      flag = xcalloc(1+nv, sizeof(char));
 184.880 +      memset(&flag[1], 0, nv * sizeof(char));
 184.881 +      if (v_wgt >= 0)
 184.882 +      {  w = 1.0;
 184.883 +         for (i = 1; i <= nv; i++)
 184.884 +         {  v = G->v[i];
 184.885 +            memcpy((char *)v->data + v_wgt, &w, sizeof(double));
 184.886 +         }
 184.887 +      }
 184.888 +      for (;;)
 184.889 +      {  read_designator(csa);
 184.890 +         if (strcmp(csa->field, "n") != 0) break;
 184.891 +         read_field(csa);
 184.892 +         if (str2int(csa->field, &i) != 0)
 184.893 +            error(csa, "vertex number missing or invalid");
 184.894 +         if (!(1 <= i && i <= nv))
 184.895 +            error(csa, "vertex number %d out of range", i);
 184.896 +         if (flag[i])
 184.897 +            error(csa, "duplicate descriptor of vertex %d", i);
 184.898 +         read_field(csa);
 184.899 +         if (str2num(csa->field, &w) != 0)
 184.900 +            error(csa, "vertex weight missing or invalid");
 184.901 +         check_int(csa, w);
 184.902 +         if (v_wgt >= 0)
 184.903 +         {  v = G->v[i];
 184.904 +            memcpy((char *)v->data + v_wgt, &w, sizeof(double));
 184.905 +         }
 184.906 +         flag[i] = 1;
 184.907 +         end_of_line(csa);
 184.908 +      }
 184.909 +      xfree(flag), flag = NULL;
 184.910 +      /* read edge descriptor lines */
 184.911 +      for (k = 1; k <= ne; k++)
 184.912 +      {  if (k > 1) read_designator(csa);
 184.913 +         if (strcmp(csa->field, "e") != 0)
 184.914 +            error(csa, "wrong line designator; `e' expected");
 184.915 +         read_field(csa);
 184.916 +         if (str2int(csa->field, &i) != 0)
 184.917 +            error(csa, "first vertex number missing or invalid");
 184.918 +         if (!(1 <= i && i <= nv))
 184.919 +            error(csa, "first vertex number %d out of range", i);
 184.920 +         read_field(csa);
 184.921 +         if (str2int(csa->field, &j) != 0)
 184.922 +            error(csa, "second vertex number missing or invalid");
 184.923 +         if (!(1 <= j && j <= nv))
 184.924 +            error(csa, "second vertex number %d out of range", j);
 184.925 +         glp_add_arc(G, i, j);
 184.926 +         end_of_line(csa);
 184.927 +      }
 184.928 +      xprintf("%d lines were read\n", csa->count);
 184.929 +done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
 184.930 +      if (csa->fp != NULL) xfclose(csa->fp);
 184.931 +      if (flag != NULL) xfree(flag);
 184.932 +      return ret;
 184.933 +}
 184.934 +
 184.935 +/***********************************************************************
 184.936 +*  NAME
 184.937 +*
 184.938 +*  glp_write_ccdata - write graph in DIMACS clique/coloring format
 184.939 +*
 184.940 +*  SYNOPSIS
 184.941 +*
 184.942 +*  int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname);
 184.943 +*
 184.944 +*  DESCRIPTION
 184.945 +*
 184.946 +*  The routine glp_write_ccdata writes the specified graph in DIMACS
 184.947 +*  clique/coloring format to a text file.
 184.948 +*
 184.949 +*  RETURNS
 184.950 +*
 184.951 +*  If the operation was successful, the routine returns zero. Otherwise
 184.952 +*  it prints an error message and returns non-zero. */
 184.953 +
 184.954 +int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname)
 184.955 +{     XFILE *fp;
 184.956 +      glp_vertex *v;
 184.957 +      glp_arc *e;
 184.958 +      int i, count = 0, ret;
 184.959 +      double w;
 184.960 +      if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double))
 184.961 +         xerror("glp_write_ccdata: v_wgt = %d; invalid offset\n",
 184.962 +            v_wgt);
 184.963 +      xprintf("Writing graph to `%s'\n", fname);
 184.964 +      fp = xfopen(fname, "w");
 184.965 +      if (fp == NULL)
 184.966 +      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
 184.967 +         ret = 1;
 184.968 +         goto done;
 184.969 +      }
 184.970 +      xfprintf(fp, "c %s\n",
 184.971 +         G->name == NULL ? "unknown" : G->name), count++;
 184.972 +      xfprintf(fp, "p edge %d %d\n", G->nv, G->na), count++;
 184.973 +      if (v_wgt >= 0)
 184.974 +      {  for (i = 1; i <= G->nv; i++)
 184.975 +         {  v = G->v[i];
 184.976 +            memcpy(&w, (char *)v->data + v_wgt, sizeof(double));
 184.977 +            if (w != 1.0)
 184.978 +               xfprintf(fp, "n %d %.*g\n", i, DBL_DIG, w), count++;
 184.979 +         }
 184.980 +      }
 184.981 +      for (i = 1; i <= G->nv; i++)
 184.982 +      {  v = G->v[i];
 184.983 +         for (e = v->out; e != NULL; e = e->t_next)
 184.984 +            xfprintf(fp, "e %d %d\n", e->tail->i, e->head->i), count++;
 184.985 +      }
 184.986 +      xfprintf(fp, "c eof\n"), count++;
 184.987 +      xfflush(fp);
 184.988 +      if (xferror(fp))
 184.989 +      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
 184.990 +         ret = 1;
 184.991 +         goto done;
 184.992 +      }
 184.993 +      xprintf("%d lines were written\n", count);
 184.994 +      ret = 0;
 184.995 +done: if (fp != NULL) xfclose(fp);
 184.996 +      return ret;
 184.997 +}
 184.998 +
 184.999 +/***********************************************************************
184.1000 +*  NAME
184.1001 +*
184.1002 +*  glp_read_prob - read problem data in GLPK format
184.1003 +*
184.1004 +*  SYNOPSIS
184.1005 +*
184.1006 +*  int glp_read_prob(glp_prob *P, int flags, const char *fname);
184.1007 +*
184.1008 +*  The routine glp_read_prob reads problem data in GLPK LP/MIP format
184.1009 +*  from a text file.
184.1010 +*
184.1011 +*  RETURNS
184.1012 +*
184.1013 +*  If the operation was successful, the routine returns zero. Otherwise
184.1014 +*  it prints an error message and returns non-zero. */
184.1015 +
184.1016 +int glp_read_prob(glp_prob *P, int flags, const char *fname)
184.1017 +{     struct csa _csa, *csa = &_csa;
184.1018 +      int mip, m, n, nnz, ne, i, j, k, type, kind, ret, *ln = NULL,
184.1019 +         *ia = NULL, *ja = NULL;
184.1020 +      double lb, ub, temp, *ar = NULL;
184.1021 +      char *rf = NULL, *cf = NULL;
184.1022 +      if (P == NULL || P->magic != GLP_PROB_MAGIC)
184.1023 +         xerror("glp_read_prob: P = %p; invalid problem object\n",
184.1024 +            P);
184.1025 +      if (flags != 0)
184.1026 +         xerror("glp_read_prob: flags = %d; invalid parameter\n",
184.1027 +            flags);
184.1028 +      if (fname == NULL)
184.1029 +         xerror("glp_read_prob: fname = %d; invalid parameter\n",
184.1030 +            fname);
184.1031 +      glp_erase_prob(P);
184.1032 +      if (setjmp(csa->jump))
184.1033 +      {  ret = 1;
184.1034 +         goto done;
184.1035 +      }
184.1036 +      csa->fname = fname;
184.1037 +      csa->fp = NULL;
184.1038 +      csa->count = 0;
184.1039 +      csa->c = '\n';
184.1040 +      csa->field[0] = '\0';
184.1041 +      csa->empty = csa->nonint = 0;
184.1042 +      xprintf("Reading problem data from `%s'...\n", fname);
184.1043 +      csa->fp = xfopen(fname, "r");
184.1044 +      if (csa->fp == NULL)
184.1045 +      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
184.1046 +         longjmp(csa->jump, 1);
184.1047 +      }
184.1048 +      /* read problem line */
184.1049 +      read_designator(csa);
184.1050 +      if (strcmp(csa->field, "p") != 0)
184.1051 +         error(csa, "problem line missing or invalid");
184.1052 +      read_field(csa);
184.1053 +      if (strcmp(csa->field, "lp") == 0)
184.1054 +         mip = 0;
184.1055 +      else if (strcmp(csa->field, "mip") == 0)
184.1056 +         mip = 1;
184.1057 +      else
184.1058 +         error(csa, "wrong problem designator; `lp' or `mip' expected\n"
184.1059 +            );
184.1060 +      read_field(csa);
184.1061 +      if (strcmp(csa->field, "min") == 0)
184.1062 +         glp_set_obj_dir(P, GLP_MIN);
184.1063 +      else if (strcmp(csa->field, "max") == 0)
184.1064 +         glp_set_obj_dir(P, GLP_MAX);
184.1065 +      else
184.1066 +         error(csa, "objective sense missing or invalid");
184.1067 +      read_field(csa);
184.1068 +      if (!(str2int(csa->field, &m) == 0 && m >= 0))
184.1069 +         error(csa, "number of rows missing or invalid");
184.1070 +      read_field(csa);
184.1071 +      if (!(str2int(csa->field, &n) == 0 && n >= 0))
184.1072 +         error(csa, "number of columns missing or invalid");
184.1073 +      read_field(csa);
184.1074 +      if (!(str2int(csa->field, &nnz) == 0 && nnz >= 0))
184.1075 +         error(csa, "number of constraint coefficients missing or inval"
184.1076 +            "id");
184.1077 +      if (m > 0)
184.1078 +      {  glp_add_rows(P, m);
184.1079 +         for (i = 1; i <= m; i++)
184.1080 +            glp_set_row_bnds(P, i, GLP_FX, 0.0, 0.0);
184.1081 +      }
184.1082 +      if (n > 0)
184.1083 +      {  glp_add_cols(P, n);
184.1084 +         for (j = 1; j <= n; j++)
184.1085 +         {  if (!mip)
184.1086 +               glp_set_col_bnds(P, j, GLP_LO, 0.0, 0.0);
184.1087 +            else
184.1088 +               glp_set_col_kind(P, j, GLP_BV);
184.1089 +         }
184.1090 +      }
184.1091 +      end_of_line(csa);
184.1092 +      /* allocate working arrays */
184.1093 +      rf = xcalloc(1+m, sizeof(char));
184.1094 +      memset(rf, 0, 1+m);
184.1095 +      cf = xcalloc(1+n, sizeof(char));
184.1096 +      memset(cf, 0, 1+n);
184.1097 +      ln = xcalloc(1+nnz, sizeof(int));
184.1098 +      ia = xcalloc(1+nnz, sizeof(int));
184.1099 +      ja = xcalloc(1+nnz, sizeof(int));
184.1100 +      ar = xcalloc(1+nnz, sizeof(double));
184.1101 +      /* read descriptor lines */
184.1102 +      ne = 0;
184.1103 +      for (;;)
184.1104 +      {  read_designator(csa);
184.1105 +         if (strcmp(csa->field, "i") == 0)
184.1106 +         {  /* row descriptor */
184.1107 +            read_field(csa);
184.1108 +            if (str2int(csa->field, &i) != 0)
184.1109 +               error(csa, "row number missing or invalid");
184.1110 +            if (!(1 <= i && i <= m))
184.1111 +               error(csa, "row number out of range");
184.1112 +            read_field(csa);
184.1113 +            if (strcmp(csa->field, "f") == 0)
184.1114 +               type = GLP_FR;
184.1115 +            else if (strcmp(csa->field, "l") == 0)
184.1116 +               type = GLP_LO;
184.1117 +            else if (strcmp(csa->field, "u") == 0)
184.1118 +               type = GLP_UP;
184.1119 +            else if (strcmp(csa->field, "d") == 0)
184.1120 +               type = GLP_DB;
184.1121 +            else if (strcmp(csa->field, "s") == 0)
184.1122 +               type = GLP_FX;
184.1123 +            else
184.1124 +               error(csa, "row type missing or invalid");
184.1125 +            if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
184.1126 +            {  read_field(csa);
184.1127 +               if (str2num(csa->field, &lb) != 0)
184.1128 +                  error(csa, "row lower bound/fixed value missing or in"
184.1129 +                     "valid");
184.1130 +            }
184.1131 +            else
184.1132 +               lb = 0.0;
184.1133 +            if (type == GLP_UP || type == GLP_DB)
184.1134 +            {  read_field(csa);
184.1135 +               if (str2num(csa->field, &ub) != 0)
184.1136 +                  error(csa, "row upper bound missing or invalid");
184.1137 +            }
184.1138 +            else
184.1139 +               ub = 0.0;
184.1140 +            if (rf[i] & 0x01)
184.1141 +               error(csa, "duplicate row descriptor");
184.1142 +            glp_set_row_bnds(P, i, type, lb, ub), rf[i] |= 0x01;
184.1143 +         }
184.1144 +         else if (strcmp(csa->field, "j") == 0)
184.1145 +         {  /* column descriptor */
184.1146 +            read_field(csa);
184.1147 +            if (str2int(csa->field, &j) != 0)
184.1148 +               error(csa, "column number missing or invalid");
184.1149 +            if (!(1 <= j && j <= n))
184.1150 +               error(csa, "column number out of range");
184.1151 +            if (!mip)
184.1152 +               kind = GLP_CV;
184.1153 +            else
184.1154 +            {  read_field(csa);
184.1155 +               if (strcmp(csa->field, "c") == 0)
184.1156 +                  kind = GLP_CV;
184.1157 +               else if (strcmp(csa->field, "i") == 0)
184.1158 +                  kind = GLP_IV;
184.1159 +               else if (strcmp(csa->field, "b") == 0)
184.1160 +               {  kind = GLP_IV;
184.1161 +                  type = GLP_DB, lb = 0.0, ub = 1.0;
184.1162 +                  goto skip;
184.1163 +               }
184.1164 +               else
184.1165 +                  error(csa, "column kind missing or invalid");
184.1166 +            }
184.1167 +            read_field(csa);
184.1168 +            if (strcmp(csa->field, "f") == 0)
184.1169 +               type = GLP_FR;
184.1170 +            else if (strcmp(csa->field, "l") == 0)
184.1171 +               type = GLP_LO;
184.1172 +            else if (strcmp(csa->field, "u") == 0)
184.1173 +               type = GLP_UP;
184.1174 +            else if (strcmp(csa->field, "d") == 0)
184.1175 +               type = GLP_DB;
184.1176 +            else if (strcmp(csa->field, "s") == 0)
184.1177 +               type = GLP_FX;
184.1178 +            else
184.1179 +               error(csa, "column type missing or invalid");
184.1180 +            if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
184.1181 +            {  read_field(csa);
184.1182 +               if (str2num(csa->field, &lb) != 0)
184.1183 +                  error(csa, "column lower bound/fixed value missing or"
184.1184 +                     " invalid");
184.1185 +            }
184.1186 +            else
184.1187 +               lb = 0.0;
184.1188 +            if (type == GLP_UP || type == GLP_DB)
184.1189 +            {  read_field(csa);
184.1190 +               if (str2num(csa->field, &ub) != 0)
184.1191 +                  error(csa, "column upper bound missing or invalid");
184.1192 +            }
184.1193 +            else
184.1194 +               ub = 0.0;
184.1195 +skip:       if (cf[j] & 0x01)
184.1196 +               error(csa, "duplicate column descriptor");
184.1197 +            glp_set_col_kind(P, j, kind);
184.1198 +            glp_set_col_bnds(P, j, type, lb, ub), cf[j] |= 0x01;
184.1199 +         }
184.1200 +         else if (strcmp(csa->field, "a") == 0)
184.1201 +         {  /* coefficient descriptor */
184.1202 +            read_field(csa);
184.1203 +            if (str2int(csa->field, &i) != 0)
184.1204 +               error(csa, "row number missing or invalid");
184.1205 +            if (!(0 <= i && i <= m))
184.1206 +               error(csa, "row number out of range");
184.1207 +            read_field(csa);
184.1208 +            if (str2int(csa->field, &j) != 0)
184.1209 +               error(csa, "column number missing or invalid");
184.1210 +            if (!((i == 0 ? 0 : 1) <= j && j <= n))
184.1211 +               error(csa, "column number out of range");
184.1212 +            read_field(csa);
184.1213 +            if (i == 0)
184.1214 +            {  if (str2num(csa->field, &temp) != 0)
184.1215 +                  error(csa, "objective %s missing or invalid",
184.1216 +                     j == 0 ? "constant term" : "coefficient");
184.1217 +               if (cf[j] & 0x10)
184.1218 +                  error(csa, "duplicate objective %s",
184.1219 +                     j == 0 ? "constant term" : "coefficient");
184.1220 +               glp_set_obj_coef(P, j, temp), cf[j] |= 0x10;
184.1221 +            }
184.1222 +            else
184.1223 +            {  if (str2num(csa->field, &temp) != 0)
184.1224 +                  error(csa, "constraint coefficient missing or invalid"
184.1225 +                     );
184.1226 +               if (ne == nnz)
184.1227 +                  error(csa, "too many constraint coefficient descripto"
184.1228 +                     "rs");
184.1229 +               ln[++ne] = csa->count;
184.1230 +               ia[ne] = i, ja[ne] = j, ar[ne] = temp;
184.1231 +            }
184.1232 +         }
184.1233 +         else if (strcmp(csa->field, "n") == 0)
184.1234 +         {  /* symbolic name descriptor */
184.1235 +            read_field(csa);
184.1236 +            if (strcmp(csa->field, "p") == 0)
184.1237 +            {  /* problem name */
184.1238 +               read_field(csa);
184.1239 +               if (P->name != NULL)
184.1240 +                  error(csa, "duplicate problem name");
184.1241 +               glp_set_prob_name(P, csa->field);
184.1242 +            }
184.1243 +            else if (strcmp(csa->field, "z") == 0)
184.1244 +            {  /* objective name */
184.1245 +               read_field(csa);
184.1246 +               if (P->obj != NULL)
184.1247 +                  error(csa, "duplicate objective name");
184.1248 +               glp_set_obj_name(P, csa->field);
184.1249 +            }
184.1250 +            else if (strcmp(csa->field, "i") == 0)
184.1251 +            {  /* row name */
184.1252 +               read_field(csa);
184.1253 +               if (str2int(csa->field, &i) != 0)
184.1254 +                  error(csa, "row number missing or invalid");
184.1255 +               if (!(1 <= i && i <= m))
184.1256 +                  error(csa, "row number out of range");
184.1257 +               read_field(csa);
184.1258 +               if (P->row[i]->name != NULL)
184.1259 +                  error(csa, "duplicate row name");
184.1260 +               glp_set_row_name(P, i, csa->field);
184.1261 +            }
184.1262 +            else if (strcmp(csa->field, "j") == 0)
184.1263 +            {  /* column name */
184.1264 +               read_field(csa);
184.1265 +               if (str2int(csa->field, &j) != 0)
184.1266 +                  error(csa, "column number missing or invalid");
184.1267 +               if (!(1 <= j && j <= n))
184.1268 +                  error(csa, "column number out of range");
184.1269 +               read_field(csa);
184.1270 +               if (P->col[j]->name != NULL)
184.1271 +                  error(csa, "duplicate column name");
184.1272 +               glp_set_col_name(P, j, csa->field);
184.1273 +            }
184.1274 +            else
184.1275 +               error(csa, "object designator missing or invalid");
184.1276 +         }
184.1277 +         else if (strcmp(csa->field, "e") == 0)
184.1278 +            break;
184.1279 +         else
184.1280 +            error(csa, "line designator missing or invalid");
184.1281 +         end_of_line(csa);
184.1282 +      }
184.1283 +      if (ne < nnz)
184.1284 +         error(csa, "too few constraint coefficient descriptors");
184.1285 +      xassert(ne == nnz);
184.1286 +      k = glp_check_dup(m, n, ne, ia, ja);
184.1287 +      xassert(0 <= k && k <= nnz);
184.1288 +      if (k > 0)
184.1289 +      {  csa->count = ln[k];
184.1290 +         error(csa, "duplicate constraint coefficient");
184.1291 +      }
184.1292 +      glp_load_matrix(P, ne, ia, ja, ar);
184.1293 +      /* print some statistics */
184.1294 +      if (P->name != NULL)
184.1295 +         xprintf("Problem: %s\n", P->name);
184.1296 +      if (P->obj != NULL)
184.1297 +         xprintf("Objective: %s\n", P->obj);
184.1298 +      xprintf("%d row%s, %d column%s, %d non-zero%s\n",
184.1299 +         m, m == 1 ? "" : "s", n, n == 1 ? "" : "s", nnz, nnz == 1 ?
184.1300 +         "" : "s");
184.1301 +      if (glp_get_num_int(P) > 0)
184.1302 +      {  int ni = glp_get_num_int(P);
184.1303 +         int nb = glp_get_num_bin(P);
184.1304 +         if (ni == 1)
184.1305 +         {  if (nb == 0)
184.1306 +               xprintf("One variable is integer\n");
184.1307 +            else
184.1308 +               xprintf("One variable is binary\n");
184.1309 +         }
184.1310 +         else
184.1311 +         {  xprintf("%d integer variables, ", ni);
184.1312 +            if (nb == 0)
184.1313 +               xprintf("none");
184.1314 +            else if (nb == 1)
184.1315 +               xprintf("one");
184.1316 +            else if (nb == ni)
184.1317 +               xprintf("all");
184.1318 +            else
184.1319 +               xprintf("%d", nb);
184.1320 +            xprintf(" of which %s binary\n", nb == 1 ? "is" : "are");
184.1321 +         }
184.1322 +      }
184.1323 +      xprintf("%d lines were read\n", csa->count);
184.1324 +      /* problem data has been successfully read */
184.1325 +      glp_sort_matrix(P);
184.1326 +      ret = 0;
184.1327 +done: if (csa->fp != NULL) xfclose(csa->fp);
184.1328 +      if (rf != NULL) xfree(rf);
184.1329 +      if (cf != NULL) xfree(cf);
184.1330 +      if (ln != NULL) xfree(ln);
184.1331 +      if (ia != NULL) xfree(ia);
184.1332 +      if (ja != NULL) xfree(ja);
184.1333 +      if (ar != NULL) xfree(ar);
184.1334 +      if (ret) glp_erase_prob(P);
184.1335 +      return ret;
184.1336 +}
184.1337 +
184.1338 +/***********************************************************************
184.1339 +*  NAME
184.1340 +*
184.1341 +*  glp_write_prob - write problem data in GLPK format
184.1342 +*
184.1343 +*  SYNOPSIS
184.1344 +*
184.1345 +*  int glp_write_prob(glp_prob *P, int flags, const char *fname);
184.1346 +*
184.1347 +*  The routine glp_write_prob writes problem data in GLPK LP/MIP format
184.1348 +*  to a text file.
184.1349 +*
184.1350 +*  RETURNS
184.1351 +*
184.1352 +*  If the operation was successful, the routine returns zero. Otherwise
184.1353 +*  it prints an error message and returns non-zero. */
184.1354 +
184.1355 +int glp_write_prob(glp_prob *P, int flags, const char *fname)
184.1356 +{     XFILE *fp;
184.1357 +      GLPROW *row;
184.1358 +      GLPCOL *col;
184.1359 +      GLPAIJ *aij;
184.1360 +      int mip, i, j, count, ret;
184.1361 +      if (P == NULL || P->magic != GLP_PROB_MAGIC)
184.1362 +         xerror("glp_write_prob: P = %p; invalid problem object\n",
184.1363 +            P);
184.1364 +      if (flags != 0)
184.1365 +         xerror("glp_write_prob: flags = %d; invalid parameter\n",
184.1366 +            flags);
184.1367 +      if (fname == NULL)
184.1368 +         xerror("glp_write_prob: fname = %d; invalid parameter\n",
184.1369 +            fname);
184.1370 +      xprintf("Writing problem data to `%s'...\n", fname);
184.1371 +      fp = xfopen(fname, "w"), count = 0;
184.1372 +      if (fp == NULL)
184.1373 +      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
184.1374 +         ret = 1;
184.1375 +         goto done;
184.1376 +      }
184.1377 +      /* write problem line */
184.1378 +      mip = (glp_get_num_int(P) > 0);
184.1379 +      xfprintf(fp, "p %s %s %d %d %d\n", !mip ? "lp" : "mip",
184.1380 +         P->dir == GLP_MIN ? "min" : P->dir == GLP_MAX ? "max" : "???",
184.1381 +         P->m, P->n, P->nnz), count++;
184.1382 +      if (P->name != NULL)
184.1383 +         xfprintf(fp, "n p %s\n", P->name), count++;
184.1384 +      if (P->obj != NULL)
184.1385 +         xfprintf(fp, "n z %s\n", P->obj), count++;
184.1386 +      /* write row descriptors */
184.1387 +      for (i = 1; i <= P->m; i++)
184.1388 +      {  row = P->row[i];
184.1389 +         if (row->type == GLP_FX && row->lb == 0.0)
184.1390 +            goto skip1;
184.1391 +         xfprintf(fp, "i %d ", i), count++;
184.1392 +         if (row->type == GLP_FR)
184.1393 +            xfprintf(fp, "f\n");
184.1394 +         else if (row->type == GLP_LO)
184.1395 +            xfprintf(fp, "l %.*g\n", DBL_DIG, row->lb);
184.1396 +         else if (row->type == GLP_UP)
184.1397 +            xfprintf(fp, "u %.*g\n", DBL_DIG, row->ub);
184.1398 +         else if (row->type == GLP_DB)
184.1399 +            xfprintf(fp, "d %.*g %.*g\n", DBL_DIG, row->lb, DBL_DIG,
184.1400 +                  row->ub);
184.1401 +         else if (row->type == GLP_FX)
184.1402 +            xfprintf(fp, "s %.*g\n", DBL_DIG, row->lb);
184.1403 +         else
184.1404 +            xassert(row != row);
184.1405 +skip1:   if (row->name != NULL)
184.1406 +            xfprintf(fp, "n i %d %s\n", i, row->name), count++;
184.1407 +      }
184.1408 +      /* write column descriptors */
184.1409 +      for (j = 1; j <= P->n; j++)
184.1410 +      {  col = P->col[j];
184.1411 +         if (!mip && col->type == GLP_LO && col->lb == 0.0)
184.1412 +            goto skip2;
184.1413 +         if (mip && col->kind == GLP_IV && col->type == GLP_DB &&
184.1414 +             col->lb == 0.0 && col->ub == 1.0)
184.1415 +            goto skip2;
184.1416 +         xfprintf(fp, "j %d ", j), count++;
184.1417 +         if (mip)
184.1418 +         {  if (col->kind == GLP_CV)
184.1419 +               xfprintf(fp, "c ");
184.1420 +            else if (col->kind == GLP_IV)
184.1421 +               xfprintf(fp, "i ");
184.1422 +            else
184.1423 +               xassert(col != col);
184.1424 +         }
184.1425 +         if (col->type == GLP_FR)
184.1426 +            xfprintf(fp, "f\n");
184.1427 +         else if (col->type == GLP_LO)
184.1428 +            xfprintf(fp, "l %.*g\n", DBL_DIG, col->lb);
184.1429 +         else if (col->type == GLP_UP)
184.1430 +            xfprintf(fp, "u %.*g\n", DBL_DIG, col->ub);
184.1431 +         else if (col->type == GLP_DB)
184.1432 +            xfprintf(fp, "d %.*g %.*g\n", DBL_DIG, col->lb, DBL_DIG,
184.1433 +                  col->ub);
184.1434 +         else if (col->type == GLP_FX)
184.1435 +            xfprintf(fp, "s %.*g\n", DBL_DIG, col->lb);
184.1436 +         else
184.1437 +            xassert(col != col);
184.1438 +skip2:   if (col->name != NULL)
184.1439 +            xfprintf(fp, "n j %d %s\n", j, col->name), count++;
184.1440 +      }
184.1441 +      /* write objective coefficient descriptors */
184.1442 +      if (P->c0 != 0.0)
184.1443 +         xfprintf(fp, "a 0 0 %.*g\n", DBL_DIG, P->c0), count++;
184.1444 +      for (j = 1; j <= P->n; j++)
184.1445 +      {  col = P->col[j];
184.1446 +         if (col->coef != 0.0)
184.1447 +            xfprintf(fp, "a 0 %d %.*g\n", j, DBL_DIG, col->coef),
184.1448 +               count++;
184.1449 +      }
184.1450 +      /* write constraint coefficient descriptors */
184.1451 +      for (i = 1; i <= P->m; i++)
184.1452 +      {  row = P->row[i];
184.1453 +         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
184.1454 +            xfprintf(fp, "a %d %d %.*g\n", i, aij->col->j, DBL_DIG,
184.1455 +               aij->val), count++;
184.1456 +      }
184.1457 +      /* write end line */
184.1458 +      xfprintf(fp, "e o f\n"), count++;
184.1459 +      xfflush(fp);
184.1460 +      if (xferror(fp))
184.1461 +      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
184.1462 +         ret = 1;
184.1463 +         goto done;
184.1464 +      }
184.1465 +      xprintf("%d lines were written\n", count);
184.1466 +      ret = 0;
184.1467 +done: if (fp != NULL) xfclose(fp);
184.1468 +      return ret;
184.1469 +}
184.1470 +
184.1471 +/* eof */
   185.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   185.2 +++ b/src/glpenv.h	Mon Dec 06 13:09:21 2010 +0100
   185.3 @@ -0,0 +1,228 @@
   185.4 +/* glpenv.h (GLPK environment) */
   185.5 +
   185.6 +/***********************************************************************
   185.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   185.8 +*
   185.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  185.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  185.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  185.12 +*  E-mail: <mao@gnu.org>.
  185.13 +*
  185.14 +*  GLPK is free software: you can redistribute it and/or modify it
  185.15 +*  under the terms of the GNU General Public License as published by
  185.16 +*  the Free Software Foundation, either version 3 of the License, or
  185.17 +*  (at your option) any later version.
  185.18 +*
  185.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  185.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  185.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  185.22 +*  License for more details.
  185.23 +*
  185.24 +*  You should have received a copy of the GNU General Public License
  185.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  185.26 +***********************************************************************/
  185.27 +
  185.28 +#ifndef GLPENV_H
  185.29 +#define GLPENV_H
  185.30 +
  185.31 +#include "glpstd.h"
  185.32 +#include "glplib.h"
  185.33 +
  185.34 +typedef struct ENV ENV;
  185.35 +typedef struct MEM MEM;
  185.36 +typedef struct XFILE XFILE;
  185.37 +
  185.38 +#define ENV_MAGIC 0x454E5631
  185.39 +/* environment block magic value */
  185.40 +
  185.41 +#define TERM_BUF_SIZE 4096
  185.42 +/* terminal output buffer size, in bytes */
  185.43 +
  185.44 +#define IOERR_MSG_SIZE 1024
  185.45 +/* i/o error message buffer size, in bytes */
  185.46 +
  185.47 +#define MEM_MAGIC 0x4D454D31
  185.48 +/* memory block descriptor magic value */
  185.49 +
  185.50 +struct ENV
  185.51 +{     /* environment block */
  185.52 +      int magic;
  185.53 +      /* magic value used for debugging */
  185.54 +      char version[7+1];
  185.55 +      /* version string returned by the routine glp_version */
  185.56 +      /*--------------------------------------------------------------*/
  185.57 +      /* terminal output */
  185.58 +      char *term_buf; /* char term_buf[TERM_BUF_SIZE]; */
  185.59 +      /* terminal output buffer */
  185.60 +      int term_out;
  185.61 +      /* flag to enable/disable terminal output */
  185.62 +      int (*term_hook)(void *info, const char *s);
  185.63 +      /* user-defined routine to intercept terminal output */
  185.64 +      void *term_info;
  185.65 +      /* transit pointer (cookie) passed to the routine term_hook */
  185.66 +      FILE *tee_file;
  185.67 +      /* output stream used to copy terminal output */
  185.68 +      /*--------------------------------------------------------------*/
  185.69 +      /* error handling */
  185.70 +      const char *err_file;
  185.71 +      /* value of the __FILE__ macro passed to glp_error */
  185.72 +      int err_line;
  185.73 +      /* value of the __LINE__ macro passed to glp_error */
  185.74 +      void (*err_hook)(void *info);
  185.75 +      /* user-defined routine to intercept abnormal termination */
  185.76 +      void *err_info;
  185.77 +      /* transit pointer (cookie) passed to the routine err_hook */
  185.78 +      /*--------------------------------------------------------------*/
  185.79 +      /* memory allocation */
  185.80 +      glp_long mem_limit;
  185.81 +      /* maximal amount of memory (in bytes) available for dynamic
  185.82 +         allocation */
  185.83 +      MEM *mem_ptr;
  185.84 +      /* pointer to the linked list of allocated memory blocks */
  185.85 +      int mem_count;
  185.86 +      /* total number of currently allocated memory blocks */
  185.87 +      int mem_cpeak;
  185.88 +      /* peak value of mem_count */
  185.89 +      glp_long mem_total;
  185.90 +      /* total amount of currently allocated memory (in bytes; is the
  185.91 +         sum of the size field over all memory block descriptors) */
  185.92 +      glp_long mem_tpeak;
  185.93 +      /* peak value of mem_total */
  185.94 +      /*--------------------------------------------------------------*/
  185.95 +      /* stream input/output */
  185.96 +      XFILE *file_ptr;
  185.97 +      /* pointer to the linked list of active stream descriptors */
  185.98 +      char *ioerr_msg; /* char ioerr_msg[IOERR_MSG_SIZE]; */
  185.99 +      /* input/output error message buffer */
 185.100 +      /*--------------------------------------------------------------*/
 185.101 +      /* shared libraries support */
 185.102 +      void *h_odbc;
 185.103 +      /* handle to ODBC shared library */
 185.104 +      void *h_mysql;
 185.105 +      /* handle to MySQL shared library */
 185.106 +};
 185.107 +
 185.108 +struct MEM
 185.109 +{     /* memory block descriptor */
 185.110 +      int flag;
 185.111 +      /* descriptor flag */
 185.112 +      int size;
 185.113 +      /* size of block (in bytes, including descriptor) */
 185.114 +      MEM *prev;
 185.115 +      /* pointer to previous memory block descriptor */
 185.116 +      MEM *next;
 185.117 +      /* pointer to next memory block descriptor */
 185.118 +};
 185.119 +
 185.120 +struct XFILE
 185.121 +{     /* input/output stream descriptor */
 185.122 +      int type;
 185.123 +      /* stream handle type: */
 185.124 +#define FH_FILE   0x11  /* FILE   */
 185.125 +#define FH_ZLIB   0x22  /* gzFile */
 185.126 +      void *fh;
 185.127 +      /* pointer to stream handle */
 185.128 +      XFILE *prev;
 185.129 +      /* pointer to previous stream descriptor */
 185.130 +      XFILE *next;
 185.131 +      /* pointer to next stream descriptor */
 185.132 +};
 185.133 +
 185.134 +#define XEOF (-1)
 185.135 +
 185.136 +#define get_env_ptr _glp_get_env_ptr
 185.137 +ENV *get_env_ptr(void);
 185.138 +/* retrieve pointer to environment block */
 185.139 +
 185.140 +#define tls_set_ptr _glp_tls_set_ptr
 185.141 +void tls_set_ptr(void *ptr);
 185.142 +/* store global pointer in TLS */
 185.143 +
 185.144 +#define tls_get_ptr _glp_tls_get_ptr
 185.145 +void *tls_get_ptr(void);
 185.146 +/* retrieve global pointer from TLS */
 185.147 +
 185.148 +#define xprintf glp_printf
 185.149 +void glp_printf(const char *fmt, ...);
 185.150 +/* write formatted output to the terminal */
 185.151 +
 185.152 +#define xvprintf glp_vprintf
 185.153 +void glp_vprintf(const char *fmt, va_list arg);
 185.154 +/* write formatted output to the terminal */
 185.155 +
 185.156 +#ifndef GLP_ERROR_DEFINED
 185.157 +#define GLP_ERROR_DEFINED
 185.158 +typedef void (*_glp_error)(const char *fmt, ...);
 185.159 +#endif
 185.160 +
 185.161 +#define xerror glp_error_(__FILE__, __LINE__)
 185.162 +_glp_error glp_error_(const char *file, int line);
 185.163 +/* display error message and terminate execution */
 185.164 +
 185.165 +#define xassert(expr) \
 185.166 +      ((void)((expr) || (glp_assert_(#expr, __FILE__, __LINE__), 1)))
 185.167 +void glp_assert_(const char *expr, const char *file, int line);
 185.168 +/* check for logical condition */
 185.169 +
 185.170 +#define xmalloc glp_malloc
 185.171 +void *glp_malloc(int size);
 185.172 +/* allocate memory block */
 185.173 +
 185.174 +#define xcalloc glp_calloc
 185.175 +void *glp_calloc(int n, int size);
 185.176 +/* allocate memory block */
 185.177 +
 185.178 +#define xfree glp_free
 185.179 +void glp_free(void *ptr);
 185.180 +/* free memory block */
 185.181 +
 185.182 +#define xtime glp_time
 185.183 +glp_long glp_time(void);
 185.184 +/* determine current universal time */
 185.185 +
 185.186 +#define xdifftime glp_difftime
 185.187 +double glp_difftime(glp_long t1, glp_long t0);
 185.188 +/* compute difference between two time values, in seconds */
 185.189 +
 185.190 +#define lib_err_msg _glp_lib_err_msg
 185.191 +void lib_err_msg(const char *msg);
 185.192 +
 185.193 +#define xerrmsg _glp_lib_xerrmsg
 185.194 +const char *xerrmsg(void);
 185.195 +
 185.196 +#define xfopen _glp_lib_xfopen
 185.197 +XFILE *xfopen(const char *fname, const char *mode);
 185.198 +
 185.199 +#define xferror _glp_lib_xferror
 185.200 +int xferror(XFILE *file);
 185.201 +
 185.202 +#define xfeof _glp_lib_xfeof
 185.203 +int xfeof(XFILE *file);
 185.204 +
 185.205 +#define xfgetc _glp_lib_xfgetc
 185.206 +int xfgetc(XFILE *file);
 185.207 +
 185.208 +#define xfputc _glp_lib_xfputc
 185.209 +int xfputc(int c, XFILE *file);
 185.210 +
 185.211 +#define xfflush _glp_lib_xfflush
 185.212 +int xfflush(XFILE *fp);
 185.213 +
 185.214 +#define xfclose _glp_lib_xfclose
 185.215 +int xfclose(XFILE *file);
 185.216 +
 185.217 +#define xfprintf _glp_lib_xfprintf
 185.218 +int xfprintf(XFILE *file, const char *fmt, ...);
 185.219 +
 185.220 +#define xdlopen _glp_xdlopen
 185.221 +void *xdlopen(const char *module);
 185.222 +
 185.223 +#define xdlsym _glp_xdlsym
 185.224 +void *xdlsym(void *h, const char *symbol);
 185.225 +
 185.226 +#define xdlclose _glp_xdlclose
 185.227 +void xdlclose(void *h);
 185.228 +
 185.229 +#endif
 185.230 +
 185.231 +/* eof */
   186.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   186.2 +++ b/src/glpenv01.c	Mon Dec 06 13:09:21 2010 +0100
   186.3 @@ -0,0 +1,233 @@
   186.4 +/* glpenv01.c (environment initialization/termination) */
   186.5 +
   186.6 +/***********************************************************************
   186.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   186.8 +*
   186.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  186.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  186.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  186.12 +*  E-mail: <mao@gnu.org>.
  186.13 +*
  186.14 +*  GLPK is free software: you can redistribute it and/or modify it
  186.15 +*  under the terms of the GNU General Public License as published by
  186.16 +*  the Free Software Foundation, either version 3 of the License, or
  186.17 +*  (at your option) any later version.
  186.18 +*
  186.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  186.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  186.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  186.22 +*  License for more details.
  186.23 +*
  186.24 +*  You should have received a copy of the GNU General Public License
  186.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  186.26 +***********************************************************************/
  186.27 +
  186.28 +#include "glpapi.h"
  186.29 +
  186.30 +/***********************************************************************
  186.31 +*  NAME
  186.32 +*
  186.33 +*  glp_init_env - initialize GLPK environment
  186.34 +*
  186.35 +*  SYNOPSIS
  186.36 +*
  186.37 +*  int glp_init_env(void);
  186.38 +*
  186.39 +*  DESCRIPTION
  186.40 +*
  186.41 +*  The routine glp_init_env initializes the GLPK environment. Normally
  186.42 +*  the application program does not need to call this routine, because
  186.43 +*  it is called automatically on the first call to any API routine.
  186.44 +*
  186.45 +*  RETURNS
  186.46 +*
  186.47 +*  The routine glp_init_env returns one of the following codes:
  186.48 +*
  186.49 +*  0 - initialization successful;
  186.50 +*  1 - environment has been already initialized;
  186.51 +*  2 - initialization failed (insufficient memory);
  186.52 +*  3 - initialization failed (unsupported programming model). */
  186.53 +
  186.54 +int glp_init_env(void)
  186.55 +{     ENV *env;
  186.56 +      int ok;
  186.57 +      /* check if the programming model is supported */
  186.58 +      ok = (CHAR_BIT == 8 && sizeof(char) == 1 &&
  186.59 +         sizeof(short) == 2 && sizeof(int) == 4 &&
  186.60 +         (sizeof(void *) == 4 || sizeof(void *) == 8));
  186.61 +      if (!ok) return 3;
  186.62 +      /* check if the environment is already initialized */
  186.63 +      if (tls_get_ptr() != NULL) return 1;
  186.64 +      /* allocate and initialize the environment block */
  186.65 +      env = malloc(sizeof(ENV));
  186.66 +      if (env == NULL) return 2;
  186.67 +      env->magic = ENV_MAGIC;
  186.68 +      sprintf(env->version, "%d.%d",
  186.69 +         GLP_MAJOR_VERSION, GLP_MINOR_VERSION);
  186.70 +      env->term_buf = malloc(TERM_BUF_SIZE);
  186.71 +      if (env->term_buf == NULL)
  186.72 +      {  free(env);
  186.73 +         return 2;
  186.74 +      }
  186.75 +      env->term_out = GLP_ON;
  186.76 +      env->term_hook = NULL;
  186.77 +      env->term_info = NULL;
  186.78 +      env->tee_file = NULL;
  186.79 +      env->err_file = "";
  186.80 +      env->err_line = 0;
  186.81 +      env->err_hook = NULL;
  186.82 +      env->err_info = NULL;
  186.83 +      env->mem_limit.hi = 0x7FFFFFFF, env->mem_limit.lo = 0xFFFFFFFF;
  186.84 +      env->mem_ptr = NULL;
  186.85 +      env->mem_count = env->mem_cpeak = 0;
  186.86 +      env->mem_total = env->mem_tpeak = xlset(0);
  186.87 +      env->file_ptr = NULL;
  186.88 +      env->ioerr_msg = malloc(IOERR_MSG_SIZE);
  186.89 +      if (env->ioerr_msg == NULL)
  186.90 +      {  free(env->term_buf);
  186.91 +         free(env);
  186.92 +         return 2;
  186.93 +      }
  186.94 +      strcpy(env->ioerr_msg, "No error");
  186.95 +      env->h_odbc = env->h_mysql = NULL;
  186.96 +      /* save pointer to the environment block */
  186.97 +      tls_set_ptr(env);
  186.98 +      /* initialization successful */
  186.99 +      return 0;
 186.100 +}
 186.101 +
 186.102 +/***********************************************************************
 186.103 +*  NAME
 186.104 +*
 186.105 +*  get_env_ptr - retrieve pointer to environment block
 186.106 +*
 186.107 +*  SYNOPSIS
 186.108 +*
 186.109 +*  #include "glpenv.h"
 186.110 +*  ENV *get_env_ptr(void);
 186.111 +*
 186.112 +*  DESCRIPTION
 186.113 +*
 186.114 +*  The routine get_env_ptr retrieves and returns a pointer to the GLPK
 186.115 +*  environment block.
 186.116 +*
 186.117 +*  If the GLPK environment has not been initialized yet, the routine
 186.118 +*  performs initialization. If initialization fails, the routine prints
 186.119 +*  an error message to stderr and terminates the program.
 186.120 +*
 186.121 +*  RETURNS
 186.122 +*
 186.123 +*  The routine returns a pointer to the environment block. */
 186.124 +
 186.125 +ENV *get_env_ptr(void)
 186.126 +{     ENV *env = tls_get_ptr();
 186.127 +      /* check if the environment has been initialized */
 186.128 +      if (env == NULL)
 186.129 +      {  /* not initialized yet; perform initialization */
 186.130 +         if (glp_init_env() != 0)
 186.131 +         {  /* initialization failed; display an error message */
 186.132 +            fprintf(stderr, "GLPK initialization failed\n");
 186.133 +            fflush(stderr);
 186.134 +            /* and abnormally terminate the program */
 186.135 +            abort();
 186.136 +         }
 186.137 +         /* initialization successful; retrieve the pointer */
 186.138 +         env = tls_get_ptr();
 186.139 +      }
 186.140 +      /* check if the environment block is valid */
 186.141 +      if (env->magic != ENV_MAGIC)
 186.142 +      {  fprintf(stderr, "Invalid GLPK environment\n");
 186.143 +         fflush(stderr);
 186.144 +         abort();
 186.145 +      }
 186.146 +      return env;
 186.147 +}
 186.148 +
 186.149 +/***********************************************************************
 186.150 +*  NAME
 186.151 +*
 186.152 +*  glp_version - determine library version
 186.153 +*
 186.154 +*  SYNOPSIS
 186.155 +*
 186.156 +*  const char *glp_version(void);
 186.157 +*
 186.158 +*  RETURNS
 186.159 +*
 186.160 +*  The routine glp_version returns a pointer to a null-terminated
 186.161 +*  character string, which specifies the version of the GLPK library in
 186.162 +*  the form "X.Y", where X is the major version number, and Y is the
 186.163 +*  minor version number, for example, "4.16". */
 186.164 +
 186.165 +const char *glp_version(void)
 186.166 +{     ENV *env = get_env_ptr();
 186.167 +      return env->version;
 186.168 +}
 186.169 +
 186.170 +/***********************************************************************
 186.171 +*  NAME
 186.172 +*
 186.173 +*  glp_free_env - free GLPK environment
 186.174 +*
 186.175 +*  SYNOPSIS
 186.176 +*
 186.177 +*  int glp_free_env(void);
 186.178 +*
 186.179 +*  DESCRIPTION
 186.180 +*
 186.181 +*  The routine glp_free_env frees all resources used by GLPK routines
 186.182 +*  (memory blocks, etc.) which are currently still in use.
 186.183 +*
 186.184 +*  Normally the application program does not need to call this routine,
 186.185 +*  because GLPK routines always free all unused resources. However, if
 186.186 +*  the application program even has deleted all problem objects, there
 186.187 +*  will be several memory blocks still allocated for the library needs.
 186.188 +*  For some reasons the application program may want GLPK to free this
 186.189 +*  memory, in which case it should call glp_free_env.
 186.190 +*
 186.191 +*  Note that a call to glp_free_env invalidates all problem objects as
 186.192 +*  if no GLPK routine were called.
 186.193 +*
 186.194 +*  RETURNS
 186.195 +*
 186.196 +*  0 - termination successful;
 186.197 +*  1 - environment is inactive (was not initialized). */
 186.198 +
 186.199 +int glp_free_env(void)
 186.200 +{     ENV *env = tls_get_ptr();
 186.201 +      MEM *desc;
 186.202 +      /* check if the environment is active */
 186.203 +      if (env == NULL) return 1;
 186.204 +      /* check if the environment block is valid */
 186.205 +      if (env->magic != ENV_MAGIC)
 186.206 +      {  fprintf(stderr, "Invalid GLPK environment\n");
 186.207 +         fflush(stderr);
 186.208 +         abort();
 186.209 +      }
 186.210 +      /* close handles to shared libraries */
 186.211 +      if (env->h_odbc != NULL)
 186.212 +         xdlclose(env->h_odbc);
 186.213 +      if (env->h_mysql != NULL)
 186.214 +         xdlclose(env->h_mysql);
 186.215 +      /* close streams which are still open */
 186.216 +      while (env->file_ptr != NULL)
 186.217 +         xfclose(env->file_ptr);
 186.218 +      /* free memory blocks which are still allocated */
 186.219 +      while (env->mem_ptr != NULL)
 186.220 +      {  desc = env->mem_ptr;
 186.221 +         env->mem_ptr = desc->next;
 186.222 +         free(desc);
 186.223 +      }
 186.224 +      /* invalidate the environment block */
 186.225 +      env->magic = -1;
 186.226 +      /* free memory allocated to the environment block */
 186.227 +      free(env->term_buf);
 186.228 +      free(env->ioerr_msg);
 186.229 +      free(env);
 186.230 +      /* reset a pointer to the environment block */
 186.231 +      tls_set_ptr(NULL);
 186.232 +      /* termination successful */
 186.233 +      return 0;
 186.234 +}
 186.235 +
 186.236 +/* eof */
   187.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   187.2 +++ b/src/glpenv02.c	Mon Dec 06 13:09:21 2010 +0100
   187.3 @@ -0,0 +1,73 @@
   187.4 +/* glpenv02.c (thread local storage) */
   187.5 +
   187.6 +/***********************************************************************
   187.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   187.8 +*
   187.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  187.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  187.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  187.12 +*  E-mail: <mao@gnu.org>.
  187.13 +*
  187.14 +*  GLPK is free software: you can redistribute it and/or modify it
  187.15 +*  under the terms of the GNU General Public License as published by
  187.16 +*  the Free Software Foundation, either version 3 of the License, or
  187.17 +*  (at your option) any later version.
  187.18 +*
  187.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  187.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  187.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  187.22 +*  License for more details.
  187.23 +*
  187.24 +*  You should have received a copy of the GNU General Public License
  187.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  187.26 +***********************************************************************/
  187.27 +
  187.28 +#include "glpenv.h"
  187.29 +
  187.30 +static void *tls = NULL;
  187.31 +/* in a re-entrant version of the package this variable must be placed
  187.32 +   in the Thread Local Storage (TLS) */
  187.33 +
  187.34 +/***********************************************************************
  187.35 +*  NAME
  187.36 +*
  187.37 +*  tls_set_ptr - store global pointer in TLS
  187.38 +*
  187.39 +*  SYNOPSIS
  187.40 +*
  187.41 +*  #include "glpenv.h"
  187.42 +*  void tls_set_ptr(void *ptr);
  187.43 +*
  187.44 +*  DESCRIPTION
  187.45 +*
  187.46 +*  The routine tls_set_ptr stores a pointer specified by the parameter
  187.47 +*  ptr in the Thread Local Storage (TLS). */
  187.48 +
  187.49 +void tls_set_ptr(void *ptr)
  187.50 +{     tls = ptr;
  187.51 +      return;
  187.52 +}
  187.53 +
  187.54 +/***********************************************************************
  187.55 +*  NAME
  187.56 +*
  187.57 +*  tls_get_ptr - retrieve global pointer from TLS
  187.58 +*
  187.59 +*  SYNOPSIS
  187.60 +*
  187.61 +*  #include "glpenv.h"
  187.62 +*  void *tls_get_ptr(void);
  187.63 +*
  187.64 +*  RETURNS
  187.65 +*
  187.66 +*  The routine tls_get_ptr returns a pointer previously stored by the
  187.67 +*  routine tls_set_ptr. If the latter has not been called yet, NULL is
  187.68 +*  returned. */
  187.69 +
  187.70 +void *tls_get_ptr(void)
  187.71 +{     void *ptr;
  187.72 +      ptr = tls;
  187.73 +      return ptr;
  187.74 +}
  187.75 +
  187.76 +/* eof */
   188.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   188.2 +++ b/src/glpenv03.c	Mon Dec 06 13:09:21 2010 +0100
   188.3 @@ -0,0 +1,228 @@
   188.4 +/* glpenv03.c (terminal output) */
   188.5 +
   188.6 +/***********************************************************************
   188.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   188.8 +*
   188.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  188.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  188.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  188.12 +*  E-mail: <mao@gnu.org>.
  188.13 +*
  188.14 +*  GLPK is free software: you can redistribute it and/or modify it
  188.15 +*  under the terms of the GNU General Public License as published by
  188.16 +*  the Free Software Foundation, either version 3 of the License, or
  188.17 +*  (at your option) any later version.
  188.18 +*
  188.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  188.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  188.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  188.22 +*  License for more details.
  188.23 +*
  188.24 +*  You should have received a copy of the GNU General Public License
  188.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  188.26 +***********************************************************************/
  188.27 +
  188.28 +#include "glpapi.h"
  188.29 +
  188.30 +/***********************************************************************
  188.31 +*  NAME
  188.32 +*
  188.33 +*  glp_printf - write formatted output to terminal
  188.34 +*
  188.35 +*  SYNOPSIS
  188.36 +*
  188.37 +*  void glp_printf(const char *fmt, ...);
  188.38 +*
  188.39 +*  DESCRIPTION
  188.40 +*
  188.41 +*  The routine glp_printf uses the format control string fmt to format
  188.42 +*  its parameters and writes the formatted output to the terminal. */
  188.43 +
  188.44 +void glp_printf(const char *fmt, ...)
  188.45 +{     va_list arg;
  188.46 +      va_start(arg, fmt);
  188.47 +      xvprintf(fmt, arg);
  188.48 +      va_end(arg);
  188.49 +      return;
  188.50 +}
  188.51 +
  188.52 +/***********************************************************************
  188.53 +*  NAME
  188.54 +*
  188.55 +*  glp_vprintf - write formatted output to terminal
  188.56 +*
  188.57 +*  SYNOPSIS
  188.58 +*
  188.59 +*  void glp_vprintf(const char *fmt, va_list arg);
  188.60 +*
  188.61 +*  DESCRIPTION
  188.62 +*
  188.63 +*  The routine glp_vprintf uses the format control string fmt to format
  188.64 +*  its parameters specified by the list arg and writes the formatted
  188.65 +*  output to the terminal. */
  188.66 +
  188.67 +void glp_vprintf(const char *fmt, va_list arg)
  188.68 +{     ENV *env = get_env_ptr();
  188.69 +      /* if terminal output is disabled, do nothing */
  188.70 +      if (!env->term_out) goto skip;
  188.71 +      /* format the output */
  188.72 +      vsprintf(env->term_buf, fmt, arg);
  188.73 +      /* pass the output to the user-defined routine */
  188.74 +      if (env->term_hook != NULL)
  188.75 +      {  if (env->term_hook(env->term_info, env->term_buf) != 0)
  188.76 +            goto skip;
  188.77 +      }
  188.78 +      /* send the output to the terminal */
  188.79 +      fputs(env->term_buf, stdout);
  188.80 +      fflush(stdout);
  188.81 +      /* copy the output to the text file */
  188.82 +      if (env->tee_file != NULL)
  188.83 +      {  fputs(env->term_buf, env->tee_file);
  188.84 +         fflush(env->tee_file);
  188.85 +      }
  188.86 +skip: return;
  188.87 +}
  188.88 +
  188.89 +/***********************************************************************
  188.90 +*  NAME
  188.91 +*
  188.92 +*  glp_term_out - enable/disable terminal output
  188.93 +*
  188.94 +*  SYNOPSIS
  188.95 +*
  188.96 +*  int glp_term_out(int flag);
  188.97 +*
  188.98 +*  DESCRIPTION
  188.99 +*
 188.100 +*  Depending on the parameter flag the routine glp_term_out enables or
 188.101 +*  disables terminal output performed by glpk routines:
 188.102 +*
 188.103 +*  GLP_ON  - enable terminal output;
 188.104 +*  GLP_OFF - disable terminal output.
 188.105 +*
 188.106 +*  RETURNS
 188.107 +*
 188.108 +*  The routine glp_term_out returns the previous value of the terminal
 188.109 +*  output flag. */
 188.110 +
 188.111 +int glp_term_out(int flag)
 188.112 +{     ENV *env = get_env_ptr();
 188.113 +      int old = env->term_out;
 188.114 +      if (!(flag == GLP_ON || flag == GLP_OFF))
 188.115 +         xerror("glp_term_out: flag = %d; invalid value\n", flag);
 188.116 +      env->term_out = flag;
 188.117 +      return old;
 188.118 +}
 188.119 +
 188.120 +/***********************************************************************
 188.121 +*  NAME
 188.122 +*
 188.123 +*  glp_term_hook - install hook to intercept terminal output
 188.124 +*
 188.125 +*  SYNOPSIS
 188.126 +*
 188.127 +*  void glp_term_hook(int (*func)(void *info, const char *s),
 188.128 +*     void *info);
 188.129 +*
 188.130 +*  DESCRIPTION
 188.131 +*
 188.132 +*  The routine glp_term_hook installs a user-defined hook routine to
 188.133 +*  intercept all terminal output performed by glpk routines.
 188.134 +*
 188.135 +*  This feature can be used to redirect the terminal output to other
 188.136 +*  destination, for example to a file or a text window.
 188.137 +*
 188.138 +*  The parameter func specifies the user-defined hook routine. It is
 188.139 +*  called from an internal printing routine, which passes to it two
 188.140 +*  parameters: info and s. The parameter info is a transit pointer,
 188.141 +*  specified in the corresponding call to the routine glp_term_hook;
 188.142 +*  it may be used to pass some information to the hook routine. The
 188.143 +*  parameter s is a pointer to the null terminated character string,
 188.144 +*  which is intended to be written to the terminal. If the hook routine
 188.145 +*  returns zero, the printing routine writes the string s to the
 188.146 +*  terminal in a usual way; otherwise, if the hook routine returns
 188.147 +*  non-zero, no terminal output is performed.
 188.148 +*
 188.149 +*  To uninstall the hook routine the parameters func and info should be
 188.150 +*  specified as NULL. */
 188.151 +
 188.152 +void glp_term_hook(int (*func)(void *info, const char *s), void *info)
 188.153 +{     ENV *env = get_env_ptr();
 188.154 +      if (func == NULL)
 188.155 +      {  env->term_hook = NULL;
 188.156 +         env->term_info = NULL;
 188.157 +      }
 188.158 +      else
 188.159 +      {  env->term_hook = func;
 188.160 +         env->term_info = info;
 188.161 +      }
 188.162 +      return;
 188.163 +}
 188.164 +
 188.165 +/***********************************************************************
 188.166 +*  NAME
 188.167 +*
 188.168 +*  glp_open_tee - start copying terminal output to text file
 188.169 +*
 188.170 +*  SYNOPSIS
 188.171 +*
 188.172 +*  int glp_open_tee(const char *fname);
 188.173 +*
 188.174 +*  DESCRIPTION
 188.175 +*
 188.176 +*  The routine glp_open_tee starts copying all the terminal output to
 188.177 +*  an output text file, whose name is specified by the character string
 188.178 +*  fname.
 188.179 +*
 188.180 +*  RETURNS
 188.181 +*
 188.182 +*  0 - operation successful
 188.183 +*  1 - copying terminal output is already active
 188.184 +*  2 - unable to create output file */
 188.185 +
 188.186 +int glp_open_tee(const char *fname)
 188.187 +{     ENV *env = get_env_ptr();
 188.188 +      if (env->tee_file != NULL)
 188.189 +      {  /* copying terminal output is already active */
 188.190 +         return 1;
 188.191 +      }
 188.192 +      env->tee_file = fopen(fname, "w");
 188.193 +      if (env->tee_file == NULL)
 188.194 +      {  /* unable to create output file */
 188.195 +         return 2;
 188.196 +      }
 188.197 +      return 0;
 188.198 +}
 188.199 +
 188.200 +/***********************************************************************
 188.201 +*  NAME
 188.202 +*
 188.203 +*  glp_close_tee - stop copying terminal output to text file
 188.204 +*
 188.205 +*  SYNOPSIS
 188.206 +*
 188.207 +*  int glp_close_tee(void);
 188.208 +*
 188.209 +*  DESCRIPTION
 188.210 +*
 188.211 +*  The routine glp_close_tee stops copying the terminal output to the
 188.212 +*  output text file previously open by the routine glp_open_tee closing
 188.213 +*  that file.
 188.214 +*
 188.215 +*  RETURNS
 188.216 +*
 188.217 +*  0 - operation successful
 188.218 +*  1 - copying terminal output was not started */
 188.219 +
 188.220 +int glp_close_tee(void)
 188.221 +{     ENV *env = get_env_ptr();
 188.222 +      if (env->tee_file == NULL)
 188.223 +      {  /* copying terminal output was not started */
 188.224 +         return 1;
 188.225 +      }
 188.226 +      fclose(env->tee_file);
 188.227 +      env->tee_file = NULL;
 188.228 +      return 0;
 188.229 +}
 188.230 +
 188.231 +/* eof */
   189.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   189.2 +++ b/src/glpenv04.c	Mon Dec 06 13:09:21 2010 +0100
   189.3 @@ -0,0 +1,124 @@
   189.4 +/* glpenv04.c (error handling) */
   189.5 +
   189.6 +/***********************************************************************
   189.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   189.8 +*
   189.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  189.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  189.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  189.12 +*  E-mail: <mao@gnu.org>.
  189.13 +*
  189.14 +*  GLPK is free software: you can redistribute it and/or modify it
  189.15 +*  under the terms of the GNU General Public License as published by
  189.16 +*  the Free Software Foundation, either version 3 of the License, or
  189.17 +*  (at your option) any later version.
  189.18 +*
  189.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  189.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  189.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  189.22 +*  License for more details.
  189.23 +*
  189.24 +*  You should have received a copy of the GNU General Public License
  189.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  189.26 +***********************************************************************/
  189.27 +
  189.28 +#include "glpapi.h"
  189.29 +
  189.30 +/***********************************************************************
  189.31 +*  NAME
  189.32 +*
  189.33 +*  glp_error - display error message and terminate execution
  189.34 +*
  189.35 +*  SYNOPSIS
  189.36 +*
  189.37 +*  void glp_error(const char *fmt, ...);
  189.38 +*
  189.39 +*  DESCRIPTION
  189.40 +*
  189.41 +*  The routine glp_error (implemented as a macro) formats its
  189.42 +*  parameters using the format control string fmt, writes the formatted
  189.43 +*  message to the terminal, and abnormally terminates the program. */
  189.44 +
  189.45 +static void error(const char *fmt, ...)
  189.46 +{     ENV *env = get_env_ptr();
  189.47 +      va_list arg;
  189.48 +      env->term_out = GLP_ON;
  189.49 +      va_start(arg, fmt);
  189.50 +      xvprintf(fmt, arg);
  189.51 +      va_end(arg);
  189.52 +      xprintf("Error detected in file %s at line %d\n", env->err_file,
  189.53 +         env->err_line);
  189.54 +      if (env->err_hook != NULL)
  189.55 +         env->err_hook(env->err_info);
  189.56 +      abort();
  189.57 +      exit(EXIT_FAILURE);
  189.58 +      /* no return */
  189.59 +}
  189.60 +
  189.61 +_glp_error glp_error_(const char *file, int line)
  189.62 +{     ENV *env = get_env_ptr();
  189.63 +      env->err_file = file;
  189.64 +      env->err_line = line;
  189.65 +      return error;
  189.66 +}
  189.67 +
  189.68 +/***********************************************************************
  189.69 +*  NAME
  189.70 +*
  189.71 +*  glp_assert - check for logical condition
  189.72 +*
  189.73 +*  SYNOPSIS
  189.74 +*
  189.75 +*  #include "glplib.h"
  189.76 +*  void glp_assert(int expr);
  189.77 +*
  189.78 +*  DESCRIPTION
  189.79 +*
  189.80 +*  The routine glp_assert (implemented as a macro) checks for a logical
  189.81 +*  condition specified by the parameter expr. If the condition is false
  189.82 +*  (i.e. the value of expr is zero), the routine writes a message to
  189.83 +*  the terminal and abnormally terminates the program. */
  189.84 +
  189.85 +void glp_assert_(const char *expr, const char *file, int line)
  189.86 +{     glp_error_(file, line)("Assertion failed: %s\n", expr);
  189.87 +      /* no return */
  189.88 +}
  189.89 +
  189.90 +/***********************************************************************
  189.91 +*  NAME
  189.92 +*
  189.93 +*  glp_error_hook - install hook to intercept abnormal termination
  189.94 +*
  189.95 +*  SYNOPSIS
  189.96 +*
  189.97 +*  void glp_error_hook(void (*func)(void *info), void *info);
  189.98 +*
  189.99 +*  DESCRIPTION
 189.100 +*
 189.101 +*  The routine glp_error_hook installs a user-defined hook routine to
 189.102 +*  intercept abnormal termination.
 189.103 +*
 189.104 +*  The parameter func specifies the user-defined hook routine. It is
 189.105 +*  called from the routine glp_error before the latter calls the abort
 189.106 +*  function to abnormally terminate the application program because of
 189.107 +*  fatal error. The parameter info is a transit pointer, specified in
 189.108 +*  the corresponding call to the routine glp_error_hook; it may be used
 189.109 +*  to pass some information to the hook routine.
 189.110 +*
 189.111 +*  To uninstall the hook routine the parameters func and info should be
 189.112 +*  specified as NULL. */
 189.113 +
 189.114 +void glp_error_hook(void (*func)(void *info), void *info)
 189.115 +{     ENV *env = get_env_ptr();
 189.116 +      if (func == NULL)
 189.117 +      {  env->err_hook = NULL;
 189.118 +         env->err_info = NULL;
 189.119 +      }
 189.120 +      else
 189.121 +      {  env->err_hook = func;
 189.122 +         env->err_info = info;
 189.123 +      }
 189.124 +      return;
 189.125 +}
 189.126 +
 189.127 +/* eof */
   190.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   190.2 +++ b/src/glpenv05.c	Mon Dec 06 13:09:21 2010 +0100
   190.3 @@ -0,0 +1,225 @@
   190.4 +/* glpenv05.c (memory allocation) */
   190.5 +
   190.6 +/***********************************************************************
   190.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   190.8 +*
   190.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  190.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  190.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  190.12 +*  E-mail: <mao@gnu.org>.
  190.13 +*
  190.14 +*  GLPK is free software: you can redistribute it and/or modify it
  190.15 +*  under the terms of the GNU General Public License as published by
  190.16 +*  the Free Software Foundation, either version 3 of the License, or
  190.17 +*  (at your option) any later version.
  190.18 +*
  190.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  190.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  190.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  190.22 +*  License for more details.
  190.23 +*
  190.24 +*  You should have received a copy of the GNU General Public License
  190.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  190.26 +***********************************************************************/
  190.27 +
  190.28 +#include "glpapi.h"
  190.29 +
  190.30 +/* some processors need data to be properly aligned; the macro
  190.31 +   align_datasize enlarges the specified size of a data item to provide
  190.32 +   a proper alignment of immediately following data */
  190.33 +
  190.34 +#define align_datasize(size) ((((size) + 15) / 16) * 16)
  190.35 +/* 16 bytes is sufficient in both 32- and 64-bit environments
  190.36 +   (8 bytes is not sufficient in 64-bit environment due to jmp_buf) */
  190.37 +
  190.38 +/***********************************************************************
  190.39 +*  NAME
  190.40 +*
  190.41 +*  glp_malloc - allocate memory block
  190.42 +*
  190.43 +*  SYNOPSIS
  190.44 +*
  190.45 +*  void *glp_malloc(int size);
  190.46 +*
  190.47 +*  DESCRIPTION
  190.48 +*
  190.49 +*  The routine glp_malloc allocates a memory block of size bytes long.
  190.50 +*
  190.51 +*  Note that being allocated the memory block contains arbitrary data
  190.52 +*  (not binary zeros).
  190.53 +*
  190.54 +*  RETURNS
  190.55 +*
  190.56 +*  The routine glp_malloc returns a pointer to the allocated block.
  190.57 +*  To free this block the routine glp_free (not free!) must be used. */
  190.58 +
  190.59 +void *glp_malloc(int size)
  190.60 +{     ENV *env = get_env_ptr();
  190.61 +      MEM *desc;
  190.62 +      int size_of_desc = align_datasize(sizeof(MEM));
  190.63 +      if (size < 1 || size > INT_MAX - size_of_desc)
  190.64 +         xerror("glp_malloc: size = %d; invalid parameter\n", size);
  190.65 +      size += size_of_desc;
  190.66 +      if (xlcmp(xlset(size),
  190.67 +          xlsub(env->mem_limit, env->mem_total)) > 0)
  190.68 +         xerror("glp_malloc: memory limit exceeded\n");
  190.69 +      if (env->mem_count == INT_MAX)
  190.70 +         xerror("glp_malloc: too many memory blocks allocated\n");
  190.71 +      desc = malloc(size);
  190.72 +      if (desc == NULL)
  190.73 +         xerror("glp_malloc: no memory available\n");
  190.74 +      memset(desc, '?', size);
  190.75 +      desc->flag = MEM_MAGIC;
  190.76 +      desc->size = size;
  190.77 +      desc->prev = NULL;
  190.78 +      desc->next = env->mem_ptr;
  190.79 +      if (desc->next != NULL) desc->next->prev = desc;
  190.80 +      env->mem_ptr = desc;
  190.81 +      env->mem_count++;
  190.82 +      if (env->mem_cpeak < env->mem_count)
  190.83 +         env->mem_cpeak = env->mem_count;
  190.84 +      env->mem_total = xladd(env->mem_total, xlset(size));
  190.85 +      if (xlcmp(env->mem_tpeak, env->mem_total) < 0)
  190.86 +         env->mem_tpeak = env->mem_total;
  190.87 +      return (void *)((char *)desc + size_of_desc);
  190.88 +}
  190.89 +
  190.90 +/***********************************************************************
  190.91 +*  NAME
  190.92 +*
  190.93 +*  glp_calloc - allocate memory block
  190.94 +*
  190.95 +*  SYNOPSIS
  190.96 +*
  190.97 +*  void *glp_calloc(int n, int size);
  190.98 +*
  190.99 +*  DESCRIPTION
 190.100 +*
 190.101 +*  The routine glp_calloc allocates a memory block of (n*size) bytes
 190.102 +*  long.
 190.103 +*
 190.104 +*  Note that being allocated the memory block contains arbitrary data
 190.105 +*  (not binary zeros).
 190.106 +*
 190.107 +*  RETURNS
 190.108 +*
 190.109 +*  The routine glp_calloc returns a pointer to the allocated block.
 190.110 +*  To free this block the routine glp_free (not free!) must be used. */
 190.111 +
 190.112 +void *glp_calloc(int n, int size)
 190.113 +{     if (n < 1)
 190.114 +         xerror("glp_calloc: n = %d; invalid parameter\n", n);
 190.115 +      if (size < 1)
 190.116 +         xerror("glp_calloc: size = %d; invalid parameter\n", size);
 190.117 +      if (n > INT_MAX / size)
 190.118 +         xerror("glp_calloc: n = %d; size = %d; array too big\n", n,
 190.119 +            size);
 190.120 +      return xmalloc(n * size);
 190.121 +}
 190.122 +
 190.123 +/***********************************************************************
 190.124 +*  NAME
 190.125 +*
 190.126 +*  glp_free - free memory block
 190.127 +*
 190.128 +*  SYNOPSIS
 190.129 +*
 190.130 +*  void glp_free(void *ptr);
 190.131 +*
 190.132 +*  DESCRIPTION
 190.133 +*
 190.134 +*  The routine glp_free frees a memory block pointed to by ptr, which
 190.135 +*  was previuosly allocated by the routine glp_malloc or glp_calloc. */
 190.136 +
 190.137 +void glp_free(void *ptr)
 190.138 +{     ENV *env = get_env_ptr();
 190.139 +      MEM *desc;
 190.140 +      int size_of_desc = align_datasize(sizeof(MEM));
 190.141 +      if (ptr == NULL)
 190.142 +         xerror("glp_free: ptr = %p; null pointer\n", ptr);
 190.143 +      desc = (void *)((char *)ptr - size_of_desc);
 190.144 +      if (desc->flag != MEM_MAGIC)
 190.145 +         xerror("glp_free: ptr = %p; invalid pointer\n", ptr);
 190.146 +      if (env->mem_count == 0 ||
 190.147 +          xlcmp(env->mem_total, xlset(desc->size)) < 0)
 190.148 +         xerror("glp_free: memory allocation error\n");
 190.149 +      if (desc->prev == NULL)
 190.150 +         env->mem_ptr = desc->next;
 190.151 +      else
 190.152 +         desc->prev->next = desc->next;
 190.153 +      if (desc->next == NULL)
 190.154 +         ;
 190.155 +      else
 190.156 +         desc->next->prev = desc->prev;
 190.157 +      env->mem_count--;
 190.158 +      env->mem_total = xlsub(env->mem_total, xlset(desc->size));
 190.159 +      memset(desc, '?', size_of_desc);
 190.160 +      free(desc);
 190.161 +      return;
 190.162 +}
 190.163 +
 190.164 +/***********************************************************************
 190.165 +*  NAME
 190.166 +*
 190.167 +*  glp_mem_limit - set memory usage limit
 190.168 +*
 190.169 +*  SYNOPSIS
 190.170 +*
 190.171 +*  void glp_mem_limit(int limit);
 190.172 +*
 190.173 +*  DESCRIPTION
 190.174 +*
 190.175 +*  The routine glp_mem_limit limits the amount of memory available for
 190.176 +*  dynamic allocation (in GLPK routines) to limit megabytes. */
 190.177 +
 190.178 +void glp_mem_limit(int limit)
 190.179 +{     ENV *env = get_env_ptr();
 190.180 +      if (limit < 0)
 190.181 +         xerror("glp_mem_limit: limit = %d; invalid parameter\n",
 190.182 +            limit);
 190.183 +      env->mem_limit = xlmul(xlset(limit), xlset(1 << 20));
 190.184 +      return;
 190.185 +}
 190.186 +
 190.187 +/***********************************************************************
 190.188 +*  NAME
 190.189 +*
 190.190 +*  glp_mem_usage - get memory usage information
 190.191 +*
 190.192 +*  SYNOPSIS
 190.193 +*
 190.194 +*  void glp_mem_usage(int *count, int *cpeak, glp_long *total,
 190.195 +*     glp_long *tpeak);
 190.196 +*
 190.197 +*  DESCRIPTION
 190.198 +*
 190.199 +*  The routine glp_mem_usage reports some information about utilization
 190.200 +*  of the memory by GLPK routines. Information is stored to locations
 190.201 +*  specified by corresponding parameters (see below). Any parameter can
 190.202 +*  be specified as NULL, in which case corresponding information is not
 190.203 +*  stored.
 190.204 +*
 190.205 +*  *count is the number of the memory blocks currently allocated by the
 190.206 +*  routines xmalloc and xcalloc (one call to xmalloc or xcalloc results
 190.207 +*  in allocating one memory block).
 190.208 +*
 190.209 +*  *cpeak is the peak value of *count reached since the initialization
 190.210 +*  of the GLPK library environment.
 190.211 +*
 190.212 +*  *total is the total amount, in bytes, of the memory blocks currently
 190.213 +*  allocated by the routines xmalloc and xcalloc.
 190.214 +*
 190.215 +*  *tpeak is the peak value of *total reached since the initialization
 190.216 +*  of the GLPK library envirionment. */
 190.217 +
 190.218 +void glp_mem_usage(int *count, int *cpeak, glp_long *total,
 190.219 +      glp_long *tpeak)
 190.220 +{     ENV *env = get_env_ptr();
 190.221 +      if (count != NULL) *count = env->mem_count;
 190.222 +      if (cpeak != NULL) *cpeak = env->mem_cpeak;
 190.223 +      if (total != NULL) *total = env->mem_total;
 190.224 +      if (tpeak != NULL) *tpeak = env->mem_tpeak;
 190.225 +      return;
 190.226 +}
 190.227 +
 190.228 +/* eof */
   191.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   191.2 +++ b/src/glpenv06.c	Mon Dec 06 13:09:21 2010 +0100
   191.3 @@ -0,0 +1,172 @@
   191.4 +/* glpenv06.c (standard time) */
   191.5 +
   191.6 +/***********************************************************************
   191.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   191.8 +*
   191.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  191.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  191.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  191.12 +*  E-mail: <mao@gnu.org>.
  191.13 +*
  191.14 +*  GLPK is free software: you can redistribute it and/or modify it
  191.15 +*  under the terms of the GNU General Public License as published by
  191.16 +*  the Free Software Foundation, either version 3 of the License, or
  191.17 +*  (at your option) any later version.
  191.18 +*
  191.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  191.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  191.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  191.22 +*  License for more details.
  191.23 +*
  191.24 +*  You should have received a copy of the GNU General Public License
  191.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  191.26 +***********************************************************************/
  191.27 +
  191.28 +#ifdef HAVE_CONFIG_H
  191.29 +#include <config.h>
  191.30 +#endif
  191.31 +
  191.32 +#include "glpapi.h"
  191.33 +
  191.34 +/***********************************************************************
  191.35 +*  NAME
  191.36 +*
  191.37 +*  glp_time - determine current universal time
  191.38 +*
  191.39 +*  SYNOPSIS
  191.40 +*
  191.41 +*  glp_long glp_time(void);
  191.42 +*
  191.43 +*  RETURNS
  191.44 +*
  191.45 +*  The routine glp_time returns the current universal time (UTC), in
  191.46 +*  milliseconds, elapsed since 00:00:00 GMT January 1, 1970. */
  191.47 +
  191.48 +static const int epoch = 2440588; /* = jday(1, 1, 1970) */
  191.49 +
  191.50 +/* POSIX version ******************************************************/
  191.51 +
  191.52 +#if defined(HAVE_SYS_TIME_H) && defined(HAVE_GETTIMEOFDAY)
  191.53 +
  191.54 +#include <sys/time.h>
  191.55 +#include <time.h>
  191.56 +
  191.57 +glp_long glp_time(void)
  191.58 +{     struct timeval tv;
  191.59 +      struct tm *tm;
  191.60 +      glp_long t;
  191.61 +      int j;
  191.62 +      gettimeofday(&tv, NULL);
  191.63 +      tm = gmtime(&tv.tv_sec);
  191.64 +      j = jday(tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year);
  191.65 +      xassert(j >= 0);
  191.66 +      t = xlset(j - epoch);
  191.67 +      t = xlmul(t, xlset(24));
  191.68 +      t = xladd(t, xlset(tm->tm_hour));
  191.69 +      t = xlmul(t, xlset(60));
  191.70 +      t = xladd(t, xlset(tm->tm_min));
  191.71 +      t = xlmul(t, xlset(60));
  191.72 +      t = xladd(t, xlset(tm->tm_sec));
  191.73 +      t = xlmul(t, xlset(1000));
  191.74 +      t = xladd(t, xlset(tv.tv_usec / 1000));
  191.75 +      return t;
  191.76 +}
  191.77 +
  191.78 +/* Windows version ****************************************************/
  191.79 +
  191.80 +#elif defined(__WOE__)
  191.81 +
  191.82 +#include <windows.h>
  191.83 +
  191.84 +glp_long glp_time(void)
  191.85 +{     SYSTEMTIME st;
  191.86 +      glp_long t;
  191.87 +      int j;
  191.88 +      GetSystemTime(&st);
  191.89 +      j = jday(st.wDay, st.wMonth, st.wYear);
  191.90 +      xassert(j >= 0);
  191.91 +      t = xlset(j - epoch);
  191.92 +      t = xlmul(t, xlset(24));
  191.93 +      t = xladd(t, xlset(st.wHour));
  191.94 +      t = xlmul(t, xlset(60));
  191.95 +      t = xladd(t, xlset(st.wMinute));
  191.96 +      t = xlmul(t, xlset(60));
  191.97 +      t = xladd(t, xlset(st.wSecond));
  191.98 +      t = xlmul(t, xlset(1000));
  191.99 +      t = xladd(t, xlset(st.wMilliseconds));
 191.100 +      return t;
 191.101 +}
 191.102 +
 191.103 +/* portable ISO C version *********************************************/
 191.104 +
 191.105 +#else
 191.106 +
 191.107 +#include <time.h>
 191.108 +
 191.109 +glp_long glp_time(void)
 191.110 +{     time_t timer;
 191.111 +      struct tm *tm;
 191.112 +      glp_long t;
 191.113 +      int j;
 191.114 +      timer = time(NULL);
 191.115 +      tm = gmtime(&timer);
 191.116 +      j = jday(tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year);
 191.117 +      xassert(j >= 0);
 191.118 +      t = xlset(j - epoch);
 191.119 +      t = xlmul(t, xlset(24));
 191.120 +      t = xladd(t, xlset(tm->tm_hour));
 191.121 +      t = xlmul(t, xlset(60));
 191.122 +      t = xladd(t, xlset(tm->tm_min));
 191.123 +      t = xlmul(t, xlset(60));
 191.124 +      t = xladd(t, xlset(tm->tm_sec));
 191.125 +      t = xlmul(t, xlset(1000));
 191.126 +      return t;
 191.127 +}
 191.128 +
 191.129 +#endif
 191.130 +
 191.131 +/***********************************************************************
 191.132 +*  NAME
 191.133 +*
 191.134 +*  glp_difftime - compute difference between two time values
 191.135 +*
 191.136 +*  SYNOPSIS
 191.137 +*
 191.138 +*  double glp_difftime(glp_long t1, glp_long t0);
 191.139 +*
 191.140 +*  RETURNS
 191.141 +*
 191.142 +*  The routine glp_difftime returns the difference between two time
 191.143 +*  values t1 and t0, expressed in seconds. */
 191.144 +
 191.145 +double glp_difftime(glp_long t1, glp_long t0)
 191.146 +{     return
 191.147 +         xltod(xlsub(t1, t0)) / 1000.0;
 191.148 +}
 191.149 +
 191.150 +/**********************************************************************/
 191.151 +
 191.152 +#if 0
 191.153 +int main(void)
 191.154 +{     glp_long t;
 191.155 +      glp_ldiv d;
 191.156 +      int ttt, ss, mm, hh, day, month, year;
 191.157 +      char s[50];
 191.158 +      t = glp_time();
 191.159 +      xprintf("t = %s\n", xltoa(t, s));
 191.160 +      d = xldiv(t, xlset(1000));
 191.161 +      ttt = d.rem.lo, t = d.quot;
 191.162 +      d = xldiv(t, xlset(60));
 191.163 +      ss = d.rem.lo, t = d.quot;
 191.164 +      d = xldiv(t, xlset(60));
 191.165 +      mm = d.rem.lo, t = d.quot;
 191.166 +      d = xldiv(t, xlset(24));
 191.167 +      hh = d.rem.lo, t = d.quot;
 191.168 +      xassert(jdate(t.lo + epoch, &day, &month, &year) == 0);
 191.169 +      xprintf("%04d-%02d-%02d %02d:%02d:%02d.%03d\n", year, month, day,
 191.170 +         hh, mm, ss, ttt);
 191.171 +      return 0;
 191.172 +}
 191.173 +#endif
 191.174 +
 191.175 +/* eof */
   192.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   192.2 +++ b/src/glpenv07.c	Mon Dec 06 13:09:21 2010 +0100
   192.3 @@ -0,0 +1,671 @@
   192.4 +/* glpenv07.c (stream input/output) */
   192.5 +
   192.6 +/***********************************************************************
   192.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   192.8 +*
   192.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  192.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  192.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  192.12 +*  E-mail: <mao@gnu.org>.
  192.13 +*
  192.14 +*  GLPK is free software: you can redistribute it and/or modify it
  192.15 +*  under the terms of the GNU General Public License as published by
  192.16 +*  the Free Software Foundation, either version 3 of the License, or
  192.17 +*  (at your option) any later version.
  192.18 +*
  192.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  192.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  192.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  192.22 +*  License for more details.
  192.23 +*
  192.24 +*  You should have received a copy of the GNU General Public License
  192.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  192.26 +***********************************************************************/
  192.27 +
  192.28 +#ifdef HAVE_CONFIG_H
  192.29 +#include <config.h>
  192.30 +#endif
  192.31 +
  192.32 +#include "glpenv.h"
  192.33 +
  192.34 +/***********************************************************************
  192.35 +*  NAME
  192.36 +*
  192.37 +*  lib_err_msg - save error message string
  192.38 +*
  192.39 +*  SYNOPSIS
  192.40 +*
  192.41 +*  #include "glpenv.h"
  192.42 +*  void lib_err_msg(const char *msg);
  192.43 +*
  192.44 +*  DESCRIPTION
  192.45 +*
  192.46 +*  The routine lib_err_msg saves an error message string specified by
  192.47 +*  the parameter msg. The message is obtained by some library routines
  192.48 +*  with a call to strerror(errno). */
  192.49 +
  192.50 +void lib_err_msg(const char *msg)
  192.51 +{     ENV *env = get_env_ptr();
  192.52 +      int len = strlen(msg);
  192.53 +      if (len >= IOERR_MSG_SIZE)
  192.54 +         len = IOERR_MSG_SIZE - 1;
  192.55 +      memcpy(env->ioerr_msg, msg, len);
  192.56 +      if (len > 0 && env->ioerr_msg[len-1] == '\n') len--;
  192.57 +      env->ioerr_msg[len] = '\0';
  192.58 +      return;
  192.59 +}
  192.60 +
  192.61 +/***********************************************************************
  192.62 +*  NAME
  192.63 +*
  192.64 +*  xerrmsg - retrieve error message string
  192.65 +*
  192.66 +*  SYNOPSIS
  192.67 +*
  192.68 +*  #include "glpenv.h"
  192.69 +*  const char *xerrmsg(void);
  192.70 +*
  192.71 +*  RETURNS
  192.72 +*
  192.73 +*  The routine xerrmsg returns a pointer to an error message string
  192.74 +*  previously set by some library routine to indicate an error. */
  192.75 +
  192.76 +const char *xerrmsg(void)
  192.77 +{     ENV *env = get_env_ptr();
  192.78 +      return env->ioerr_msg;
  192.79 +}
  192.80 +
  192.81 +/***********************************************************************
  192.82 +*  NAME
  192.83 +*
  192.84 +*  xfopen - open a stream
  192.85 +*
  192.86 +*  SYNOPSIS
  192.87 +*
  192.88 +*  #include "glpenv.h"
  192.89 +*  XFILE *xfopen(const char *fname, const char *mode);
  192.90 +*
  192.91 +*  DESCRIPTION
  192.92 +*
  192.93 +*  The routine xfopen opens the file whose name is a string pointed to
  192.94 +*  by fname and associates a stream with it.
  192.95 +*
  192.96 +*  The parameter mode points to a string, which indicates the open mode
  192.97 +*  and should be one of the following:
  192.98 +*
  192.99 +*  "r"   open text file for reading;
 192.100 +*  "w"   truncate to zero length or create text file for writing;
 192.101 +*  "rb"  open binary file for reading;
 192.102 +*  "wb"  truncate to zero length or create binary file for writing.
 192.103 +*
 192.104 +*  RETURNS
 192.105 +*
 192.106 +*  The routine xfopen returns a pointer to the object controlling the
 192.107 +*  stream. If the open operation fails, xfopen returns NULL. */
 192.108 +
 192.109 +static void *c_fopen(const char *fname, const char *mode);
 192.110 +static void *z_fopen(const char *fname, const char *mode);
 192.111 +
 192.112 +static int is_gz_file(const char *fname)
 192.113 +{     char *ext = strrchr(fname, '.');
 192.114 +      return ext != NULL && strcmp(ext, ".gz") == 0;
 192.115 +}
 192.116 +
 192.117 +XFILE *xfopen(const char *fname, const char *mode)
 192.118 +{     ENV *env = get_env_ptr();
 192.119 +      XFILE *fp;
 192.120 +      int type;
 192.121 +      void *fh;
 192.122 +      if (!is_gz_file(fname))
 192.123 +      {  type = FH_FILE;
 192.124 +         fh = c_fopen(fname, mode);
 192.125 +      }
 192.126 +      else
 192.127 +      {  type = FH_ZLIB;
 192.128 +         fh = z_fopen(fname, mode);
 192.129 +      }
 192.130 +      if (fh == NULL)
 192.131 +      {  fp = NULL;
 192.132 +         goto done;
 192.133 +      }
 192.134 +      fp = xmalloc(sizeof(XFILE));
 192.135 +      fp->type = type;
 192.136 +      fp->fh = fh;
 192.137 +      fp->prev = NULL;
 192.138 +      fp->next = env->file_ptr;
 192.139 +      if (fp->next != NULL) fp->next->prev = fp;
 192.140 +      env->file_ptr = fp;
 192.141 +done: return fp;
 192.142 +}
 192.143 +
 192.144 +/***********************************************************************
 192.145 +*  NAME
 192.146 +*
 192.147 +*  xfgetc - read character from the stream
 192.148 +*
 192.149 +*  SYNOPSIS
 192.150 +*
 192.151 +*  #include "glpenv.h"
 192.152 +*  int xfgetc(XFILE *fp);
 192.153 +*
 192.154 +*  DESCRIPTION
 192.155 +*
 192.156 +*  If the end-of-file indicator for the input stream pointed to by fp
 192.157 +*  is not set and a next character is present, the routine xfgetc
 192.158 +*  obtains that character as an unsigned char converted to an int and
 192.159 +*  advances the associated file position indicator for the stream (if
 192.160 +*  defined).
 192.161 +*
 192.162 +*  RETURNS
 192.163 +*
 192.164 +*  If the end-of-file indicator for the stream is set, or if the
 192.165 +*  stream is at end-of-file, the end-of-file indicator for the stream
 192.166 +*  is set and the routine xfgetc returns XEOF. Otherwise, the routine
 192.167 +*  xfgetc returns the next character from the input stream pointed to
 192.168 +*  by fp. If a read error occurs, the error indicator for the stream is
 192.169 +*  set and the xfgetc routine returns XEOF.
 192.170 +*
 192.171 +*  Note: An end-of-file and a read error can be distinguished by use of
 192.172 +*  the routines xfeof and xferror. */
 192.173 +
 192.174 +static int c_fgetc(void *fh);
 192.175 +static int z_fgetc(void *fh);
 192.176 +
 192.177 +int xfgetc(XFILE *fp)
 192.178 +{     int c;
 192.179 +      switch (fp->type)
 192.180 +      {  case FH_FILE:
 192.181 +            c = c_fgetc(fp->fh);
 192.182 +            break;
 192.183 +         case FH_ZLIB:
 192.184 +            c = z_fgetc(fp->fh);
 192.185 +            break;
 192.186 +         default:
 192.187 +            xassert(fp != fp);
 192.188 +      }
 192.189 +      return c;
 192.190 +}
 192.191 +
 192.192 +/***********************************************************************
 192.193 +*  NAME
 192.194 +*
 192.195 +*  xfputc - write character to the stream
 192.196 +*
 192.197 +*  SYNOPSIS
 192.198 +*
 192.199 +*  #include "glpenv.h"
 192.200 +*  int xfputc(int c, XFILE *fp);
 192.201 +*
 192.202 +*  DESCRIPTION
 192.203 +*
 192.204 +*  The routine xfputc writes the character specified by c (converted
 192.205 +*  to an unsigned char) to the output stream pointed to by fp, at the
 192.206 +*  position indicated by the associated file position indicator (if
 192.207 +*  defined), and advances the indicator appropriately.
 192.208 +*
 192.209 +*  RETURNS
 192.210 +*
 192.211 +*  The routine xfputc returns the character written. If a write error
 192.212 +*  occurs, the error indicator for the stream is set and xfputc returns
 192.213 +*  XEOF. */
 192.214 +
 192.215 +static int c_fputc(int c, void *fh);
 192.216 +static int z_fputc(int c, void *fh);
 192.217 +
 192.218 +int xfputc(int c, XFILE *fp)
 192.219 +{     switch (fp->type)
 192.220 +      {  case FH_FILE:
 192.221 +            c = c_fputc(c, fp->fh);
 192.222 +            break;
 192.223 +         case FH_ZLIB:
 192.224 +            c = z_fputc(c, fp->fh);
 192.225 +            break;
 192.226 +         default:
 192.227 +            xassert(fp != fp);
 192.228 +      }
 192.229 +      return c;
 192.230 +}
 192.231 +
 192.232 +/***********************************************************************
 192.233 +*  NAME
 192.234 +*
 192.235 +*  xferror - test error indicator for the stream
 192.236 +*
 192.237 +*  SYNOPSIS
 192.238 +*
 192.239 +*  #include "glpenv.h"
 192.240 +*  int xferror(XFILE *fp);
 192.241 +*
 192.242 +*  DESCRIPTION
 192.243 +*
 192.244 +*  The routine xferror tests the error indicator for the stream
 192.245 +*  pointed to by fp.
 192.246 +*
 192.247 +*  RETURNS
 192.248 +*
 192.249 +*  The routine xferror returns non-zero if and only if the error
 192.250 +*  indicator is set for the stream. */
 192.251 +
 192.252 +static int c_ferror(void *fh);
 192.253 +static int z_ferror(void *fh);
 192.254 +
 192.255 +int xferror(XFILE *fp)
 192.256 +{     int ret;
 192.257 +      switch (fp->type)
 192.258 +      {  case FH_FILE:
 192.259 +            ret = c_ferror(fp->fh);
 192.260 +            break;
 192.261 +         case FH_ZLIB:
 192.262 +            ret = z_ferror(fp->fh);
 192.263 +            break;
 192.264 +         default:
 192.265 +            xassert(fp != fp);
 192.266 +      }
 192.267 +      return ret;
 192.268 +}
 192.269 +
 192.270 +/***********************************************************************
 192.271 +*  NAME
 192.272 +*
 192.273 +*  xfeof - test end-of-file indicator for the stream
 192.274 +*
 192.275 +*  SYNOPSIS
 192.276 +*
 192.277 +*  #include "glpenv.h"
 192.278 +*  int xfeof(XFILE *fp);
 192.279 +*
 192.280 +*  DESCRIPTION
 192.281 +*
 192.282 +*  The routine xfeof tests the end-of-file indicator for the stream
 192.283 +*  pointed to by fp.
 192.284 +*
 192.285 +*  RETURNS
 192.286 +*
 192.287 +*  The routine xfeof returns non-zero if and only if the end-of-file
 192.288 +*  indicator is set for the stream. */
 192.289 +
 192.290 +static int c_feof(void *fh);
 192.291 +static int z_feof(void *fh);
 192.292 +
 192.293 +int xfeof(XFILE *fp)
 192.294 +{     int ret;
 192.295 +      switch (fp->type)
 192.296 +      {  case FH_FILE:
 192.297 +            ret = c_feof(fp->fh);
 192.298 +            break;
 192.299 +         case FH_ZLIB:
 192.300 +            ret = z_feof(fp->fh);
 192.301 +            break;
 192.302 +         default:
 192.303 +            xassert(fp != fp);
 192.304 +      }
 192.305 +      return ret;
 192.306 +}
 192.307 +
 192.308 +int xfprintf(XFILE *file, const char *fmt, ...)
 192.309 +{     ENV *env = get_env_ptr();
 192.310 +      int cnt, j;
 192.311 +      va_list arg;
 192.312 +      va_start(arg, fmt);
 192.313 +      cnt = vsprintf(env->term_buf, fmt, arg);
 192.314 +      va_end(arg);
 192.315 +      for (j = 0; j < cnt; j++)
 192.316 +      {  if (xfputc(env->term_buf[j], file) < 0)
 192.317 +         {  cnt = -1;
 192.318 +            break;
 192.319 +         }
 192.320 +      }
 192.321 +      return cnt;
 192.322 +}
 192.323 +
 192.324 +/***********************************************************************
 192.325 +*  NAME
 192.326 +*
 192.327 +*  xfflush - flush the stream
 192.328 +*
 192.329 +*  SYNOPSIS
 192.330 +*
 192.331 +*  #include "glpenv.h"
 192.332 +*  int xfflush(XFILE *fp);
 192.333 +*
 192.334 +*  DESCRIPTION
 192.335 +*
 192.336 +*  The routine xfflush causes any unwritten data for the output stream
 192.337 +*  pointed to by fp to be written to the associated file.
 192.338 +*
 192.339 +*  RETURNS
 192.340 +*
 192.341 +*  The routine xfflush returns zero if the stream was successfully
 192.342 +*  flushed. Otherwise, xfflush sets the error indicator for the stream
 192.343 +*  and returns XEOF. */
 192.344 +
 192.345 +static int c_fflush(void *fh);
 192.346 +static int z_fflush(void *fh);
 192.347 +
 192.348 +int xfflush(XFILE *fp)
 192.349 +{     int ret;
 192.350 +      switch (fp->type)
 192.351 +      {  case FH_FILE:
 192.352 +            ret = c_fflush(fp->fh);
 192.353 +            break;
 192.354 +         case FH_ZLIB:
 192.355 +            ret = z_fflush(fp->fh);
 192.356 +            break;
 192.357 +         default:
 192.358 +            xassert(fp != fp);
 192.359 +      }
 192.360 +      return ret;
 192.361 +}
 192.362 +
 192.363 +/***********************************************************************
 192.364 +*  NAME
 192.365 +*
 192.366 +*  xfclose - close the stream
 192.367 +*
 192.368 +*  SYNOPSIS
 192.369 +*
 192.370 +*  #include "glpenv.h"
 192.371 +*  int xfclose(XFILE *fp);
 192.372 +*
 192.373 +*  DESCRIPTION
 192.374 +*
 192.375 +*  A successful call to the routine xfclose causes the stream pointed
 192.376 +*  to by fp to be flushed and the associated file to be closed. Whether
 192.377 +*  or not the call succeeds, the stream is disassociated from the file.
 192.378 +*
 192.379 +*  RETURNS
 192.380 +*
 192.381 +*  The routine xfclose returns zero if the stream was successfully
 192.382 +*  closed, or XEOF if any errors were detected. */
 192.383 +
 192.384 +static int c_fclose(void *fh);
 192.385 +static int z_fclose(void *fh);
 192.386 +
 192.387 +int xfclose(XFILE *fp)
 192.388 +{     ENV *env = get_env_ptr();
 192.389 +      int ret;
 192.390 +      switch (fp->type)
 192.391 +      {  case FH_FILE:
 192.392 +            ret = c_fclose(fp->fh);
 192.393 +            break;
 192.394 +         case FH_ZLIB:
 192.395 +            ret = z_fclose(fp->fh);
 192.396 +            break;
 192.397 +         default:
 192.398 +            xassert(fp != fp);
 192.399 +      }
 192.400 +      fp->type = 0xF00BAD;
 192.401 +      if (fp->prev == NULL)
 192.402 +         env->file_ptr = fp->next;
 192.403 +      else
 192.404 +         fp->prev->next = fp->next;
 192.405 +      if (fp->next == NULL)
 192.406 +         ;
 192.407 +      else
 192.408 +         fp->next->prev = fp->prev;
 192.409 +      xfree(fp);
 192.410 +      return ret;
 192.411 +}
 192.412 +
 192.413 +/***********************************************************************
 192.414 +*  The following routines implement stream input/output based on the
 192.415 +*  standard C streams. */
 192.416 +
 192.417 +static void *c_fopen(const char *fname, const char *mode)
 192.418 +{     FILE *fh;
 192.419 +      if (strcmp(fname, "/dev/stdin") == 0)
 192.420 +         fh = stdin;
 192.421 +      else if (strcmp(fname, "/dev/stdout") == 0)
 192.422 +         fh = stdout;
 192.423 +      else if (strcmp(fname, "/dev/stderr") == 0)
 192.424 +         fh = stderr;
 192.425 +      else
 192.426 +         fh = fopen(fname, mode);
 192.427 +      if (fh == NULL)
 192.428 +         lib_err_msg(strerror(errno));
 192.429 +      return fh;
 192.430 +}
 192.431 +
 192.432 +static int c_fgetc(void *_fh)
 192.433 +{     FILE *fh = _fh;
 192.434 +      int c;
 192.435 +      if (ferror(fh) || feof(fh))
 192.436 +      {  c = XEOF;
 192.437 +         goto done;
 192.438 +      }
 192.439 +      c = fgetc(fh);
 192.440 +      if (ferror(fh))
 192.441 +      {  lib_err_msg(strerror(errno));
 192.442 +         c = XEOF;
 192.443 +      }
 192.444 +      else if (feof(fh))
 192.445 +         c = XEOF;
 192.446 +      else
 192.447 +         xassert(0x00 <= c && c <= 0xFF);
 192.448 +done: return c;
 192.449 +}
 192.450 +
 192.451 +static int c_fputc(int c, void *_fh)
 192.452 +{     FILE *fh = _fh;
 192.453 +      if (ferror(fh))
 192.454 +      {  c = XEOF;
 192.455 +         goto done;
 192.456 +      }
 192.457 +      c = (unsigned char)c;
 192.458 +      fputc(c, fh);
 192.459 +      if (ferror(fh))
 192.460 +      {  lib_err_msg(strerror(errno));
 192.461 +         c = XEOF;
 192.462 +      }
 192.463 +done: return c;
 192.464 +}
 192.465 +
 192.466 +static int c_ferror(void *_fh)
 192.467 +{     FILE *fh = _fh;
 192.468 +      return ferror(fh);
 192.469 +}
 192.470 +
 192.471 +static int c_feof(void *_fh)
 192.472 +{     FILE *fh = _fh;
 192.473 +      return feof(fh);
 192.474 +}
 192.475 +
 192.476 +static int c_fflush(void *_fh)
 192.477 +{     FILE *fh = _fh;
 192.478 +      int ret;
 192.479 +      ret = fflush(fh);
 192.480 +      if (ret != 0)
 192.481 +      {  lib_err_msg(strerror(errno));
 192.482 +         ret = XEOF;
 192.483 +      }
 192.484 +      return ret;
 192.485 +}
 192.486 +
 192.487 +static int c_fclose(void *_fh)
 192.488 +{     FILE *fh = _fh;
 192.489 +      int ret;
 192.490 +      if (fh == stdin)
 192.491 +         ret = 0;
 192.492 +      else if (fh == stdout || fh == stderr)
 192.493 +         fflush(fh), ret = 0;
 192.494 +      else
 192.495 +         ret = fclose(fh);
 192.496 +      if (ret != 0)
 192.497 +      {  lib_err_msg(strerror(errno));
 192.498 +         ret = XEOF;
 192.499 +      }
 192.500 +      return ret;
 192.501 +}
 192.502 +
 192.503 +/***********************************************************************
 192.504 +*  The following routines implement stream input/output based on the
 192.505 +*  zlib library, which provides processing .gz files "on the fly". */
 192.506 +
 192.507 +#ifndef HAVE_ZLIB
 192.508 +
 192.509 +static void *z_fopen(const char *fname, const char *mode)
 192.510 +{     xassert(fname == fname);
 192.511 +      xassert(mode == mode);
 192.512 +      lib_err_msg("Compressed files not supported");
 192.513 +      return NULL;
 192.514 +}
 192.515 +
 192.516 +static int z_fgetc(void *fh)
 192.517 +{     xassert(fh != fh);
 192.518 +      return 0;
 192.519 +}
 192.520 +
 192.521 +static int z_fputc(int c, void *fh)
 192.522 +{     xassert(c != c);
 192.523 +      xassert(fh != fh);
 192.524 +      return 0;
 192.525 +}
 192.526 +
 192.527 +static int z_ferror(void *fh)
 192.528 +{     xassert(fh != fh);
 192.529 +      return 0;
 192.530 +}
 192.531 +
 192.532 +static int z_feof(void *fh)
 192.533 +{     xassert(fh != fh);
 192.534 +      return 0;
 192.535 +}
 192.536 +
 192.537 +static int z_fflush(void *fh)
 192.538 +{     xassert(fh != fh);
 192.539 +      return 0;
 192.540 +}
 192.541 +
 192.542 +static int z_fclose(void *fh)
 192.543 +{     xassert(fh != fh);
 192.544 +      return 0;
 192.545 +}
 192.546 +
 192.547 +#else
 192.548 +
 192.549 +#include <zlib.h>
 192.550 +
 192.551 +struct z_file
 192.552 +{     /* .gz file handle */
 192.553 +      gzFile file;
 192.554 +      /* pointer to .gz stream */
 192.555 +      int err;
 192.556 +      /* i/o error indicator */
 192.557 +      int eof;
 192.558 +      /* end-of-file indicator */
 192.559 +};
 192.560 +
 192.561 +static void *z_fopen(const char *fname, const char *mode)
 192.562 +{     struct z_file *fh;
 192.563 +      gzFile file;
 192.564 +      if (strcmp(mode, "r") == 0 || strcmp(mode, "rb") == 0)
 192.565 +         mode = "rb";
 192.566 +      else if (strcmp(mode, "w") == 0 || strcmp(mode, "wb") == 0)
 192.567 +         mode = "wb";
 192.568 +      else
 192.569 +      {  lib_err_msg("Invalid open mode");
 192.570 +         fh = NULL;
 192.571 +         goto done;
 192.572 +      }
 192.573 +      file = gzopen(fname, mode);
 192.574 +      if (file == NULL)
 192.575 +      {  lib_err_msg(strerror(errno));
 192.576 +         fh = NULL;
 192.577 +         goto done;
 192.578 +      }
 192.579 +      fh = xmalloc(sizeof(struct z_file));
 192.580 +      fh->file = file;
 192.581 +      fh->err = fh->eof = 0;
 192.582 +done: return fh;
 192.583 +}
 192.584 +
 192.585 +static int z_fgetc(void *_fh)
 192.586 +{     struct z_file *fh = _fh;
 192.587 +      int c;
 192.588 +      if (fh->err || fh->eof)
 192.589 +      {  c = XEOF;
 192.590 +         goto done;
 192.591 +      }
 192.592 +      c = gzgetc(fh->file);
 192.593 +      if (c < 0)
 192.594 +      {  int errnum;
 192.595 +         const char *msg;
 192.596 +         msg = gzerror(fh->file, &errnum);
 192.597 +         if (errnum == Z_STREAM_END)
 192.598 +            fh->eof = 1;
 192.599 +         else if (errnum == Z_ERRNO)
 192.600 +         {  fh->err = 1;
 192.601 +            lib_err_msg(strerror(errno));
 192.602 +         }
 192.603 +         else
 192.604 +         {  fh->err = 1;
 192.605 +            lib_err_msg(msg);
 192.606 +         }
 192.607 +         c = XEOF;
 192.608 +      }
 192.609 +      else
 192.610 +         xassert(0x00 <= c && c <= 0xFF);
 192.611 +done: return c;
 192.612 +}
 192.613 +
 192.614 +static int z_fputc(int c, void *_fh)
 192.615 +{     struct z_file *fh = _fh;
 192.616 +      if (fh->err)
 192.617 +      {  c = XEOF;
 192.618 +         goto done;
 192.619 +      }
 192.620 +      c = (unsigned char)c;
 192.621 +      if (gzputc(fh->file, c) < 0)
 192.622 +      {  int errnum;
 192.623 +         const char *msg;
 192.624 +         fh->err = 1;
 192.625 +         msg = gzerror(fh->file, &errnum);
 192.626 +         if (errnum == Z_ERRNO)
 192.627 +            lib_err_msg(strerror(errno));
 192.628 +         else
 192.629 +            lib_err_msg(msg);
 192.630 +         c = XEOF;
 192.631 +      }
 192.632 +done: return c;
 192.633 +}
 192.634 +
 192.635 +static int z_ferror(void *_fh)
 192.636 +{     struct z_file *fh = _fh;
 192.637 +      return fh->err;
 192.638 +}
 192.639 +
 192.640 +static int z_feof(void *_fh)
 192.641 +{     struct z_file *fh = _fh;
 192.642 +      return fh->eof;
 192.643 +}
 192.644 +
 192.645 +static int z_fflush(void *_fh)
 192.646 +{     struct z_file *fh = _fh;
 192.647 +      int ret;
 192.648 +      ret = gzflush(fh->file, Z_FINISH);
 192.649 +      if (ret == Z_OK)
 192.650 +         ret = 0;
 192.651 +      else
 192.652 +      {  int errnum;
 192.653 +         const char *msg;
 192.654 +         fh->err = 1;
 192.655 +         msg = gzerror(fh->file, &errnum);
 192.656 +         if (errnum == Z_ERRNO)
 192.657 +            lib_err_msg(strerror(errno));
 192.658 +         else
 192.659 +            lib_err_msg(msg);
 192.660 +         ret = XEOF;
 192.661 +      }
 192.662 +      return ret;
 192.663 +}
 192.664 +
 192.665 +static int z_fclose(void *_fh)
 192.666 +{     struct z_file *fh = _fh;
 192.667 +      gzclose(fh->file);
 192.668 +      xfree(fh);
 192.669 +      return 0;
 192.670 +}
 192.671 +
 192.672 +#endif
 192.673 +
 192.674 +/* eof */
   193.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   193.2 +++ b/src/glpenv08.c	Mon Dec 06 13:09:21 2010 +0100
   193.3 @@ -0,0 +1,156 @@
   193.4 +/* glpenv08.c (shared library support) */
   193.5 +
   193.6 +/***********************************************************************
   193.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   193.8 +*
   193.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  193.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  193.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  193.12 +*  E-mail: <mao@gnu.org>.
  193.13 +*
  193.14 +*  GLPK is free software: you can redistribute it and/or modify it
  193.15 +*  under the terms of the GNU General Public License as published by
  193.16 +*  the Free Software Foundation, either version 3 of the License, or
  193.17 +*  (at your option) any later version.
  193.18 +*
  193.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  193.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  193.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  193.22 +*  License for more details.
  193.23 +*
  193.24 +*  You should have received a copy of the GNU General Public License
  193.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  193.26 +***********************************************************************/
  193.27 +
  193.28 +#ifdef HAVE_CONFIG_H
  193.29 +#include <config.h>
  193.30 +#endif
  193.31 +
  193.32 +#include "glpenv.h"
  193.33 +
  193.34 +/* GNU version ********************************************************/
  193.35 +
  193.36 +#if defined(HAVE_LTDL)
  193.37 +
  193.38 +#include <ltdl.h>
  193.39 +
  193.40 +void *xdlopen(const char *module)
  193.41 +{     void *h = NULL;
  193.42 +      if (lt_dlinit() != 0)
  193.43 +      {  lib_err_msg(lt_dlerror());
  193.44 +         goto done;
  193.45 +      }
  193.46 +      h = lt_dlopen(module);
  193.47 +      if (h == NULL)
  193.48 +      {  lib_err_msg(lt_dlerror());
  193.49 +         if (lt_dlexit() != 0)
  193.50 +            xerror("xdlopen: %s\n", lt_dlerror());
  193.51 +      }
  193.52 +done: return h;
  193.53 +}
  193.54 +
  193.55 +void *xdlsym(void *h, const char *symbol)
  193.56 +{     void *ptr;
  193.57 +      xassert(h != NULL);
  193.58 +      ptr = lt_dlsym(h, symbol);
  193.59 +      if (ptr == NULL)
  193.60 +         xerror("xdlsym: %s: %s\n", symbol, lt_dlerror());
  193.61 +      return ptr;
  193.62 +}
  193.63 +
  193.64 +void xdlclose(void *h)
  193.65 +{     xassert(h != NULL);
  193.66 +      if (lt_dlclose(h) != 0)
  193.67 +         xerror("xdlclose: %s\n", lt_dlerror());
  193.68 +      if (lt_dlexit() != 0)
  193.69 +         xerror("xdlclose: %s\n", lt_dlerror());
  193.70 +      return;
  193.71 +}
  193.72 +
  193.73 +/* POSIX version ******************************************************/
  193.74 +
  193.75 +#elif defined(HAVE_DLFCN)
  193.76 +
  193.77 +#include <dlfcn.h>
  193.78 +
  193.79 +void *xdlopen(const char *module)
  193.80 +{     void *h;
  193.81 +      h = dlopen(module, RTLD_NOW);
  193.82 +      if (h == NULL)
  193.83 +         lib_err_msg(dlerror());
  193.84 +      return h;
  193.85 +}
  193.86 +
  193.87 +void *xdlsym(void *h, const char *symbol)
  193.88 +{     void *ptr;
  193.89 +      xassert(h != NULL);
  193.90 +      ptr = dlsym(h, symbol);
  193.91 +      if (ptr == NULL)
  193.92 +         xerror("xdlsym: %s: %s\n", symbol, dlerror());
  193.93 +      return ptr;
  193.94 +}
  193.95 +
  193.96 +void xdlclose(void *h)
  193.97 +{     xassert(h != NULL);
  193.98 +      if (dlclose(h) != 0)
  193.99 +         xerror("xdlclose: %s\n", dlerror());
 193.100 +      return;
 193.101 +}
 193.102 +
 193.103 +/* Windows version ****************************************************/
 193.104 +
 193.105 +#elif defined(__WOE__)
 193.106 +
 193.107 +#include <windows.h>
 193.108 +
 193.109 +void *xdlopen(const char *module)
 193.110 +{     void *h;
 193.111 +      h = LoadLibrary(module);
 193.112 +      if (h == NULL)
 193.113 +      {  char msg[20];
 193.114 +         sprintf(msg, "Error %d", GetLastError());
 193.115 +         lib_err_msg(msg);
 193.116 +      }
 193.117 +      return h;
 193.118 +}
 193.119 +
 193.120 +void *xdlsym(void *h, const char *symbol)
 193.121 +{     void *ptr;
 193.122 +      xassert(h != NULL);
 193.123 +      ptr = GetProcAddress(h, symbol);
 193.124 +      if (ptr == NULL)
 193.125 +         xerror("xdlsym: %s: Error %d\n", symbol, GetLastError());
 193.126 +      return ptr;
 193.127 +}
 193.128 +
 193.129 +void xdlclose(void *h)
 193.130 +{     xassert(h != NULL);
 193.131 +      if (!FreeLibrary(h))
 193.132 +         xerror("xdlclose: Error %d\n", GetLastError());
 193.133 +      return;
 193.134 +}
 193.135 +
 193.136 +/* NULL version *******************************************************/
 193.137 +
 193.138 +#else
 193.139 +
 193.140 +void *xdlopen(const char *module)
 193.141 +{     xassert(module == module);
 193.142 +      lib_err_msg("Shared libraries not supported");
 193.143 +      return NULL;
 193.144 +}
 193.145 +
 193.146 +void *xdlsym(void *h, const char *symbol)
 193.147 +{     xassert(h != h);
 193.148 +      xassert(symbol != symbol);
 193.149 +      return NULL;
 193.150 +}
 193.151 +
 193.152 +void xdlclose(void *h)
 193.153 +{     xassert(h != h);
 193.154 +      return;
 193.155 +}
 193.156 +
 193.157 +#endif
 193.158 +
 193.159 +/* eof */
   194.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   194.2 +++ b/src/glpfhv.c	Mon Dec 06 13:09:21 2010 +0100
   194.3 @@ -0,0 +1,774 @@
   194.4 +/* glpfhv.c (LP basis factorization, FHV eta file version) */
   194.5 +
   194.6 +/***********************************************************************
   194.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   194.8 +*
   194.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  194.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  194.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  194.12 +*  E-mail: <mao@gnu.org>.
  194.13 +*
  194.14 +*  GLPK is free software: you can redistribute it and/or modify it
  194.15 +*  under the terms of the GNU General Public License as published by
  194.16 +*  the Free Software Foundation, either version 3 of the License, or
  194.17 +*  (at your option) any later version.
  194.18 +*
  194.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  194.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  194.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  194.22 +*  License for more details.
  194.23 +*
  194.24 +*  You should have received a copy of the GNU General Public License
  194.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  194.26 +***********************************************************************/
  194.27 +
  194.28 +#include "glpfhv.h"
  194.29 +#include "glpenv.h"
  194.30 +#define xfault xerror
  194.31 +
  194.32 +/* CAUTION: DO NOT CHANGE THE LIMIT BELOW */
  194.33 +
  194.34 +#define M_MAX 100000000 /* = 100*10^6 */
  194.35 +/* maximal order of the basis matrix */
  194.36 +
  194.37 +/***********************************************************************
  194.38 +*  NAME
  194.39 +*
  194.40 +*  fhv_create_it - create LP basis factorization
  194.41 +*
  194.42 +*  SYNOPSIS
  194.43 +*
  194.44 +*  #include "glpfhv.h"
  194.45 +*  FHV *fhv_create_it(void);
  194.46 +*
  194.47 +*  DESCRIPTION
  194.48 +*
  194.49 +*  The routine fhv_create_it creates a program object, which represents
  194.50 +*  a factorization of LP basis.
  194.51 +*
  194.52 +*  RETURNS
  194.53 +*
  194.54 +*  The routine fhv_create_it returns a pointer to the object created. */
  194.55 +
  194.56 +FHV *fhv_create_it(void)
  194.57 +{     FHV *fhv;
  194.58 +      fhv = xmalloc(sizeof(FHV));
  194.59 +      fhv->m_max = fhv->m = 0;
  194.60 +      fhv->valid = 0;
  194.61 +      fhv->luf = luf_create_it();
  194.62 +      fhv->hh_max = 50;
  194.63 +      fhv->hh_nfs = 0;
  194.64 +      fhv->hh_ind = fhv->hh_ptr = fhv->hh_len = NULL;
  194.65 +      fhv->p0_row = fhv->p0_col = NULL;
  194.66 +      fhv->cc_ind = NULL;
  194.67 +      fhv->cc_val = NULL;
  194.68 +      fhv->upd_tol = 1e-6;
  194.69 +      fhv->nnz_h = 0;
  194.70 +      return fhv;
  194.71 +}
  194.72 +
  194.73 +/***********************************************************************
  194.74 +*  NAME
  194.75 +*
  194.76 +*  fhv_factorize - compute LP basis factorization
  194.77 +*
  194.78 +*  SYNOPSIS
  194.79 +*
  194.80 +*  #include "glpfhv.h"
  194.81 +*  int fhv_factorize(FHV *fhv, int m, int (*col)(void *info, int j,
  194.82 +*     int ind[], double val[]), void *info);
  194.83 +*
  194.84 +*  DESCRIPTION
  194.85 +*
  194.86 +*  The routine fhv_factorize computes the factorization of the basis
  194.87 +*  matrix B specified by the routine col.
  194.88 +*
  194.89 +*  The parameter fhv specified the basis factorization data structure
  194.90 +*  created by the routine fhv_create_it.
  194.91 +*
  194.92 +*  The parameter m specifies the order of B, m > 0.
  194.93 +*
  194.94 +*  The formal routine col specifies the matrix B to be factorized. To
  194.95 +*  obtain j-th column of A the routine fhv_factorize calls the routine
  194.96 +*  col with the parameter j (1 <= j <= n). In response the routine col
  194.97 +*  should store row indices and numerical values of non-zero elements
  194.98 +*  of j-th column of B to locations ind[1,...,len] and val[1,...,len],
  194.99 +*  respectively, where len is the number of non-zeros in j-th column
 194.100 +*  returned on exit. Neither zero nor duplicate elements are allowed.
 194.101 +*
 194.102 +*  The parameter info is a transit pointer passed to the routine col.
 194.103 +*
 194.104 +*  RETURNS
 194.105 +*
 194.106 +*  0  The factorization has been successfully computed.
 194.107 +*
 194.108 +*  FHV_ESING
 194.109 +*     The specified matrix is singular within the working precision.
 194.110 +*
 194.111 +*  FHV_ECOND
 194.112 +*     The specified matrix is ill-conditioned.
 194.113 +*
 194.114 +*  For more details see comments to the routine luf_factorize.
 194.115 +*
 194.116 +*  ALGORITHM
 194.117 +*
 194.118 +*  The routine fhv_factorize calls the routine luf_factorize (see the
 194.119 +*  module GLPLUF), which actually computes LU-factorization of the basis
 194.120 +*  matrix B in the form
 194.121 +*
 194.122 +*     [B] = (F, V, P, Q),
 194.123 +*
 194.124 +*  where F and V are such matrices that
 194.125 +*
 194.126 +*     B = F * V,
 194.127 +*
 194.128 +*  and P and Q are such permutation matrices that the matrix
 194.129 +*
 194.130 +*     L = P * F * inv(P)
 194.131 +*
 194.132 +*  is lower triangular with unity diagonal, and the matrix
 194.133 +*
 194.134 +*     U = P * V * Q
 194.135 +*
 194.136 +*  is upper triangular.
 194.137 +*
 194.138 +*  In order to build the complete representation of the factorization
 194.139 +*  (see formula (1) in the file glpfhv.h) the routine fhv_factorize just
 194.140 +*  additionally sets H = I and P0 = P. */
 194.141 +
 194.142 +int fhv_factorize(FHV *fhv, int m, int (*col)(void *info, int j,
 194.143 +      int ind[], double val[]), void *info)
 194.144 +{     int ret;
 194.145 +      if (m < 1)
 194.146 +         xfault("fhv_factorize: m = %d; invalid parameter\n", m);
 194.147 +      if (m > M_MAX)
 194.148 +         xfault("fhv_factorize: m = %d; matrix too big\n", m);
 194.149 +      fhv->m = m;
 194.150 +      /* invalidate the factorization */
 194.151 +      fhv->valid = 0;
 194.152 +      /* allocate/reallocate arrays, if necessary */
 194.153 +      if (fhv->hh_ind == NULL)
 194.154 +         fhv->hh_ind = xcalloc(1+fhv->hh_max, sizeof(int));
 194.155 +      if (fhv->hh_ptr == NULL)
 194.156 +         fhv->hh_ptr = xcalloc(1+fhv->hh_max, sizeof(int));
 194.157 +      if (fhv->hh_len == NULL)
 194.158 +         fhv->hh_len = xcalloc(1+fhv->hh_max, sizeof(int));
 194.159 +      if (fhv->m_max < m)
 194.160 +      {  if (fhv->p0_row != NULL) xfree(fhv->p0_row);
 194.161 +         if (fhv->p0_col != NULL) xfree(fhv->p0_col);
 194.162 +         if (fhv->cc_ind != NULL) xfree(fhv->cc_ind);
 194.163 +         if (fhv->cc_val != NULL) xfree(fhv->cc_val);
 194.164 +         fhv->m_max = m + 100;
 194.165 +         fhv->p0_row = xcalloc(1+fhv->m_max, sizeof(int));
 194.166 +         fhv->p0_col = xcalloc(1+fhv->m_max, sizeof(int));
 194.167 +         fhv->cc_ind = xcalloc(1+fhv->m_max, sizeof(int));
 194.168 +         fhv->cc_val = xcalloc(1+fhv->m_max, sizeof(double));
 194.169 +      }
 194.170 +      /* try to factorize the basis matrix */
 194.171 +      switch (luf_factorize(fhv->luf, m, col, info))
 194.172 +      {  case 0:
 194.173 +            break;
 194.174 +         case LUF_ESING:
 194.175 +            ret = FHV_ESING;
 194.176 +            goto done;
 194.177 +         case LUF_ECOND:
 194.178 +            ret = FHV_ECOND;
 194.179 +            goto done;
 194.180 +         default:
 194.181 +            xassert(fhv != fhv);
 194.182 +      }
 194.183 +      /* the basis matrix has been successfully factorized */
 194.184 +      fhv->valid = 1;
 194.185 +      /* H := I */
 194.186 +      fhv->hh_nfs = 0;
 194.187 +      /* P0 := P */
 194.188 +      memcpy(&fhv->p0_row[1], &fhv->luf->pp_row[1], sizeof(int) * m);
 194.189 +      memcpy(&fhv->p0_col[1], &fhv->luf->pp_col[1], sizeof(int) * m);
 194.190 +      /* currently H has no factors */
 194.191 +      fhv->nnz_h = 0;
 194.192 +      ret = 0;
 194.193 +done: /* return to the calling program */
 194.194 +      return ret;
 194.195 +}
 194.196 +
 194.197 +/***********************************************************************
 194.198 +*  NAME
 194.199 +*
 194.200 +*  fhv_h_solve - solve system H*x = b or H'*x = b
 194.201 +*
 194.202 +*  SYNOPSIS
 194.203 +*
 194.204 +*  #include "glpfhv.h"
 194.205 +*  void fhv_h_solve(FHV *fhv, int tr, double x[]);
 194.206 +*
 194.207 +*  DESCRIPTION
 194.208 +*
 194.209 +*  The routine fhv_h_solve solves either the system H*x = b (if the
 194.210 +*  flag tr is zero) or the system H'*x = b (if the flag tr is non-zero),
 194.211 +*  where the matrix H is a component of the factorization specified by
 194.212 +*  the parameter fhv, H' is a matrix transposed to H.
 194.213 +*
 194.214 +*  On entry the array x should contain elements of the right-hand side
 194.215 +*  vector b in locations x[1], ..., x[m], where m is the order of the
 194.216 +*  matrix H. On exit this array will contain elements of the solution
 194.217 +*  vector x in the same locations. */
 194.218 +
 194.219 +void fhv_h_solve(FHV *fhv, int tr, double x[])
 194.220 +{     int nfs = fhv->hh_nfs;
 194.221 +      int *hh_ind = fhv->hh_ind;
 194.222 +      int *hh_ptr = fhv->hh_ptr;
 194.223 +      int *hh_len = fhv->hh_len;
 194.224 +      int *sv_ind = fhv->luf->sv_ind;
 194.225 +      double *sv_val = fhv->luf->sv_val;
 194.226 +      int i, k, beg, end, ptr;
 194.227 +      double temp;
 194.228 +      if (!fhv->valid)
 194.229 +         xfault("fhv_h_solve: the factorization is not valid\n");
 194.230 +      if (!tr)
 194.231 +      {  /* solve the system H*x = b */
 194.232 +         for (k = 1; k <= nfs; k++)
 194.233 +         {  i = hh_ind[k];
 194.234 +            temp = x[i];
 194.235 +            beg = hh_ptr[k];
 194.236 +            end = beg + hh_len[k] - 1;
 194.237 +            for (ptr = beg; ptr <= end; ptr++)
 194.238 +               temp -= sv_val[ptr] * x[sv_ind[ptr]];
 194.239 +            x[i] = temp;
 194.240 +         }
 194.241 +      }
 194.242 +      else
 194.243 +      {  /* solve the system H'*x = b */
 194.244 +         for (k = nfs; k >= 1; k--)
 194.245 +         {  i = hh_ind[k];
 194.246 +            temp = x[i];
 194.247 +            if (temp == 0.0) continue;
 194.248 +            beg = hh_ptr[k];
 194.249 +            end = beg + hh_len[k] - 1;
 194.250 +            for (ptr = beg; ptr <= end; ptr++)
 194.251 +               x[sv_ind[ptr]] -= sv_val[ptr] * temp;
 194.252 +         }
 194.253 +      }
 194.254 +      return;
 194.255 +}
 194.256 +
 194.257 +/***********************************************************************
 194.258 +*  NAME
 194.259 +*
 194.260 +*  fhv_ftran - perform forward transformation (solve system B*x = b)
 194.261 +*
 194.262 +*  SYNOPSIS
 194.263 +*
 194.264 +*  #include "glpfhv.h"
 194.265 +*  void fhv_ftran(FHV *fhv, double x[]);
 194.266 +*
 194.267 +*  DESCRIPTION
 194.268 +*
 194.269 +*  The routine fhv_ftran performs forward transformation, i.e. solves
 194.270 +*  the system B*x = b, where B is the basis matrix, x is the vector of
 194.271 +*  unknowns to be computed, b is the vector of right-hand sides.
 194.272 +*
 194.273 +*  On entry elements of the vector b should be stored in dense format
 194.274 +*  in locations x[1], ..., x[m], where m is the number of rows. On exit
 194.275 +*  the routine stores elements of the vector x in the same locations. */
 194.276 +
 194.277 +void fhv_ftran(FHV *fhv, double x[])
 194.278 +{     int *pp_row = fhv->luf->pp_row;
 194.279 +      int *pp_col = fhv->luf->pp_col;
 194.280 +      int *p0_row = fhv->p0_row;
 194.281 +      int *p0_col = fhv->p0_col;
 194.282 +      if (!fhv->valid)
 194.283 +         xfault("fhv_ftran: the factorization is not valid\n");
 194.284 +      /* B = F*H*V, therefore inv(B) = inv(V)*inv(H)*inv(F) */
 194.285 +      fhv->luf->pp_row = p0_row;
 194.286 +      fhv->luf->pp_col = p0_col;
 194.287 +      luf_f_solve(fhv->luf, 0, x);
 194.288 +      fhv->luf->pp_row = pp_row;
 194.289 +      fhv->luf->pp_col = pp_col;
 194.290 +      fhv_h_solve(fhv, 0, x);
 194.291 +      luf_v_solve(fhv->luf, 0, x);
 194.292 +      return;
 194.293 +}
 194.294 +
 194.295 +/***********************************************************************
 194.296 +*  NAME
 194.297 +*
 194.298 +*  fhv_btran - perform backward transformation (solve system B'*x = b)
 194.299 +*
 194.300 +*  SYNOPSIS
 194.301 +*
 194.302 +*  #include "glpfhv.h"
 194.303 +*  void fhv_btran(FHV *fhv, double x[]);
 194.304 +*
 194.305 +*  DESCRIPTION
 194.306 +*
 194.307 +*  The routine fhv_btran performs backward transformation, i.e. solves
 194.308 +*  the system B'*x = b, where B' is a matrix transposed to the basis
 194.309 +*  matrix B, x is the vector of unknowns to be computed, b is the vector
 194.310 +*  of right-hand sides.
 194.311 +*
 194.312 +*  On entry elements of the vector b should be stored in dense format
 194.313 +*  in locations x[1], ..., x[m], where m is the number of rows. On exit
 194.314 +*  the routine stores elements of the vector x in the same locations. */
 194.315 +
 194.316 +void fhv_btran(FHV *fhv, double x[])
 194.317 +{     int *pp_row = fhv->luf->pp_row;
 194.318 +      int *pp_col = fhv->luf->pp_col;
 194.319 +      int *p0_row = fhv->p0_row;
 194.320 +      int *p0_col = fhv->p0_col;
 194.321 +      if (!fhv->valid)
 194.322 +         xfault("fhv_btran: the factorization is not valid\n");
 194.323 +      /* B = F*H*V, therefore inv(B') = inv(F')*inv(H')*inv(V') */
 194.324 +      luf_v_solve(fhv->luf, 1, x);
 194.325 +      fhv_h_solve(fhv, 1, x);
 194.326 +      fhv->luf->pp_row = p0_row;
 194.327 +      fhv->luf->pp_col = p0_col;
 194.328 +      luf_f_solve(fhv->luf, 1, x);
 194.329 +      fhv->luf->pp_row = pp_row;
 194.330 +      fhv->luf->pp_col = pp_col;
 194.331 +      return;
 194.332 +}
 194.333 +
 194.334 +/***********************************************************************
 194.335 +*  NAME
 194.336 +*
 194.337 +*  fhv_update_it - update LP basis factorization
 194.338 +*
 194.339 +*  SYNOPSIS
 194.340 +*
 194.341 +*  #include "glpfhv.h"
 194.342 +*  int fhv_update_it(FHV *fhv, int j, int len, const int ind[],
 194.343 +*     const double val[]);
 194.344 +*
 194.345 +*  DESCRIPTION
 194.346 +*
 194.347 +*  The routine fhv_update_it updates the factorization of the basis
 194.348 +*  matrix B after replacing its j-th column by a new vector.
 194.349 +*
 194.350 +*  The parameter j specifies the number of column of B, which has been
 194.351 +*  replaced, 1 <= j <= m, where m is the order of B.
 194.352 +*
 194.353 +*  Row indices and numerical values of non-zero elements of the new
 194.354 +*  column of B should be placed in locations ind[1], ..., ind[len] and
 194.355 +*  val[1], ..., val[len], resp., where len is the number of non-zeros
 194.356 +*  in the column. Neither zero nor duplicate elements are allowed.
 194.357 +*
 194.358 +*  RETURNS
 194.359 +*
 194.360 +*  0  The factorization has been successfully updated.
 194.361 +*
 194.362 +*  FHV_ESING
 194.363 +*     The adjacent basis matrix is structurally singular, since after
 194.364 +*     changing j-th column of matrix V by the new column (see algorithm
 194.365 +*     below) the case k1 > k2 occured.
 194.366 +*
 194.367 +*  FHV_ECHECK
 194.368 +*     The factorization is inaccurate, since after transforming k2-th
 194.369 +*     row of matrix U = P*V*Q, its diagonal element u[k2,k2] is zero or
 194.370 +*     close to zero,
 194.371 +*
 194.372 +*  FHV_ELIMIT
 194.373 +*     Maximal number of H factors has been reached.
 194.374 +*
 194.375 +*  FHV_EROOM
 194.376 +*     Overflow of the sparse vector area.
 194.377 +*
 194.378 +*  In case of non-zero return code the factorization becomes invalid.
 194.379 +*  It should not be used until it has been recomputed with the routine
 194.380 +*  fhv_factorize.
 194.381 +*
 194.382 +*  ALGORITHM
 194.383 +*
 194.384 +*  The routine fhv_update_it is based on the transformation proposed by
 194.385 +*  Forrest and Tomlin.
 194.386 +*
 194.387 +*  Let j-th column of the basis matrix B have been replaced by new
 194.388 +*  column B[j]. In order to keep the equality B = F*H*V j-th column of
 194.389 +*  matrix V should be replaced by the column inv(F*H)*B[j].
 194.390 +*
 194.391 +*  From the standpoint of matrix U = P*V*Q, replacement of j-th column
 194.392 +*  of matrix V is equivalent to replacement of k1-th column of matrix U,
 194.393 +*  where k1 is determined by permutation matrix Q. Thus, matrix U loses
 194.394 +*  its upper triangular form and becomes the following:
 194.395 +*
 194.396 +*         1   k1       k2   m
 194.397 +*     1   x x * x x x x x x x
 194.398 +*         . x * x x x x x x x
 194.399 +*     k1  . . * x x x x x x x
 194.400 +*         . . * x x x x x x x
 194.401 +*         . . * . x x x x x x
 194.402 +*         . . * . . x x x x x
 194.403 +*         . . * . . . x x x x
 194.404 +*     k2  . . * . . . . x x x
 194.405 +*         . . . . . . . . x x
 194.406 +*     m   . . . . . . . . . x
 194.407 +*
 194.408 +*  where row index k2 corresponds to the lowest non-zero element of
 194.409 +*  k1-th column.
 194.410 +*
 194.411 +*  The routine moves rows and columns k1+1, k1+2, ..., k2 of matrix U
 194.412 +*  by one position to the left and upwards and moves k1-th row and k1-th
 194.413 +*  column to position k2. As the result of such symmetric permutations
 194.414 +*  matrix U becomes the following:
 194.415 +*
 194.416 +*         1   k1       k2   m
 194.417 +*     1   x x x x x x x * x x
 194.418 +*         . x x x x x x * x x
 194.419 +*     k1  . . x x x x x * x x
 194.420 +*         . . . x x x x * x x
 194.421 +*         . . . . x x x * x x
 194.422 +*         . . . . . x x * x x
 194.423 +*         . . . . . . x * x x
 194.424 +*     k2  . . x x x x x * x x
 194.425 +*         . . . . . . . . x x
 194.426 +*     m   . . . . . . . . . x
 194.427 +*
 194.428 +*  Then the routine performs gaussian elimination to eliminate elements
 194.429 +*  u[k2,k1], u[k2,k1+1], ..., u[k2,k2-1] using diagonal elements
 194.430 +*  u[k1,k1], u[k1+1,k1+1], ..., u[k2-1,k2-1] as pivots in the same way
 194.431 +*  as described in comments to the routine luf_factorize (see the module
 194.432 +*  GLPLUF). Note that actually all operations are performed on matrix V,
 194.433 +*  not on matrix U. During the elimination process the routine permutes
 194.434 +*  neither rows nor columns, so only k2-th row of matrix U is changed.
 194.435 +*
 194.436 +*  To keep the main equality B = F*H*V, each time when the routine
 194.437 +*  applies elementary gaussian transformation to the transformed row of
 194.438 +*  matrix V (which corresponds to k2-th row of matrix U), it also adds
 194.439 +*  a new element (gaussian multiplier) to the current row-like factor
 194.440 +*  of matrix H, which corresponds to the transformed row of matrix V. */
 194.441 +
 194.442 +int fhv_update_it(FHV *fhv, int j, int len, const int ind[],
 194.443 +      const double val[])
 194.444 +{     int m = fhv->m;
 194.445 +      LUF *luf = fhv->luf;
 194.446 +      int *vr_ptr = luf->vr_ptr;
 194.447 +      int *vr_len = luf->vr_len;
 194.448 +      int *vr_cap = luf->vr_cap;
 194.449 +      double *vr_piv = luf->vr_piv;
 194.450 +      int *vc_ptr = luf->vc_ptr;
 194.451 +      int *vc_len = luf->vc_len;
 194.452 +      int *vc_cap = luf->vc_cap;
 194.453 +      int *pp_row = luf->pp_row;
 194.454 +      int *pp_col = luf->pp_col;
 194.455 +      int *qq_row = luf->qq_row;
 194.456 +      int *qq_col = luf->qq_col;
 194.457 +      int *sv_ind = luf->sv_ind;
 194.458 +      double *sv_val = luf->sv_val;
 194.459 +      double *work = luf->work;
 194.460 +      double eps_tol = luf->eps_tol;
 194.461 +      int *hh_ind = fhv->hh_ind;
 194.462 +      int *hh_ptr = fhv->hh_ptr;
 194.463 +      int *hh_len = fhv->hh_len;
 194.464 +      int *p0_row = fhv->p0_row;
 194.465 +      int *p0_col = fhv->p0_col;
 194.466 +      int *cc_ind = fhv->cc_ind;
 194.467 +      double *cc_val = fhv->cc_val;
 194.468 +      double upd_tol = fhv->upd_tol;
 194.469 +      int i, i_beg, i_end, i_ptr, j_beg, j_end, j_ptr, k, k1, k2, p, q,
 194.470 +         p_beg, p_end, p_ptr, ptr, ret;
 194.471 +      double f, temp;
 194.472 +      if (!fhv->valid)
 194.473 +         xfault("fhv_update_it: the factorization is not valid\n");
 194.474 +      if (!(1 <= j && j <= m))
 194.475 +         xfault("fhv_update_it: j = %d; column number out of range\n",
 194.476 +            j);
 194.477 +      /* check if the new factor of matrix H can be created */
 194.478 +      if (fhv->hh_nfs == fhv->hh_max)
 194.479 +      {  /* maximal number of updates has been reached */
 194.480 +         fhv->valid = 0;
 194.481 +         ret = FHV_ELIMIT;
 194.482 +         goto done;
 194.483 +      }
 194.484 +      /* convert new j-th column of B to dense format */
 194.485 +      for (i = 1; i <= m; i++)
 194.486 +         cc_val[i] = 0.0;
 194.487 +      for (k = 1; k <= len; k++)
 194.488 +      {  i = ind[k];
 194.489 +         if (!(1 <= i && i <= m))
 194.490 +            xfault("fhv_update_it: ind[%d] = %d; row number out of rang"
 194.491 +               "e\n", k, i);
 194.492 +         if (cc_val[i] != 0.0)
 194.493 +            xfault("fhv_update_it: ind[%d] = %d; duplicate row index no"
 194.494 +               "t allowed\n", k, i);
 194.495 +         if (val[k] == 0.0)
 194.496 +            xfault("fhv_update_it: val[%d] = %g; zero element not allow"
 194.497 +               "ed\n", k, val[k]);
 194.498 +         cc_val[i] = val[k];
 194.499 +      }
 194.500 +      /* new j-th column of V := inv(F * H) * (new B[j]) */
 194.501 +      fhv->luf->pp_row = p0_row;
 194.502 +      fhv->luf->pp_col = p0_col;
 194.503 +      luf_f_solve(fhv->luf, 0, cc_val);
 194.504 +      fhv->luf->pp_row = pp_row;
 194.505 +      fhv->luf->pp_col = pp_col;
 194.506 +      fhv_h_solve(fhv, 0, cc_val);
 194.507 +      /* convert new j-th column of V to sparse format */
 194.508 +      len = 0;
 194.509 +      for (i = 1; i <= m; i++)
 194.510 +      {  temp = cc_val[i];
 194.511 +         if (temp == 0.0 || fabs(temp) < eps_tol) continue;
 194.512 +         len++, cc_ind[len] = i, cc_val[len] = temp;
 194.513 +      }
 194.514 +      /* clear old content of j-th column of matrix V */
 194.515 +      j_beg = vc_ptr[j];
 194.516 +      j_end = j_beg + vc_len[j] - 1;
 194.517 +      for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
 194.518 +      {  /* get row index of v[i,j] */
 194.519 +         i = sv_ind[j_ptr];
 194.520 +         /* find v[i,j] in the i-th row */
 194.521 +         i_beg = vr_ptr[i];
 194.522 +         i_end = i_beg + vr_len[i] - 1;
 194.523 +         for (i_ptr = i_beg; sv_ind[i_ptr] != j; i_ptr++) /* nop */;
 194.524 +         xassert(i_ptr <= i_end);
 194.525 +         /* remove v[i,j] from the i-th row */
 194.526 +         sv_ind[i_ptr] = sv_ind[i_end];
 194.527 +         sv_val[i_ptr] = sv_val[i_end];
 194.528 +         vr_len[i]--;
 194.529 +      }
 194.530 +      /* now j-th column of matrix V is empty */
 194.531 +      luf->nnz_v -= vc_len[j];
 194.532 +      vc_len[j] = 0;
 194.533 +      /* add new elements of j-th column of matrix V to corresponding
 194.534 +         row lists; determine indices k1 and k2 */
 194.535 +      k1 = qq_row[j], k2 = 0;
 194.536 +      for (ptr = 1; ptr <= len; ptr++)
 194.537 +      {  /* get row index of v[i,j] */
 194.538 +         i = cc_ind[ptr];
 194.539 +         /* at least one unused location is needed in i-th row */
 194.540 +         if (vr_len[i] + 1 > vr_cap[i])
 194.541 +         {  if (luf_enlarge_row(luf, i, vr_len[i] + 10))
 194.542 +            {  /* overflow of the sparse vector area */
 194.543 +               fhv->valid = 0;
 194.544 +               luf->new_sva = luf->sv_size + luf->sv_size;
 194.545 +               xassert(luf->new_sva > luf->sv_size);
 194.546 +               ret = FHV_EROOM;
 194.547 +               goto done;
 194.548 +            }
 194.549 +         }
 194.550 +         /* add v[i,j] to i-th row */
 194.551 +         i_ptr = vr_ptr[i] + vr_len[i];
 194.552 +         sv_ind[i_ptr] = j;
 194.553 +         sv_val[i_ptr] = cc_val[ptr];
 194.554 +         vr_len[i]++;
 194.555 +         /* adjust index k2 */
 194.556 +         if (k2 < pp_col[i]) k2 = pp_col[i];
 194.557 +      }
 194.558 +      /* capacity of j-th column (which is currently empty) should be
 194.559 +         not less than len locations */
 194.560 +      if (vc_cap[j] < len)
 194.561 +      {  if (luf_enlarge_col(luf, j, len))
 194.562 +         {  /* overflow of the sparse vector area */
 194.563 +            fhv->valid = 0;
 194.564 +            luf->new_sva = luf->sv_size + luf->sv_size;
 194.565 +            xassert(luf->new_sva > luf->sv_size);
 194.566 +            ret = FHV_EROOM;
 194.567 +            goto done;
 194.568 +         }
 194.569 +      }
 194.570 +      /* add new elements of matrix V to j-th column list */
 194.571 +      j_ptr = vc_ptr[j];
 194.572 +      memmove(&sv_ind[j_ptr], &cc_ind[1], len * sizeof(int));
 194.573 +      memmove(&sv_val[j_ptr], &cc_val[1], len * sizeof(double));
 194.574 +      vc_len[j] = len;
 194.575 +      luf->nnz_v += len;
 194.576 +      /* if k1 > k2, diagonal element u[k2,k2] of matrix U is zero and
 194.577 +         therefore the adjacent basis matrix is structurally singular */
 194.578 +      if (k1 > k2)
 194.579 +      {  fhv->valid = 0;
 194.580 +         ret = FHV_ESING;
 194.581 +         goto done;
 194.582 +      }
 194.583 +      /* perform implicit symmetric permutations of rows and columns of
 194.584 +         matrix U */
 194.585 +      i = pp_row[k1], j = qq_col[k1];
 194.586 +      for (k = k1; k < k2; k++)
 194.587 +      {  pp_row[k] = pp_row[k+1], pp_col[pp_row[k]] = k;
 194.588 +         qq_col[k] = qq_col[k+1], qq_row[qq_col[k]] = k;
 194.589 +      }
 194.590 +      pp_row[k2] = i, pp_col[i] = k2;
 194.591 +      qq_col[k2] = j, qq_row[j] = k2;
 194.592 +      /* now i-th row of the matrix V is k2-th row of matrix U; since
 194.593 +         no pivoting is used, only this row will be transformed */
 194.594 +      /* copy elements of i-th row of matrix V to the working array and
 194.595 +         remove these elements from matrix V */
 194.596 +      for (j = 1; j <= m; j++) work[j] = 0.0;
 194.597 +      i_beg = vr_ptr[i];
 194.598 +      i_end = i_beg + vr_len[i] - 1;
 194.599 +      for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
 194.600 +      {  /* get column index of v[i,j] */
 194.601 +         j = sv_ind[i_ptr];
 194.602 +         /* store v[i,j] to the working array */
 194.603 +         work[j] = sv_val[i_ptr];
 194.604 +         /* find v[i,j] in the j-th column */
 194.605 +         j_beg = vc_ptr[j];
 194.606 +         j_end = j_beg + vc_len[j] - 1;
 194.607 +         for (j_ptr = j_beg; sv_ind[j_ptr] != i; j_ptr++) /* nop */;
 194.608 +         xassert(j_ptr <= j_end);
 194.609 +         /* remove v[i,j] from the j-th column */
 194.610 +         sv_ind[j_ptr] = sv_ind[j_end];
 194.611 +         sv_val[j_ptr] = sv_val[j_end];
 194.612 +         vc_len[j]--;
 194.613 +      }
 194.614 +      /* now i-th row of matrix V is empty */
 194.615 +      luf->nnz_v -= vr_len[i];
 194.616 +      vr_len[i] = 0;
 194.617 +      /* create the next row-like factor of the matrix H; this factor
 194.618 +         corresponds to i-th (transformed) row */
 194.619 +      fhv->hh_nfs++;
 194.620 +      hh_ind[fhv->hh_nfs] = i;
 194.621 +      /* hh_ptr[] will be set later */
 194.622 +      hh_len[fhv->hh_nfs] = 0;
 194.623 +      /* up to (k2 - k1) free locations are needed to add new elements
 194.624 +         to the non-trivial row of the row-like factor */
 194.625 +      if (luf->sv_end - luf->sv_beg < k2 - k1)
 194.626 +      {  luf_defrag_sva(luf);
 194.627 +         if (luf->sv_end - luf->sv_beg < k2 - k1)
 194.628 +         {  /* overflow of the sparse vector area */
 194.629 +            fhv->valid = luf->valid = 0;
 194.630 +            luf->new_sva = luf->sv_size + luf->sv_size;
 194.631 +            xassert(luf->new_sva > luf->sv_size);
 194.632 +            ret = FHV_EROOM;
 194.633 +            goto done;
 194.634 +         }
 194.635 +      }
 194.636 +      /* eliminate subdiagonal elements of matrix U */
 194.637 +      for (k = k1; k < k2; k++)
 194.638 +      {  /* v[p,q] = u[k,k] */
 194.639 +         p = pp_row[k], q = qq_col[k];
 194.640 +         /* this is the crucial point, where even tiny non-zeros should
 194.641 +            not be dropped */
 194.642 +         if (work[q] == 0.0) continue;
 194.643 +         /* compute gaussian multiplier f = v[i,q] / v[p,q] */
 194.644 +         f = work[q] / vr_piv[p];
 194.645 +         /* perform gaussian transformation:
 194.646 +            (i-th row) := (i-th row) - f * (p-th row)
 194.647 +            in order to eliminate v[i,q] = u[k2,k] */
 194.648 +         p_beg = vr_ptr[p];
 194.649 +         p_end = p_beg + vr_len[p] - 1;
 194.650 +         for (p_ptr = p_beg; p_ptr <= p_end; p_ptr++)
 194.651 +            work[sv_ind[p_ptr]] -= f * sv_val[p_ptr];
 194.652 +         /* store new element (gaussian multiplier that corresponds to
 194.653 +            p-th row) in the current row-like factor */
 194.654 +         luf->sv_end--;
 194.655 +         sv_ind[luf->sv_end] = p;
 194.656 +         sv_val[luf->sv_end] = f;
 194.657 +         hh_len[fhv->hh_nfs]++;
 194.658 +      }
 194.659 +      /* set pointer to the current row-like factor of the matrix H
 194.660 +         (if no elements were added to this factor, it is unity matrix
 194.661 +         and therefore can be discarded) */
 194.662 +      if (hh_len[fhv->hh_nfs] == 0)
 194.663 +         fhv->hh_nfs--;
 194.664 +      else
 194.665 +      {  hh_ptr[fhv->hh_nfs] = luf->sv_end;
 194.666 +         fhv->nnz_h += hh_len[fhv->hh_nfs];
 194.667 +      }
 194.668 +      /* store new pivot which corresponds to u[k2,k2] */
 194.669 +      vr_piv[i] = work[qq_col[k2]];
 194.670 +      /* new elements of i-th row of matrix V (which are non-diagonal
 194.671 +         elements u[k2,k2+1], ..., u[k2,m] of matrix U = P*V*Q) now are
 194.672 +         contained in the working array; add them to matrix V */
 194.673 +      len = 0;
 194.674 +      for (k = k2+1; k <= m; k++)
 194.675 +      {  /* get column index and value of v[i,j] = u[k2,k] */
 194.676 +         j = qq_col[k];
 194.677 +         temp = work[j];
 194.678 +         /* if v[i,j] is close to zero, skip it */
 194.679 +         if (fabs(temp) < eps_tol) continue;
 194.680 +         /* at least one unused location is needed in j-th column */
 194.681 +         if (vc_len[j] + 1 > vc_cap[j])
 194.682 +         {  if (luf_enlarge_col(luf, j, vc_len[j] + 10))
 194.683 +            {  /* overflow of the sparse vector area */
 194.684 +               fhv->valid = 0;
 194.685 +               luf->new_sva = luf->sv_size + luf->sv_size;
 194.686 +               xassert(luf->new_sva > luf->sv_size);
 194.687 +               ret = FHV_EROOM;
 194.688 +               goto done;
 194.689 +            }
 194.690 +         }
 194.691 +         /* add v[i,j] to j-th column */
 194.692 +         j_ptr = vc_ptr[j] + vc_len[j];
 194.693 +         sv_ind[j_ptr] = i;
 194.694 +         sv_val[j_ptr] = temp;
 194.695 +         vc_len[j]++;
 194.696 +         /* also store v[i,j] to the auxiliary array */
 194.697 +         len++, cc_ind[len] = j, cc_val[len] = temp;
 194.698 +      }
 194.699 +      /* capacity of i-th row (which is currently empty) should be not
 194.700 +         less than len locations */
 194.701 +      if (vr_cap[i] < len)
 194.702 +      {  if (luf_enlarge_row(luf, i, len))
 194.703 +         {  /* overflow of the sparse vector area */
 194.704 +            fhv->valid = 0;
 194.705 +            luf->new_sva = luf->sv_size + luf->sv_size;
 194.706 +            xassert(luf->new_sva > luf->sv_size);
 194.707 +            ret = FHV_EROOM;
 194.708 +            goto done;
 194.709 +         }
 194.710 +      }
 194.711 +      /* add new elements to i-th row list */
 194.712 +      i_ptr = vr_ptr[i];
 194.713 +      memmove(&sv_ind[i_ptr], &cc_ind[1], len * sizeof(int));
 194.714 +      memmove(&sv_val[i_ptr], &cc_val[1], len * sizeof(double));
 194.715 +      vr_len[i] = len;
 194.716 +      luf->nnz_v += len;
 194.717 +      /* updating is finished; check that diagonal element u[k2,k2] is
 194.718 +         not very small in absolute value among other elements in k2-th
 194.719 +         row and k2-th column of matrix U = P*V*Q */
 194.720 +      /* temp = max(|u[k2,*]|, |u[*,k2]|) */
 194.721 +      temp = 0.0;
 194.722 +      /* walk through k2-th row of U which is i-th row of V */
 194.723 +      i = pp_row[k2];
 194.724 +      i_beg = vr_ptr[i];
 194.725 +      i_end = i_beg + vr_len[i] - 1;
 194.726 +      for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
 194.727 +         if (temp < fabs(sv_val[i_ptr])) temp = fabs(sv_val[i_ptr]);
 194.728 +      /* walk through k2-th column of U which is j-th column of V */
 194.729 +      j = qq_col[k2];
 194.730 +      j_beg = vc_ptr[j];
 194.731 +      j_end = j_beg + vc_len[j] - 1;
 194.732 +      for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
 194.733 +         if (temp < fabs(sv_val[j_ptr])) temp = fabs(sv_val[j_ptr]);
 194.734 +      /* check that u[k2,k2] is not very small */
 194.735 +      if (fabs(vr_piv[i]) < upd_tol * temp)
 194.736 +      {  /* the factorization seems to be inaccurate and therefore must
 194.737 +            be recomputed */
 194.738 +         fhv->valid = 0;
 194.739 +         ret = FHV_ECHECK;
 194.740 +         goto done;
 194.741 +      }
 194.742 +      /* the factorization has been successfully updated */
 194.743 +      ret = 0;
 194.744 +done: /* return to the calling program */
 194.745 +      return ret;
 194.746 +}
 194.747 +
 194.748 +/***********************************************************************
 194.749 +*  NAME
 194.750 +*
 194.751 +*  fhv_delete_it - delete LP basis factorization
 194.752 +*
 194.753 +*  SYNOPSIS
 194.754 +*
 194.755 +*  #include "glpfhv.h"
 194.756 +*  void fhv_delete_it(FHV *fhv);
 194.757 +*
 194.758 +*  DESCRIPTION
 194.759 +*
 194.760 +*  The routine fhv_delete_it deletes LP basis factorization specified
 194.761 +*  by the parameter fhv and frees all memory allocated to this program
 194.762 +*  object. */
 194.763 +
 194.764 +void fhv_delete_it(FHV *fhv)
 194.765 +{     luf_delete_it(fhv->luf);
 194.766 +      if (fhv->hh_ind != NULL) xfree(fhv->hh_ind);
 194.767 +      if (fhv->hh_ptr != NULL) xfree(fhv->hh_ptr);
 194.768 +      if (fhv->hh_len != NULL) xfree(fhv->hh_len);
 194.769 +      if (fhv->p0_row != NULL) xfree(fhv->p0_row);
 194.770 +      if (fhv->p0_col != NULL) xfree(fhv->p0_col);
 194.771 +      if (fhv->cc_ind != NULL) xfree(fhv->cc_ind);
 194.772 +      if (fhv->cc_val != NULL) xfree(fhv->cc_val);
 194.773 +      xfree(fhv);
 194.774 +      return;
 194.775 +}
 194.776 +
 194.777 +/* eof */
   195.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   195.2 +++ b/src/glpfhv.h	Mon Dec 06 13:09:21 2010 +0100
   195.3 @@ -0,0 +1,170 @@
   195.4 +/* glpfhv.h (LP basis factorization, FHV eta file version) */
   195.5 +
   195.6 +/***********************************************************************
   195.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   195.8 +*
   195.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  195.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  195.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  195.12 +*  E-mail: <mao@gnu.org>.
  195.13 +*
  195.14 +*  GLPK is free software: you can redistribute it and/or modify it
  195.15 +*  under the terms of the GNU General Public License as published by
  195.16 +*  the Free Software Foundation, either version 3 of the License, or
  195.17 +*  (at your option) any later version.
  195.18 +*
  195.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  195.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  195.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  195.22 +*  License for more details.
  195.23 +*
  195.24 +*  You should have received a copy of the GNU General Public License
  195.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  195.26 +***********************************************************************/
  195.27 +
  195.28 +#ifndef GLPFHV_H
  195.29 +#define GLPFHV_H
  195.30 +
  195.31 +#include "glpluf.h"
  195.32 +
  195.33 +/***********************************************************************
  195.34 +*  The structure FHV defines the factorization of the basis mxm-matrix
  195.35 +*  B, where m is the number of rows in corresponding problem instance.
  195.36 +*
  195.37 +*  This factorization is the following sextet:
  195.38 +*
  195.39 +*     [B] = (F, H, V, P0, P, Q),                                     (1)
  195.40 +*
  195.41 +*  where F, H, and V are such matrices that
  195.42 +*
  195.43 +*     B = F * H * V,                                                 (2)
  195.44 +*
  195.45 +*  and P0, P, and Q are such permutation matrices that the matrix
  195.46 +*
  195.47 +*     L = P0 * F * inv(P0)                                           (3)
  195.48 +*
  195.49 +*  is lower triangular with unity diagonal, and the matrix
  195.50 +*
  195.51 +*     U = P * V * Q                                                  (4)
  195.52 +*
  195.53 +*  is upper triangular. All the matrices have the same order m, which
  195.54 +*  is the order of the basis matrix B.
  195.55 +*
  195.56 +*  The matrices F, V, P, and Q are stored in the structure LUF (see the
  195.57 +*  module GLPLUF), which is a member of the structure FHV.
  195.58 +*
  195.59 +*  The matrix H is stored in the form of eta file using row-like format
  195.60 +*  as follows:
  195.61 +*
  195.62 +*     H = H[1] * H[2] * ... * H[nfs],                                (5)
  195.63 +*
  195.64 +*  where H[k], k = 1, 2, ..., nfs, is a row-like factor, which differs
  195.65 +*  from the unity matrix only by one row, nfs is current number of row-
  195.66 +*  like factors. After the factorization has been built for some given
  195.67 +*  basis matrix B the matrix H has no factors and thus it is the unity
  195.68 +*  matrix. Then each time when the factorization is recomputed for an
  195.69 +*  adjacent basis matrix, the next factor H[k], k = 1, 2, ... is built
  195.70 +*  and added to the end of the eta file H.
  195.71 +*
  195.72 +*  Being sparse vectors non-trivial rows of the factors H[k] are stored
  195.73 +*  in the right part of the sparse vector area (SVA) in the same manner
  195.74 +*  as rows and columns of the matrix F.
  195.75 +*
  195.76 +*  For more details see the program documentation. */
  195.77 +
  195.78 +typedef struct FHV FHV;
  195.79 +
  195.80 +struct FHV
  195.81 +{     /* LP basis factorization */
  195.82 +      int m_max;
  195.83 +      /* maximal value of m (increased automatically, if necessary) */
  195.84 +      int m;
  195.85 +      /* the order of matrices B, F, H, V, P0, P, Q */
  195.86 +      int valid;
  195.87 +      /* the factorization is valid only if this flag is set */
  195.88 +      LUF *luf;
  195.89 +      /* LU-factorization (contains the matrices F, V, P, Q) */
  195.90 +      /*--------------------------------------------------------------*/
  195.91 +      /* matrix H in the form of eta file */
  195.92 +      int hh_max;
  195.93 +      /* maximal number of row-like factors (which limits the number of
  195.94 +         updates of the factorization) */
  195.95 +      int hh_nfs;
  195.96 +      /* current number of row-like factors (0 <= hh_nfs <= hh_max) */
  195.97 +      int *hh_ind; /* int hh_ind[1+hh_max]; */
  195.98 +      /* hh_ind[k], k = 1, ..., nfs, is the number of a non-trivial row
  195.99 +         of factor H[k] */
 195.100 +      int *hh_ptr; /* int hh_ptr[1+hh_max]; */
 195.101 +      /* hh_ptr[k], k = 1, ..., nfs, is a pointer to the first element
 195.102 +         of the non-trivial row of factor H[k] in the SVA */
 195.103 +      int *hh_len; /* int hh_len[1+hh_max]; */
 195.104 +      /* hh_len[k], k = 1, ..., nfs, is the number of non-zero elements
 195.105 +         in the non-trivial row of factor H[k] */
 195.106 +      /*--------------------------------------------------------------*/
 195.107 +      /* matrix P0 */
 195.108 +      int *p0_row; /* int p0_row[1+m_max]; */
 195.109 +      /* p0_row[i] = j means that p0[i,j] = 1 */
 195.110 +      int *p0_col; /* int p0_col[1+m_max]; */
 195.111 +      /* p0_col[j] = i means that p0[i,j] = 1 */
 195.112 +      /* if i-th row or column of the matrix F corresponds to i'-th row
 195.113 +         or column of the matrix L = P0*F*inv(P0), then p0_row[i'] = i
 195.114 +         and p0_col[i] = i' */
 195.115 +      /*--------------------------------------------------------------*/
 195.116 +      /* working arrays */
 195.117 +      int *cc_ind; /* int cc_ind[1+m_max]; */
 195.118 +      /* integer working array */
 195.119 +      double *cc_val; /* double cc_val[1+m_max]; */
 195.120 +      /* floating-point working array */
 195.121 +      /*--------------------------------------------------------------*/
 195.122 +      /* control parameters */
 195.123 +      double upd_tol;
 195.124 +      /* update tolerance; if after updating the factorization absolute
 195.125 +         value of some diagonal element u[k,k] of matrix U = P*V*Q is
 195.126 +         less than upd_tol * max(|u[k,*]|, |u[*,k]|), the factorization
 195.127 +         is considered as inaccurate */
 195.128 +      /*--------------------------------------------------------------*/
 195.129 +      /* some statistics */
 195.130 +      int nnz_h;
 195.131 +      /* current number of non-zeros in all factors of matrix H */
 195.132 +};
 195.133 +
 195.134 +/* return codes: */
 195.135 +#define FHV_ESING    1  /* singular matrix */
 195.136 +#define FHV_ECOND    2  /* ill-conditioned matrix */
 195.137 +#define FHV_ECHECK   3  /* insufficient accuracy */
 195.138 +#define FHV_ELIMIT   4  /* update limit reached */
 195.139 +#define FHV_EROOM    5  /* SVA overflow */
 195.140 +
 195.141 +#define fhv_create_it _glp_fhv_create_it
 195.142 +FHV *fhv_create_it(void);
 195.143 +/* create LP basis factorization */
 195.144 +
 195.145 +#define fhv_factorize _glp_fhv_factorize
 195.146 +int fhv_factorize(FHV *fhv, int m, int (*col)(void *info, int j,
 195.147 +      int ind[], double val[]), void *info);
 195.148 +/* compute LP basis factorization */
 195.149 +
 195.150 +#define fhv_h_solve _glp_fhv_h_solve
 195.151 +void fhv_h_solve(FHV *fhv, int tr, double x[]);
 195.152 +/* solve system H*x = b or H'*x = b */
 195.153 +
 195.154 +#define fhv_ftran _glp_fhv_ftran
 195.155 +void fhv_ftran(FHV *fhv, double x[]);
 195.156 +/* perform forward transformation (solve system B*x = b) */
 195.157 +
 195.158 +#define fhv_btran _glp_fhv_btran
 195.159 +void fhv_btran(FHV *fhv, double x[]);
 195.160 +/* perform backward transformation (solve system B'*x = b) */
 195.161 +
 195.162 +#define fhv_update_it _glp_fhv_update_it
 195.163 +int fhv_update_it(FHV *fhv, int j, int len, const int ind[],
 195.164 +      const double val[]);
 195.165 +/* update LP basis factorization */
 195.166 +
 195.167 +#define fhv_delete_it _glp_fhv_delete_it
 195.168 +void fhv_delete_it(FHV *fhv);
 195.169 +/* delete LP basis factorization */
 195.170 +
 195.171 +#endif
 195.172 +
 195.173 +/* eof */
   196.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   196.2 +++ b/src/glpgmp.c	Mon Dec 06 13:09:21 2010 +0100
   196.3 @@ -0,0 +1,1108 @@
   196.4 +/* glpgmp.c */
   196.5 +
   196.6 +/***********************************************************************
   196.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   196.8 +*
   196.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  196.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  196.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  196.12 +*  E-mail: <mao@gnu.org>.
  196.13 +*
  196.14 +*  GLPK is free software: you can redistribute it and/or modify it
  196.15 +*  under the terms of the GNU General Public License as published by
  196.16 +*  the Free Software Foundation, either version 3 of the License, or
  196.17 +*  (at your option) any later version.
  196.18 +*
  196.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  196.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  196.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  196.22 +*  License for more details.
  196.23 +*
  196.24 +*  You should have received a copy of the GNU General Public License
  196.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  196.26 +***********************************************************************/
  196.27 +
  196.28 +#define _GLPSTD_STDIO
  196.29 +#include "glpdmp.h"
  196.30 +#include "glpgmp.h"
  196.31 +#define xfault xerror
  196.32 +
  196.33 +#ifdef HAVE_GMP               /* use GNU MP bignum library */
  196.34 +
  196.35 +int gmp_pool_count(void) { return 0; }
  196.36 +
  196.37 +void gmp_free_mem(void) { return; }
  196.38 +
  196.39 +#else                         /* use GLPK bignum module */
  196.40 +
  196.41 +static DMP *gmp_pool = NULL;
  196.42 +static int gmp_size = 0;
  196.43 +static unsigned short *gmp_work = NULL;
  196.44 +
  196.45 +void *gmp_get_atom(int size)
  196.46 +{     if (gmp_pool == NULL)
  196.47 +         gmp_pool = dmp_create_pool();
  196.48 +      return dmp_get_atom(gmp_pool, size);
  196.49 +}
  196.50 +
  196.51 +void gmp_free_atom(void *ptr, int size)
  196.52 +{     xassert(gmp_pool != NULL);
  196.53 +      dmp_free_atom(gmp_pool, ptr, size);
  196.54 +      return;
  196.55 +}
  196.56 +
  196.57 +int gmp_pool_count(void)
  196.58 +{     if (gmp_pool == NULL)
  196.59 +         return 0;
  196.60 +      else
  196.61 +         return dmp_in_use(gmp_pool).lo;
  196.62 +}
  196.63 +
  196.64 +unsigned short *gmp_get_work(int size)
  196.65 +{     xassert(size > 0);
  196.66 +      if (gmp_size < size)
  196.67 +      {  if (gmp_size == 0)
  196.68 +         {  xassert(gmp_work == NULL);
  196.69 +            gmp_size = 100;
  196.70 +         }
  196.71 +         else
  196.72 +         {  xassert(gmp_work != NULL);
  196.73 +            xfree(gmp_work);
  196.74 +         }
  196.75 +         while (gmp_size < size) gmp_size += gmp_size;
  196.76 +         gmp_work = xcalloc(gmp_size, sizeof(unsigned short));
  196.77 +      }
  196.78 +      return gmp_work;
  196.79 +}
  196.80 +
  196.81 +void gmp_free_mem(void)
  196.82 +{     if (gmp_pool != NULL) dmp_delete_pool(gmp_pool);
  196.83 +      if (gmp_work != NULL) xfree(gmp_work);
  196.84 +      gmp_pool = NULL;
  196.85 +      gmp_size = 0;
  196.86 +      gmp_work = NULL;
  196.87 +      return;
  196.88 +}
  196.89 +
  196.90 +/*====================================================================*/
  196.91 +
  196.92 +mpz_t _mpz_init(void)
  196.93 +{     /* initialize x, and set its value to 0 */
  196.94 +      mpz_t x;
  196.95 +      x = gmp_get_atom(sizeof(struct mpz));
  196.96 +      x->val = 0;
  196.97 +      x->ptr = NULL;
  196.98 +      return x;
  196.99 +}
 196.100 +
 196.101 +void mpz_clear(mpz_t x)
 196.102 +{     /* free the space occupied by x */
 196.103 +      mpz_set_si(x, 0);
 196.104 +      xassert(x->ptr == NULL);
 196.105 +      /* free the number descriptor */
 196.106 +      gmp_free_atom(x, sizeof(struct mpz));
 196.107 +      return;
 196.108 +}
 196.109 +
 196.110 +void mpz_set(mpz_t z, mpz_t x)
 196.111 +{     /* set the value of z from x */
 196.112 +      struct mpz_seg *e, *ee, *es;
 196.113 +      if (z != x)
 196.114 +      {  mpz_set_si(z, 0);
 196.115 +         z->val = x->val;
 196.116 +         xassert(z->ptr == NULL);
 196.117 +         for (e = x->ptr, es = NULL; e != NULL; e = e->next)
 196.118 +         {  ee = gmp_get_atom(sizeof(struct mpz_seg));
 196.119 +            memcpy(ee->d, e->d, 12);
 196.120 +            ee->next = NULL;
 196.121 +            if (z->ptr == NULL)
 196.122 +               z->ptr = ee;
 196.123 +            else
 196.124 +               es->next = ee;
 196.125 +            es = ee;
 196.126 +         }
 196.127 +      }
 196.128 +      return;
 196.129 +}
 196.130 +
 196.131 +void mpz_set_si(mpz_t x, int val)
 196.132 +{     /* set the value of x to val */
 196.133 +      struct mpz_seg *e;
 196.134 +      /* free existing segments, if any */
 196.135 +      while (x->ptr != NULL)
 196.136 +      {  e = x->ptr;
 196.137 +         x->ptr = e->next;
 196.138 +         gmp_free_atom(e, sizeof(struct mpz_seg));
 196.139 +      }
 196.140 +      /* assign new value */
 196.141 +      if (val == 0x80000000)
 196.142 +      {  /* long format is needed */
 196.143 +         x->val = -1;
 196.144 +         x->ptr = e = gmp_get_atom(sizeof(struct mpz_seg));
 196.145 +         memset(e->d, 0, 12);
 196.146 +         e->d[1] = 0x8000;
 196.147 +         e->next = NULL;
 196.148 +      }
 196.149 +      else
 196.150 +      {  /* short format is enough */
 196.151 +         x->val = val;
 196.152 +      }
 196.153 +      return;
 196.154 +}
 196.155 +
 196.156 +double mpz_get_d(mpz_t x)
 196.157 +{     /* convert x to a double, truncating if necessary */
 196.158 +      struct mpz_seg *e;
 196.159 +      int j;
 196.160 +      double val, deg;
 196.161 +      if (x->ptr == NULL)
 196.162 +         val = (double)x->val;
 196.163 +      else
 196.164 +      {  xassert(x->val != 0);
 196.165 +         val = 0.0;
 196.166 +         deg = 1.0;
 196.167 +         for (e = x->ptr; e != NULL; e = e->next)
 196.168 +         {  for (j = 0; j <= 5; j++)
 196.169 +            {  val += deg * (double)((int)e->d[j]);
 196.170 +               deg *= 65536.0;
 196.171 +            }
 196.172 +         }
 196.173 +         if (x->val < 0) val = - val;
 196.174 +      }
 196.175 +      return val;
 196.176 +}
 196.177 +
 196.178 +double mpz_get_d_2exp(int *exp, mpz_t x)
 196.179 +{     /* convert x to a double, truncating if necessary (i.e. rounding
 196.180 +         towards zero), and returning the exponent separately;
 196.181 +         the return value is in the range 0.5 <= |d| < 1 and the
 196.182 +         exponent is stored to *exp; d*2^exp is the (truncated) x value;
 196.183 +         if x is zero, the return is 0.0 and 0 is stored to *exp;
 196.184 +         this is similar to the standard C frexp function */
 196.185 +      struct mpz_seg *e;
 196.186 +      int j, n, n1;
 196.187 +      double val;
 196.188 +      if (x->ptr == NULL)
 196.189 +         val = (double)x->val, n = 0;
 196.190 +      else
 196.191 +      {  xassert(x->val != 0);
 196.192 +         val = 0.0, n = 0;
 196.193 +         for (e = x->ptr; e != NULL; e = e->next)
 196.194 +         {  for (j = 0; j <= 5; j++)
 196.195 +            {  val += (double)((int)e->d[j]);
 196.196 +               val /= 65536.0, n += 16;
 196.197 +            }
 196.198 +         }
 196.199 +         if (x->val < 0) val = - val;
 196.200 +      }
 196.201 +      val = frexp(val, &n1);
 196.202 +      *exp = n + n1;
 196.203 +      return val;
 196.204 +}
 196.205 +
 196.206 +void mpz_swap(mpz_t x, mpz_t y)
 196.207 +{     /* swap the values x and y efficiently */
 196.208 +      int val;
 196.209 +      void *ptr;
 196.210 +      val = x->val, ptr = x->ptr;
 196.211 +      x->val = y->val, x->ptr = y->ptr;
 196.212 +      y->val = val, y->ptr = ptr;
 196.213 +      return;
 196.214 +}
 196.215 +
 196.216 +static void normalize(mpz_t x)
 196.217 +{     /* normalize integer x that includes removing non-significant
 196.218 +         (leading) zeros and converting to short format, if possible */
 196.219 +      struct mpz_seg *es, *e;
 196.220 +      /* if the integer is in short format, it remains unchanged */
 196.221 +      if (x->ptr == NULL)
 196.222 +      {  xassert(x->val != 0x80000000);
 196.223 +         goto done;
 196.224 +      }
 196.225 +      xassert(x->val == +1 || x->val == -1);
 196.226 +      /* find the last (most significant) non-zero segment */
 196.227 +      es = NULL;
 196.228 +      for (e = x->ptr; e != NULL; e = e->next)
 196.229 +      {  if (e->d[0] || e->d[1] || e->d[2] ||
 196.230 +             e->d[3] || e->d[4] || e->d[5]) es = e;
 196.231 +      }
 196.232 +      /* if all segments contain zeros, the integer is zero */
 196.233 +      if (es == NULL)
 196.234 +      {  mpz_set_si(x, 0);
 196.235 +         goto done;
 196.236 +      }
 196.237 +      /* remove non-significant (leading) zero segments */
 196.238 +      while (es->next != NULL)
 196.239 +      {  e = es->next;
 196.240 +         es->next = e->next;
 196.241 +         gmp_free_atom(e, sizeof(struct mpz_seg));
 196.242 +      }
 196.243 +      /* convert the integer to short format, if possible */
 196.244 +      e = x->ptr;
 196.245 +      if (e->next == NULL && e->d[1] <= 0x7FFF &&
 196.246 +         !e->d[2] && !e->d[3] && !e->d[4] && !e->d[5])
 196.247 +      {  int val;
 196.248 +         val = (int)e->d[0] + ((int)e->d[1] << 16);
 196.249 +         if (x->val < 0) val = - val;
 196.250 +         mpz_set_si(x, val);
 196.251 +      }
 196.252 +done: return;
 196.253 +}
 196.254 +
 196.255 +void mpz_add(mpz_t z, mpz_t x, mpz_t y)
 196.256 +{     /* set z to x + y */
 196.257 +      static struct mpz_seg zero = { { 0, 0, 0, 0, 0, 0 }, NULL };
 196.258 +      struct mpz_seg dumx, dumy, *ex, *ey, *ez, *es, *ee;
 196.259 +      int k, sx, sy, sz;
 196.260 +      unsigned int t;
 196.261 +      /* if [x] = 0 then [z] = [y] */
 196.262 +      if (x->val == 0)
 196.263 +      {  xassert(x->ptr == NULL);
 196.264 +         mpz_set(z, y);
 196.265 +         goto done;
 196.266 +      }
 196.267 +      /* if [y] = 0 then [z] = [x] */
 196.268 +      if (y->val == 0)
 196.269 +      {  xassert(y->ptr == NULL);
 196.270 +         mpz_set(z, x);
 196.271 +         goto done;
 196.272 +      }
 196.273 +      /* special case when both [x] and [y] are in short format */
 196.274 +      if (x->ptr == NULL && y->ptr == NULL)
 196.275 +      {  int xval = x->val, yval = y->val, zval = x->val + y->val;
 196.276 +         xassert(xval != 0x80000000 && yval != 0x80000000);
 196.277 +         if (!(xval > 0 && yval > 0 && zval <= 0 ||
 196.278 +               xval < 0 && yval < 0 && zval >= 0))
 196.279 +         {  mpz_set_si(z, zval);
 196.280 +            goto done;
 196.281 +         }
 196.282 +      }
 196.283 +      /* convert [x] to long format, if necessary */
 196.284 +      if (x->ptr == NULL)
 196.285 +      {  xassert(x->val != 0x80000000);
 196.286 +         if (x->val >= 0)
 196.287 +         {  sx = +1;
 196.288 +            t = (unsigned int)(+ x->val);
 196.289 +         }
 196.290 +         else
 196.291 +         {  sx = -1;
 196.292 +            t = (unsigned int)(- x->val);
 196.293 +         }
 196.294 +         ex = &dumx;
 196.295 +         ex->d[0] = (unsigned short)t;
 196.296 +         ex->d[1] = (unsigned short)(t >> 16);
 196.297 +         ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0;
 196.298 +         ex->next = NULL;
 196.299 +      }
 196.300 +      else
 196.301 +      {  sx = x->val;
 196.302 +         xassert(sx == +1 || sx == -1);
 196.303 +         ex = x->ptr;
 196.304 +      }
 196.305 +      /* convert [y] to long format, if necessary */
 196.306 +      if (y->ptr == NULL)
 196.307 +      {  xassert(y->val != 0x80000000);
 196.308 +         if (y->val >= 0)
 196.309 +         {  sy = +1;
 196.310 +            t = (unsigned int)(+ y->val);
 196.311 +         }
 196.312 +         else
 196.313 +         {  sy = -1;
 196.314 +            t = (unsigned int)(- y->val);
 196.315 +         }
 196.316 +         ey = &dumy;
 196.317 +         ey->d[0] = (unsigned short)t;
 196.318 +         ey->d[1] = (unsigned short)(t >> 16);
 196.319 +         ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0;
 196.320 +         ey->next = NULL;
 196.321 +      }
 196.322 +      else
 196.323 +      {  sy = y->val;
 196.324 +         xassert(sy == +1 || sy == -1);
 196.325 +         ey = y->ptr;
 196.326 +      }
 196.327 +      /* main fragment */
 196.328 +      sz = sx;
 196.329 +      ez = es = NULL;
 196.330 +      if (sx > 0 && sy > 0 || sx < 0 && sy < 0)
 196.331 +      {  /* [x] and [y] have identical signs -- addition */
 196.332 +         t = 0;
 196.333 +         for (; ex || ey; ex = ex->next, ey = ey->next)
 196.334 +         {  if (ex == NULL) ex = &zero;
 196.335 +            if (ey == NULL) ey = &zero;
 196.336 +            ee = gmp_get_atom(sizeof(struct mpz_seg));
 196.337 +            for (k = 0; k <= 5; k++)
 196.338 +            {  t += (unsigned int)ex->d[k];
 196.339 +               t += (unsigned int)ey->d[k];
 196.340 +               ee->d[k] = (unsigned short)t;
 196.341 +               t >>= 16;
 196.342 +            }
 196.343 +            ee->next = NULL;
 196.344 +            if (ez == NULL)
 196.345 +               ez = ee;
 196.346 +            else
 196.347 +               es->next = ee;
 196.348 +            es = ee;
 196.349 +         }
 196.350 +         if (t)
 196.351 +         {  /* overflow -- one extra digit is needed */
 196.352 +            ee = gmp_get_atom(sizeof(struct mpz_seg));
 196.353 +            ee->d[0] = 1;
 196.354 +            ee->d[1] = ee->d[2] = ee->d[3] = ee->d[4] = ee->d[5] = 0;
 196.355 +            ee->next = NULL;
 196.356 +            xassert(es != NULL);
 196.357 +            es->next = ee;
 196.358 +         }
 196.359 +      }
 196.360 +      else
 196.361 +      {  /* [x] and [y] have different signs -- subtraction */
 196.362 +         t = 1;
 196.363 +         for (; ex || ey; ex = ex->next, ey = ey->next)
 196.364 +         {  if (ex == NULL) ex = &zero;
 196.365 +            if (ey == NULL) ey = &zero;
 196.366 +            ee = gmp_get_atom(sizeof(struct mpz_seg));
 196.367 +            for (k = 0; k <= 5; k++)
 196.368 +            {  t += (unsigned int)ex->d[k];
 196.369 +               t += (0xFFFF - (unsigned int)ey->d[k]);
 196.370 +               ee->d[k] = (unsigned short)t;
 196.371 +               t >>= 16;
 196.372 +            }
 196.373 +            ee->next = NULL;
 196.374 +            if (ez == NULL)
 196.375 +               ez = ee;
 196.376 +            else
 196.377 +               es->next = ee;
 196.378 +            es = ee;
 196.379 +         }
 196.380 +         if (!t)
 196.381 +         {  /* |[x]| < |[y]| -- result in complement coding */
 196.382 +            sz = - sz;
 196.383 +            t = 1;
 196.384 +            for (ee = ez; ee != NULL; ee = ee->next)
 196.385 +            for (k = 0; k <= 5; k++)
 196.386 +            {  t += (0xFFFF - (unsigned int)ee->d[k]);
 196.387 +               ee->d[k] = (unsigned short)t;
 196.388 +               t >>= 16;
 196.389 +            }
 196.390 +         }
 196.391 +      }
 196.392 +      /* contruct and normalize result */
 196.393 +      mpz_set_si(z, 0);
 196.394 +      z->val = sz;
 196.395 +      z->ptr = ez;
 196.396 +      normalize(z);
 196.397 +done: return;
 196.398 +}
 196.399 +
 196.400 +void mpz_sub(mpz_t z, mpz_t x, mpz_t y)
 196.401 +{     /* set z to x - y */
 196.402 +      if (x == y)
 196.403 +         mpz_set_si(z, 0);
 196.404 +      else
 196.405 +      {  y->val = - y->val;
 196.406 +         mpz_add(z, x, y);
 196.407 +         if (y != z) y->val = - y->val;
 196.408 +      }
 196.409 +      return;
 196.410 +}
 196.411 +
 196.412 +void mpz_mul(mpz_t z, mpz_t x, mpz_t y)
 196.413 +{     /* set z to x * y */
 196.414 +      struct mpz_seg dumx, dumy, *ex, *ey, *es, *e;
 196.415 +      int sx, sy, k, nx, ny, n;
 196.416 +      unsigned int t;
 196.417 +      unsigned short *work, *wx, *wy;
 196.418 +      /* if [x] = 0 then [z] = 0 */
 196.419 +      if (x->val == 0)
 196.420 +      {  xassert(x->ptr == NULL);
 196.421 +         mpz_set_si(z, 0);
 196.422 +         goto done;
 196.423 +      }
 196.424 +      /* if [y] = 0 then [z] = 0 */
 196.425 +      if (y->val == 0)
 196.426 +      {  xassert(y->ptr == NULL);
 196.427 +         mpz_set_si(z, 0);
 196.428 +         goto done;
 196.429 +      }
 196.430 +      /* special case when both [x] and [y] are in short format */
 196.431 +      if (x->ptr == NULL && y->ptr == NULL)
 196.432 +      {  int xval = x->val, yval = y->val, sz = +1;
 196.433 +         xassert(xval != 0x80000000 && yval != 0x80000000);
 196.434 +         if (xval < 0) xval = - xval, sz = - sz;
 196.435 +         if (yval < 0) yval = - yval, sz = - sz;
 196.436 +         if (xval <= 0x7FFFFFFF / yval)
 196.437 +         {  mpz_set_si(z, sz * (xval * yval));
 196.438 +            goto done;
 196.439 +         }
 196.440 +      }
 196.441 +      /* convert [x] to long format, if necessary */
 196.442 +      if (x->ptr == NULL)
 196.443 +      {  xassert(x->val != 0x80000000);
 196.444 +         if (x->val >= 0)
 196.445 +         {  sx = +1;
 196.446 +            t = (unsigned int)(+ x->val);
 196.447 +         }
 196.448 +         else
 196.449 +         {  sx = -1;
 196.450 +            t = (unsigned int)(- x->val);
 196.451 +         }
 196.452 +         ex = &dumx;
 196.453 +         ex->d[0] = (unsigned short)t;
 196.454 +         ex->d[1] = (unsigned short)(t >> 16);
 196.455 +         ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0;
 196.456 +         ex->next = NULL;
 196.457 +      }
 196.458 +      else
 196.459 +      {  sx = x->val;
 196.460 +         xassert(sx == +1 || sx == -1);
 196.461 +         ex = x->ptr;
 196.462 +      }
 196.463 +      /* convert [y] to long format, if necessary */
 196.464 +      if (y->ptr == NULL)
 196.465 +      {  xassert(y->val != 0x80000000);
 196.466 +         if (y->val >= 0)
 196.467 +         {  sy = +1;
 196.468 +            t = (unsigned int)(+ y->val);
 196.469 +         }
 196.470 +         else
 196.471 +         {  sy = -1;
 196.472 +            t = (unsigned int)(- y->val);
 196.473 +         }
 196.474 +         ey = &dumy;
 196.475 +         ey->d[0] = (unsigned short)t;
 196.476 +         ey->d[1] = (unsigned short)(t >> 16);
 196.477 +         ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0;
 196.478 +         ey->next = NULL;
 196.479 +      }
 196.480 +      else
 196.481 +      {  sy = y->val;
 196.482 +         xassert(sy == +1 || sy == -1);
 196.483 +         ey = y->ptr;
 196.484 +      }
 196.485 +      /* determine the number of digits of [x] */
 196.486 +      nx = n = 0;
 196.487 +      for (e = ex; e != NULL; e = e->next)
 196.488 +      for (k = 0; k <= 5; k++)
 196.489 +      {  n++;
 196.490 +         if (e->d[k]) nx = n;
 196.491 +      }
 196.492 +      xassert(nx > 0);
 196.493 +      /* determine the number of digits of [y] */
 196.494 +      ny = n = 0;
 196.495 +      for (e = ey; e != NULL; e = e->next)
 196.496 +      for (k = 0; k <= 5; k++)
 196.497 +      {  n++;
 196.498 +         if (e->d[k]) ny = n;
 196.499 +      }
 196.500 +      xassert(ny > 0);
 196.501 +      /* we need working array containing at least nx+ny+ny places */
 196.502 +      work = gmp_get_work(nx+ny+ny);
 196.503 +      /* load digits of [x] */
 196.504 +      wx = &work[0];
 196.505 +      for (n = 0; n < nx; n++) wx[ny+n] = 0;
 196.506 +      for (n = 0, e = ex; e != NULL; e = e->next)
 196.507 +         for (k = 0; k <= 5; k++, n++)
 196.508 +            if (e->d[k]) wx[ny+n] = e->d[k];
 196.509 +      /* load digits of [y] */
 196.510 +      wy = &work[nx+ny];
 196.511 +      for (n = 0; n < ny; n++) wy[n] = 0;
 196.512 +      for (n = 0, e = ey; e != NULL; e = e->next)
 196.513 +         for (k = 0; k <= 5; k++, n++)
 196.514 +            if (e->d[k]) wy[n] = e->d[k];
 196.515 +      /* compute [x] * [y] */
 196.516 +      bigmul(nx, ny, wx, wy);
 196.517 +      /* construct and normalize result */
 196.518 +      mpz_set_si(z, 0);
 196.519 +      z->val = sx * sy;
 196.520 +      es = NULL;
 196.521 +      k = 6;
 196.522 +      for (n = 0; n < nx+ny; n++)
 196.523 +      {  if (k > 5)
 196.524 +         {  e = gmp_get_atom(sizeof(struct mpz_seg));
 196.525 +            e->d[0] = e->d[1] = e->d[2] = 0;
 196.526 +            e->d[3] = e->d[4] = e->d[5] = 0;
 196.527 +            e->next = NULL;
 196.528 +            if (z->ptr == NULL)
 196.529 +               z->ptr = e;
 196.530 +            else
 196.531 +               es->next = e;
 196.532 +            es = e;
 196.533 +            k = 0;
 196.534 +         }
 196.535 +         es->d[k++] = wx[n];
 196.536 +      }
 196.537 +      normalize(z);
 196.538 +done: return;
 196.539 +}
 196.540 +
 196.541 +void mpz_neg(mpz_t z, mpz_t x)
 196.542 +{     /* set z to 0 - x */
 196.543 +      mpz_set(z, x);
 196.544 +      z->val = - z->val;
 196.545 +      return;
 196.546 +}
 196.547 +
 196.548 +void mpz_abs(mpz_t z, mpz_t x)
 196.549 +{     /* set z to the absolute value of x */
 196.550 +      mpz_set(z, x);
 196.551 +      if (z->val < 0) z->val = - z->val;
 196.552 +      return;
 196.553 +}
 196.554 +
 196.555 +void mpz_div(mpz_t q, mpz_t r, mpz_t x, mpz_t y)
 196.556 +{     /* divide x by y, forming quotient q and/or remainder r
 196.557 +         if q = NULL then quotient is not stored; if r = NULL then
 196.558 +         remainder is not stored
 196.559 +         the sign of quotient is determined as in algebra while the
 196.560 +         sign of remainder is the same as the sign of dividend:
 196.561 +         +26 : +7 = +3, remainder is +5
 196.562 +         -26 : +7 = -3, remainder is -5
 196.563 +         +26 : -7 = -3, remainder is +5
 196.564 +         -26 : -7 = +3, remainder is -5 */
 196.565 +      struct mpz_seg dumx, dumy, *ex, *ey, *es, *e;
 196.566 +      int sx, sy, k, nx, ny, n;
 196.567 +      unsigned int t;
 196.568 +      unsigned short *work, *wx, *wy;
 196.569 +      /* divide by zero is not allowed */
 196.570 +      if (y->val == 0)
 196.571 +      {  xassert(y->ptr == NULL);
 196.572 +         xfault("mpz_div: divide by zero not allowed\n");
 196.573 +      }
 196.574 +      /* if [x] = 0 then [q] = [r] = 0 */
 196.575 +      if (x->val == 0)
 196.576 +      {  xassert(x->ptr == NULL);
 196.577 +         if (q != NULL) mpz_set_si(q, 0);
 196.578 +         if (r != NULL) mpz_set_si(r, 0);
 196.579 +         goto done;
 196.580 +      }
 196.581 +      /* special case when both [x] and [y] are in short format */
 196.582 +      if (x->ptr == NULL && y->ptr == NULL)
 196.583 +      {  int xval = x->val, yval = y->val;
 196.584 +         xassert(xval != 0x80000000 && yval != 0x80000000);
 196.585 +         if (q != NULL) mpz_set_si(q, xval / yval);
 196.586 +         if (r != NULL) mpz_set_si(r, xval % yval);
 196.587 +         goto done;
 196.588 +      }
 196.589 +      /* convert [x] to long format, if necessary */
 196.590 +      if (x->ptr == NULL)
 196.591 +      {  xassert(x->val != 0x80000000);
 196.592 +         if (x->val >= 0)
 196.593 +         {  sx = +1;
 196.594 +            t = (unsigned int)(+ x->val);
 196.595 +         }
 196.596 +         else
 196.597 +         {  sx = -1;
 196.598 +            t = (unsigned int)(- x->val);
 196.599 +         }
 196.600 +         ex = &dumx;
 196.601 +         ex->d[0] = (unsigned short)t;
 196.602 +         ex->d[1] = (unsigned short)(t >> 16);
 196.603 +         ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0;
 196.604 +         ex->next = NULL;
 196.605 +      }
 196.606 +      else
 196.607 +      {  sx = x->val;
 196.608 +         xassert(sx == +1 || sx == -1);
 196.609 +         ex = x->ptr;
 196.610 +      }
 196.611 +      /* convert [y] to long format, if necessary */
 196.612 +      if (y->ptr == NULL)
 196.613 +      {  xassert(y->val != 0x80000000);
 196.614 +         if (y->val >= 0)
 196.615 +         {  sy = +1;
 196.616 +            t = (unsigned int)(+ y->val);
 196.617 +         }
 196.618 +         else
 196.619 +         {  sy = -1;
 196.620 +            t = (unsigned int)(- y->val);
 196.621 +         }
 196.622 +         ey = &dumy;
 196.623 +         ey->d[0] = (unsigned short)t;
 196.624 +         ey->d[1] = (unsigned short)(t >> 16);
 196.625 +         ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0;
 196.626 +         ey->next = NULL;
 196.627 +      }
 196.628 +      else
 196.629 +      {  sy = y->val;
 196.630 +         xassert(sy == +1 || sy == -1);
 196.631 +         ey = y->ptr;
 196.632 +      }
 196.633 +      /* determine the number of digits of [x] */
 196.634 +      nx = n = 0;
 196.635 +      for (e = ex; e != NULL; e = e->next)
 196.636 +      for (k = 0; k <= 5; k++)
 196.637 +      {  n++;
 196.638 +         if (e->d[k]) nx = n;
 196.639 +      }
 196.640 +      xassert(nx > 0);
 196.641 +      /* determine the number of digits of [y] */
 196.642 +      ny = n = 0;
 196.643 +      for (e = ey; e != NULL; e = e->next)
 196.644 +      for (k = 0; k <= 5; k++)
 196.645 +      {  n++;
 196.646 +         if (e->d[k]) ny = n;
 196.647 +      }
 196.648 +      xassert(ny > 0);
 196.649 +      /* if nx < ny then [q] = 0 and [r] = [x] */
 196.650 +      if (nx < ny)
 196.651 +      {  if (r != NULL) mpz_set(r, x);
 196.652 +         if (q != NULL) mpz_set_si(q, 0);
 196.653 +         goto done;
 196.654 +      }
 196.655 +      /* we need working array containing at least nx+ny+1 places */
 196.656 +      work = gmp_get_work(nx+ny+1);
 196.657 +      /* load digits of [x] */
 196.658 +      wx = &work[0];
 196.659 +      for (n = 0; n < nx; n++) wx[n] = 0;
 196.660 +      for (n = 0, e = ex; e != NULL; e = e->next)
 196.661 +         for (k = 0; k <= 5; k++, n++)
 196.662 +            if (e->d[k]) wx[n] = e->d[k];
 196.663 +      /* load digits of [y] */
 196.664 +      wy = &work[nx+1];
 196.665 +      for (n = 0; n < ny; n++) wy[n] = 0;
 196.666 +      for (n = 0, e = ey; e != NULL; e = e->next)
 196.667 +         for (k = 0; k <= 5; k++, n++)
 196.668 +            if (e->d[k]) wy[n] = e->d[k];
 196.669 +      /* compute quotient and remainder */
 196.670 +      xassert(wy[ny-1] != 0);
 196.671 +      bigdiv(nx-ny, ny, wx, wy);
 196.672 +      /* construct and normalize quotient */
 196.673 +      if (q != NULL)
 196.674 +      {  mpz_set_si(q, 0);
 196.675 +         q->val = sx * sy;
 196.676 +         es = NULL;
 196.677 +         k = 6;
 196.678 +         for (n = ny; n <= nx; n++)
 196.679 +         {  if (k > 5)
 196.680 +            {  e = gmp_get_atom(sizeof(struct mpz_seg));
 196.681 +               e->d[0] = e->d[1] = e->d[2] = 0;
 196.682 +               e->d[3] = e->d[4] = e->d[5] = 0;
 196.683 +               e->next = NULL;
 196.684 +               if (q->ptr == NULL)
 196.685 +                  q->ptr = e;
 196.686 +               else
 196.687 +                  es->next = e;
 196.688 +               es = e;
 196.689 +               k = 0;
 196.690 +            }
 196.691 +            es->d[k++] = wx[n];
 196.692 +         }
 196.693 +         normalize(q);
 196.694 +      }
 196.695 +      /* construct and normalize remainder */
 196.696 +      if (r != NULL)
 196.697 +      {  mpz_set_si(r, 0);
 196.698 +         r->val = sx;
 196.699 +         es = NULL;
 196.700 +         k = 6;
 196.701 +         for (n = 0; n < ny; n++)
 196.702 +         {  if (k > 5)
 196.703 +            {  e = gmp_get_atom(sizeof(struct mpz_seg));
 196.704 +               e->d[0] = e->d[1] = e->d[2] = 0;
 196.705 +               e->d[3] = e->d[4] = e->d[5] = 0;
 196.706 +               e->next = NULL;
 196.707 +               if (r->ptr == NULL)
 196.708 +                  r->ptr = e;
 196.709 +               else
 196.710 +                  es->next = e;
 196.711 +               es = e;
 196.712 +               k = 0;
 196.713 +            }
 196.714 +            es->d[k++] = wx[n];
 196.715 +         }
 196.716 +         normalize(r);
 196.717 +      }
 196.718 +done: return;
 196.719 +}
 196.720 +
 196.721 +void mpz_gcd(mpz_t z, mpz_t x, mpz_t y)
 196.722 +{     /* set z to the greatest common divisor of x and y */
 196.723 +      /* in case of arbitrary integers GCD(x, y) = GCD(|x|, |y|), and,
 196.724 +         in particular, GCD(0, 0) = 0 */
 196.725 +      mpz_t u, v, r;
 196.726 +      mpz_init(u);
 196.727 +      mpz_init(v);
 196.728 +      mpz_init(r);
 196.729 +      mpz_abs(u, x);
 196.730 +      mpz_abs(v, y);
 196.731 +      while (mpz_sgn(v))
 196.732 +      {  mpz_div(NULL, r, u, v);
 196.733 +         mpz_set(u, v);
 196.734 +         mpz_set(v, r);
 196.735 +      }
 196.736 +      mpz_set(z, u);
 196.737 +      mpz_clear(u);
 196.738 +      mpz_clear(v);
 196.739 +      mpz_clear(r);
 196.740 +      return;
 196.741 +}
 196.742 +
 196.743 +int mpz_cmp(mpz_t x, mpz_t y)
 196.744 +{     /* compare x and y; return a positive value if x > y, zero if
 196.745 +         x = y, or a nefative value if x < y */
 196.746 +      static struct mpz_seg zero = { { 0, 0, 0, 0, 0, 0 }, NULL };
 196.747 +      struct mpz_seg dumx, dumy, *ex, *ey;
 196.748 +      int cc, sx, sy, k;
 196.749 +      unsigned int t;
 196.750 +      if (x == y)
 196.751 +      {  cc = 0;
 196.752 +         goto done;
 196.753 +      }
 196.754 +      /* special case when both [x] and [y] are in short format */
 196.755 +      if (x->ptr == NULL && y->ptr == NULL)
 196.756 +      {  int xval = x->val, yval = y->val;
 196.757 +         xassert(xval != 0x80000000 && yval != 0x80000000);
 196.758 +         cc = (xval > yval ? +1 : xval < yval ? -1 : 0);
 196.759 +         goto done;
 196.760 +      }
 196.761 +      /* special case when [x] and [y] have different signs */
 196.762 +      if (x->val > 0 && y->val <= 0 || x->val == 0 && y->val < 0)
 196.763 +      {  cc = +1;
 196.764 +         goto done;
 196.765 +      }
 196.766 +      if (x->val < 0 && y->val >= 0 || x->val == 0 && y->val > 0)
 196.767 +      {  cc = -1;
 196.768 +         goto done;
 196.769 +      }
 196.770 +      /* convert [x] to long format, if necessary */
 196.771 +      if (x->ptr == NULL)
 196.772 +      {  xassert(x->val != 0x80000000);
 196.773 +         if (x->val >= 0)
 196.774 +         {  sx = +1;
 196.775 +            t = (unsigned int)(+ x->val);
 196.776 +         }
 196.777 +         else
 196.778 +         {  sx = -1;
 196.779 +            t = (unsigned int)(- x->val);
 196.780 +         }
 196.781 +         ex = &dumx;
 196.782 +         ex->d[0] = (unsigned short)t;
 196.783 +         ex->d[1] = (unsigned short)(t >> 16);
 196.784 +         ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0;
 196.785 +         ex->next = NULL;
 196.786 +      }
 196.787 +      else
 196.788 +      {  sx = x->val;
 196.789 +         xassert(sx == +1 || sx == -1);
 196.790 +         ex = x->ptr;
 196.791 +      }
 196.792 +      /* convert [y] to long format, if necessary */
 196.793 +      if (y->ptr == NULL)
 196.794 +      {  xassert(y->val != 0x80000000);
 196.795 +         if (y->val >= 0)
 196.796 +         {  sy = +1;
 196.797 +            t = (unsigned int)(+ y->val);
 196.798 +         }
 196.799 +         else
 196.800 +         {  sy = -1;
 196.801 +            t = (unsigned int)(- y->val);
 196.802 +         }
 196.803 +         ey = &dumy;
 196.804 +         ey->d[0] = (unsigned short)t;
 196.805 +         ey->d[1] = (unsigned short)(t >> 16);
 196.806 +         ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0;
 196.807 +         ey->next = NULL;
 196.808 +      }
 196.809 +      else
 196.810 +      {  sy = y->val;
 196.811 +         xassert(sy == +1 || sy == -1);
 196.812 +         ey = y->ptr;
 196.813 +      }
 196.814 +      /* main fragment */
 196.815 +      xassert(sx > 0 && sy > 0 || sx < 0 && sy < 0);
 196.816 +      cc = 0;
 196.817 +      for (; ex || ey; ex = ex->next, ey = ey->next)
 196.818 +      {  if (ex == NULL) ex = &zero;
 196.819 +         if (ey == NULL) ey = &zero;
 196.820 +         for (k = 0; k <= 5; k++)
 196.821 +         {  if (ex->d[k] > ey->d[k]) cc = +1;
 196.822 +            if (ex->d[k] < ey->d[k]) cc = -1;
 196.823 +         }
 196.824 +      }
 196.825 +      if (sx < 0) cc = - cc;
 196.826 +done: return cc;
 196.827 +}
 196.828 +
 196.829 +int mpz_sgn(mpz_t x)
 196.830 +{     /* return +1 if x > 0, 0 if x = 0, and -1 if x < 0 */
 196.831 +      int s;
 196.832 +      s = (x->val > 0 ? +1 : x->val < 0 ? -1 : 0);
 196.833 +      return s;
 196.834 +}
 196.835 +
 196.836 +int mpz_out_str(void *_fp, int base, mpz_t x)
 196.837 +{     /* output x on stream fp, as a string in given base; the base
 196.838 +         may vary from 2 to 36;
 196.839 +         return the number of bytes written, or if an error occurred,
 196.840 +         return 0 */
 196.841 +      FILE *fp = _fp;
 196.842 +      mpz_t b, y, r;
 196.843 +      int n, j, nwr = 0;
 196.844 +      unsigned char *d;
 196.845 +      static char *set = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 196.846 +      if (!(2 <= base && base <= 36))
 196.847 +         xfault("mpz_out_str: base = %d; invalid base\n", base);
 196.848 +      mpz_init(b);
 196.849 +      mpz_set_si(b, base);
 196.850 +      mpz_init(y);
 196.851 +      mpz_init(r);
 196.852 +      /* determine the number of digits */
 196.853 +      mpz_abs(y, x);
 196.854 +      for (n = 0; mpz_sgn(y) != 0; n++)
 196.855 +         mpz_div(y, NULL, y, b);
 196.856 +      if (n == 0) n = 1;
 196.857 +      /* compute the digits */
 196.858 +      d = xmalloc(n);
 196.859 +      mpz_abs(y, x);
 196.860 +      for (j = 0; j < n; j++)
 196.861 +      {  mpz_div(y, r, y, b);
 196.862 +         xassert(0 <= r->val && r->val < base && r->ptr == NULL);
 196.863 +         d[j] = (unsigned char)r->val;
 196.864 +      }
 196.865 +      /* output the integer to the stream */
 196.866 +      if (fp == NULL) fp = stdout;
 196.867 +      if (mpz_sgn(x) < 0)
 196.868 +         fputc('-', fp), nwr++;
 196.869 +      for (j = n-1; j >= 0; j--)
 196.870 +         fputc(set[d[j]], fp), nwr++;
 196.871 +      if (ferror(fp)) nwr = 0;
 196.872 +      mpz_clear(b);
 196.873 +      mpz_clear(y);
 196.874 +      mpz_clear(r);
 196.875 +      xfree(d);
 196.876 +      return nwr;
 196.877 +}
 196.878 +
 196.879 +/*====================================================================*/
 196.880 +
 196.881 +mpq_t _mpq_init(void)
 196.882 +{     /* initialize x, and set its value to 0/1 */
 196.883 +      mpq_t x;
 196.884 +      x = gmp_get_atom(sizeof(struct mpq));
 196.885 +      x->p.val = 0;
 196.886 +      x->p.ptr = NULL;
 196.887 +      x->q.val = 1;
 196.888 +      x->q.ptr = NULL;
 196.889 +      return x;
 196.890 +}
 196.891 +
 196.892 +void mpq_clear(mpq_t x)
 196.893 +{     /* free the space occupied by x */
 196.894 +      mpz_set_si(&x->p, 0);
 196.895 +      xassert(x->p.ptr == NULL);
 196.896 +      mpz_set_si(&x->q, 0);
 196.897 +      xassert(x->q.ptr == NULL);
 196.898 +      /* free the number descriptor */
 196.899 +      gmp_free_atom(x, sizeof(struct mpq));
 196.900 +      return;
 196.901 +}
 196.902 +
 196.903 +void mpq_canonicalize(mpq_t x)
 196.904 +{     /* remove any factors that are common to the numerator and
 196.905 +         denominator of x, and make the denominator positive */
 196.906 +      mpz_t f;
 196.907 +      xassert(x->q.val != 0);
 196.908 +      if (x->q.val < 0)
 196.909 +      {  mpz_neg(&x->p, &x->p);
 196.910 +         mpz_neg(&x->q, &x->q);
 196.911 +      }
 196.912 +      mpz_init(f);
 196.913 +      mpz_gcd(f, &x->p, &x->q);
 196.914 +      if (!(f->val == 1 && f->ptr == NULL))
 196.915 +      {  mpz_div(&x->p, NULL, &x->p, f);
 196.916 +         mpz_div(&x->q, NULL, &x->q, f);
 196.917 +      }
 196.918 +      mpz_clear(f);
 196.919 +      return;
 196.920 +}
 196.921 +
 196.922 +void mpq_set(mpq_t z, mpq_t x)
 196.923 +{     /* set the value of z from x */
 196.924 +      if (z != x)
 196.925 +      {  mpz_set(&z->p, &x->p);
 196.926 +         mpz_set(&z->q, &x->q);
 196.927 +      }
 196.928 +      return;
 196.929 +}
 196.930 +
 196.931 +void mpq_set_si(mpq_t x, int p, unsigned int q)
 196.932 +{     /* set the value of x to p/q */
 196.933 +      if (q == 0)
 196.934 +         xfault("mpq_set_si: zero denominator not allowed\n");
 196.935 +      mpz_set_si(&x->p, p);
 196.936 +      xassert(q <= 0x7FFFFFFF);
 196.937 +      mpz_set_si(&x->q, q);
 196.938 +      return;
 196.939 +}
 196.940 +
 196.941 +double mpq_get_d(mpq_t x)
 196.942 +{     /* convert x to a double, truncating if necessary */
 196.943 +      int np, nq;
 196.944 +      double p, q;
 196.945 +      p = mpz_get_d_2exp(&np, &x->p);
 196.946 +      q = mpz_get_d_2exp(&nq, &x->q);
 196.947 +      return ldexp(p / q, np - nq);
 196.948 +}
 196.949 +
 196.950 +void mpq_set_d(mpq_t x, double val)
 196.951 +{     /* set x to val; there is no rounding, the conversion is exact */
 196.952 +      int s, n, d, j;
 196.953 +      double f;
 196.954 +      mpz_t temp;
 196.955 +      xassert(-DBL_MAX <= val && val <= +DBL_MAX);
 196.956 +      mpq_set_si(x, 0, 1);
 196.957 +      if (val > 0.0)
 196.958 +         s = +1;
 196.959 +      else if (val < 0.0)
 196.960 +         s = -1;
 196.961 +      else
 196.962 +         goto done;
 196.963 +      f = frexp(fabs(val), &n);
 196.964 +      /* |val| = f * 2^n, where 0.5 <= f < 1.0 */
 196.965 +      mpz_init(temp);
 196.966 +      while (f != 0.0)
 196.967 +      {  f *= 16.0, n -= 4;
 196.968 +         d = (int)f;
 196.969 +         xassert(0 <= d && d <= 15);
 196.970 +         f -= (double)d;
 196.971 +         /* x := 16 * x + d */
 196.972 +         mpz_set_si(temp, 16);
 196.973 +         mpz_mul(&x->p, &x->p, temp);
 196.974 +         mpz_set_si(temp, d);
 196.975 +         mpz_add(&x->p, &x->p, temp);
 196.976 +      }
 196.977 +      mpz_clear(temp);
 196.978 +      /* x := x * 2^n */
 196.979 +      if (n > 0)
 196.980 +      {  for (j = 1; j <= n; j++)
 196.981 +            mpz_add(&x->p, &x->p, &x->p);
 196.982 +      }
 196.983 +      else if (n < 0)
 196.984 +      {  for (j = 1; j <= -n; j++)
 196.985 +            mpz_add(&x->q, &x->q, &x->q);
 196.986 +         mpq_canonicalize(x);
 196.987 +      }
 196.988 +      if (s < 0) mpq_neg(x, x);
 196.989 +done: return;
 196.990 +}
 196.991 +
 196.992 +void mpq_add(mpq_t z, mpq_t x, mpq_t y)
 196.993 +{     /* set z to x + y */
 196.994 +      mpz_t p, q;
 196.995 +      mpz_init(p);
 196.996 +      mpz_init(q);
 196.997 +      mpz_mul(p, &x->p, &y->q);
 196.998 +      mpz_mul(q, &x->q, &y->p);
 196.999 +      mpz_add(p, p, q);
196.1000 +      mpz_mul(q, &x->q, &y->q);
196.1001 +      mpz_set(&z->p, p);
196.1002 +      mpz_set(&z->q, q);
196.1003 +      mpz_clear(p);
196.1004 +      mpz_clear(q);
196.1005 +      mpq_canonicalize(z);
196.1006 +      return;
196.1007 +}
196.1008 +
196.1009 +void mpq_sub(mpq_t z, mpq_t x, mpq_t y)
196.1010 +{     /* set z to x - y */
196.1011 +      mpz_t p, q;
196.1012 +      mpz_init(p);
196.1013 +      mpz_init(q);
196.1014 +      mpz_mul(p, &x->p, &y->q);
196.1015 +      mpz_mul(q, &x->q, &y->p);
196.1016 +      mpz_sub(p, p, q);
196.1017 +      mpz_mul(q, &x->q, &y->q);
196.1018 +      mpz_set(&z->p, p);
196.1019 +      mpz_set(&z->q, q);
196.1020 +      mpz_clear(p);
196.1021 +      mpz_clear(q);
196.1022 +      mpq_canonicalize(z);
196.1023 +      return;
196.1024 +}
196.1025 +
196.1026 +void mpq_mul(mpq_t z, mpq_t x, mpq_t y)
196.1027 +{     /* set z to x * y */
196.1028 +      mpz_mul(&z->p, &x->p, &y->p);
196.1029 +      mpz_mul(&z->q, &x->q, &y->q);
196.1030 +      mpq_canonicalize(z);
196.1031 +      return;
196.1032 +}
196.1033 +
196.1034 +void mpq_div(mpq_t z, mpq_t x, mpq_t y)
196.1035 +{     /* set z to x / y */
196.1036 +      mpz_t p, q;
196.1037 +      if (mpq_sgn(y) == 0)
196.1038 +         xfault("mpq_div: zero divisor not allowed\n");
196.1039 +      mpz_init(p);
196.1040 +      mpz_init(q);
196.1041 +      mpz_mul(p, &x->p, &y->q);
196.1042 +      mpz_mul(q, &x->q, &y->p);
196.1043 +      mpz_set(&z->p, p);
196.1044 +      mpz_set(&z->q, q);
196.1045 +      mpz_clear(p);
196.1046 +      mpz_clear(q);
196.1047 +      mpq_canonicalize(z);
196.1048 +      return;
196.1049 +}
196.1050 +
196.1051 +void mpq_neg(mpq_t z, mpq_t x)
196.1052 +{     /* set z to 0 - x */
196.1053 +      mpq_set(z, x);
196.1054 +      mpz_neg(&z->p, &z->p);
196.1055 +      return;
196.1056 +}
196.1057 +
196.1058 +void mpq_abs(mpq_t z, mpq_t x)
196.1059 +{     /* set z to the absolute value of x */
196.1060 +      mpq_set(z, x);
196.1061 +      mpz_abs(&z->p, &z->p);
196.1062 +      xassert(mpz_sgn(&x->q) > 0);
196.1063 +      return;
196.1064 +}
196.1065 +
196.1066 +int mpq_cmp(mpq_t x, mpq_t y)
196.1067 +{     /* compare x and y; return a positive value if x > y, zero if
196.1068 +         x = y, or a nefative value if x < y */
196.1069 +      mpq_t temp;
196.1070 +      int s;
196.1071 +      mpq_init(temp);
196.1072 +      mpq_sub(temp, x, y);
196.1073 +      s = mpq_sgn(temp);
196.1074 +      mpq_clear(temp);
196.1075 +      return s;
196.1076 +}
196.1077 +
196.1078 +int mpq_sgn(mpq_t x)
196.1079 +{     /* return +1 if x > 0, 0 if x = 0, and -1 if x < 0 */
196.1080 +      int s;
196.1081 +      s = mpz_sgn(&x->p);
196.1082 +      xassert(mpz_sgn(&x->q) > 0);
196.1083 +      return s;
196.1084 +}
196.1085 +
196.1086 +int mpq_out_str(void *_fp, int base, mpq_t x)
196.1087 +{     /* output x on stream fp, as a string in given base; the base
196.1088 +         may vary from 2 to 36; output is in the form 'num/den' or if
196.1089 +         the denominator is 1 then just 'num';
196.1090 +         if the parameter fp is a null pointer, stdout is assumed;
196.1091 +         return the number of bytes written, or if an error occurred,
196.1092 +         return 0 */
196.1093 +      FILE *fp = _fp;
196.1094 +      int nwr;
196.1095 +      if (!(2 <= base && base <= 36))
196.1096 +         xfault("mpq_out_str: base = %d; invalid base\n", base);
196.1097 +      if (fp == NULL) fp = stdout;
196.1098 +      nwr = mpz_out_str(fp, base, &x->p);
196.1099 +      if (x->q.val == 1 && x->q.ptr == NULL)
196.1100 +         ;
196.1101 +      else
196.1102 +      {  fputc('/', fp), nwr++;
196.1103 +         nwr += mpz_out_str(fp, base, &x->q);
196.1104 +      }
196.1105 +      if (ferror(fp)) nwr = 0;
196.1106 +      return nwr;
196.1107 +}
196.1108 +
196.1109 +#endif
196.1110 +
196.1111 +/* eof */
   197.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   197.2 +++ b/src/glpgmp.h	Mon Dec 06 13:09:21 2010 +0100
   197.3 @@ -0,0 +1,190 @@
   197.4 +/* glpgmp.h (bignum arithmetic) */
   197.5 +
   197.6 +/***********************************************************************
   197.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   197.8 +*
   197.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  197.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  197.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  197.12 +*  E-mail: <mao@gnu.org>.
  197.13 +*
  197.14 +*  GLPK is free software: you can redistribute it and/or modify it
  197.15 +*  under the terms of the GNU General Public License as published by
  197.16 +*  the Free Software Foundation, either version 3 of the License, or
  197.17 +*  (at your option) any later version.
  197.18 +*
  197.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  197.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  197.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  197.22 +*  License for more details.
  197.23 +*
  197.24 +*  You should have received a copy of the GNU General Public License
  197.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  197.26 +***********************************************************************/
  197.27 +
  197.28 +#ifndef GLPGMP_H
  197.29 +#define GLPGMP_H
  197.30 +
  197.31 +#ifdef HAVE_CONFIG_H
  197.32 +#include <config.h>
  197.33 +#endif
  197.34 +
  197.35 +#ifdef HAVE_GMP               /* use GNU MP bignum library */
  197.36 +
  197.37 +#include <gmp.h>
  197.38 +
  197.39 +#define gmp_pool_count        _glp_gmp_pool_count
  197.40 +#define gmp_free_mem          _glp_gmp_free_mem
  197.41 +
  197.42 +int gmp_pool_count(void);
  197.43 +void gmp_free_mem(void);
  197.44 +
  197.45 +#else                         /* use GLPK bignum module */
  197.46 +
  197.47 +/*----------------------------------------------------------------------
  197.48 +// INTEGER NUMBERS
  197.49 +//
  197.50 +// Depending on its magnitude an integer number of arbitrary precision
  197.51 +// is represented either in short format or in long format.
  197.52 +//
  197.53 +// Short format corresponds to the int type and allows representing
  197.54 +// integer numbers in the range [-(2^31-1), +(2^31-1)]. Note that for
  197.55 +// the most negative number of int type the short format is not used.
  197.56 +//
  197.57 +// In long format integer numbers are represented using the positional
  197.58 +// system with the base (radix) 2^16 = 65536:
  197.59 +//
  197.60 +//    x = (-1)^s sum{j in 0..n-1} d[j] * 65536^j,
  197.61 +//
  197.62 +// where x is the integer to be represented, s is its sign (+1 or -1),
  197.63 +// d[j] are its digits (0 <= d[j] <= 65535).
  197.64 +//
  197.65 +// RATIONAL NUMBERS
  197.66 +//
  197.67 +// A rational number is represented as an irreducible fraction:
  197.68 +//
  197.69 +//    p / q,
  197.70 +//
  197.71 +// where p (numerator) and q (denominator) are integer numbers (q > 0)
  197.72 +// having no common divisors. */
  197.73 +
  197.74 +struct mpz
  197.75 +{     /* integer number */
  197.76 +      int val;
  197.77 +      /* if ptr is a null pointer, the number is in short format, and
  197.78 +         val is its value; otherwise, the number is in long format, and
  197.79 +         val is its sign (+1 or -1) */
  197.80 +      struct mpz_seg *ptr;
  197.81 +      /* pointer to the linked list of the number segments ordered in
  197.82 +         ascending of powers of the base */
  197.83 +};
  197.84 +
  197.85 +struct mpz_seg
  197.86 +{     /* integer number segment */
  197.87 +      unsigned short d[6];
  197.88 +      /* six digits of the number ordered in ascending of powers of the
  197.89 +         base */
  197.90 +      struct mpz_seg *next;
  197.91 +      /* pointer to the next number segment */
  197.92 +};
  197.93 +
  197.94 +struct mpq
  197.95 +{     /* rational number (p / q) */
  197.96 +      struct mpz p;
  197.97 +      /* numerator */
  197.98 +      struct mpz q;
  197.99 +      /* denominator */
 197.100 +};
 197.101 +
 197.102 +typedef struct mpz *mpz_t;
 197.103 +typedef struct mpq *mpq_t;
 197.104 +
 197.105 +#define gmp_get_atom          _glp_gmp_get_atom
 197.106 +#define gmp_free_atom         _glp_gmp_free_atom
 197.107 +#define gmp_pool_count        _glp_gmp_pool_count
 197.108 +#define gmp_get_work          _glp_gmp_get_work
 197.109 +#define gmp_free_mem          _glp_gmp_free_mem
 197.110 +
 197.111 +#define _mpz_init             _glp_mpz_init
 197.112 +#define mpz_clear             _glp_mpz_clear
 197.113 +#define mpz_set               _glp_mpz_set
 197.114 +#define mpz_set_si            _glp_mpz_set_si
 197.115 +#define mpz_get_d             _glp_mpz_get_d
 197.116 +#define mpz_get_d_2exp        _glp_mpz_get_d_2exp
 197.117 +#define mpz_swap              _glp_mpz_swap
 197.118 +#define mpz_add               _glp_mpz_add
 197.119 +#define mpz_sub               _glp_mpz_sub
 197.120 +#define mpz_mul               _glp_mpz_mul
 197.121 +#define mpz_neg               _glp_mpz_neg
 197.122 +#define mpz_abs               _glp_mpz_abs
 197.123 +#define mpz_div               _glp_mpz_div
 197.124 +#define mpz_gcd               _glp_mpz_gcd
 197.125 +#define mpz_cmp               _glp_mpz_cmp
 197.126 +#define mpz_sgn               _glp_mpz_sgn
 197.127 +#define mpz_out_str           _glp_mpz_out_str
 197.128 +
 197.129 +#define _mpq_init             _glp_mpq_init
 197.130 +#define mpq_clear             _glp_mpq_clear
 197.131 +#define mpq_canonicalize      _glp_mpq_canonicalize
 197.132 +#define mpq_set               _glp_mpq_set
 197.133 +#define mpq_set_si            _glp_mpq_set_si
 197.134 +#define mpq_get_d             _glp_mpq_get_d
 197.135 +#define mpq_set_d             _glp_mpq_set_d
 197.136 +#define mpq_add               _glp_mpq_add
 197.137 +#define mpq_sub               _glp_mpq_sub
 197.138 +#define mpq_mul               _glp_mpq_mul
 197.139 +#define mpq_div               _glp_mpq_div
 197.140 +#define mpq_neg               _glp_mpq_neg
 197.141 +#define mpq_abs               _glp_mpq_abs
 197.142 +#define mpq_cmp               _glp_mpq_cmp
 197.143 +#define mpq_sgn               _glp_mpq_sgn
 197.144 +#define mpq_out_str           _glp_mpq_out_str
 197.145 +
 197.146 +void *gmp_get_atom(int size);
 197.147 +void gmp_free_atom(void *ptr, int size);
 197.148 +int gmp_pool_count(void);
 197.149 +unsigned short *gmp_get_work(int size);
 197.150 +void gmp_free_mem(void);
 197.151 +
 197.152 +mpz_t _mpz_init(void);
 197.153 +#define mpz_init(x) (void)((x) = _mpz_init())
 197.154 +void mpz_clear(mpz_t x);
 197.155 +void mpz_set(mpz_t z, mpz_t x);
 197.156 +void mpz_set_si(mpz_t x, int val);
 197.157 +double mpz_get_d(mpz_t x);
 197.158 +double mpz_get_d_2exp(int *exp, mpz_t x);
 197.159 +void mpz_swap(mpz_t x, mpz_t y);
 197.160 +void mpz_add(mpz_t, mpz_t, mpz_t);
 197.161 +void mpz_sub(mpz_t, mpz_t, mpz_t);
 197.162 +void mpz_mul(mpz_t, mpz_t, mpz_t);
 197.163 +void mpz_neg(mpz_t z, mpz_t x);
 197.164 +void mpz_abs(mpz_t z, mpz_t x);
 197.165 +void mpz_div(mpz_t q, mpz_t r, mpz_t x, mpz_t y);
 197.166 +void mpz_gcd(mpz_t z, mpz_t x, mpz_t y);
 197.167 +int mpz_cmp(mpz_t x, mpz_t y);
 197.168 +int mpz_sgn(mpz_t x);
 197.169 +int mpz_out_str(void *fp, int base, mpz_t x);
 197.170 +
 197.171 +mpq_t _mpq_init(void);
 197.172 +#define mpq_init(x) (void)((x) = _mpq_init())
 197.173 +void mpq_clear(mpq_t x);
 197.174 +void mpq_canonicalize(mpq_t x);
 197.175 +void mpq_set(mpq_t z, mpq_t x);
 197.176 +void mpq_set_si(mpq_t x, int p, unsigned int q);
 197.177 +double mpq_get_d(mpq_t x);
 197.178 +void mpq_set_d(mpq_t x, double val);
 197.179 +void mpq_add(mpq_t z, mpq_t x, mpq_t y);
 197.180 +void mpq_sub(mpq_t z, mpq_t x, mpq_t y);
 197.181 +void mpq_mul(mpq_t z, mpq_t x, mpq_t y);
 197.182 +void mpq_div(mpq_t z, mpq_t x, mpq_t y);
 197.183 +void mpq_neg(mpq_t z, mpq_t x);
 197.184 +void mpq_abs(mpq_t z, mpq_t x);
 197.185 +int mpq_cmp(mpq_t x, mpq_t y);
 197.186 +int mpq_sgn(mpq_t x);
 197.187 +int mpq_out_str(void *fp, int base, mpq_t x);
 197.188 +
 197.189 +#endif
 197.190 +
 197.191 +#endif
 197.192 +
 197.193 +/* eof */
   198.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   198.2 +++ b/src/glphbm.c	Mon Dec 06 13:09:21 2010 +0100
   198.3 @@ -0,0 +1,519 @@
   198.4 +/* glphbm.c */
   198.5 +
   198.6 +/***********************************************************************
   198.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   198.8 +*
   198.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  198.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  198.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  198.12 +*  E-mail: <mao@gnu.org>.
  198.13 +*
  198.14 +*  GLPK is free software: you can redistribute it and/or modify it
  198.15 +*  under the terms of the GNU General Public License as published by
  198.16 +*  the Free Software Foundation, either version 3 of the License, or
  198.17 +*  (at your option) any later version.
  198.18 +*
  198.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  198.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  198.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  198.22 +*  License for more details.
  198.23 +*
  198.24 +*  You should have received a copy of the GNU General Public License
  198.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  198.26 +***********************************************************************/
  198.27 +
  198.28 +#define _GLPSTD_ERRNO
  198.29 +#define _GLPSTD_STDIO
  198.30 +#include "glphbm.h"
  198.31 +#include "glpenv.h"
  198.32 +
  198.33 +/***********************************************************************
  198.34 +*  NAME
  198.35 +*
  198.36 +*  hbm_read_mat - read sparse matrix in Harwell-Boeing format
  198.37 +*
  198.38 +*  SYNOPSIS
  198.39 +*
  198.40 +*  #include "glphbm.h"
  198.41 +*  HBM *hbm_read_mat(const char *fname);
  198.42 +*
  198.43 +*  DESCRIPTION
  198.44 +*
  198.45 +*  The routine hbm_read_mat reads a sparse matrix in the Harwell-Boeing
  198.46 +*  format from a text file whose name is the character string fname.
  198.47 +*
  198.48 +*  Detailed description of the Harwell-Boeing format recognised by this
  198.49 +*  routine is given in the following report:
  198.50 +*
  198.51 +*  I.S.Duff, R.G.Grimes, J.G.Lewis. User's Guide for the Harwell-Boeing
  198.52 +*  Sparse Matrix Collection (Release I), TR/PA/92/86, October 1992.
  198.53 +*
  198.54 +*  RETURNS
  198.55 +*
  198.56 +*  If no error occured, the routine hbm_read_mat returns a pointer to
  198.57 +*  a data structure containing the matrix. In case of error the routine
  198.58 +*  prints an appropriate error message and returns NULL. */
  198.59 +
  198.60 +struct dsa
  198.61 +{     /* working area used by routine hbm_read_mat */
  198.62 +      const char *fname;
  198.63 +      /* name of input text file */
  198.64 +      FILE *fp;
  198.65 +      /* stream assigned to input text file */
  198.66 +      int seqn;
  198.67 +      /* card sequential number */
  198.68 +      char card[80+1];
  198.69 +      /* card image buffer */
  198.70 +      int fmt_p;
  198.71 +      /* scale factor */
  198.72 +      int fmt_k;
  198.73 +      /* iterator */
  198.74 +      int fmt_f;
  198.75 +      /* format code */
  198.76 +      int fmt_w;
  198.77 +      /* field width */
  198.78 +      int fmt_d;
  198.79 +      /* number of decimal places after point */
  198.80 +};
  198.81 +
  198.82 +/***********************************************************************
  198.83 +*  read_card - read next data card
  198.84 +*
  198.85 +*  This routine reads the next 80-column card from the input text file
  198.86 +*  and stores its image into the character string card. If the card was
  198.87 +*  read successfully, the routine returns zero, otherwise non-zero. */
  198.88 +
  198.89 +static int read_card(struct dsa *dsa)
  198.90 +{     int k, c;
  198.91 +      dsa->seqn++;
  198.92 +      memset(dsa->card, ' ', 80), dsa->card[80] = '\0';
  198.93 +      k = 0;
  198.94 +      for (;;)
  198.95 +      {  c = fgetc(dsa->fp);
  198.96 +         if (ferror(dsa->fp))
  198.97 +         {  xprintf("%s:%d: read error - %s\n", dsa->fname, dsa->seqn,
  198.98 +               strerror(errno));
  198.99 +            return 1;
 198.100 +         }
 198.101 +         if (feof(dsa->fp))
 198.102 +         {  if (k == 0)
 198.103 +               xprintf("%s:%d: unexpected EOF\n", dsa->fname,
 198.104 +                  dsa->seqn);
 198.105 +            else
 198.106 +               xprintf("%s:%d: missing final LF\n", dsa->fname,
 198.107 +                  dsa->seqn);
 198.108 +            return 1;
 198.109 +         }
 198.110 +         if (c == '\r') continue;
 198.111 +         if (c == '\n') break;
 198.112 +         if (iscntrl(c))
 198.113 +         {  xprintf("%s:%d: invalid control character 0x%02X\n",
 198.114 +               dsa->fname, dsa->seqn, c);
 198.115 +            return 1;
 198.116 +         }
 198.117 +         if (k == 80)
 198.118 +         {  xprintf("%s:%d: card image too long\n", dsa->fname,
 198.119 +               dsa->seqn);
 198.120 +            return 1;
 198.121 +         }
 198.122 +         dsa->card[k++] = (char)c;
 198.123 +      }
 198.124 +      return 0;
 198.125 +}
 198.126 +
 198.127 +/***********************************************************************
 198.128 +*  scan_int - scan integer value from the current card
 198.129 +*
 198.130 +*  This routine scans an integer value from the current card, where fld
 198.131 +*  is the name of the field, pos is the position of the field, width is
 198.132 +*  the width of the field, val points to a location to which the scanned
 198.133 +*  value should be stored. If the value was scanned successfully, the
 198.134 +*  routine returns zero, otherwise non-zero. */
 198.135 +
 198.136 +static int scan_int(struct dsa *dsa, char *fld, int pos, int width,
 198.137 +      int *val)
 198.138 +{     char str[80+1];
 198.139 +      xassert(1 <= width && width <= 80);
 198.140 +      memcpy(str, dsa->card + pos, width), str[width] = '\0';
 198.141 +      if (str2int(strspx(str), val))
 198.142 +      {  xprintf("%s:%d: field `%s' contains invalid value `%s'\n",
 198.143 +            dsa->fname, dsa->seqn, fld, str);
 198.144 +         return 1;
 198.145 +      }
 198.146 +      return 0;
 198.147 +}
 198.148 +
 198.149 +/***********************************************************************
 198.150 +*  parse_fmt - parse Fortran format specification
 198.151 +*
 198.152 +*  This routine parses the Fortran format specification represented as
 198.153 +*  character string which fmt points to and stores format elements into
 198.154 +*  appropriate static locations. Should note that not all valid Fortran
 198.155 +*  format specifications may be recognised. If the format specification
 198.156 +*  was recognised, the routine returns zero, otherwise non-zero. */
 198.157 +
 198.158 +static int parse_fmt(struct dsa *dsa, char *fmt)
 198.159 +{     int k, s, val;
 198.160 +      char str[80+1];
 198.161 +      /* first character should be left parenthesis */
 198.162 +      if (fmt[0] != '(')
 198.163 +fail: {  xprintf("hbm_read_mat: format `%s' not recognised\n", fmt);
 198.164 +         return 1;
 198.165 +      }
 198.166 +      k = 1;
 198.167 +      /* optional scale factor */
 198.168 +      dsa->fmt_p = 0;
 198.169 +      if (isdigit((unsigned char)fmt[k]))
 198.170 +      {  s = 0;
 198.171 +         while (isdigit((unsigned char)fmt[k]))
 198.172 +         {  if (s == 80) goto fail;
 198.173 +            str[s++] = fmt[k++];
 198.174 +         }
 198.175 +         str[s] = '\0';
 198.176 +         if (str2int(str, &val)) goto fail;
 198.177 +         if (toupper((unsigned char)fmt[k]) != 'P') goto iter;
 198.178 +         dsa->fmt_p = val, k++;
 198.179 +         if (!(0 <= dsa->fmt_p && dsa->fmt_p <= 255)) goto fail;
 198.180 +         /* optional comma may follow scale factor */
 198.181 +         if (fmt[k] == ',') k++;
 198.182 +      }
 198.183 +      /* optional iterator */
 198.184 +      dsa->fmt_k = 1;
 198.185 +      if (isdigit((unsigned char)fmt[k]))
 198.186 +      {  s = 0;
 198.187 +         while (isdigit((unsigned char)fmt[k]))
 198.188 +         {  if (s == 80) goto fail;
 198.189 +            str[s++] = fmt[k++];
 198.190 +         }
 198.191 +         str[s] = '\0';
 198.192 +         if (str2int(str, &val)) goto fail;
 198.193 +iter:    dsa->fmt_k = val;
 198.194 +         if (!(1 <= dsa->fmt_k && dsa->fmt_k <= 255)) goto fail;
 198.195 +      }
 198.196 +      /* format code */
 198.197 +      dsa->fmt_f = toupper((unsigned char)fmt[k++]);
 198.198 +      if (!(dsa->fmt_f == 'D' || dsa->fmt_f == 'E' ||
 198.199 +            dsa->fmt_f == 'F' || dsa->fmt_f == 'G' ||
 198.200 +            dsa->fmt_f == 'I')) goto fail;
 198.201 +      /* field width */
 198.202 +      if (!isdigit((unsigned char)fmt[k])) goto fail;
 198.203 +      s = 0;
 198.204 +      while (isdigit((unsigned char)fmt[k]))
 198.205 +      {  if (s == 80) goto fail;
 198.206 +         str[s++] = fmt[k++];
 198.207 +      }
 198.208 +      str[s] = '\0';
 198.209 +      if (str2int(str, &dsa->fmt_w)) goto fail;
 198.210 +      if (!(1 <= dsa->fmt_w && dsa->fmt_w <= 255)) goto fail;
 198.211 +      /* optional number of decimal places after point */
 198.212 +      dsa->fmt_d = 0;
 198.213 +      if (fmt[k] == '.')
 198.214 +      {  k++;
 198.215 +         if (!isdigit((unsigned char)fmt[k])) goto fail;
 198.216 +         s = 0;
 198.217 +         while (isdigit((unsigned char)fmt[k]))
 198.218 +         {  if (s == 80) goto fail;
 198.219 +            str[s++] = fmt[k++];
 198.220 +         }
 198.221 +         str[s] = '\0';
 198.222 +         if (str2int(str, &dsa->fmt_d)) goto fail;
 198.223 +         if (!(0 <= dsa->fmt_d && dsa->fmt_d <= 255)) goto fail;
 198.224 +      }
 198.225 +      /* last character should be right parenthesis */
 198.226 +      if (!(fmt[k] == ')' && fmt[k+1] == '\0')) goto fail;
 198.227 +      return 0;
 198.228 +}
 198.229 +
 198.230 +/***********************************************************************
 198.231 +*  read_int_array - read array of integer type
 198.232 +*
 198.233 +*  This routine reads an integer array from the input text file, where
 198.234 +*  name is array name, fmt is Fortran format specification that controls
 198.235 +*  reading, n is number of array elements, val is array of integer type.
 198.236 +*  If the array was read successful, the routine returns zero, otherwise
 198.237 +*  non-zero. */
 198.238 +
 198.239 +static int read_int_array(struct dsa *dsa, char *name, char *fmt,
 198.240 +      int n, int val[])
 198.241 +{     int k, pos;
 198.242 +      char str[80+1];
 198.243 +      if (parse_fmt(dsa, fmt)) return 1;
 198.244 +      if (!(dsa->fmt_f == 'I' && dsa->fmt_w <= 80 &&
 198.245 +            dsa->fmt_k * dsa->fmt_w <= 80))
 198.246 +      {  xprintf(
 198.247 +            "%s:%d: can't read array `%s' - invalid format `%s'\n",
 198.248 +            dsa->fname, dsa->seqn, name, fmt);
 198.249 +         return 1;
 198.250 +      }
 198.251 +      for (k = 1, pos = INT_MAX; k <= n; k++, pos++)
 198.252 +      {  if (pos >= dsa->fmt_k)
 198.253 +         {  if (read_card(dsa)) return 1;
 198.254 +            pos = 0;
 198.255 +         }
 198.256 +         memcpy(str, dsa->card + dsa->fmt_w * pos, dsa->fmt_w);
 198.257 +         str[dsa->fmt_w] = '\0';
 198.258 +         strspx(str);
 198.259 +         if (str2int(str, &val[k]))
 198.260 +         {  xprintf(
 198.261 +               "%s:%d: can't read array `%s' - invalid value `%s'\n",
 198.262 +               dsa->fname, dsa->seqn, name, str);
 198.263 +            return 1;
 198.264 +         }
 198.265 +      }
 198.266 +      return 0;
 198.267 +}
 198.268 +
 198.269 +/***********************************************************************
 198.270 +*  read_real_array - read array of real type
 198.271 +*
 198.272 +*  This routine reads a real array from the input text file, where name
 198.273 +*  is array name, fmt is Fortran format specification that controls
 198.274 +*  reading, n is number of array elements, val is array of real type.
 198.275 +*  If the array was read successful, the routine returns zero, otherwise
 198.276 +*  non-zero. */
 198.277 +
 198.278 +static int read_real_array(struct dsa *dsa, char *name, char *fmt,
 198.279 +      int n, double val[])
 198.280 +{     int k, pos;
 198.281 +      char str[80+1], *ptr;
 198.282 +      if (parse_fmt(dsa, fmt)) return 1;
 198.283 +      if (!(dsa->fmt_f != 'I' && dsa->fmt_w <= 80 &&
 198.284 +            dsa->fmt_k * dsa->fmt_w <= 80))
 198.285 +      {  xprintf(
 198.286 +            "%s:%d: can't read array `%s' - invalid format `%s'\n",
 198.287 +            dsa->fname, dsa->seqn, name, fmt);
 198.288 +         return 1;
 198.289 +      }
 198.290 +      for (k = 1, pos = INT_MAX; k <= n; k++, pos++)
 198.291 +      {  if (pos >= dsa->fmt_k)
 198.292 +         {  if (read_card(dsa)) return 1;
 198.293 +            pos = 0;
 198.294 +         }
 198.295 +         memcpy(str, dsa->card + dsa->fmt_w * pos, dsa->fmt_w);
 198.296 +         str[dsa->fmt_w] = '\0';
 198.297 +         strspx(str);
 198.298 +         if (strchr(str, '.') == NULL && strcmp(str, "0"))
 198.299 +         {  xprintf("%s(%d): can't read array `%s' - value `%s' has no "
 198.300 +               "decimal point\n", dsa->fname, dsa->seqn, name, str);
 198.301 +            return 1;
 198.302 +         }
 198.303 +         /* sometimes lower case letters appear */
 198.304 +         for (ptr = str; *ptr; ptr++)
 198.305 +            *ptr = (char)toupper((unsigned char)*ptr);
 198.306 +         ptr = strchr(str, 'D');
 198.307 +         if (ptr != NULL) *ptr = 'E';
 198.308 +         /* value may appear with decimal exponent but without letters
 198.309 +            E or D (for example, -123.456-012), so missing letter should
 198.310 +            be inserted */
 198.311 +         ptr = strchr(str+1, '+');
 198.312 +         if (ptr == NULL) ptr = strchr(str+1, '-');
 198.313 +         if (ptr != NULL && *(ptr-1) != 'E')
 198.314 +         {  xassert(strlen(str) < 80);
 198.315 +            memmove(ptr+1, ptr, strlen(ptr)+1);
 198.316 +            *ptr = 'E';
 198.317 +         }
 198.318 +         if (str2num(str, &val[k]))
 198.319 +         {  xprintf(
 198.320 +               "%s:%d: can't read array `%s' - invalid value `%s'\n",
 198.321 +               dsa->fname, dsa->seqn, name, str);
 198.322 +            return 1;
 198.323 +         }
 198.324 +      }
 198.325 +      return 0;
 198.326 +}
 198.327 +
 198.328 +HBM *hbm_read_mat(const char *fname)
 198.329 +{     struct dsa _dsa, *dsa = &_dsa;
 198.330 +      HBM *hbm = NULL;
 198.331 +      dsa->fname = fname;
 198.332 +      xprintf("hbm_read_mat: reading matrix from `%s'...\n",
 198.333 +         dsa->fname);
 198.334 +      dsa->fp = fopen(dsa->fname, "r");
 198.335 +      if (dsa->fp == NULL)
 198.336 +      {  xprintf("hbm_read_mat: unable to open `%s' - %s\n",
 198.337 +            dsa->fname, strerror(errno));
 198.338 +         goto fail;
 198.339 +      }
 198.340 +      dsa->seqn = 0;
 198.341 +      hbm = xmalloc(sizeof(HBM));
 198.342 +      memset(hbm, 0, sizeof(HBM));
 198.343 +      /* read the first heading card */
 198.344 +      if (read_card(dsa)) goto fail;
 198.345 +      memcpy(hbm->title, dsa->card, 72), hbm->title[72] = '\0';
 198.346 +      strtrim(hbm->title);
 198.347 +      xprintf("%s\n", hbm->title);
 198.348 +      memcpy(hbm->key, dsa->card+72, 8), hbm->key[8] = '\0';
 198.349 +      strspx(hbm->key);
 198.350 +      xprintf("key = %s\n", hbm->key);
 198.351 +      /* read the second heading card */
 198.352 +      if (read_card(dsa)) goto fail;
 198.353 +      if (scan_int(dsa, "totcrd",  0, 14, &hbm->totcrd)) goto fail;
 198.354 +      if (scan_int(dsa, "ptrcrd", 14, 14, &hbm->ptrcrd)) goto fail;
 198.355 +      if (scan_int(dsa, "indcrd", 28, 14, &hbm->indcrd)) goto fail;
 198.356 +      if (scan_int(dsa, "valcrd", 42, 14, &hbm->valcrd)) goto fail;
 198.357 +      if (scan_int(dsa, "rhscrd", 56, 14, &hbm->rhscrd)) goto fail;
 198.358 +      xprintf("totcrd = %d; ptrcrd = %d; indcrd = %d; valcrd = %d; rhsc"
 198.359 +         "rd = %d\n", hbm->totcrd, hbm->ptrcrd, hbm->indcrd,
 198.360 +         hbm->valcrd, hbm->rhscrd);
 198.361 +      /* read the third heading card */
 198.362 +      if (read_card(dsa)) goto fail;
 198.363 +      memcpy(hbm->mxtype, dsa->card, 3), hbm->mxtype[3] = '\0';
 198.364 +      if (strchr("RCP",   hbm->mxtype[0]) == NULL ||
 198.365 +          strchr("SUHZR", hbm->mxtype[1]) == NULL ||
 198.366 +          strchr("AE",    hbm->mxtype[2]) == NULL)
 198.367 +      {  xprintf("%s:%d: matrix type `%s' not recognised\n",
 198.368 +            dsa->fname, dsa->seqn, hbm->mxtype);
 198.369 +         goto fail;
 198.370 +      }
 198.371 +      if (scan_int(dsa, "nrow", 14, 14, &hbm->nrow)) goto fail;
 198.372 +      if (scan_int(dsa, "ncol", 28, 14, &hbm->ncol)) goto fail;
 198.373 +      if (scan_int(dsa, "nnzero", 42, 14, &hbm->nnzero)) goto fail;
 198.374 +      if (scan_int(dsa, "neltvl", 56, 14, &hbm->neltvl)) goto fail;
 198.375 +      xprintf("mxtype = %s; nrow = %d; ncol = %d; nnzero = %d; neltvl ="
 198.376 +         " %d\n", hbm->mxtype, hbm->nrow, hbm->ncol, hbm->nnzero,
 198.377 +         hbm->neltvl);
 198.378 +      /* read the fourth heading card */
 198.379 +      if (read_card(dsa)) goto fail;
 198.380 +      memcpy(hbm->ptrfmt, dsa->card, 16), hbm->ptrfmt[16] = '\0';
 198.381 +      strspx(hbm->ptrfmt);
 198.382 +      memcpy(hbm->indfmt, dsa->card+16, 16), hbm->indfmt[16] = '\0';
 198.383 +      strspx(hbm->indfmt);
 198.384 +      memcpy(hbm->valfmt, dsa->card+32, 20), hbm->valfmt[20] = '\0';
 198.385 +      strspx(hbm->valfmt);
 198.386 +      memcpy(hbm->rhsfmt, dsa->card+52, 20), hbm->rhsfmt[20] = '\0';
 198.387 +      strspx(hbm->rhsfmt);
 198.388 +      xprintf("ptrfmt = %s; indfmt = %s; valfmt = %s; rhsfmt = %s\n",
 198.389 +         hbm->ptrfmt, hbm->indfmt, hbm->valfmt, hbm->rhsfmt);
 198.390 +      /* read the fifth heading card (optional) */
 198.391 +      if (hbm->rhscrd <= 0)
 198.392 +      {  strcpy(hbm->rhstyp, "???");
 198.393 +         hbm->nrhs = 0;
 198.394 +         hbm->nrhsix = 0;
 198.395 +      }
 198.396 +      else
 198.397 +      {  if (read_card(dsa)) goto fail;
 198.398 +         memcpy(hbm->rhstyp, dsa->card, 3), hbm->rhstyp[3] = '\0';
 198.399 +         if (scan_int(dsa, "nrhs", 14, 14, &hbm->nrhs)) goto fail;
 198.400 +         if (scan_int(dsa, "nrhsix", 28, 14, &hbm->nrhsix)) goto fail;
 198.401 +         xprintf("rhstyp = `%s'; nrhs = %d; nrhsix = %d\n",
 198.402 +            hbm->rhstyp, hbm->nrhs, hbm->nrhsix);
 198.403 +      }
 198.404 +      /* read matrix structure */
 198.405 +      hbm->colptr = xcalloc(1+hbm->ncol+1, sizeof(int));
 198.406 +      if (read_int_array(dsa, "colptr", hbm->ptrfmt, hbm->ncol+1,
 198.407 +         hbm->colptr)) goto fail;
 198.408 +      hbm->rowind = xcalloc(1+hbm->nnzero, sizeof(int));
 198.409 +      if (read_int_array(dsa, "rowind", hbm->indfmt, hbm->nnzero,
 198.410 +         hbm->rowind)) goto fail;
 198.411 +      /* read matrix values */
 198.412 +      if (hbm->valcrd <= 0) goto done;
 198.413 +      if (hbm->mxtype[2] == 'A')
 198.414 +      {  /* assembled matrix */
 198.415 +         hbm->values = xcalloc(1+hbm->nnzero, sizeof(double));
 198.416 +         if (read_real_array(dsa, "values", hbm->valfmt, hbm->nnzero,
 198.417 +            hbm->values)) goto fail;
 198.418 +      }
 198.419 +      else
 198.420 +      {  /* elemental (unassembled) matrix */
 198.421 +         hbm->values = xcalloc(1+hbm->neltvl, sizeof(double));
 198.422 +         if (read_real_array(dsa, "values", hbm->valfmt, hbm->neltvl,
 198.423 +            hbm->values)) goto fail;
 198.424 +      }
 198.425 +      /* read right-hand sides */
 198.426 +      if (hbm->nrhs <= 0) goto done;
 198.427 +      if (hbm->rhstyp[0] == 'F')
 198.428 +      {  /* dense format */
 198.429 +         hbm->nrhsvl = hbm->nrow * hbm->nrhs;
 198.430 +         hbm->rhsval = xcalloc(1+hbm->nrhsvl, sizeof(double));
 198.431 +         if (read_real_array(dsa, "rhsval", hbm->rhsfmt, hbm->nrhsvl,
 198.432 +            hbm->rhsval)) goto fail;
 198.433 +      }
 198.434 +      else if (hbm->rhstyp[0] == 'M' && hbm->mxtype[2] == 'A')
 198.435 +      {  /* sparse format */
 198.436 +         /* read pointers */
 198.437 +         hbm->rhsptr = xcalloc(1+hbm->nrhs+1, sizeof(int));
 198.438 +         if (read_int_array(dsa, "rhsptr", hbm->ptrfmt, hbm->nrhs+1,
 198.439 +            hbm->rhsptr)) goto fail;
 198.440 +         /* read sparsity pattern */
 198.441 +         hbm->rhsind = xcalloc(1+hbm->nrhsix, sizeof(int));
 198.442 +         if (read_int_array(dsa, "rhsind", hbm->indfmt, hbm->nrhsix,
 198.443 +            hbm->rhsind)) goto fail;
 198.444 +         /* read values */
 198.445 +         hbm->rhsval = xcalloc(1+hbm->nrhsix, sizeof(double));
 198.446 +         if (read_real_array(dsa, "rhsval", hbm->rhsfmt, hbm->nrhsix,
 198.447 +            hbm->rhsval)) goto fail;
 198.448 +      }
 198.449 +      else if (hbm->rhstyp[0] == 'M' && hbm->mxtype[2] == 'E')
 198.450 +      {  /* elemental format */
 198.451 +         hbm->rhsval = xcalloc(1+hbm->nrhsvl, sizeof(double));
 198.452 +         if (read_real_array(dsa, "rhsval", hbm->rhsfmt, hbm->nrhsvl,
 198.453 +            hbm->rhsval)) goto fail;
 198.454 +      }
 198.455 +      else
 198.456 +      {  xprintf("%s:%d: right-hand side type `%c' not recognised\n",
 198.457 +            dsa->fname, dsa->seqn, hbm->rhstyp[0]);
 198.458 +         goto fail;
 198.459 +      }
 198.460 +      /* read starting guesses */
 198.461 +      if (hbm->rhstyp[1] == 'G')
 198.462 +      {  hbm->nguess = hbm->nrow * hbm->nrhs;
 198.463 +         hbm->sguess = xcalloc(1+hbm->nguess, sizeof(double));
 198.464 +         if (read_real_array(dsa, "sguess", hbm->rhsfmt, hbm->nguess,
 198.465 +            hbm->sguess)) goto fail;
 198.466 +      }
 198.467 +      /* read solution vectors */
 198.468 +      if (hbm->rhstyp[2] == 'X')
 198.469 +      {  hbm->nexact = hbm->nrow * hbm->nrhs;
 198.470 +         hbm->xexact = xcalloc(1+hbm->nexact, sizeof(double));
 198.471 +         if (read_real_array(dsa, "xexact", hbm->rhsfmt, hbm->nexact,
 198.472 +            hbm->xexact)) goto fail;
 198.473 +      }
 198.474 +done: /* reading has been completed */
 198.475 +      xprintf("hbm_read_mat: %d cards were read\n", dsa->seqn);
 198.476 +      fclose(dsa->fp);
 198.477 +      return hbm;
 198.478 +fail: /* something wrong in Danish kingdom */
 198.479 +      if (hbm != NULL)
 198.480 +      {  if (hbm->colptr != NULL) xfree(hbm->colptr);
 198.481 +         if (hbm->rowind != NULL) xfree(hbm->rowind);
 198.482 +         if (hbm->rhsptr != NULL) xfree(hbm->rhsptr);
 198.483 +         if (hbm->rhsind != NULL) xfree(hbm->rhsind);
 198.484 +         if (hbm->values != NULL) xfree(hbm->values);
 198.485 +         if (hbm->rhsval != NULL) xfree(hbm->rhsval);
 198.486 +         if (hbm->sguess != NULL) xfree(hbm->sguess);
 198.487 +         if (hbm->xexact != NULL) xfree(hbm->xexact);
 198.488 +         xfree(hbm);
 198.489 +      }
 198.490 +      if (dsa->fp != NULL) fclose(dsa->fp);
 198.491 +      return NULL;
 198.492 +}
 198.493 +
 198.494 +/***********************************************************************
 198.495 +*  NAME
 198.496 +*
 198.497 +*  hbm_free_mat - free sparse matrix in Harwell-Boeing format
 198.498 +*
 198.499 +*  SYNOPSIS
 198.500 +*
 198.501 +*  #include "glphbm.h"
 198.502 +*  void hbm_free_mat(HBM *hbm);
 198.503 +*
 198.504 +*  DESCRIPTION
 198.505 +*
 198.506 +*  The hbm_free_mat routine frees all the memory allocated to the data
 198.507 +*  structure containing a sparse matrix in the Harwell-Boeing format. */
 198.508 +
 198.509 +void hbm_free_mat(HBM *hbm)
 198.510 +{     if (hbm->colptr != NULL) xfree(hbm->colptr);
 198.511 +      if (hbm->rowind != NULL) xfree(hbm->rowind);
 198.512 +      if (hbm->rhsptr != NULL) xfree(hbm->rhsptr);
 198.513 +      if (hbm->rhsind != NULL) xfree(hbm->rhsind);
 198.514 +      if (hbm->values != NULL) xfree(hbm->values);
 198.515 +      if (hbm->rhsval != NULL) xfree(hbm->rhsval);
 198.516 +      if (hbm->sguess != NULL) xfree(hbm->sguess);
 198.517 +      if (hbm->xexact != NULL) xfree(hbm->xexact);
 198.518 +      xfree(hbm);
 198.519 +      return;
 198.520 +}
 198.521 +
 198.522 +/* eof */
   199.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   199.2 +++ b/src/glphbm.h	Mon Dec 06 13:09:21 2010 +0100
   199.3 @@ -0,0 +1,127 @@
   199.4 +/* glphbm.h (Harwell-Boeing sparse matrix format) */
   199.5 +
   199.6 +/***********************************************************************
   199.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   199.8 +*
   199.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  199.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  199.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  199.12 +*  E-mail: <mao@gnu.org>.
  199.13 +*
  199.14 +*  GLPK is free software: you can redistribute it and/or modify it
  199.15 +*  under the terms of the GNU General Public License as published by
  199.16 +*  the Free Software Foundation, either version 3 of the License, or
  199.17 +*  (at your option) any later version.
  199.18 +*
  199.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  199.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  199.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  199.22 +*  License for more details.
  199.23 +*
  199.24 +*  You should have received a copy of the GNU General Public License
  199.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  199.26 +***********************************************************************/
  199.27 +
  199.28 +#ifndef GLPHBM_H
  199.29 +#define GLPHBM_H
  199.30 +
  199.31 +typedef struct HBM HBM;
  199.32 +
  199.33 +struct HBM
  199.34 +{     /* sparse matrix in Harwell-Boeing format; for details see the
  199.35 +         report: I.S.Duff, R.G.Grimes, J.G.Lewis. User's Guide for the
  199.36 +         Harwell-Boeing Sparse Matrix Collection (Release I), 1992 */
  199.37 +      char title[72+1];
  199.38 +      /* matrix title (informative) */
  199.39 +      char key[8+1];
  199.40 +      /* matrix key (informative) */
  199.41 +      char mxtype[3+1];
  199.42 +      /* matrix type:
  199.43 +         R.. real matrix
  199.44 +         C.. complex matrix
  199.45 +         P.. pattern only (no numerical values supplied)
  199.46 +         .S. symmetric (lower triangle + main diagonal)
  199.47 +         .U. unsymmetric
  199.48 +         .H. hermitian (lower triangle + main diagonal)
  199.49 +         .Z. skew symmetric (lower triangle only)
  199.50 +         .R. rectangular
  199.51 +         ..A assembled
  199.52 +         ..E elemental (unassembled) */
  199.53 +      char rhstyp[3+1];
  199.54 +      /* optional types:
  199.55 +         F.. right-hand sides in dense format
  199.56 +         M.. right-hand sides in same format as matrix
  199.57 +         .G. starting vector(s) (guess) is supplied
  199.58 +         ..X exact solution vector(s) is supplied */
  199.59 +      char ptrfmt[16+1];
  199.60 +      /* format for pointers */
  199.61 +      char indfmt[16+1];
  199.62 +      /* format for row (or variable) indices */
  199.63 +      char valfmt[20+1];
  199.64 +      /* format for numerical values of coefficient matrix */
  199.65 +      char rhsfmt[20+1];
  199.66 +      /* format for numerical values of right-hand sides */
  199.67 +      int totcrd;
  199.68 +      /* total number of cards excluding header */
  199.69 +      int ptrcrd;
  199.70 +      /* number of cards for ponters */
  199.71 +      int indcrd;
  199.72 +      /* number of cards for row (or variable) indices */
  199.73 +      int valcrd;
  199.74 +      /* number of cards for numerical values */
  199.75 +      int rhscrd;
  199.76 +      /* number of lines for right-hand sides;
  199.77 +         including starting guesses and solution vectors if present;
  199.78 +         zero indicates no right-hand side data is present */
  199.79 +      int nrow;
  199.80 +      /* number of rows (or variables) */
  199.81 +      int ncol;
  199.82 +      /* number of columns (or elements) */
  199.83 +      int nnzero;
  199.84 +      /* number of row (or variable) indices;
  199.85 +         equal to number of entries for assembled matrix */
  199.86 +      int neltvl;
  199.87 +      /* number of elemental matrix entries;
  199.88 +         zero in case of assembled matrix */
  199.89 +      int nrhs;
  199.90 +      /* number of right-hand sides */
  199.91 +      int nrhsix;
  199.92 +      /* number of row indices;
  199.93 +         ignored in case of unassembled matrix */
  199.94 +      int nrhsvl;
  199.95 +      /* total number of entries in all right-hand sides */
  199.96 +      int nguess;
  199.97 +      /* total number of entries in all starting guesses */
  199.98 +      int nexact;
  199.99 +      /* total number of entries in all solution vectors */
 199.100 +      int *colptr; /* alias: eltptr */
 199.101 +      /* column pointers (in case of assembled matrix);
 199.102 +         elemental matrix pointers (in case of unassembled matrix) */
 199.103 +      int *rowind; /* alias: varind */
 199.104 +      /* row indices (in case of assembled matrix);
 199.105 +         variable indices (in case of unassembled matrix) */
 199.106 +      int *rhsptr;
 199.107 +      /* right-hand side pointers */
 199.108 +      int *rhsind;
 199.109 +      /* right-hand side indices */
 199.110 +      double *values;
 199.111 +      /* matrix values */
 199.112 +      double *rhsval;
 199.113 +      /* right-hand side values */
 199.114 +      double *sguess;
 199.115 +      /* starting guess values */
 199.116 +      double *xexact;
 199.117 +      /* solution vector values */
 199.118 +};
 199.119 +
 199.120 +#define hbm_read_mat _glp_hbm_read_mat
 199.121 +HBM *hbm_read_mat(const char *fname);
 199.122 +/* read sparse matrix in Harwell-Boeing format */
 199.123 +
 199.124 +#define hbm_free_mat _glp_hbm_free_mat
 199.125 +void hbm_free_mat(HBM *hbm);
 199.126 +/* free sparse matrix in Harwell-Boeing format */
 199.127 +
 199.128 +#endif
 199.129 +
 199.130 +/* eof */
   200.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   200.2 +++ b/src/glpini01.c	Mon Dec 06 13:09:21 2010 +0100
   200.3 @@ -0,0 +1,577 @@
   200.4 +/* glpini01.c */
   200.5 +
   200.6 +/***********************************************************************
   200.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   200.8 +*
   200.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  200.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  200.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  200.12 +*  E-mail: <mao@gnu.org>.
  200.13 +*
  200.14 +*  GLPK is free software: you can redistribute it and/or modify it
  200.15 +*  under the terms of the GNU General Public License as published by
  200.16 +*  the Free Software Foundation, either version 3 of the License, or
  200.17 +*  (at your option) any later version.
  200.18 +*
  200.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  200.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  200.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  200.22 +*  License for more details.
  200.23 +*
  200.24 +*  You should have received a copy of the GNU General Public License
  200.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  200.26 +***********************************************************************/
  200.27 +
  200.28 +#include "glpapi.h"
  200.29 +
  200.30 +/*----------------------------------------------------------------------
  200.31 +-- triang - find maximal triangular part of a rectangular matrix.
  200.32 +--
  200.33 +-- *Synopsis*
  200.34 +--
  200.35 +-- int triang(int m, int n,
  200.36 +--    void *info, int (*mat)(void *info, int k, int ndx[]),
  200.37 +--    int rn[], int cn[]);
  200.38 +--
  200.39 +-- *Description*
  200.40 +--
  200.41 +-- For a given rectangular (sparse) matrix A with m rows and n columns
  200.42 +-- the routine triang tries to find such permutation matrices P and Q
  200.43 +-- that the first rows and columns of the matrix B = P*A*Q form a lower
  200.44 +-- triangular submatrix of as greatest size as possible:
  200.45 +--
  200.46 +--                   1                       n
  200.47 +--                1  * . . . . . . x x x x x x
  200.48 +--                   * * . . . . . x x x x x x
  200.49 +--                   * * * . . . . x x x x x x
  200.50 +--                   * * * * . . . x x x x x x
  200.51 +--    B = P*A*Q =    * * * * * . . x x x x x x
  200.52 +--                   * * * * * * . x x x x x x
  200.53 +--                   * * * * * * * x x x x x x
  200.54 +--                   x x x x x x x x x x x x x
  200.55 +--                   x x x x x x x x x x x x x
  200.56 +--                m  x x x x x x x x x x x x x
  200.57 +--
  200.58 +-- where: '*' - elements of the lower triangular part, '.' - structural
  200.59 +-- zeros, 'x' - other (either non-zero or zero) elements.
  200.60 +--
  200.61 +-- The parameter info is a transit pointer passed to the formal routine
  200.62 +-- mat (see below).
  200.63 +--
  200.64 +-- The formal routine mat specifies the given matrix A in both row- and
  200.65 +-- column-wise formats. In order to obtain an i-th row of the matrix A
  200.66 +-- the routine triang calls the routine mat with the parameter k = +i,
  200.67 +-- 1 <= i <= m. In response the routine mat should store column indices
  200.68 +-- of (non-zero) elements of the i-th row to the locations ndx[1], ...,
  200.69 +-- ndx[len], where len is number of non-zeros in the i-th row returned
  200.70 +-- on exit. Analogously, in order to obtain a j-th column of the matrix
  200.71 +-- A, the routine mat is called with the parameter k = -j, 1 <= j <= n,
  200.72 +-- and should return pattern of the j-th column in the same way as for
  200.73 +-- row patterns. Note that the routine mat may be called more than once
  200.74 +-- for the same rows and columns.
  200.75 +--
  200.76 +-- On exit the routine computes two resultant arrays rn and cn, which
  200.77 +-- define the permutation matrices P and Q, respectively. The array rn
  200.78 +-- should have at least 1+m locations, where rn[i] = i' (1 <= i <= m)
  200.79 +-- means that i-th row of the original matrix A corresponds to i'-th row
  200.80 +-- of the matrix B = P*A*Q. Similarly, the array cn should have at least
  200.81 +-- 1+n locations, where cn[j] = j' (1 <= j <= n) means that j-th column
  200.82 +-- of the matrix A corresponds to j'-th column of the matrix B.
  200.83 +--
  200.84 +-- *Returns*
  200.85 +--
  200.86 +-- The routine triang returns the size of the lower tringular part of
  200.87 +-- the matrix B = P*A*Q (see the figure above).
  200.88 +--
  200.89 +-- *Complexity*
  200.90 +--
  200.91 +-- The time complexity of the routine triang is O(nnz), where nnz is
  200.92 +-- number of non-zeros in the given matrix A.
  200.93 +--
  200.94 +-- *Algorithm*
  200.95 +--
  200.96 +-- The routine triang starts from the matrix B = P*Q*A, where P and Q
  200.97 +-- are unity matrices, so initially B = A.
  200.98 +--
  200.99 +-- Before the next iteration B = (B1 | B2 | B3), where B1 is partially
 200.100 +-- built a lower triangular submatrix, B2 is the active submatrix, and
 200.101 +-- B3 is a submatrix that contains rejected columns. Thus, the current
 200.102 +-- matrix B looks like follows (initially k1 = 1 and k2 = n):
 200.103 +--
 200.104 +--       1         k1         k2         n
 200.105 +--    1  x . . . . . . . . . . . . . # # #
 200.106 +--       x x . . . . . . . . . . . . # # #
 200.107 +--       x x x . . . . . . . . . . # # # #
 200.108 +--       x x x x . . . . . . . . . # # # #
 200.109 +--       x x x x x . . . . . . . # # # # #
 200.110 +--    k1 x x x x x * * * * * * * # # # # #
 200.111 +--       x x x x x * * * * * * * # # # # #
 200.112 +--       x x x x x * * * * * * * # # # # #
 200.113 +--       x x x x x * * * * * * * # # # # #
 200.114 +--    m  x x x x x * * * * * * * # # # # #
 200.115 +--       <--B1---> <----B2-----> <---B3-->
 200.116 +--
 200.117 +-- On each iteartion the routine looks for a singleton row, i.e. some
 200.118 +-- row that has the only non-zero in the active submatrix B2. If such
 200.119 +-- row exists and the corresponding non-zero is b[i,j], where (by the
 200.120 +-- definition) k1 <= i <= m and k1 <= j <= k2, the routine permutes
 200.121 +-- k1-th and i-th rows and k1-th and j-th columns of the matrix B (in
 200.122 +-- order to place the element in the position b[k1,k1]), removes the
 200.123 +-- k1-th column from the active submatrix B2, and adds this column to
 200.124 +-- the submatrix B1. If no row singletons exist, but B2 is not empty
 200.125 +-- yet, the routine chooses a j-th column, which has maximal number of
 200.126 +-- non-zeros among other columns of B2, removes this column from B2 and
 200.127 +-- adds it to the submatrix B3 in the hope that new row singletons will
 200.128 +-- appear in the active submatrix. */
 200.129 +
 200.130 +static int triang(int m, int n,
 200.131 +      void *info, int (*mat)(void *info, int k, int ndx[]),
 200.132 +      int rn[], int cn[])
 200.133 +{     int *ndx; /* int ndx[1+max(m,n)]; */
 200.134 +      /* this array is used for querying row and column patterns of the
 200.135 +         given matrix A (the third parameter to the routine mat) */
 200.136 +      int *rs_len; /* int rs_len[1+m]; */
 200.137 +      /* rs_len[0] is not used;
 200.138 +         rs_len[i], 1 <= i <= m, is number of non-zeros in the i-th row
 200.139 +         of the matrix A, which (non-zeros) belong to the current active
 200.140 +         submatrix */
 200.141 +      int *rs_head; /* int rs_head[1+n]; */
 200.142 +      /* rs_head[len], 0 <= len <= n, is the number i of the first row
 200.143 +         of the matrix A, for which rs_len[i] = len */
 200.144 +      int *rs_prev; /* int rs_prev[1+m]; */
 200.145 +      /* rs_prev[0] is not used;
 200.146 +         rs_prev[i], 1 <= i <= m, is a number i' of the previous row of
 200.147 +         the matrix A, for which rs_len[i] = rs_len[i'] (zero marks the
 200.148 +         end of this linked list) */
 200.149 +      int *rs_next; /* int rs_next[1+m]; */
 200.150 +      /* rs_next[0] is not used;
 200.151 +         rs_next[i], 1 <= i <= m, is a number i' of the next row of the
 200.152 +         matrix A, for which rs_len[i] = rs_len[i'] (zero marks the end
 200.153 +         this linked list) */
 200.154 +      int cs_head;
 200.155 +      /* is a number j of the first column of the matrix A, which has
 200.156 +         maximal number of non-zeros among other columns */
 200.157 +      int *cs_prev; /* cs_prev[1+n]; */
 200.158 +      /* cs_prev[0] is not used;
 200.159 +         cs_prev[j], 1 <= j <= n, is a number of the previous column of
 200.160 +         the matrix A with the same or greater number of non-zeros than
 200.161 +         in the j-th column (zero marks the end of this linked list) */
 200.162 +      int *cs_next; /* cs_next[1+n]; */
 200.163 +      /* cs_next[0] is not used;
 200.164 +         cs_next[j], 1 <= j <= n, is a number of the next column of
 200.165 +         the matrix A with the same or lesser number of non-zeros than
 200.166 +         in the j-th column (zero marks the end of this linked list) */
 200.167 +      int i, j, ii, jj, k1, k2, len, t, size = 0;
 200.168 +      int *head, *rn_inv, *cn_inv;
 200.169 +      if (!(m > 0 && n > 0))
 200.170 +         xerror("triang: m = %d; n = %d; invalid dimension\n", m, n);
 200.171 +      /* allocate working arrays */
 200.172 +      ndx = xcalloc(1+(m >= n ? m : n), sizeof(int));
 200.173 +      rs_len = xcalloc(1+m, sizeof(int));
 200.174 +      rs_head = xcalloc(1+n, sizeof(int));
 200.175 +      rs_prev = xcalloc(1+m, sizeof(int));
 200.176 +      rs_next = xcalloc(1+m, sizeof(int));
 200.177 +      cs_prev = xcalloc(1+n, sizeof(int));
 200.178 +      cs_next = xcalloc(1+n, sizeof(int));
 200.179 +      /* build linked lists of columns of the matrix A with the same
 200.180 +         number of non-zeros */
 200.181 +      head = rs_len; /* currently rs_len is used as working array */
 200.182 +      for (len = 0; len <= m; len ++) head[len] = 0;
 200.183 +      for (j = 1; j <= n; j++)
 200.184 +      {  /* obtain length of the j-th column */
 200.185 +         len = mat(info, -j, ndx);
 200.186 +         xassert(0 <= len && len <= m);
 200.187 +         /* include the j-th column in the corresponding linked list */
 200.188 +         cs_prev[j] = head[len];
 200.189 +         head[len] = j;
 200.190 +      }
 200.191 +      /* merge all linked lists of columns in one linked list, where
 200.192 +         columns are ordered by descending of their lengths */
 200.193 +      cs_head = 0;
 200.194 +      for (len = 0; len <= m; len++)
 200.195 +      {  for (j = head[len]; j != 0; j = cs_prev[j])
 200.196 +         {  cs_next[j] = cs_head;
 200.197 +            cs_head = j;
 200.198 +         }
 200.199 +      }
 200.200 +      jj = 0;
 200.201 +      for (j = cs_head; j != 0; j = cs_next[j])
 200.202 +      {  cs_prev[j] = jj;
 200.203 +         jj = j;
 200.204 +      }
 200.205 +      /* build initial doubly linked lists of rows of the matrix A with
 200.206 +         the same number of non-zeros */
 200.207 +      for (len = 0; len <= n; len++) rs_head[len] = 0;
 200.208 +      for (i = 1; i <= m; i++)
 200.209 +      {  /* obtain length of the i-th row */
 200.210 +         rs_len[i] = len = mat(info, +i, ndx);
 200.211 +         xassert(0 <= len && len <= n);
 200.212 +         /* include the i-th row in the correspondng linked list */
 200.213 +         rs_prev[i] = 0;
 200.214 +         rs_next[i] = rs_head[len];
 200.215 +         if (rs_next[i] != 0) rs_prev[rs_next[i]] = i;
 200.216 +         rs_head[len] = i;
 200.217 +      }
 200.218 +      /* initially all rows and columns of the matrix A are active */
 200.219 +      for (i = 1; i <= m; i++) rn[i] = 0;
 200.220 +      for (j = 1; j <= n; j++) cn[j] = 0;
 200.221 +      /* set initial bounds of the active submatrix */
 200.222 +      k1 = 1, k2 = n;
 200.223 +      /* main loop starts here */
 200.224 +      while (k1 <= k2)
 200.225 +      {  i = rs_head[1];
 200.226 +         if (i != 0)
 200.227 +         {  /* the i-th row of the matrix A is a row singleton, since
 200.228 +               it has the only non-zero in the active submatrix */
 200.229 +            xassert(rs_len[i] == 1);
 200.230 +            /* determine the number j of an active column of the matrix
 200.231 +               A, in which this non-zero is placed */
 200.232 +            j = 0;
 200.233 +            t = mat(info, +i, ndx);
 200.234 +            xassert(0 <= t && t <= n);
 200.235 +            for (t = t; t >= 1; t--)
 200.236 +            {  jj = ndx[t];
 200.237 +               xassert(1 <= jj && jj <= n);
 200.238 +               if (cn[jj] == 0)
 200.239 +               {  xassert(j == 0);
 200.240 +                  j = jj;
 200.241 +               }
 200.242 +            }
 200.243 +            xassert(j != 0);
 200.244 +            /* the singleton is a[i,j]; move a[i,j] to the position
 200.245 +               b[k1,k1] of the matrix B */
 200.246 +            rn[i] = cn[j] = k1;
 200.247 +            /* shift the left bound of the active submatrix */
 200.248 +            k1++;
 200.249 +            /* increase the size of the lower triangular part */
 200.250 +            size++;
 200.251 +         }
 200.252 +         else
 200.253 +         {  /* the current active submatrix has no row singletons */
 200.254 +            /* remove an active column with maximal number of non-zeros
 200.255 +               from the active submatrix */
 200.256 +            j = cs_head;
 200.257 +            xassert(j != 0);
 200.258 +            cn[j] = k2;
 200.259 +            /* shift the right bound of the active submatrix */
 200.260 +            k2--;
 200.261 +         }
 200.262 +         /* the j-th column of the matrix A has been removed from the
 200.263 +            active submatrix */
 200.264 +         /* remove the j-th column from the linked list */
 200.265 +         if (cs_prev[j] == 0)
 200.266 +            cs_head = cs_next[j];
 200.267 +         else
 200.268 +            cs_next[cs_prev[j]] = cs_next[j];
 200.269 +         if (cs_next[j] == 0)
 200.270 +            /* nop */;
 200.271 +         else
 200.272 +            cs_prev[cs_next[j]] = cs_prev[j];
 200.273 +         /* go through non-zeros of the j-th columns and update active
 200.274 +            lengths of the corresponding rows */
 200.275 +         t = mat(info, -j, ndx);
 200.276 +         xassert(0 <= t && t <= m);
 200.277 +         for (t = t; t >= 1; t--)
 200.278 +         {  i = ndx[t];
 200.279 +            xassert(1 <= i && i <= m);
 200.280 +            /* the non-zero a[i,j] has left the active submatrix */
 200.281 +            len = rs_len[i];
 200.282 +            xassert(len >= 1);
 200.283 +            /* remove the i-th row from the linked list of rows with
 200.284 +               active length len */
 200.285 +            if (rs_prev[i] == 0)
 200.286 +               rs_head[len] = rs_next[i];
 200.287 +            else
 200.288 +               rs_next[rs_prev[i]] = rs_next[i];
 200.289 +            if (rs_next[i] == 0)
 200.290 +               /* nop */;
 200.291 +            else
 200.292 +               rs_prev[rs_next[i]] = rs_prev[i];
 200.293 +            /* decrease the active length of the i-th row */
 200.294 +            rs_len[i] = --len;
 200.295 +            /* return the i-th row to the corresponding linked list */
 200.296 +            rs_prev[i] = 0;
 200.297 +            rs_next[i] = rs_head[len];
 200.298 +            if (rs_next[i] != 0) rs_prev[rs_next[i]] = i;
 200.299 +            rs_head[len] = i;
 200.300 +         }
 200.301 +      }
 200.302 +      /* other rows of the matrix A, which are still active, correspond
 200.303 +         to rows k1, ..., m of the matrix B (in arbitrary order) */
 200.304 +      for (i = 1; i <= m; i++) if (rn[i] == 0) rn[i] = k1++;
 200.305 +      /* but for columns this is not needed, because now the submatrix
 200.306 +         B2 has no columns */
 200.307 +      for (j = 1; j <= n; j++) xassert(cn[j] != 0);
 200.308 +      /* perform some optional checks */
 200.309 +      /* make sure that rn is a permutation of {1, ..., m} and cn is a
 200.310 +         permutation of {1, ..., n} */
 200.311 +      rn_inv = rs_len; /* used as working array */
 200.312 +      for (ii = 1; ii <= m; ii++) rn_inv[ii] = 0;
 200.313 +      for (i = 1; i <= m; i++)
 200.314 +      {  ii = rn[i];
 200.315 +         xassert(1 <= ii && ii <= m);
 200.316 +         xassert(rn_inv[ii] == 0);
 200.317 +         rn_inv[ii] = i;
 200.318 +      }
 200.319 +      cn_inv = rs_head; /* used as working array */
 200.320 +      for (jj = 1; jj <= n; jj++) cn_inv[jj] = 0;
 200.321 +      for (j = 1; j <= n; j++)
 200.322 +      {  jj = cn[j];
 200.323 +         xassert(1 <= jj && jj <= n);
 200.324 +         xassert(cn_inv[jj] == 0);
 200.325 +         cn_inv[jj] = j;
 200.326 +      }
 200.327 +      /* make sure that the matrix B = P*A*Q really has the form, which
 200.328 +         was declared */
 200.329 +      for (ii = 1; ii <= size; ii++)
 200.330 +      {  int diag = 0;
 200.331 +         i = rn_inv[ii];
 200.332 +         t = mat(info, +i, ndx);
 200.333 +         xassert(0 <= t && t <= n);
 200.334 +         for (t = t; t >= 1; t--)
 200.335 +         {  j = ndx[t];
 200.336 +            xassert(1 <= j && j <= n);
 200.337 +            jj = cn[j];
 200.338 +            if (jj <= size) xassert(jj <= ii);
 200.339 +            if (jj == ii)
 200.340 +            {  xassert(!diag);
 200.341 +               diag = 1;
 200.342 +            }
 200.343 +         }
 200.344 +         xassert(diag);
 200.345 +      }
 200.346 +      /* free working arrays */
 200.347 +      xfree(ndx);
 200.348 +      xfree(rs_len);
 200.349 +      xfree(rs_head);
 200.350 +      xfree(rs_prev);
 200.351 +      xfree(rs_next);
 200.352 +      xfree(cs_prev);
 200.353 +      xfree(cs_next);
 200.354 +      /* return to the calling program */
 200.355 +      return size;
 200.356 +}
 200.357 +
 200.358 +/*----------------------------------------------------------------------
 200.359 +-- adv_basis - construct advanced initial LP basis.
 200.360 +--
 200.361 +-- *Synopsis*
 200.362 +--
 200.363 +-- #include "glpini.h"
 200.364 +-- void adv_basis(glp_prob *lp);
 200.365 +--
 200.366 +-- *Description*
 200.367 +--
 200.368 +-- The routine adv_basis constructs an advanced initial basis for an LP
 200.369 +-- problem object, which the parameter lp points to.
 200.370 +--
 200.371 +-- In order to build the initial basis the routine does the following:
 200.372 +--
 200.373 +-- 1) includes in the basis all non-fixed auxiliary variables;
 200.374 +--
 200.375 +-- 2) includes in the basis as many as possible non-fixed structural
 200.376 +--    variables preserving triangular form of the basis matrix;
 200.377 +--
 200.378 +-- 3) includes in the basis appropriate (fixed) auxiliary variables
 200.379 +--    in order to complete the basis.
 200.380 +--
 200.381 +-- As a result the initial basis has minimum of fixed variables and the
 200.382 +-- corresponding basis matrix is triangular. */
 200.383 +
 200.384 +static int mat(void *info, int k, int ndx[])
 200.385 +{     /* this auxiliary routine returns the pattern of a given row or
 200.386 +         a given column of the augmented constraint matrix A~ = (I|-A),
 200.387 +         in which columns of fixed variables are implicitly cleared */
 200.388 +      LPX *lp = info;
 200.389 +      int m = lpx_get_num_rows(lp);
 200.390 +      int n = lpx_get_num_cols(lp);
 200.391 +      int typx, i, j, lll, len = 0;
 200.392 +      if (k > 0)
 200.393 +      {  /* the pattern of the i-th row is required */
 200.394 +         i = +k;
 200.395 +         xassert(1 <= i && i <= m);
 200.396 +#if 0 /* 22/XII-2003 */
 200.397 +         /* if the auxiliary variable x[i] is non-fixed, include its
 200.398 +            element (placed in the i-th column) in the pattern */
 200.399 +         lpx_get_row_bnds(lp, i, &typx, NULL, NULL);
 200.400 +         if (typx != LPX_FX) ndx[++len] = i;
 200.401 +         /* include in the pattern elements placed in columns, which
 200.402 +            correspond to non-fixed structural varables */
 200.403 +         i_beg = aa_ptr[i];
 200.404 +         i_end = i_beg + aa_len[i] - 1;
 200.405 +         for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
 200.406 +         {  j = m + sv_ndx[i_ptr];
 200.407 +            lpx_get_col_bnds(lp, j-m, &typx, NULL, NULL);
 200.408 +            if (typx != LPX_FX) ndx[++len] = j;
 200.409 +         }
 200.410 +#else
 200.411 +         lll = lpx_get_mat_row(lp, i, ndx, NULL);
 200.412 +         for (k = 1; k <= lll; k++)
 200.413 +         {  lpx_get_col_bnds(lp, ndx[k], &typx, NULL, NULL);
 200.414 +            if (typx != LPX_FX) ndx[++len] = m + ndx[k];
 200.415 +         }
 200.416 +         lpx_get_row_bnds(lp, i, &typx, NULL, NULL);
 200.417 +         if (typx != LPX_FX) ndx[++len] = i;
 200.418 +#endif
 200.419 +      }
 200.420 +      else
 200.421 +      {  /* the pattern of the j-th column is required */
 200.422 +         j = -k;
 200.423 +         xassert(1 <= j && j <= m+n);
 200.424 +         /* if the (auxiliary or structural) variable x[j] is fixed,
 200.425 +            the pattern of its column is empty */
 200.426 +         if (j <= m)
 200.427 +            lpx_get_row_bnds(lp, j, &typx, NULL, NULL);
 200.428 +         else
 200.429 +            lpx_get_col_bnds(lp, j-m, &typx, NULL, NULL);
 200.430 +         if (typx != LPX_FX)
 200.431 +         {  if (j <= m)
 200.432 +            {  /* x[j] is non-fixed auxiliary variable */
 200.433 +               ndx[++len] = j;
 200.434 +            }
 200.435 +            else
 200.436 +            {  /* x[j] is non-fixed structural variables */
 200.437 +#if 0 /* 22/XII-2003 */
 200.438 +               j_beg = aa_ptr[j];
 200.439 +               j_end = j_beg + aa_len[j] - 1;
 200.440 +               for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
 200.441 +                  ndx[++len] = sv_ndx[j_ptr];
 200.442 +#else
 200.443 +               len = lpx_get_mat_col(lp, j-m, ndx, NULL);
 200.444 +#endif
 200.445 +            }
 200.446 +         }
 200.447 +      }
 200.448 +      /* return the length of the row/column pattern */
 200.449 +      return len;
 200.450 +}
 200.451 +
 200.452 +static void adv_basis(glp_prob *lp)
 200.453 +{     int m = lpx_get_num_rows(lp);
 200.454 +      int n = lpx_get_num_cols(lp);
 200.455 +      int i, j, jj, k, size;
 200.456 +      int *rn, *cn, *rn_inv, *cn_inv;
 200.457 +      int typx, *tagx = xcalloc(1+m+n, sizeof(int));
 200.458 +      double lb, ub;
 200.459 +      xprintf("Constructing initial basis...\n");
 200.460 +#if 0 /* 13/V-2009 */
 200.461 +      if (m == 0)
 200.462 +         xerror("glp_adv_basis: problem has no rows\n");
 200.463 +      if (n == 0)
 200.464 +         xerror("glp_adv_basis: problem has no columns\n");
 200.465 +#else
 200.466 +      if (m == 0 || n == 0)
 200.467 +      {  glp_std_basis(lp);
 200.468 +         return;
 200.469 +      }
 200.470 +#endif
 200.471 +      /* use the routine triang (see above) to find maximal triangular
 200.472 +         part of the augmented constraint matrix A~ = (I|-A); in order
 200.473 +         to prevent columns of fixed variables to be included in the
 200.474 +         triangular part, such columns are implictly removed from the
 200.475 +         matrix A~ by the routine adv_mat */
 200.476 +      rn = xcalloc(1+m, sizeof(int));
 200.477 +      cn = xcalloc(1+m+n, sizeof(int));
 200.478 +      size = triang(m, m+n, lp, mat, rn, cn);
 200.479 +      if (lpx_get_int_parm(lp, LPX_K_MSGLEV) >= 3)
 200.480 +         xprintf("Size of triangular part = %d\n", size);
 200.481 +      /* the first size rows and columns of the matrix P*A~*Q (where
 200.482 +         P and Q are permutation matrices defined by the arrays rn and
 200.483 +         cn) form a lower triangular matrix; build the arrays (rn_inv
 200.484 +         and cn_inv), which define the matrices inv(P) and inv(Q) */
 200.485 +      rn_inv = xcalloc(1+m, sizeof(int));
 200.486 +      cn_inv = xcalloc(1+m+n, sizeof(int));
 200.487 +      for (i = 1; i <= m; i++) rn_inv[rn[i]] = i;
 200.488 +      for (j = 1; j <= m+n; j++) cn_inv[cn[j]] = j;
 200.489 +      /* include the columns of the matrix A~, which correspond to the
 200.490 +         first size columns of the matrix P*A~*Q, in the basis */
 200.491 +      for (k = 1; k <= m+n; k++) tagx[k] = -1;
 200.492 +      for (jj = 1; jj <= size; jj++)
 200.493 +      {  j = cn_inv[jj];
 200.494 +         /* the j-th column of A~ is the jj-th column of P*A~*Q */
 200.495 +         tagx[j] = LPX_BS;
 200.496 +      }
 200.497 +      /* if size < m, we need to add appropriate columns of auxiliary
 200.498 +         variables to the basis */
 200.499 +      for (jj = size + 1; jj <= m; jj++)
 200.500 +      {  /* the jj-th column of P*A~*Q should be replaced by the column
 200.501 +            of the auxiliary variable, for which the only unity element
 200.502 +            is placed in the position [jj,jj] */
 200.503 +         i = rn_inv[jj];
 200.504 +         /* the jj-th row of P*A~*Q is the i-th row of A~, but in the
 200.505 +            i-th row of A~ the unity element belongs to the i-th column
 200.506 +            of A~; therefore the disired column corresponds to the i-th
 200.507 +            auxiliary variable (note that this column doesn't belong to
 200.508 +            the triangular part found by the routine triang) */
 200.509 +         xassert(1 <= i && i <= m);
 200.510 +         xassert(cn[i] > size);
 200.511 +         tagx[i] = LPX_BS;
 200.512 +      }
 200.513 +      /* free working arrays */
 200.514 +      xfree(rn);
 200.515 +      xfree(cn);
 200.516 +      xfree(rn_inv);
 200.517 +      xfree(cn_inv);
 200.518 +      /* build tags of non-basic variables */
 200.519 +      for (k = 1; k <= m+n; k++)
 200.520 +      {  if (tagx[k] != LPX_BS)
 200.521 +         {  if (k <= m)
 200.522 +               lpx_get_row_bnds(lp, k, &typx, &lb, &ub);
 200.523 +            else
 200.524 +               lpx_get_col_bnds(lp, k-m, &typx, &lb, &ub);
 200.525 +            switch (typx)
 200.526 +            {  case LPX_FR:
 200.527 +                  tagx[k] = LPX_NF; break;
 200.528 +               case LPX_LO:
 200.529 +                  tagx[k] = LPX_NL; break;
 200.530 +               case LPX_UP:
 200.531 +                  tagx[k] = LPX_NU; break;
 200.532 +               case LPX_DB:
 200.533 +                  tagx[k] =
 200.534 +                     (fabs(lb) <= fabs(ub) ? LPX_NL : LPX_NU);
 200.535 +                  break;
 200.536 +               case LPX_FX:
 200.537 +                  tagx[k] = LPX_NS; break;
 200.538 +               default:
 200.539 +                  xassert(typx != typx);
 200.540 +            }
 200.541 +         }
 200.542 +      }
 200.543 +      for (k = 1; k <= m+n; k++)
 200.544 +      {  if (k <= m)
 200.545 +            lpx_set_row_stat(lp, k, tagx[k]);
 200.546 +         else
 200.547 +            lpx_set_col_stat(lp, k-m, tagx[k]);
 200.548 +      }
 200.549 +      xfree(tagx);
 200.550 +      return;
 200.551 +}
 200.552 +
 200.553 +/***********************************************************************
 200.554 +*  NAME
 200.555 +*
 200.556 +*  glp_adv_basis - construct advanced initial LP basis
 200.557 +*
 200.558 +*  SYNOPSIS
 200.559 +*
 200.560 +*  void glp_adv_basis(glp_prob *lp, int flags);
 200.561 +*
 200.562 +*  DESCRIPTION
 200.563 +*
 200.564 +*  The routine glp_adv_basis constructs an advanced initial basis for
 200.565 +*  the specified problem object.
 200.566 +*
 200.567 +*  The parameter flags is reserved for use in the future and must be
 200.568 +*  specified as zero. */
 200.569 +
 200.570 +void glp_adv_basis(glp_prob *lp, int flags)
 200.571 +{     if (flags != 0)
 200.572 +         xerror("glp_adv_basis: flags = %d; invalid flags\n", flags);
 200.573 +      if (lp->m == 0 || lp->n == 0)
 200.574 +         glp_std_basis(lp);
 200.575 +      else
 200.576 +         adv_basis(lp);
 200.577 +      return;
 200.578 +}
 200.579 +
 200.580 +/* eof */
   201.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   201.2 +++ b/src/glpini02.c	Mon Dec 06 13:09:21 2010 +0100
   201.3 @@ -0,0 +1,269 @@
   201.4 +/* glpini02.c */
   201.5 +
   201.6 +/***********************************************************************
   201.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   201.8 +*
   201.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  201.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  201.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  201.12 +*  E-mail: <mao@gnu.org>.
  201.13 +*
  201.14 +*  GLPK is free software: you can redistribute it and/or modify it
  201.15 +*  under the terms of the GNU General Public License as published by
  201.16 +*  the Free Software Foundation, either version 3 of the License, or
  201.17 +*  (at your option) any later version.
  201.18 +*
  201.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  201.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  201.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  201.22 +*  License for more details.
  201.23 +*
  201.24 +*  You should have received a copy of the GNU General Public License
  201.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  201.26 +***********************************************************************/
  201.27 +
  201.28 +#include "glpapi.h"
  201.29 +
  201.30 +struct var
  201.31 +{     /* structural variable */
  201.32 +      int j;
  201.33 +      /* ordinal number */
  201.34 +      double q;
  201.35 +      /* penalty value */
  201.36 +};
  201.37 +
  201.38 +static int fcmp(const void *ptr1, const void *ptr2)
  201.39 +{     /* this routine is passed to the qsort() function */
  201.40 +      struct var *col1 = (void *)ptr1, *col2 = (void *)ptr2;
  201.41 +      if (col1->q < col2->q) return -1;
  201.42 +      if (col1->q > col2->q) return +1;
  201.43 +      return 0;
  201.44 +}
  201.45 +
  201.46 +static int get_column(glp_prob *lp, int j, int ind[], double val[])
  201.47 +{     /* Bixby's algorithm assumes that the constraint matrix is scaled
  201.48 +         such that the maximum absolute value in every non-zero row and
  201.49 +         column is 1 */
  201.50 +      int k, len;
  201.51 +      double big;
  201.52 +      len = glp_get_mat_col(lp, j, ind, val);
  201.53 +      big = 0.0;
  201.54 +      for (k = 1; k <= len; k++)
  201.55 +         if (big < fabs(val[k])) big = fabs(val[k]);
  201.56 +      if (big == 0.0) big = 1.0;
  201.57 +      for (k = 1; k <= len; k++) val[k] /= big;
  201.58 +      return len;
  201.59 +}
  201.60 +
  201.61 +static void cpx_basis(glp_prob *lp)
  201.62 +{     /* main routine */
  201.63 +      struct var *C, *C2, *C3, *C4;
  201.64 +      int m, n, i, j, jk, k, l, ll, t, n2, n3, n4, type, len, *I, *r,
  201.65 +         *ind;
  201.66 +      double alpha, gamma, cmax, temp, *v, *val;
  201.67 +      xprintf("Constructing initial basis...\n");
  201.68 +      /* determine the number of rows and columns */
  201.69 +      m = glp_get_num_rows(lp);
  201.70 +      n = glp_get_num_cols(lp);
  201.71 +      /* allocate working arrays */
  201.72 +      C = xcalloc(1+n, sizeof(struct var));
  201.73 +      I = xcalloc(1+m, sizeof(int));
  201.74 +      r = xcalloc(1+m, sizeof(int));
  201.75 +      v = xcalloc(1+m, sizeof(double));
  201.76 +      ind = xcalloc(1+m, sizeof(int));
  201.77 +      val = xcalloc(1+m, sizeof(double));
  201.78 +      /* make all auxiliary variables non-basic */
  201.79 +      for (i = 1; i <= m; i++)
  201.80 +      {  if (glp_get_row_type(lp, i) != GLP_DB)
  201.81 +            glp_set_row_stat(lp, i, GLP_NS);
  201.82 +         else if (fabs(glp_get_row_lb(lp, i)) <=
  201.83 +                  fabs(glp_get_row_ub(lp, i)))
  201.84 +            glp_set_row_stat(lp, i, GLP_NL);
  201.85 +         else
  201.86 +            glp_set_row_stat(lp, i, GLP_NU);
  201.87 +      }
  201.88 +      /* make all structural variables non-basic */
  201.89 +      for (j = 1; j <= n; j++)
  201.90 +      {  if (glp_get_col_type(lp, j) != GLP_DB)
  201.91 +            glp_set_col_stat(lp, j, GLP_NS);
  201.92 +         else if (fabs(glp_get_col_lb(lp, j)) <=
  201.93 +                  fabs(glp_get_col_ub(lp, j)))
  201.94 +            glp_set_col_stat(lp, j, GLP_NL);
  201.95 +         else
  201.96 +            glp_set_col_stat(lp, j, GLP_NU);
  201.97 +      }
  201.98 +      /* C2 is a set of free structural variables */
  201.99 +      n2 = 0, C2 = C + 0;
 201.100 +      for (j = 1; j <= n; j++)
 201.101 +      {  type = glp_get_col_type(lp, j);
 201.102 +         if (type == GLP_FR)
 201.103 +         {  n2++;
 201.104 +            C2[n2].j = j;
 201.105 +            C2[n2].q = 0.0;
 201.106 +         }
 201.107 +      }
 201.108 +      /* C3 is a set of structural variables having excatly one (lower
 201.109 +         or upper) bound */
 201.110 +      n3 = 0, C3 = C2 + n2;
 201.111 +      for (j = 1; j <= n; j++)
 201.112 +      {  type = glp_get_col_type(lp, j);
 201.113 +         if (type == GLP_LO)
 201.114 +         {  n3++;
 201.115 +            C3[n3].j = j;
 201.116 +            C3[n3].q = + glp_get_col_lb(lp, j);
 201.117 +         }
 201.118 +         else if (type == GLP_UP)
 201.119 +         {  n3++;
 201.120 +            C3[n3].j = j;
 201.121 +            C3[n3].q = - glp_get_col_ub(lp, j);
 201.122 +         }
 201.123 +      }
 201.124 +      /* C4 is a set of structural variables having both (lower and
 201.125 +         upper) bounds */
 201.126 +      n4 = 0, C4 = C3 + n3;
 201.127 +      for (j = 1; j <= n; j++)
 201.128 +      {  type = glp_get_col_type(lp, j);
 201.129 +         if (type == GLP_DB)
 201.130 +         {  n4++;
 201.131 +            C4[n4].j = j;
 201.132 +            C4[n4].q = glp_get_col_lb(lp, j) - glp_get_col_ub(lp, j);
 201.133 +         }
 201.134 +      }
 201.135 +      /* compute gamma = max{|c[j]|: 1 <= j <= n} */
 201.136 +      gamma = 0.0;
 201.137 +      for (j = 1; j <= n; j++)
 201.138 +      {  temp = fabs(glp_get_obj_coef(lp, j));
 201.139 +         if (gamma < temp) gamma = temp;
 201.140 +      }
 201.141 +      /* compute cmax */
 201.142 +      cmax = (gamma == 0.0 ? 1.0 : 1000.0 * gamma);
 201.143 +      /* compute final penalty for all structural variables within sets
 201.144 +         C2, C3, and C4 */
 201.145 +      switch (glp_get_obj_dir(lp))
 201.146 +      {  case GLP_MIN: temp = +1.0; break;
 201.147 +         case GLP_MAX: temp = -1.0; break;
 201.148 +         default: xassert(lp != lp);
 201.149 +      }
 201.150 +      for (k = 1; k <= n2+n3+n4; k++)
 201.151 +      {  j = C[k].j;
 201.152 +         C[k].q += (temp * glp_get_obj_coef(lp, j)) / cmax;
 201.153 +      }
 201.154 +      /* sort structural variables within C2, C3, and C4 in ascending
 201.155 +         order of penalty value */
 201.156 +      qsort(C2+1, n2, sizeof(struct var), fcmp);
 201.157 +      for (k = 1; k < n2; k++) xassert(C2[k].q <= C2[k+1].q);
 201.158 +      qsort(C3+1, n3, sizeof(struct var), fcmp);
 201.159 +      for (k = 1; k < n3; k++) xassert(C3[k].q <= C3[k+1].q);
 201.160 +      qsort(C4+1, n4, sizeof(struct var), fcmp);
 201.161 +      for (k = 1; k < n4; k++) xassert(C4[k].q <= C4[k+1].q);
 201.162 +      /*** STEP 1 ***/
 201.163 +      for (i = 1; i <= m; i++)
 201.164 +      {  type = glp_get_row_type(lp, i);
 201.165 +         if (type != GLP_FX)
 201.166 +         {  /* row i is either free or inequality constraint */
 201.167 +            glp_set_row_stat(lp, i, GLP_BS);
 201.168 +            I[i] = 1;
 201.169 +            r[i] = 1;
 201.170 +         }
 201.171 +         else
 201.172 +         {  /* row i is equality constraint */
 201.173 +            I[i] = 0;
 201.174 +            r[i] = 0;
 201.175 +         }
 201.176 +         v[i] = +DBL_MAX;
 201.177 +      }
 201.178 +      /*** STEP 2 ***/
 201.179 +      for (k = 1; k <= n2+n3+n4; k++)
 201.180 +      {  jk = C[k].j;
 201.181 +         len = get_column(lp, jk, ind, val);
 201.182 +         /* let alpha = max{|A[l,jk]|: r[l] = 0} and let l' be such
 201.183 +            that alpha = |A[l',jk]| */
 201.184 +         alpha = 0.0, ll = 0;
 201.185 +         for (t = 1; t <= len; t++)
 201.186 +         {  l = ind[t];
 201.187 +            if (r[l] == 0 && alpha < fabs(val[t]))
 201.188 +               alpha = fabs(val[t]), ll = l;
 201.189 +         }
 201.190 +         if (alpha >= 0.99)
 201.191 +         {  /* B := B union {jk} */
 201.192 +            glp_set_col_stat(lp, jk, GLP_BS);
 201.193 +            I[ll] = 1;
 201.194 +            v[ll] = alpha;
 201.195 +            /* r[l] := r[l] + 1 for all l such that |A[l,jk]| != 0 */
 201.196 +            for (t = 1; t <= len; t++)
 201.197 +            {  l = ind[t];
 201.198 +               if (val[t] != 0.0) r[l]++;
 201.199 +            }
 201.200 +            /* continue to the next k */
 201.201 +            continue;
 201.202 +         }
 201.203 +         /* if |A[l,jk]| > 0.01 * v[l] for some l, continue to the
 201.204 +            next k */
 201.205 +         for (t = 1; t <= len; t++)
 201.206 +         {  l = ind[t];
 201.207 +            if (fabs(val[t]) > 0.01 * v[l]) break;
 201.208 +         }
 201.209 +         if (t <= len) continue;
 201.210 +         /* otherwise, let alpha = max{|A[l,jk]|: I[l] = 0} and let l'
 201.211 +            be such that alpha = |A[l',jk]| */
 201.212 +         alpha = 0.0, ll = 0;
 201.213 +         for (t = 1; t <= len; t++)
 201.214 +         {  l = ind[t];
 201.215 +            if (I[l] == 0 && alpha < fabs(val[t]))
 201.216 +               alpha = fabs(val[t]), ll = l;
 201.217 +         }
 201.218 +         /* if alpha = 0, continue to the next k */
 201.219 +         if (alpha == 0.0) continue;
 201.220 +         /* B := B union {jk} */
 201.221 +         glp_set_col_stat(lp, jk, GLP_BS);
 201.222 +         I[ll] = 1;
 201.223 +         v[ll] = alpha;
 201.224 +         /* r[l] := r[l] + 1 for all l such that |A[l,jk]| != 0 */
 201.225 +         for (t = 1; t <= len; t++)
 201.226 +         {  l = ind[t];
 201.227 +            if (val[t] != 0.0) r[l]++;
 201.228 +         }
 201.229 +      }
 201.230 +      /*** STEP 3 ***/
 201.231 +      /* add an artificial variable (auxiliary variable for equality
 201.232 +         constraint) to cover each remaining uncovered row */
 201.233 +      for (i = 1; i <= m; i++)
 201.234 +         if (I[i] == 0) glp_set_row_stat(lp, i, GLP_BS);
 201.235 +      /* free working arrays */
 201.236 +      xfree(C);
 201.237 +      xfree(I);
 201.238 +      xfree(r);
 201.239 +      xfree(v);
 201.240 +      xfree(ind);
 201.241 +      xfree(val);
 201.242 +      return;
 201.243 +}
 201.244 +
 201.245 +/***********************************************************************
 201.246 +*  NAME
 201.247 +*
 201.248 +*  glp_cpx_basis - construct Bixby's initial LP basis
 201.249 +*
 201.250 +*  SYNOPSIS
 201.251 +*
 201.252 +*  void glp_cpx_basis(glp_prob *lp);
 201.253 +*
 201.254 +*  DESCRIPTION
 201.255 +*
 201.256 +*  The routine glp_cpx_basis constructs an advanced initial basis for
 201.257 +*  the specified problem object.
 201.258 +*
 201.259 +*  The routine is based on Bixby's algorithm described in the paper:
 201.260 +*
 201.261 +*  Robert E. Bixby. Implementing the Simplex Method: The Initial Basis.
 201.262 +*  ORSA Journal on Computing, Vol. 4, No. 3, 1992, pp. 267-84. */
 201.263 +
 201.264 +void glp_cpx_basis(glp_prob *lp)
 201.265 +{     if (lp->m == 0 || lp->n == 0)
 201.266 +         glp_std_basis(lp);
 201.267 +      else
 201.268 +         cpx_basis(lp);
 201.269 +      return;
 201.270 +}
 201.271 +
 201.272 +/* eof */
   202.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   202.2 +++ b/src/glpios.h	Mon Dec 06 13:09:21 2010 +0100
   202.3 @@ -0,0 +1,593 @@
   202.4 +/* glpios.h (integer optimization suite) */
   202.5 +
   202.6 +/***********************************************************************
   202.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   202.8 +*
   202.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  202.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  202.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  202.12 +*  E-mail: <mao@gnu.org>.
  202.13 +*
  202.14 +*  GLPK is free software: you can redistribute it and/or modify it
  202.15 +*  under the terms of the GNU General Public License as published by
  202.16 +*  the Free Software Foundation, either version 3 of the License, or
  202.17 +*  (at your option) any later version.
  202.18 +*
  202.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  202.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  202.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  202.22 +*  License for more details.
  202.23 +*
  202.24 +*  You should have received a copy of the GNU General Public License
  202.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  202.26 +***********************************************************************/
  202.27 +
  202.28 +#ifndef GLPIOS_H
  202.29 +#define GLPIOS_H
  202.30 +
  202.31 +#define GLP_TREE_DEFINED
  202.32 +typedef struct glp_tree glp_tree;
  202.33 +
  202.34 +#include "glpapi.h"
  202.35 +
  202.36 +typedef struct IOSLOT IOSLOT;
  202.37 +typedef struct IOSNPD IOSNPD;
  202.38 +typedef struct IOSBND IOSBND;
  202.39 +typedef struct IOSTAT IOSTAT;
  202.40 +typedef struct IOSROW IOSROW;
  202.41 +typedef struct IOSAIJ IOSAIJ;
  202.42 +typedef struct IOSPOOL IOSPOOL;
  202.43 +typedef struct IOSCUT IOSCUT;
  202.44 +
  202.45 +struct glp_tree
  202.46 +{     /* branch-and-bound tree */
  202.47 +      int magic;
  202.48 +      /* magic value used for debugging */
  202.49 +      DMP *pool;
  202.50 +      /* memory pool to store all IOS components */
  202.51 +      int n;
  202.52 +      /* number of columns (variables) */
  202.53 +      /*--------------------------------------------------------------*/
  202.54 +      /* problem components corresponding to the original MIP and its
  202.55 +         LP relaxation (used to restore the original problem object on
  202.56 +         exit from the solver) */
  202.57 +      int orig_m;
  202.58 +      /* number of rows */
  202.59 +      unsigned char *orig_type; /* uchar orig_type[1+orig_m+n]; */
  202.60 +      /* types of all variables */
  202.61 +      double *orig_lb; /* double orig_lb[1+orig_m+n]; */
  202.62 +      /* lower bounds of all variables */
  202.63 +      double *orig_ub; /* double orig_ub[1+orig_m+n]; */
  202.64 +      /* upper bounds of all variables */
  202.65 +      unsigned char *orig_stat; /* uchar orig_stat[1+orig_m+n]; */
  202.66 +      /* statuses of all variables */
  202.67 +      double *orig_prim; /* double orig_prim[1+orig_m+n]; */
  202.68 +      /* primal values of all variables */
  202.69 +      double *orig_dual; /* double orig_dual[1+orig_m+n]; */
  202.70 +      /* dual values of all variables */
  202.71 +      double orig_obj;
  202.72 +      /* optimal objective value for LP relaxation */
  202.73 +      /*--------------------------------------------------------------*/
  202.74 +      /* branch-and-bound tree */
  202.75 +      int nslots;
  202.76 +      /* length of the array of slots (enlarged automatically) */
  202.77 +      int avail;
  202.78 +      /* index of the first free slot; 0 means all slots are in use */
  202.79 +      IOSLOT *slot; /* IOSLOT slot[1+nslots]; */
  202.80 +      /* array of slots:
  202.81 +         slot[0] is not used;
  202.82 +         slot[p], 1 <= p <= nslots, either contains a pointer to some
  202.83 +         node of the branch-and-bound tree, in which case p is used on
  202.84 +         API level as the reference number of corresponding subproblem,
  202.85 +         or is free; all free slots are linked into single linked list;
  202.86 +         slot[1] always contains a pointer to the root node (it is free
  202.87 +         only if the tree is empty) */
  202.88 +      IOSNPD *head;
  202.89 +      /* pointer to the head of the active list */
  202.90 +      IOSNPD *tail;
  202.91 +      /* pointer to the tail of the active list */
  202.92 +      /* the active list is a doubly linked list of active subproblems
  202.93 +         which correspond to leaves of the tree; all subproblems in the
  202.94 +         active list are ordered chronologically (each a new subproblem
  202.95 +         is always added to the tail of the list) */
  202.96 +      int a_cnt;
  202.97 +      /* current number of active nodes (including the current one) */
  202.98 +      int n_cnt;
  202.99 +      /* current number of all (active and inactive) nodes */
 202.100 +      int t_cnt;
 202.101 +      /* total number of nodes including those which have been already
 202.102 +         removed from the tree; this count is increased by one whenever
 202.103 +         a new node is created and never decreased */
 202.104 +      /*--------------------------------------------------------------*/
 202.105 +      /* problem components corresponding to the root subproblem */
 202.106 +      int root_m;
 202.107 +      /* number of rows */
 202.108 +      unsigned char *root_type; /* uchar root_type[1+root_m+n]; */
 202.109 +      /* types of all variables */
 202.110 +      double *root_lb; /* double root_lb[1+root_m+n]; */
 202.111 +      /* lower bounds of all variables */
 202.112 +      double *root_ub; /* double root_ub[1+root_m+n]; */
 202.113 +      /* upper bounds of all variables */
 202.114 +      unsigned char *root_stat; /* uchar root_stat[1+root_m+n]; */
 202.115 +      /* statuses of all variables */
 202.116 +      /*--------------------------------------------------------------*/
 202.117 +      /* current subproblem and its LP relaxation */
 202.118 +      IOSNPD *curr;
 202.119 +      /* pointer to the current subproblem (which can be only active);
 202.120 +         NULL means the current subproblem does not exist */
 202.121 +      glp_prob *mip;
 202.122 +      /* original problem object passed to the solver; if the current
 202.123 +         subproblem exists, its LP segment corresponds to LP relaxation
 202.124 +         of the current subproblem; if the current subproblem does not
 202.125 +         exist, its LP segment corresponds to LP relaxation of the root
 202.126 +         subproblem (note that the root subproblem may differ from the
 202.127 +         original MIP, because it may be preprocessed and/or may have
 202.128 +         additional rows) */
 202.129 +      unsigned char *non_int; /* uchar non_int[1+n]; */
 202.130 +      /* these column flags are set each time when LP relaxation of the
 202.131 +         current subproblem has been solved;
 202.132 +         non_int[0] is not used;
 202.133 +         non_int[j], 1 <= j <= n, is j-th column flag; if this flag is
 202.134 +         set, corresponding variable is required to be integer, but its
 202.135 +         value in basic solution is fractional */
 202.136 +      /*--------------------------------------------------------------*/
 202.137 +      /* problem components corresponding to the parent (predecessor)
 202.138 +         subproblem for the current subproblem; used to inspect changes
 202.139 +         on freezing the current subproblem */
 202.140 +      int pred_m;
 202.141 +      /* number of rows */
 202.142 +      int pred_max;
 202.143 +      /* length of the following four arrays (enlarged automatically),
 202.144 +         pred_max >= pred_m + n */
 202.145 +      unsigned char *pred_type; /* uchar pred_type[1+pred_m+n]; */
 202.146 +      /* types of all variables */
 202.147 +      double *pred_lb; /* double pred_lb[1+pred_m+n]; */
 202.148 +      /* lower bounds of all variables */
 202.149 +      double *pred_ub; /* double pred_ub[1+pred_m+n]; */
 202.150 +      /* upper bounds of all variables */
 202.151 +      unsigned char *pred_stat; /* uchar pred_stat[1+pred_m+n]; */
 202.152 +      /* statuses of all variables */
 202.153 +      /****************************************************************/
 202.154 +      /* built-in cut generators segment */
 202.155 +      IOSPOOL *local;
 202.156 +      /* local cut pool */
 202.157 +      void *mir_gen;
 202.158 +      /* pointer to working area used by the MIR cut generator */
 202.159 +      void *clq_gen;
 202.160 +      /* pointer to working area used by the clique cut generator */
 202.161 +      /*--------------------------------------------------------------*/
 202.162 +      void *pcost;
 202.163 +      /* pointer to working area used on pseudocost branching */
 202.164 +      int *iwrk; /* int iwrk[1+n]; */
 202.165 +      /* working array */
 202.166 +      double *dwrk; /* double dwrk[1+n]; */
 202.167 +      /* working array */
 202.168 +      /*--------------------------------------------------------------*/
 202.169 +      /* control parameters and statistics */
 202.170 +      const glp_iocp *parm;
 202.171 +      /* copy of control parameters passed to the solver */
 202.172 +      glp_long tm_beg;
 202.173 +      /* starting time of the search, in seconds; the total time of the
 202.174 +         search is the difference between xtime() and tm_beg */
 202.175 +      glp_long tm_lag;
 202.176 +      /* the most recent time, in seconds, at which the progress of the
 202.177 +         the search was displayed */
 202.178 +      int sol_cnt;
 202.179 +      /* number of integer feasible solutions found */
 202.180 +      /*--------------------------------------------------------------*/
 202.181 +      /* advanced solver interface */
 202.182 +      int reason;
 202.183 +      /* flag indicating the reason why the callback routine is being
 202.184 +         called (see glpk.h) */
 202.185 +      int stop;
 202.186 +      /* flag indicating that the callback routine requires premature
 202.187 +         termination of the search */
 202.188 +      int next_p;
 202.189 +      /* reference number of active subproblem selected to continue
 202.190 +         the search; 0 means no subproblem has been selected */
 202.191 +      int reopt;
 202.192 +      /* flag indicating that the current LP relaxation needs to be
 202.193 +         re-optimized */
 202.194 +      int reinv;
 202.195 +      /* flag indicating that some (non-active) rows were removed from
 202.196 +         the current LP relaxation, so if there no new rows appear, the
 202.197 +         basis must be re-factorized */
 202.198 +      int br_var;
 202.199 +      /* the number of variable chosen to branch on */
 202.200 +      int br_sel;
 202.201 +      /* flag indicating which branch (subproblem) is suggested to be
 202.202 +         selected to continue the search:
 202.203 +         GLP_DN_BRNCH - select down-branch
 202.204 +         GLP_UP_BRNCH - select up-branch
 202.205 +         GLP_NO_BRNCH - use general selection technique */
 202.206 +      int child;
 202.207 +      /* subproblem reference number corresponding to br_sel */
 202.208 +};
 202.209 +
 202.210 +struct IOSLOT
 202.211 +{     /* node subproblem slot */
 202.212 +      IOSNPD *node;
 202.213 +      /* pointer to subproblem descriptor; NULL means free slot */
 202.214 +      int next;
 202.215 +      /* index of another free slot (only if this slot is free) */
 202.216 +};
 202.217 +
 202.218 +struct IOSNPD
 202.219 +{     /* node subproblem descriptor */
 202.220 +      int p;
 202.221 +      /* subproblem reference number (it is the index to corresponding
 202.222 +         slot, i.e. slot[p] points to this descriptor) */
 202.223 +      IOSNPD *up;
 202.224 +      /* pointer to the parent subproblem; NULL means this node is the
 202.225 +         root of the tree, in which case p = 1 */
 202.226 +      int level;
 202.227 +      /* node level (the root node has level 0) */
 202.228 +      int count;
 202.229 +      /* if count = 0, this subproblem is active; if count > 0, this
 202.230 +         subproblem is inactive, in which case count is the number of
 202.231 +         its child subproblems */
 202.232 +      /* the following three linked lists are destroyed on reviving and
 202.233 +         built anew on freezing the subproblem: */
 202.234 +      IOSBND *b_ptr;
 202.235 +      /* linked list of rows and columns of the parent subproblem whose
 202.236 +         types and bounds were changed */
 202.237 +      IOSTAT *s_ptr;
 202.238 +      /* linked list of rows and columns of the parent subproblem whose
 202.239 +         statuses were changed */
 202.240 +      IOSROW *r_ptr;
 202.241 +      /* linked list of rows (cuts) added to the parent subproblem */
 202.242 +      int solved;
 202.243 +      /* how many times LP relaxation of this subproblem was solved;
 202.244 +         for inactive subproblem this count is always non-zero;
 202.245 +         for active subproblem, which is not current, this count may be
 202.246 +         non-zero, if the subproblem was temporarily suspended */
 202.247 +      double lp_obj;
 202.248 +      /* optimal objective value to LP relaxation of this subproblem;
 202.249 +         on creating a subproblem this value is inherited from its
 202.250 +         parent; for the root subproblem, which has no parent, this
 202.251 +         value is initially set to -DBL_MAX (minimization) or +DBL_MAX
 202.252 +         (maximization); each time the subproblem is re-optimized, this
 202.253 +         value is appropriately changed */
 202.254 +      double bound;
 202.255 +      /* local lower (minimization) or upper (maximization) bound for
 202.256 +         integer optimal solution to *this* subproblem; this bound is
 202.257 +         local in the sense that only subproblems in the subtree rooted
 202.258 +         at this node cannot have better integer feasible solutions;
 202.259 +         on creating a subproblem its local bound is inherited from its
 202.260 +         parent and then can be made stronger (never weaker); for the
 202.261 +         root subproblem its local bound is initially set to -DBL_MAX
 202.262 +         (minimization) or +DBL_MAX (maximization) and then improved as
 202.263 +         the root LP relaxation has been solved */
 202.264 +      /* the following two quantities are defined only if LP relaxation
 202.265 +         of this subproblem was solved at least once (solved > 0): */
 202.266 +      int ii_cnt;
 202.267 +      /* number of integer variables whose value in optimal solution to
 202.268 +         LP relaxation of this subproblem is fractional */
 202.269 +      double ii_sum;
 202.270 +      /* sum of integer infeasibilities */
 202.271 +#if 1 /* 30/XI-2009 */
 202.272 +      int changed;
 202.273 +      /* how many times this subproblem was re-formulated (by adding
 202.274 +         cutting plane constraints) */
 202.275 +#endif
 202.276 +      int br_var;
 202.277 +      /* ordinal number of branching variable, 1 <= br_var <= n, used
 202.278 +         to split this subproblem; 0 means that either this subproblem
 202.279 +         is active or branching was made on a constraint */
 202.280 +      double br_val;
 202.281 +      /* (fractional) value of branching variable in optimal solution
 202.282 +         to final LP relaxation of this subproblem */
 202.283 +      void *data; /* char data[tree->cb_size]; */
 202.284 +      /* pointer to the application-specific data */
 202.285 +      IOSNPD *temp;
 202.286 +      /* working pointer used by some routines */
 202.287 +      IOSNPD *prev;
 202.288 +      /* pointer to previous subproblem in the active list */
 202.289 +      IOSNPD *next;
 202.290 +      /* pointer to next subproblem in the active list */
 202.291 +};
 202.292 +
 202.293 +struct IOSBND
 202.294 +{     /* bounds change entry */
 202.295 +      int k;
 202.296 +      /* ordinal number of corresponding row (1 <= k <= m) or column
 202.297 +         (m+1 <= k <= m+n), where m and n are the number of rows and
 202.298 +         columns, resp., in the parent subproblem */
 202.299 +      unsigned char type;
 202.300 +      /* new type */
 202.301 +      double lb;
 202.302 +      /* new lower bound */
 202.303 +      double ub;
 202.304 +      /* new upper bound */
 202.305 +      IOSBND *next;
 202.306 +      /* pointer to next entry for the same subproblem */
 202.307 +};
 202.308 +
 202.309 +struct IOSTAT
 202.310 +{     /* status change entry */
 202.311 +      int k;
 202.312 +      /* ordinal number of corresponding row (1 <= k <= m) or column
 202.313 +         (m+1 <= k <= m+n), where m and n are the number of rows and
 202.314 +         columns, resp., in the parent subproblem */
 202.315 +      unsigned char stat;
 202.316 +      /* new status */
 202.317 +      IOSTAT *next;
 202.318 +      /* pointer to next entry for the same subproblem */
 202.319 +};
 202.320 +
 202.321 +struct IOSROW
 202.322 +{     /* row (constraint) addition entry */
 202.323 +      char *name;
 202.324 +      /* row name or NULL */
 202.325 +      unsigned char origin;
 202.326 +      /* row origin flag (see glp_attr.origin) */
 202.327 +      unsigned char klass;
 202.328 +      /* row class descriptor (see glp_attr.klass) */
 202.329 +      unsigned char type;
 202.330 +      /* row type (GLP_LO, GLP_UP, etc.) */
 202.331 +      double lb;
 202.332 +      /* row lower bound */
 202.333 +      double ub;
 202.334 +      /* row upper bound */
 202.335 +      IOSAIJ *ptr;
 202.336 +      /* pointer to the row coefficient list */
 202.337 +      double rii;
 202.338 +      /* row scale factor */
 202.339 +      unsigned char stat;
 202.340 +      /* row status (GLP_BS, GLP_NL, etc.) */
 202.341 +      IOSROW *next;
 202.342 +      /* pointer to next entry for the same subproblem */
 202.343 +};
 202.344 +
 202.345 +struct IOSAIJ
 202.346 +{     /* constraint coefficient */
 202.347 +      int j;
 202.348 +      /* variable (column) number, 1 <= j <= n */
 202.349 +      double val;
 202.350 +      /* non-zero coefficient value */
 202.351 +      IOSAIJ *next;
 202.352 +      /* pointer to next coefficient for the same row */
 202.353 +};
 202.354 +
 202.355 +struct IOSPOOL
 202.356 +{     /* cut pool */
 202.357 +      int size;
 202.358 +      /* pool size = number of cuts in the pool */
 202.359 +      IOSCUT *head;
 202.360 +      /* pointer to the first cut */
 202.361 +      IOSCUT *tail;
 202.362 +      /* pointer to the last cut */
 202.363 +      int ord;
 202.364 +      /* ordinal number of the current cut, 1 <= ord <= size */
 202.365 +      IOSCUT *curr;
 202.366 +      /* pointer to the current cut */
 202.367 +};
 202.368 +
 202.369 +struct IOSCUT
 202.370 +{     /* cut (cutting plane constraint) */
 202.371 +      char *name;
 202.372 +      /* cut name or NULL */
 202.373 +      unsigned char klass;
 202.374 +      /* cut class descriptor (see glp_attr.klass) */
 202.375 +      IOSAIJ *ptr;
 202.376 +      /* pointer to the cut coefficient list */
 202.377 +      unsigned char type;
 202.378 +      /* cut type:
 202.379 +         GLP_LO: sum a[j] * x[j] >= b
 202.380 +         GLP_UP: sum a[j] * x[j] <= b
 202.381 +         GLP_FX: sum a[j] * x[j]  = b */
 202.382 +      double rhs;
 202.383 +      /* cut right-hand side */
 202.384 +      IOSCUT *prev;
 202.385 +      /* pointer to previous cut */
 202.386 +      IOSCUT *next;
 202.387 +      /* pointer to next cut */
 202.388 +};
 202.389 +
 202.390 +#define ios_create_tree _glp_ios_create_tree
 202.391 +glp_tree *ios_create_tree(glp_prob *mip, const glp_iocp *parm);
 202.392 +/* create branch-and-bound tree */
 202.393 +
 202.394 +#define ios_revive_node _glp_ios_revive_node
 202.395 +void ios_revive_node(glp_tree *tree, int p);
 202.396 +/* revive specified subproblem */
 202.397 +
 202.398 +#define ios_freeze_node _glp_ios_freeze_node
 202.399 +void ios_freeze_node(glp_tree *tree);
 202.400 +/* freeze current subproblem */
 202.401 +
 202.402 +#define ios_clone_node _glp_ios_clone_node
 202.403 +void ios_clone_node(glp_tree *tree, int p, int nnn, int ref[]);
 202.404 +/* clone specified subproblem */
 202.405 +
 202.406 +#define ios_delete_node _glp_ios_delete_node
 202.407 +void ios_delete_node(glp_tree *tree, int p);
 202.408 +/* delete specified subproblem */
 202.409 +
 202.410 +#define ios_delete_tree _glp_ios_delete_tree
 202.411 +void ios_delete_tree(glp_tree *tree);
 202.412 +/* delete branch-and-bound tree */
 202.413 +
 202.414 +#define ios_eval_degrad _glp_ios_eval_degrad
 202.415 +void ios_eval_degrad(glp_tree *tree, int j, double *dn, double *up);
 202.416 +/* estimate obj. degrad. for down- and up-branches */
 202.417 +
 202.418 +#define ios_round_bound _glp_ios_round_bound
 202.419 +double ios_round_bound(glp_tree *tree, double bound);
 202.420 +/* improve local bound by rounding */
 202.421 +
 202.422 +#define ios_is_hopeful _glp_ios_is_hopeful
 202.423 +int ios_is_hopeful(glp_tree *tree, double bound);
 202.424 +/* check if subproblem is hopeful */
 202.425 +
 202.426 +#define ios_best_node _glp_ios_best_node
 202.427 +int ios_best_node(glp_tree *tree);
 202.428 +/* find active node with best local bound */
 202.429 +
 202.430 +#define ios_relative_gap _glp_ios_relative_gap
 202.431 +double ios_relative_gap(glp_tree *tree);
 202.432 +/* compute relative mip gap */
 202.433 +
 202.434 +#define ios_solve_node _glp_ios_solve_node
 202.435 +int ios_solve_node(glp_tree *tree);
 202.436 +/* solve LP relaxation of current subproblem */
 202.437 +
 202.438 +#define ios_create_pool _glp_ios_create_pool
 202.439 +IOSPOOL *ios_create_pool(glp_tree *tree);
 202.440 +/* create cut pool */
 202.441 +
 202.442 +#define ios_add_row _glp_ios_add_row
 202.443 +int ios_add_row(glp_tree *tree, IOSPOOL *pool,
 202.444 +      const char *name, int klass, int flags, int len, const int ind[],
 202.445 +      const double val[], int type, double rhs);
 202.446 +/* add row (constraint) to the cut pool */
 202.447 +
 202.448 +#define ios_find_row _glp_ios_find_row
 202.449 +IOSCUT *ios_find_row(IOSPOOL *pool, int i);
 202.450 +/* find row (constraint) in the cut pool */
 202.451 +
 202.452 +#define ios_del_row _glp_ios_del_row
 202.453 +void ios_del_row(glp_tree *tree, IOSPOOL *pool, int i);
 202.454 +/* remove row (constraint) from the cut pool */
 202.455 +
 202.456 +#define ios_clear_pool _glp_ios_clear_pool
 202.457 +void ios_clear_pool(glp_tree *tree, IOSPOOL *pool);
 202.458 +/* remove all rows (constraints) from the cut pool */
 202.459 +
 202.460 +#define ios_delete_pool _glp_ios_delete_pool
 202.461 +void ios_delete_pool(glp_tree *tree, IOSPOOL *pool);
 202.462 +/* delete cut pool */
 202.463 +
 202.464 +#define ios_preprocess_node _glp_ios_preprocess_node
 202.465 +int ios_preprocess_node(glp_tree *tree, int max_pass);
 202.466 +/* preprocess current subproblem */
 202.467 +
 202.468 +#define ios_driver _glp_ios_driver
 202.469 +int ios_driver(glp_tree *tree);
 202.470 +/* branch-and-bound driver */
 202.471 +
 202.472 +/**********************************************************************/
 202.473 +
 202.474 +typedef struct IOSVEC IOSVEC;
 202.475 +
 202.476 +struct IOSVEC
 202.477 +{     /* sparse vector v = (v[j]) */
 202.478 +      int n;
 202.479 +      /* dimension, n >= 0 */
 202.480 +      int nnz;
 202.481 +      /* number of non-zero components, 0 <= nnz <= n */
 202.482 +      int *pos; /* int pos[1+n]; */
 202.483 +      /* pos[j] = k, 1 <= j <= n, is position of (non-zero) v[j] in the
 202.484 +         arrays ind and val, where 1 <= k <= nnz; pos[j] = 0 means that
 202.485 +         v[j] is structural zero */
 202.486 +      int *ind; /* int ind[1+n]; */
 202.487 +      /* ind[k] = j, 1 <= k <= nnz, is index of v[j] */
 202.488 +      double *val; /* double val[1+n]; */
 202.489 +      /* val[k], 1 <= k <= nnz, is a numeric value of v[j] */
 202.490 +};
 202.491 +
 202.492 +#define ios_create_vec _glp_ios_create_vec
 202.493 +IOSVEC *ios_create_vec(int n);
 202.494 +/* create sparse vector */
 202.495 +
 202.496 +#define ios_check_vec _glp_ios_check_vec
 202.497 +void ios_check_vec(IOSVEC *v);
 202.498 +/* check that sparse vector has correct representation */
 202.499 +
 202.500 +#define ios_get_vj _glp_ios_get_vj
 202.501 +double ios_get_vj(IOSVEC *v, int j);
 202.502 +/* retrieve component of sparse vector */
 202.503 +
 202.504 +#define ios_set_vj _glp_ios_set_vj
 202.505 +void ios_set_vj(IOSVEC *v, int j, double val);
 202.506 +/* set/change component of sparse vector */
 202.507 +
 202.508 +#define ios_clear_vec _glp_ios_clear_vec
 202.509 +void ios_clear_vec(IOSVEC *v);
 202.510 +/* set all components of sparse vector to zero */
 202.511 +
 202.512 +#define ios_clean_vec _glp_ios_clean_vec
 202.513 +void ios_clean_vec(IOSVEC *v, double eps);
 202.514 +/* remove zero or small components from sparse vector */
 202.515 +
 202.516 +#define ios_copy_vec _glp_ios_copy_vec
 202.517 +void ios_copy_vec(IOSVEC *x, IOSVEC *y);
 202.518 +/* copy sparse vector (x := y) */
 202.519 +
 202.520 +#define ios_linear_comb _glp_ios_linear_comb
 202.521 +void ios_linear_comb(IOSVEC *x, double a, IOSVEC *y);
 202.522 +/* compute linear combination (x := x + a * y) */
 202.523 +
 202.524 +#define ios_delete_vec _glp_ios_delete_vec
 202.525 +void ios_delete_vec(IOSVEC *v);
 202.526 +/* delete sparse vector */
 202.527 +
 202.528 +/**********************************************************************/
 202.529 +
 202.530 +#define ios_gmi_gen _glp_ios_gmi_gen
 202.531 +void ios_gmi_gen(glp_tree *tree);
 202.532 +/* generate Gomory's mixed integer cuts */
 202.533 +
 202.534 +#define ios_mir_init _glp_ios_mir_init
 202.535 +void *ios_mir_init(glp_tree *tree);
 202.536 +/* initialize MIR cut generator */
 202.537 +
 202.538 +#define ios_mir_gen _glp_ios_mir_gen
 202.539 +void ios_mir_gen(glp_tree *tree, void *gen);
 202.540 +/* generate MIR cuts */
 202.541 +
 202.542 +#define ios_mir_term _glp_ios_mir_term
 202.543 +void ios_mir_term(void *gen);
 202.544 +/* terminate MIR cut generator */
 202.545 +
 202.546 +#define ios_cov_gen _glp_ios_cov_gen
 202.547 +void ios_cov_gen(glp_tree *tree);
 202.548 +/* generate mixed cover cuts */
 202.549 +
 202.550 +#define ios_clq_init _glp_ios_clq_init
 202.551 +void *ios_clq_init(glp_tree *tree);
 202.552 +/* initialize clique cut generator */
 202.553 +
 202.554 +#define ios_clq_gen _glp_ios_clq_gen
 202.555 +void ios_clq_gen(glp_tree *tree, void *gen);
 202.556 +/* generate clique cuts */
 202.557 +
 202.558 +#define ios_clq_term _glp_ios_clq_term
 202.559 +void ios_clq_term(void *gen);
 202.560 +/* terminate clique cut generator */
 202.561 +
 202.562 +#define ios_pcost_init _glp_ios_pcost_init
 202.563 +void *ios_pcost_init(glp_tree *tree);
 202.564 +/* initialize working data used on pseudocost branching */
 202.565 +
 202.566 +#define ios_pcost_branch _glp_ios_pcost_branch
 202.567 +int ios_pcost_branch(glp_tree *T, int *next);
 202.568 +/* choose branching variable with pseudocost branching */
 202.569 +
 202.570 +#define ios_pcost_update _glp_ios_pcost_update
 202.571 +void ios_pcost_update(glp_tree *tree);
 202.572 +/* update history information for pseudocost branching */
 202.573 +
 202.574 +#define ios_pcost_free _glp_ios_pcost_free
 202.575 +void ios_pcost_free(glp_tree *tree);
 202.576 +/* free working area used on pseudocost branching */
 202.577 +
 202.578 +#define ios_feas_pump _glp_ios_feas_pump
 202.579 +void ios_feas_pump(glp_tree *T);
 202.580 +/* feasibility pump heuristic */
 202.581 +
 202.582 +#define ios_process_cuts _glp_ios_process_cuts
 202.583 +void ios_process_cuts(glp_tree *T);
 202.584 +/* process cuts stored in the local cut pool */
 202.585 +
 202.586 +#define ios_choose_node _glp_ios_choose_node
 202.587 +int ios_choose_node(glp_tree *T);
 202.588 +/* select subproblem to continue the search */
 202.589 +
 202.590 +#define ios_choose_var _glp_ios_choose_var
 202.591 +int ios_choose_var(glp_tree *T, int *next);
 202.592 +/* select variable to branch on */
 202.593 +
 202.594 +#endif
 202.595 +
 202.596 +/* eof */
   203.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   203.2 +++ b/src/glpios01.c	Mon Dec 06 13:09:21 2010 +0100
   203.3 @@ -0,0 +1,1611 @@
   203.4 +/* glpios01.c */
   203.5 +
   203.6 +/***********************************************************************
   203.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   203.8 +*
   203.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  203.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  203.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  203.12 +*  E-mail: <mao@gnu.org>.
  203.13 +*
  203.14 +*  GLPK is free software: you can redistribute it and/or modify it
  203.15 +*  under the terms of the GNU General Public License as published by
  203.16 +*  the Free Software Foundation, either version 3 of the License, or
  203.17 +*  (at your option) any later version.
  203.18 +*
  203.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  203.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  203.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  203.22 +*  License for more details.
  203.23 +*
  203.24 +*  You should have received a copy of the GNU General Public License
  203.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  203.26 +***********************************************************************/
  203.27 +
  203.28 +#include "glpios.h"
  203.29 +
  203.30 +/***********************************************************************
  203.31 +*  NAME
  203.32 +*
  203.33 +*  ios_create_tree - create branch-and-bound tree
  203.34 +*
  203.35 +*  SYNOPSIS
  203.36 +*
  203.37 +*  #include "glpios.h"
  203.38 +*  glp_tree *ios_create_tree(glp_prob *mip, const glp_iocp *parm);
  203.39 +*
  203.40 +*  DESCRIPTION
  203.41 +*
  203.42 +*  The routine ios_create_tree creates the branch-and-bound tree.
  203.43 +*
  203.44 +*  Being created the tree consists of the only root subproblem whose
  203.45 +*  reference number is 1. Note that initially the root subproblem is in
  203.46 +*  frozen state and therefore needs to be revived.
  203.47 +*
  203.48 +*  RETURNS
  203.49 +*
  203.50 +*  The routine returns a pointer to the tree created. */
  203.51 +
  203.52 +static IOSNPD *new_node(glp_tree *tree, IOSNPD *parent);
  203.53 +
  203.54 +glp_tree *ios_create_tree(glp_prob *mip, const glp_iocp *parm)
  203.55 +{     int m = mip->m;
  203.56 +      int n = mip->n;
  203.57 +      glp_tree *tree;
  203.58 +      int i, j;
  203.59 +      xassert(mip->tree == NULL);
  203.60 +      mip->tree = tree = xmalloc(sizeof(glp_tree));
  203.61 +      tree->pool = dmp_create_pool();
  203.62 +      tree->n = n;
  203.63 +      /* save original problem components */
  203.64 +      tree->orig_m = m;
  203.65 +      tree->orig_type = xcalloc(1+m+n, sizeof(char));
  203.66 +      tree->orig_lb = xcalloc(1+m+n, sizeof(double));
  203.67 +      tree->orig_ub = xcalloc(1+m+n, sizeof(double));
  203.68 +      tree->orig_stat = xcalloc(1+m+n, sizeof(char));
  203.69 +      tree->orig_prim = xcalloc(1+m+n, sizeof(double));
  203.70 +      tree->orig_dual = xcalloc(1+m+n, sizeof(double));
  203.71 +      for (i = 1; i <= m; i++)
  203.72 +      {  GLPROW *row = mip->row[i];
  203.73 +         tree->orig_type[i] = (char)row->type;
  203.74 +         tree->orig_lb[i] = row->lb;
  203.75 +         tree->orig_ub[i] = row->ub;
  203.76 +         tree->orig_stat[i] = (char)row->stat;
  203.77 +         tree->orig_prim[i] = row->prim;
  203.78 +         tree->orig_dual[i] = row->dual;
  203.79 +      }
  203.80 +      for (j = 1; j <= n; j++)
  203.81 +      {  GLPCOL *col = mip->col[j];
  203.82 +         tree->orig_type[m+j] = (char)col->type;
  203.83 +         tree->orig_lb[m+j] = col->lb;
  203.84 +         tree->orig_ub[m+j] = col->ub;
  203.85 +         tree->orig_stat[m+j] = (char)col->stat;
  203.86 +         tree->orig_prim[m+j] = col->prim;
  203.87 +         tree->orig_dual[m+j] = col->dual;
  203.88 +      }
  203.89 +      tree->orig_obj = mip->obj_val;
  203.90 +      /* initialize the branch-and-bound tree */
  203.91 +      tree->nslots = 0;
  203.92 +      tree->avail = 0;
  203.93 +      tree->slot = NULL;
  203.94 +      tree->head = tree->tail = NULL;
  203.95 +      tree->a_cnt = tree->n_cnt = tree->t_cnt = 0;
  203.96 +      /* the root subproblem is not solved yet, so its final components
  203.97 +         are unknown so far */
  203.98 +      tree->root_m = 0;
  203.99 +      tree->root_type = NULL;
 203.100 +      tree->root_lb = tree->root_ub = NULL;
 203.101 +      tree->root_stat = NULL;
 203.102 +      /* the current subproblem does not exist yet */
 203.103 +      tree->curr = NULL;
 203.104 +      tree->mip = mip;
 203.105 +      /*tree->solved = 0;*/
 203.106 +      tree->non_int = xcalloc(1+n, sizeof(char));
 203.107 +      memset(&tree->non_int[1], 0, n);
 203.108 +      /* arrays to save parent subproblem components will be allocated
 203.109 +         later */
 203.110 +      tree->pred_m = tree->pred_max = 0;
 203.111 +      tree->pred_type = NULL;
 203.112 +      tree->pred_lb = tree->pred_ub = NULL;
 203.113 +      tree->pred_stat = NULL;
 203.114 +      /* cut generator */
 203.115 +      tree->local = ios_create_pool(tree);
 203.116 +      /*tree->first_attempt = 1;*/
 203.117 +      /*tree->max_added_cuts = 0;*/
 203.118 +      /*tree->min_eff = 0.0;*/
 203.119 +      /*tree->miss = 0;*/
 203.120 +      /*tree->just_selected = 0;*/
 203.121 +      tree->mir_gen = NULL;
 203.122 +      tree->clq_gen = NULL;
 203.123 +      /*tree->round = 0;*/
 203.124 +#if 0
 203.125 +      /* create the conflict graph */
 203.126 +      tree->n_ref = xcalloc(1+n, sizeof(int));
 203.127 +      memset(&tree->n_ref[1], 0, n * sizeof(int));
 203.128 +      tree->c_ref = xcalloc(1+n, sizeof(int));
 203.129 +      memset(&tree->c_ref[1], 0, n * sizeof(int));
 203.130 +      tree->g = scg_create_graph(0);
 203.131 +      tree->j_ref = xcalloc(1+tree->g->n_max, sizeof(int));
 203.132 +#endif
 203.133 +      /* pseudocost branching */
 203.134 +      tree->pcost = NULL;
 203.135 +      tree->iwrk = xcalloc(1+n, sizeof(int));
 203.136 +      tree->dwrk = xcalloc(1+n, sizeof(double));
 203.137 +      /* initialize control parameters */
 203.138 +      tree->parm = parm;
 203.139 +      tree->tm_beg = xtime();
 203.140 +      tree->tm_lag = xlset(0);
 203.141 +      tree->sol_cnt = 0;
 203.142 +      /* initialize advanced solver interface */
 203.143 +      tree->reason = 0;
 203.144 +      tree->reopt = 0;
 203.145 +      tree->reinv = 0;
 203.146 +      tree->br_var = 0;
 203.147 +      tree->br_sel = 0;
 203.148 +      tree->child = 0;
 203.149 +      tree->next_p = 0;
 203.150 +      /*tree->btrack = NULL;*/
 203.151 +      tree->stop = 0;
 203.152 +      /* create the root subproblem, which initially is identical to
 203.153 +         the original MIP */
 203.154 +      new_node(tree, NULL);
 203.155 +      return tree;
 203.156 +}
 203.157 +
 203.158 +/***********************************************************************
 203.159 +*  NAME
 203.160 +*
 203.161 +*  ios_revive_node - revive specified subproblem
 203.162 +*
 203.163 +*  SYNOPSIS
 203.164 +*
 203.165 +*  #include "glpios.h"
 203.166 +*  void ios_revive_node(glp_tree *tree, int p);
 203.167 +*
 203.168 +*  DESCRIPTION
 203.169 +*
 203.170 +*  The routine ios_revive_node revives the specified subproblem, whose
 203.171 +*  reference number is p, and thereby makes it the current subproblem.
 203.172 +*  Note that the specified subproblem must be active. Besides, if the
 203.173 +*  current subproblem already exists, it must be frozen before reviving
 203.174 +*  another subproblem. */
 203.175 +
 203.176 +void ios_revive_node(glp_tree *tree, int p)
 203.177 +{     glp_prob *mip = tree->mip;
 203.178 +      IOSNPD *node, *root;
 203.179 +      /* obtain pointer to the specified subproblem */
 203.180 +      xassert(1 <= p && p <= tree->nslots);
 203.181 +      node = tree->slot[p].node;
 203.182 +      xassert(node != NULL);
 203.183 +      /* the specified subproblem must be active */
 203.184 +      xassert(node->count == 0);
 203.185 +      /* the current subproblem must not exist */
 203.186 +      xassert(tree->curr == NULL);
 203.187 +      /* the specified subproblem becomes current */
 203.188 +      tree->curr = node;
 203.189 +      /*tree->solved = 0;*/
 203.190 +      /* obtain pointer to the root subproblem */
 203.191 +      root = tree->slot[1].node;
 203.192 +      xassert(root != NULL);
 203.193 +      /* at this point problem object components correspond to the root
 203.194 +         subproblem, so if the root subproblem should be revived, there
 203.195 +         is nothing more to do */
 203.196 +      if (node == root) goto done;
 203.197 +      xassert(mip->m == tree->root_m);
 203.198 +      /* build path from the root to the current node */
 203.199 +      node->temp = NULL;
 203.200 +      for (node = node; node != NULL; node = node->up)
 203.201 +      {  if (node->up == NULL)
 203.202 +            xassert(node == root);
 203.203 +         else
 203.204 +            node->up->temp = node;
 203.205 +      }
 203.206 +      /* go down from the root to the current node and make necessary
 203.207 +         changes to restore components of the current subproblem */
 203.208 +      for (node = root; node != NULL; node = node->temp)
 203.209 +      {  int m = mip->m;
 203.210 +         int n = mip->n;
 203.211 +         /* if the current node is reached, the problem object at this
 203.212 +            point corresponds to its parent, so save attributes of rows
 203.213 +            and columns for the parent subproblem */
 203.214 +         if (node->temp == NULL)
 203.215 +         {  int i, j;
 203.216 +            tree->pred_m = m;
 203.217 +            /* allocate/reallocate arrays, if necessary */
 203.218 +            if (tree->pred_max < m + n)
 203.219 +            {  int new_size = m + n + 100;
 203.220 +               if (tree->pred_type != NULL) xfree(tree->pred_type);
 203.221 +               if (tree->pred_lb != NULL) xfree(tree->pred_lb);
 203.222 +               if (tree->pred_ub != NULL) xfree(tree->pred_ub);
 203.223 +               if (tree->pred_stat != NULL) xfree(tree->pred_stat);
 203.224 +               tree->pred_max = new_size;
 203.225 +               tree->pred_type = xcalloc(1+new_size, sizeof(char));
 203.226 +               tree->pred_lb = xcalloc(1+new_size, sizeof(double));
 203.227 +               tree->pred_ub = xcalloc(1+new_size, sizeof(double));
 203.228 +               tree->pred_stat = xcalloc(1+new_size, sizeof(char));
 203.229 +            }
 203.230 +            /* save row attributes */
 203.231 +            for (i = 1; i <= m; i++)
 203.232 +            {  GLPROW *row = mip->row[i];
 203.233 +               tree->pred_type[i] = (char)row->type;
 203.234 +               tree->pred_lb[i] = row->lb;
 203.235 +               tree->pred_ub[i] = row->ub;
 203.236 +               tree->pred_stat[i] = (char)row->stat;
 203.237 +            }
 203.238 +            /* save column attributes */
 203.239 +            for (j = 1; j <= n; j++)
 203.240 +            {  GLPCOL *col = mip->col[j];
 203.241 +               tree->pred_type[mip->m+j] = (char)col->type;
 203.242 +               tree->pred_lb[mip->m+j] = col->lb;
 203.243 +               tree->pred_ub[mip->m+j] = col->ub;
 203.244 +               tree->pred_stat[mip->m+j] = (char)col->stat;
 203.245 +            }
 203.246 +         }
 203.247 +         /* change bounds of rows and columns */
 203.248 +         {  IOSBND *b;
 203.249 +            for (b = node->b_ptr; b != NULL; b = b->next)
 203.250 +            {  if (b->k <= m)
 203.251 +                  glp_set_row_bnds(mip, b->k, b->type, b->lb, b->ub);
 203.252 +               else
 203.253 +                  glp_set_col_bnds(mip, b->k-m, b->type, b->lb, b->ub);
 203.254 +            }
 203.255 +         }
 203.256 +         /* change statuses of rows and columns */
 203.257 +         {  IOSTAT *s;
 203.258 +            for (s = node->s_ptr; s != NULL; s = s->next)
 203.259 +            {  if (s->k <= m)
 203.260 +                  glp_set_row_stat(mip, s->k, s->stat);
 203.261 +               else
 203.262 +                  glp_set_col_stat(mip, s->k-m, s->stat);
 203.263 +            }
 203.264 +         }
 203.265 +         /* add new rows */
 203.266 +         if (node->r_ptr != NULL)
 203.267 +         {  IOSROW *r;
 203.268 +            IOSAIJ *a;
 203.269 +            int i, len, *ind;
 203.270 +            double *val;
 203.271 +            ind = xcalloc(1+n, sizeof(int));
 203.272 +            val = xcalloc(1+n, sizeof(double));
 203.273 +            for (r = node->r_ptr; r != NULL; r = r->next)
 203.274 +            {  i = glp_add_rows(mip, 1);
 203.275 +               glp_set_row_name(mip, i, r->name);
 203.276 +#if 1 /* 20/IX-2008 */
 203.277 +               xassert(mip->row[i]->level == 0);
 203.278 +               mip->row[i]->level = node->level;
 203.279 +               mip->row[i]->origin = r->origin;
 203.280 +               mip->row[i]->klass = r->klass;
 203.281 +#endif
 203.282 +               glp_set_row_bnds(mip, i, r->type, r->lb, r->ub);
 203.283 +               len = 0;
 203.284 +               for (a = r->ptr; a != NULL; a = a->next)
 203.285 +                  len++, ind[len] = a->j, val[len] = a->val;
 203.286 +               glp_set_mat_row(mip, i, len, ind, val);
 203.287 +               glp_set_rii(mip, i, r->rii);
 203.288 +               glp_set_row_stat(mip, i, r->stat);
 203.289 +            }
 203.290 +            xfree(ind);
 203.291 +            xfree(val);
 203.292 +         }
 203.293 +#if 0
 203.294 +         /* add new edges to the conflict graph */
 203.295 +         /* add new cliques to the conflict graph */
 203.296 +         /* (not implemented yet) */
 203.297 +         xassert(node->own_nn == 0);
 203.298 +         xassert(node->own_nc == 0);
 203.299 +         xassert(node->e_ptr == NULL);
 203.300 +#endif
 203.301 +      }
 203.302 +      /* the specified subproblem has been revived */
 203.303 +      node = tree->curr;
 203.304 +      /* delete its bound change list */
 203.305 +      while (node->b_ptr != NULL)
 203.306 +      {  IOSBND *b;
 203.307 +         b = node->b_ptr;
 203.308 +         node->b_ptr = b->next;
 203.309 +         dmp_free_atom(tree->pool, b, sizeof(IOSBND));
 203.310 +      }
 203.311 +      /* delete its status change list */
 203.312 +      while (node->s_ptr != NULL)
 203.313 +      {  IOSTAT *s;
 203.314 +         s = node->s_ptr;
 203.315 +         node->s_ptr = s->next;
 203.316 +         dmp_free_atom(tree->pool, s, sizeof(IOSTAT));
 203.317 +      }
 203.318 +#if 1 /* 20/XI-2009 */
 203.319 +      /* delete its row addition list (additional rows may appear, for
 203.320 +         example, due to branching on GUB constraints */
 203.321 +      while (node->r_ptr != NULL)
 203.322 +      {  IOSROW *r;
 203.323 +         r = node->r_ptr;
 203.324 +         node->r_ptr = r->next;
 203.325 +         xassert(r->name == NULL);
 203.326 +         while (r->ptr != NULL)
 203.327 +         {  IOSAIJ *a;
 203.328 +            a = r->ptr;
 203.329 +            r->ptr = a->next;
 203.330 +            dmp_free_atom(tree->pool, a, sizeof(IOSAIJ));
 203.331 +         }
 203.332 +         dmp_free_atom(tree->pool, r, sizeof(IOSROW));
 203.333 +      }
 203.334 +#endif
 203.335 +done: return;
 203.336 +}
 203.337 +
 203.338 +/***********************************************************************
 203.339 +*  NAME
 203.340 +*
 203.341 +*  ios_freeze_node - freeze current subproblem
 203.342 +*
 203.343 +*  SYNOPSIS
 203.344 +*
 203.345 +*  #include "glpios.h"
 203.346 +*  void ios_freeze_node(glp_tree *tree);
 203.347 +*
 203.348 +*  DESCRIPTION
 203.349 +*
 203.350 +*  The routine ios_freeze_node freezes the current subproblem. */
 203.351 +
 203.352 +void ios_freeze_node(glp_tree *tree)
 203.353 +{     glp_prob *mip = tree->mip;
 203.354 +      int m = mip->m;
 203.355 +      int n = mip->n;
 203.356 +      IOSNPD *node;
 203.357 +      /* obtain pointer to the current subproblem */
 203.358 +      node = tree->curr;
 203.359 +      xassert(node != NULL);
 203.360 +      if (node->up == NULL)
 203.361 +      {  /* freeze the root subproblem */
 203.362 +         int k;
 203.363 +         xassert(node->p == 1);
 203.364 +         xassert(tree->root_m == 0);
 203.365 +         xassert(tree->root_type == NULL);
 203.366 +         xassert(tree->root_lb == NULL);
 203.367 +         xassert(tree->root_ub == NULL);
 203.368 +         xassert(tree->root_stat == NULL);
 203.369 +         tree->root_m = m;
 203.370 +         tree->root_type = xcalloc(1+m+n, sizeof(char));
 203.371 +         tree->root_lb = xcalloc(1+m+n, sizeof(double));
 203.372 +         tree->root_ub = xcalloc(1+m+n, sizeof(double));
 203.373 +         tree->root_stat = xcalloc(1+m+n, sizeof(char));
 203.374 +         for (k = 1; k <= m+n; k++)
 203.375 +         {  if (k <= m)
 203.376 +            {  GLPROW *row = mip->row[k];
 203.377 +               tree->root_type[k] = (char)row->type;
 203.378 +               tree->root_lb[k] = row->lb;
 203.379 +               tree->root_ub[k] = row->ub;
 203.380 +               tree->root_stat[k] = (char)row->stat;
 203.381 +            }
 203.382 +            else
 203.383 +            {  GLPCOL *col = mip->col[k-m];
 203.384 +               tree->root_type[k] = (char)col->type;
 203.385 +               tree->root_lb[k] = col->lb;
 203.386 +               tree->root_ub[k] = col->ub;
 203.387 +               tree->root_stat[k] = (char)col->stat;
 203.388 +            }
 203.389 +         }
 203.390 +      }
 203.391 +      else
 203.392 +      {  /* freeze non-root subproblem */
 203.393 +         int root_m = tree->root_m;
 203.394 +         int pred_m = tree->pred_m;
 203.395 +         int i, j, k;
 203.396 +         xassert(pred_m <= m);
 203.397 +         /* build change lists for rows and columns which exist in the
 203.398 +            parent subproblem */
 203.399 +         xassert(node->b_ptr == NULL);
 203.400 +         xassert(node->s_ptr == NULL);
 203.401 +         for (k = 1; k <= pred_m + n; k++)
 203.402 +         {  int pred_type, pred_stat, type, stat;
 203.403 +            double pred_lb, pred_ub, lb, ub;
 203.404 +            /* determine attributes in the parent subproblem */
 203.405 +            pred_type = tree->pred_type[k];
 203.406 +            pred_lb = tree->pred_lb[k];
 203.407 +            pred_ub = tree->pred_ub[k];
 203.408 +            pred_stat = tree->pred_stat[k];
 203.409 +            /* determine attributes in the current subproblem */
 203.410 +            if (k <= pred_m)
 203.411 +            {  GLPROW *row = mip->row[k];
 203.412 +               type = row->type;
 203.413 +               lb = row->lb;
 203.414 +               ub = row->ub;
 203.415 +               stat = row->stat;
 203.416 +            }
 203.417 +            else
 203.418 +            {  GLPCOL *col = mip->col[k - pred_m];
 203.419 +               type = col->type;
 203.420 +               lb = col->lb;
 203.421 +               ub = col->ub;
 203.422 +               stat = col->stat;
 203.423 +            }
 203.424 +            /* save type and bounds of a row/column, if changed */
 203.425 +            if (!(pred_type == type && pred_lb == lb && pred_ub == ub))
 203.426 +            {  IOSBND *b;
 203.427 +               b = dmp_get_atom(tree->pool, sizeof(IOSBND));
 203.428 +               b->k = k;
 203.429 +               b->type = (unsigned char)type;
 203.430 +               b->lb = lb;
 203.431 +               b->ub = ub;
 203.432 +               b->next = node->b_ptr;
 203.433 +               node->b_ptr = b;
 203.434 +            }
 203.435 +            /* save status of a row/column, if changed */
 203.436 +            if (pred_stat != stat)
 203.437 +            {  IOSTAT *s;
 203.438 +               s = dmp_get_atom(tree->pool, sizeof(IOSTAT));
 203.439 +               s->k = k;
 203.440 +               s->stat = (unsigned char)stat;
 203.441 +               s->next = node->s_ptr;
 203.442 +               node->s_ptr = s;
 203.443 +            }
 203.444 +         }
 203.445 +         /* save new rows added to the current subproblem */
 203.446 +         xassert(node->r_ptr == NULL);
 203.447 +         if (pred_m < m)
 203.448 +         {  int i, len, *ind;
 203.449 +            double *val;
 203.450 +            ind = xcalloc(1+n, sizeof(int));
 203.451 +            val = xcalloc(1+n, sizeof(double));
 203.452 +            for (i = m; i > pred_m; i--)
 203.453 +            {  GLPROW *row = mip->row[i];
 203.454 +               IOSROW *r;
 203.455 +               const char *name;
 203.456 +               r = dmp_get_atom(tree->pool, sizeof(IOSROW));
 203.457 +               name = glp_get_row_name(mip, i);
 203.458 +               if (name == NULL)
 203.459 +                  r->name = NULL;
 203.460 +               else
 203.461 +               {  r->name = dmp_get_atom(tree->pool, strlen(name)+1);
 203.462 +                  strcpy(r->name, name);
 203.463 +               }
 203.464 +#if 1 /* 20/IX-2008 */
 203.465 +               r->origin = row->origin;
 203.466 +               r->klass = row->klass;
 203.467 +#endif
 203.468 +               r->type = (unsigned char)row->type;
 203.469 +               r->lb = row->lb;
 203.470 +               r->ub = row->ub;
 203.471 +               r->ptr = NULL;
 203.472 +               len = glp_get_mat_row(mip, i, ind, val);
 203.473 +               for (k = 1; k <= len; k++)
 203.474 +               {  IOSAIJ *a;
 203.475 +                  a = dmp_get_atom(tree->pool, sizeof(IOSAIJ));
 203.476 +                  a->j = ind[k];
 203.477 +                  a->val = val[k];
 203.478 +                  a->next = r->ptr;
 203.479 +                  r->ptr = a;
 203.480 +               }
 203.481 +               r->rii = row->rii;
 203.482 +               r->stat = (unsigned char)row->stat;
 203.483 +               r->next = node->r_ptr;
 203.484 +               node->r_ptr = r;
 203.485 +            }
 203.486 +            xfree(ind);
 203.487 +            xfree(val);
 203.488 +         }
 203.489 +         /* remove all rows missing in the root subproblem */
 203.490 +         if (m != root_m)
 203.491 +         {  int nrs, *num;
 203.492 +            nrs = m - root_m;
 203.493 +            xassert(nrs > 0);
 203.494 +            num = xcalloc(1+nrs, sizeof(int));
 203.495 +            for (i = 1; i <= nrs; i++) num[i] = root_m + i;
 203.496 +            glp_del_rows(mip, nrs, num);
 203.497 +            xfree(num);
 203.498 +         }
 203.499 +         m = mip->m;
 203.500 +         /* and restore attributes of all rows and columns for the root
 203.501 +            subproblem */
 203.502 +         xassert(m == root_m);
 203.503 +         for (i = 1; i <= m; i++)
 203.504 +         {  glp_set_row_bnds(mip, i, tree->root_type[i],
 203.505 +               tree->root_lb[i], tree->root_ub[i]);
 203.506 +            glp_set_row_stat(mip, i, tree->root_stat[i]);
 203.507 +         }
 203.508 +         for (j = 1; j <= n; j++)
 203.509 +         {  glp_set_col_bnds(mip, j, tree->root_type[m+j],
 203.510 +               tree->root_lb[m+j], tree->root_ub[m+j]);
 203.511 +            glp_set_col_stat(mip, j, tree->root_stat[m+j]);
 203.512 +         }
 203.513 +#if 1
 203.514 +         /* remove all edges and cliques missing in the conflict graph
 203.515 +            for the root subproblem */
 203.516 +         /* (not implemented yet) */
 203.517 +#endif
 203.518 +      }
 203.519 +      /* the current subproblem has been frozen */
 203.520 +      tree->curr = NULL;
 203.521 +      return;
 203.522 +}
 203.523 +
 203.524 +/***********************************************************************
 203.525 +*  NAME
 203.526 +*
 203.527 +*  ios_clone_node - clone specified subproblem
 203.528 +*
 203.529 +*  SYNOPSIS
 203.530 +*
 203.531 +*  #include "glpios.h"
 203.532 +*  void ios_clone_node(glp_tree *tree, int p, int nnn, int ref[]);
 203.533 +*
 203.534 +*  DESCRIPTION
 203.535 +*
 203.536 +*  The routine ios_clone_node clones the specified subproblem, whose
 203.537 +*  reference number is p, creating its nnn exact copies. Note that the
 203.538 +*  specified subproblem must be active and must be in the frozen state
 203.539 +*  (i.e. it must not be the current subproblem).
 203.540 +*
 203.541 +*  Each clone, an exact copy of the specified subproblem, becomes a new
 203.542 +*  active subproblem added to the end of the active list. After cloning
 203.543 +*  the specified subproblem becomes inactive.
 203.544 +*
 203.545 +*  The reference numbers of clone subproblems are stored to locations
 203.546 +*  ref[1], ..., ref[nnn]. */
 203.547 +
 203.548 +static int get_slot(glp_tree *tree)
 203.549 +{     int p;
 203.550 +      /* if no free slots are available, increase the room */
 203.551 +      if (tree->avail == 0)
 203.552 +      {  int nslots = tree->nslots;
 203.553 +         IOSLOT *save = tree->slot;
 203.554 +         if (nslots == 0)
 203.555 +            tree->nslots = 20;
 203.556 +         else
 203.557 +         {  tree->nslots = nslots + nslots;
 203.558 +            xassert(tree->nslots > nslots);
 203.559 +         }
 203.560 +         tree->slot = xcalloc(1+tree->nslots, sizeof(IOSLOT));
 203.561 +         if (save != NULL)
 203.562 +         {  memcpy(&tree->slot[1], &save[1], nslots * sizeof(IOSLOT));
 203.563 +            xfree(save);
 203.564 +         }
 203.565 +         /* push more free slots into the stack */
 203.566 +         for (p = tree->nslots; p > nslots; p--)
 203.567 +         {  tree->slot[p].node = NULL;
 203.568 +            tree->slot[p].next = tree->avail;
 203.569 +            tree->avail = p;
 203.570 +         }
 203.571 +      }
 203.572 +      /* pull a free slot from the stack */
 203.573 +      p = tree->avail;
 203.574 +      tree->avail = tree->slot[p].next;
 203.575 +      xassert(tree->slot[p].node == NULL);
 203.576 +      tree->slot[p].next = 0;
 203.577 +      return p;
 203.578 +}
 203.579 +
 203.580 +static IOSNPD *new_node(glp_tree *tree, IOSNPD *parent)
 203.581 +{     IOSNPD *node;
 203.582 +      int p;
 203.583 +      /* pull a free slot for the new node */
 203.584 +      p = get_slot(tree);
 203.585 +      /* create descriptor of the new subproblem */
 203.586 +      node = dmp_get_atom(tree->pool, sizeof(IOSNPD));
 203.587 +      tree->slot[p].node = node;
 203.588 +      node->p = p;
 203.589 +      node->up = parent;
 203.590 +      node->level = (parent == NULL ? 0 : parent->level + 1);
 203.591 +      node->count = 0;
 203.592 +      node->b_ptr = NULL;
 203.593 +      node->s_ptr = NULL;
 203.594 +      node->r_ptr = NULL;
 203.595 +      node->solved = 0;
 203.596 +#if 0
 203.597 +      node->own_nn = node->own_nc = 0;
 203.598 +      node->e_ptr = NULL;
 203.599 +#endif
 203.600 +#if 1 /* 04/X-2008 */
 203.601 +      node->lp_obj = (parent == NULL ? (tree->mip->dir == GLP_MIN ?
 203.602 +         -DBL_MAX : +DBL_MAX) : parent->lp_obj);
 203.603 +#endif
 203.604 +      node->bound = (parent == NULL ? (tree->mip->dir == GLP_MIN ?
 203.605 +         -DBL_MAX : +DBL_MAX) : parent->bound);
 203.606 +      node->br_var = 0;
 203.607 +      node->br_val = 0.0;
 203.608 +      node->ii_cnt = 0;
 203.609 +      node->ii_sum = 0.0;
 203.610 +#if 1 /* 30/XI-2009 */
 203.611 +      node->changed = 0;
 203.612 +#endif
 203.613 +      if (tree->parm->cb_size == 0)
 203.614 +         node->data = NULL;
 203.615 +      else
 203.616 +      {  node->data = dmp_get_atom(tree->pool, tree->parm->cb_size);
 203.617 +         memset(node->data, 0, tree->parm->cb_size);
 203.618 +      }
 203.619 +      node->temp = NULL;
 203.620 +      node->prev = tree->tail;
 203.621 +      node->next = NULL;
 203.622 +      /* add the new subproblem to the end of the active list */
 203.623 +      if (tree->head == NULL)
 203.624 +         tree->head = node;
 203.625 +      else
 203.626 +         tree->tail->next = node;
 203.627 +      tree->tail = node;
 203.628 +      tree->a_cnt++;
 203.629 +      tree->n_cnt++;
 203.630 +      tree->t_cnt++;
 203.631 +      /* increase the number of child subproblems */
 203.632 +      if (parent == NULL)
 203.633 +         xassert(p == 1);
 203.634 +      else
 203.635 +         parent->count++;
 203.636 +      return node;
 203.637 +}
 203.638 +
 203.639 +void ios_clone_node(glp_tree *tree, int p, int nnn, int ref[])
 203.640 +{     IOSNPD *node;
 203.641 +      int k;
 203.642 +      /* obtain pointer to the subproblem to be cloned */
 203.643 +      xassert(1 <= p && p <= tree->nslots);
 203.644 +      node = tree->slot[p].node;
 203.645 +      xassert(node != NULL);
 203.646 +      /* the specified subproblem must be active */
 203.647 +      xassert(node->count == 0);
 203.648 +      /* and must be in the frozen state */
 203.649 +      xassert(tree->curr != node);
 203.650 +      /* remove the specified subproblem from the active list, because
 203.651 +         it becomes inactive */
 203.652 +      if (node->prev == NULL)
 203.653 +         tree->head = node->next;
 203.654 +      else
 203.655 +         node->prev->next = node->next;
 203.656 +      if (node->next == NULL)
 203.657 +         tree->tail = node->prev;
 203.658 +      else
 203.659 +         node->next->prev = node->prev;
 203.660 +      node->prev = node->next = NULL;
 203.661 +      tree->a_cnt--;
 203.662 +      /* create clone subproblems */
 203.663 +      xassert(nnn > 0);
 203.664 +      for (k = 1; k <= nnn; k++)
 203.665 +         ref[k] = new_node(tree, node)->p;
 203.666 +      return;
 203.667 +}
 203.668 +
 203.669 +/***********************************************************************
 203.670 +*  NAME
 203.671 +*
 203.672 +*  ios_delete_node - delete specified subproblem
 203.673 +*
 203.674 +*  SYNOPSIS
 203.675 +*
 203.676 +*  #include "glpios.h"
 203.677 +*  void ios_delete_node(glp_tree *tree, int p);
 203.678 +*
 203.679 +*  DESCRIPTION
 203.680 +*
 203.681 +*  The routine ios_delete_node deletes the specified subproblem, whose
 203.682 +*  reference number is p. The subproblem must be active and must be in
 203.683 +*  the frozen state (i.e. it must not be the current subproblem).
 203.684 +*
 203.685 +*  Note that deletion is performed recursively, i.e. if a subproblem to
 203.686 +*  be deleted is the only child of its parent, the parent subproblem is
 203.687 +*  also deleted, etc. */
 203.688 +
 203.689 +void ios_delete_node(glp_tree *tree, int p)
 203.690 +{     IOSNPD *node, *temp;
 203.691 +      /* obtain pointer to the subproblem to be deleted */
 203.692 +      xassert(1 <= p && p <= tree->nslots);
 203.693 +      node = tree->slot[p].node;
 203.694 +      xassert(node != NULL);
 203.695 +      /* the specified subproblem must be active */
 203.696 +      xassert(node->count == 0);
 203.697 +      /* and must be in the frozen state */
 203.698 +      xassert(tree->curr != node);
 203.699 +      /* remove the specified subproblem from the active list, because
 203.700 +         it is gone from the tree */
 203.701 +      if (node->prev == NULL)
 203.702 +         tree->head = node->next;
 203.703 +      else
 203.704 +         node->prev->next = node->next;
 203.705 +      if (node->next == NULL)
 203.706 +         tree->tail = node->prev;
 203.707 +      else
 203.708 +         node->next->prev = node->prev;
 203.709 +      node->prev = node->next = NULL;
 203.710 +      tree->a_cnt--;
 203.711 +loop: /* recursive deletion starts here */
 203.712 +      /* delete the bound change list */
 203.713 +      {  IOSBND *b;
 203.714 +         while (node->b_ptr != NULL)
 203.715 +         {  b = node->b_ptr;
 203.716 +            node->b_ptr = b->next;
 203.717 +            dmp_free_atom(tree->pool, b, sizeof(IOSBND));
 203.718 +         }
 203.719 +      }
 203.720 +      /* delete the status change list */
 203.721 +      {  IOSTAT *s;
 203.722 +         while (node->s_ptr != NULL)
 203.723 +         {  s = node->s_ptr;
 203.724 +            node->s_ptr = s->next;
 203.725 +            dmp_free_atom(tree->pool, s, sizeof(IOSTAT));
 203.726 +         }
 203.727 +      }
 203.728 +      /* delete the row addition list */
 203.729 +      while (node->r_ptr != NULL)
 203.730 +      {  IOSROW *r;
 203.731 +         r = node->r_ptr;
 203.732 +         if (r->name != NULL)
 203.733 +            dmp_free_atom(tree->pool, r->name, strlen(r->name)+1);
 203.734 +         while (r->ptr != NULL)
 203.735 +         {  IOSAIJ *a;
 203.736 +            a = r->ptr;
 203.737 +            r->ptr = a->next;
 203.738 +            dmp_free_atom(tree->pool, a, sizeof(IOSAIJ));
 203.739 +         }
 203.740 +         node->r_ptr = r->next;
 203.741 +         dmp_free_atom(tree->pool, r, sizeof(IOSROW));
 203.742 +      }
 203.743 +#if 0
 203.744 +      /* delete the edge addition list */
 203.745 +      /* delete the clique addition list */
 203.746 +      /* (not implemented yet) */
 203.747 +      xassert(node->own_nn == 0);
 203.748 +      xassert(node->own_nc == 0);
 203.749 +      xassert(node->e_ptr == NULL);
 203.750 +#endif
 203.751 +      /* free application-specific data */
 203.752 +      if (tree->parm->cb_size == 0)
 203.753 +         xassert(node->data == NULL);
 203.754 +      else
 203.755 +         dmp_free_atom(tree->pool, node->data, tree->parm->cb_size);
 203.756 +      /* free the corresponding node slot */
 203.757 +      p = node->p;
 203.758 +      xassert(tree->slot[p].node == node);
 203.759 +      tree->slot[p].node = NULL;
 203.760 +      tree->slot[p].next = tree->avail;
 203.761 +      tree->avail = p;
 203.762 +      /* save pointer to the parent subproblem */
 203.763 +      temp = node->up;
 203.764 +      /* delete the subproblem descriptor */
 203.765 +      dmp_free_atom(tree->pool, node, sizeof(IOSNPD));
 203.766 +      tree->n_cnt--;
 203.767 +      /* take pointer to the parent subproblem */
 203.768 +      node = temp;
 203.769 +      if (node != NULL)
 203.770 +      {  /* the parent subproblem exists; decrease the number of its
 203.771 +            child subproblems */
 203.772 +         xassert(node->count > 0);
 203.773 +         node->count--;
 203.774 +         /* if now the parent subproblem has no childs, it also must be
 203.775 +            deleted */
 203.776 +         if (node->count == 0) goto loop;
 203.777 +      }
 203.778 +      return;
 203.779 +}
 203.780 +
 203.781 +/***********************************************************************
 203.782 +*  NAME
 203.783 +*
 203.784 +*  ios_delete_tree - delete branch-and-bound tree
 203.785 +*
 203.786 +*  SYNOPSIS
 203.787 +*
 203.788 +*  #include "glpios.h"
 203.789 +*  void ios_delete_tree(glp_tree *tree);
 203.790 +*
 203.791 +*  DESCRIPTION
 203.792 +*
 203.793 +*  The routine ios_delete_tree deletes the branch-and-bound tree, which
 203.794 +*  the parameter tree points to, and frees all the memory allocated to
 203.795 +*  this program object.
 203.796 +*
 203.797 +*  On exit components of the problem object are restored to correspond
 203.798 +*  to the original MIP passed to the routine ios_create_tree. */
 203.799 +
 203.800 +void ios_delete_tree(glp_tree *tree)
 203.801 +{     glp_prob *mip = tree->mip;
 203.802 +      int i, j;
 203.803 +      int m = mip->m;
 203.804 +      int n = mip->n;
 203.805 +      xassert(mip->tree == tree);
 203.806 +      /* remove all additional rows */
 203.807 +      if (m != tree->orig_m)
 203.808 +      {  int nrs, *num;
 203.809 +         nrs = m - tree->orig_m;
 203.810 +         xassert(nrs > 0);
 203.811 +         num = xcalloc(1+nrs, sizeof(int));
 203.812 +         for (i = 1; i <= nrs; i++) num[i] = tree->orig_m + i;
 203.813 +         glp_del_rows(mip, nrs, num);
 203.814 +         xfree(num);
 203.815 +      }
 203.816 +      m = tree->orig_m;
 203.817 +      /* restore original attributes of rows and columns */
 203.818 +      xassert(m == tree->orig_m);
 203.819 +      xassert(n == tree->n);
 203.820 +      for (i = 1; i <= m; i++)
 203.821 +      {  glp_set_row_bnds(mip, i, tree->orig_type[i],
 203.822 +            tree->orig_lb[i], tree->orig_ub[i]);
 203.823 +         glp_set_row_stat(mip, i, tree->orig_stat[i]);
 203.824 +         mip->row[i]->prim = tree->orig_prim[i];
 203.825 +         mip->row[i]->dual = tree->orig_dual[i];
 203.826 +      }
 203.827 +      for (j = 1; j <= n; j++)
 203.828 +      {  glp_set_col_bnds(mip, j, tree->orig_type[m+j],
 203.829 +            tree->orig_lb[m+j], tree->orig_ub[m+j]);
 203.830 +         glp_set_col_stat(mip, j, tree->orig_stat[m+j]);
 203.831 +         mip->col[j]->prim = tree->orig_prim[m+j];
 203.832 +         mip->col[j]->dual = tree->orig_dual[m+j];
 203.833 +      }
 203.834 +      mip->pbs_stat = mip->dbs_stat = GLP_FEAS;
 203.835 +      mip->obj_val = tree->orig_obj;
 203.836 +      /* delete the branch-and-bound tree */
 203.837 +      xassert(tree->local != NULL);
 203.838 +      ios_delete_pool(tree, tree->local);
 203.839 +      dmp_delete_pool(tree->pool);
 203.840 +      xfree(tree->orig_type);
 203.841 +      xfree(tree->orig_lb);
 203.842 +      xfree(tree->orig_ub);
 203.843 +      xfree(tree->orig_stat);
 203.844 +      xfree(tree->orig_prim);
 203.845 +      xfree(tree->orig_dual);
 203.846 +      xfree(tree->slot);
 203.847 +      if (tree->root_type != NULL) xfree(tree->root_type);
 203.848 +      if (tree->root_lb != NULL) xfree(tree->root_lb);
 203.849 +      if (tree->root_ub != NULL) xfree(tree->root_ub);
 203.850 +      if (tree->root_stat != NULL) xfree(tree->root_stat);
 203.851 +      xfree(tree->non_int);
 203.852 +#if 0
 203.853 +      xfree(tree->n_ref);
 203.854 +      xfree(tree->c_ref);
 203.855 +      xfree(tree->j_ref);
 203.856 +#endif
 203.857 +      if (tree->pcost != NULL) ios_pcost_free(tree);
 203.858 +      xfree(tree->iwrk);
 203.859 +      xfree(tree->dwrk);
 203.860 +#if 0
 203.861 +      scg_delete_graph(tree->g);
 203.862 +#endif
 203.863 +      if (tree->pred_type != NULL) xfree(tree->pred_type);
 203.864 +      if (tree->pred_lb != NULL) xfree(tree->pred_lb);
 203.865 +      if (tree->pred_ub != NULL) xfree(tree->pred_ub);
 203.866 +      if (tree->pred_stat != NULL) xfree(tree->pred_stat);
 203.867 +#if 0
 203.868 +      xassert(tree->cut_gen == NULL);
 203.869 +#endif
 203.870 +      xassert(tree->mir_gen == NULL);
 203.871 +      xassert(tree->clq_gen == NULL);
 203.872 +      xfree(tree);
 203.873 +      mip->tree = NULL;
 203.874 +      return;
 203.875 +}
 203.876 +
 203.877 +/***********************************************************************
 203.878 +*  NAME
 203.879 +*
 203.880 +*  ios_eval_degrad - estimate obj. degrad. for down- and up-branches
 203.881 +*
 203.882 +*  SYNOPSIS
 203.883 +*
 203.884 +*  #include "glpios.h"
 203.885 +*  void ios_eval_degrad(glp_tree *tree, int j, double *dn, double *up);
 203.886 +*
 203.887 +*  DESCRIPTION
 203.888 +*
 203.889 +*  Given optimal basis to LP relaxation of the current subproblem the
 203.890 +*  routine ios_eval_degrad performs the dual ratio test to compute the
 203.891 +*  objective values in the adjacent basis for down- and up-branches,
 203.892 +*  which are stored in locations *dn and *up, assuming that x[j] is a
 203.893 +*  variable chosen to branch upon. */
 203.894 +
 203.895 +void ios_eval_degrad(glp_tree *tree, int j, double *dn, double *up)
 203.896 +{     glp_prob *mip = tree->mip;
 203.897 +      int m = mip->m, n = mip->n;
 203.898 +      int len, kase, k, t, stat;
 203.899 +      double alfa, beta, gamma, delta, dz;
 203.900 +      int *ind = tree->iwrk;
 203.901 +      double *val = tree->dwrk;
 203.902 +      /* current basis must be optimal */
 203.903 +      xassert(glp_get_status(mip) == GLP_OPT);
 203.904 +      /* basis factorization must exist */
 203.905 +      xassert(glp_bf_exists(mip));
 203.906 +      /* obtain (fractional) value of x[j] in optimal basic solution
 203.907 +         to LP relaxation of the current subproblem */
 203.908 +      xassert(1 <= j && j <= n);
 203.909 +      beta = mip->col[j]->prim;
 203.910 +      /* since the value of x[j] is fractional, it is basic; compute
 203.911 +         corresponding row of the simplex table */
 203.912 +      len = lpx_eval_tab_row(mip, m+j, ind, val);
 203.913 +      /* kase < 0 means down-branch; kase > 0 means up-branch */
 203.914 +      for (kase = -1; kase <= +1; kase += 2)
 203.915 +      {  /* for down-branch we introduce new upper bound floor(beta)
 203.916 +            for x[j]; similarly, for up-branch we introduce new lower
 203.917 +            bound ceil(beta) for x[j]; in the current basis this new
 203.918 +            upper/lower bound is violated, so in the adjacent basis
 203.919 +            x[j] will leave the basis and go to its new upper/lower
 203.920 +            bound; we need to know which non-basic variable x[k] should
 203.921 +            enter the basis to keep dual feasibility */
 203.922 +#if 0 /* 23/XI-2009 */
 203.923 +         k = lpx_dual_ratio_test(mip, len, ind, val, kase, 1e-7);
 203.924 +#else
 203.925 +         k = lpx_dual_ratio_test(mip, len, ind, val, kase, 1e-9);
 203.926 +#endif
 203.927 +         /* if no variable has been chosen, current basis being primal
 203.928 +            infeasible due to the new upper/lower bound of x[j] is dual
 203.929 +            unbounded, therefore, LP relaxation to corresponding branch
 203.930 +            has no primal feasible solution */
 203.931 +         if (k == 0)
 203.932 +         {  if (mip->dir == GLP_MIN)
 203.933 +            {  if (kase < 0)
 203.934 +                  *dn = +DBL_MAX;
 203.935 +               else
 203.936 +                  *up = +DBL_MAX;
 203.937 +            }
 203.938 +            else if (mip->dir == GLP_MAX)
 203.939 +            {  if (kase < 0)
 203.940 +                  *dn = -DBL_MAX;
 203.941 +               else
 203.942 +                  *up = -DBL_MAX;
 203.943 +            }
 203.944 +            else
 203.945 +               xassert(mip != mip);
 203.946 +            continue;
 203.947 +         }
 203.948 +         xassert(1 <= k && k <= m+n);
 203.949 +         /* row of the simplex table corresponding to specified basic
 203.950 +            variable x[j] is the following:
 203.951 +               x[j] = ... + alfa * x[k] + ... ;
 203.952 +            we need to know influence coefficient, alfa, at non-basic
 203.953 +            variable x[k] chosen with the dual ratio test */
 203.954 +         for (t = 1; t <= len; t++)
 203.955 +            if (ind[t] == k) break;
 203.956 +         xassert(1 <= t && t <= len);
 203.957 +         alfa = val[t];
 203.958 +         /* determine status and reduced cost of variable x[k] */
 203.959 +         if (k <= m)
 203.960 +         {  stat = mip->row[k]->stat;
 203.961 +            gamma = mip->row[k]->dual;
 203.962 +         }
 203.963 +         else
 203.964 +         {  stat = mip->col[k-m]->stat;
 203.965 +            gamma = mip->col[k-m]->dual;
 203.966 +         }
 203.967 +         /* x[k] cannot be basic or fixed non-basic */
 203.968 +         xassert(stat == GLP_NL || stat == GLP_NU || stat == GLP_NF);
 203.969 +         /* if the current basis is dual degenerative, some reduced
 203.970 +            costs, which are close to zero, may have wrong sign due to
 203.971 +            round-off errors, so correct the sign of gamma */
 203.972 +         if (mip->dir == GLP_MIN)
 203.973 +         {  if (stat == GLP_NL && gamma < 0.0 ||
 203.974 +                stat == GLP_NU && gamma > 0.0 ||
 203.975 +                stat == GLP_NF) gamma = 0.0;
 203.976 +         }
 203.977 +         else if (mip->dir == GLP_MAX)
 203.978 +         {  if (stat == GLP_NL && gamma > 0.0 ||
 203.979 +                stat == GLP_NU && gamma < 0.0 ||
 203.980 +                stat == GLP_NF) gamma = 0.0;
 203.981 +         }
 203.982 +         else
 203.983 +            xassert(mip != mip);
 203.984 +         /* determine the change of x[j] in the adjacent basis:
 203.985 +            delta x[j] = new x[j] - old x[j] */
 203.986 +         delta = (kase < 0 ? floor(beta) : ceil(beta)) - beta;
 203.987 +         /* compute the change of x[k] in the adjacent basis:
 203.988 +            delta x[k] = new x[k] - old x[k] = delta x[j] / alfa */
 203.989 +         delta /= alfa;
 203.990 +         /* compute the change of the objective in the adjacent basis:
 203.991 +            delta z = new z - old z = gamma * delta x[k] */
 203.992 +         dz = gamma * delta;
 203.993 +         if (mip->dir == GLP_MIN)
 203.994 +            xassert(dz >= 0.0);
 203.995 +         else if (mip->dir == GLP_MAX)
 203.996 +            xassert(dz <= 0.0);
 203.997 +         else
 203.998 +            xassert(mip != mip);
 203.999 +         /* compute the new objective value in the adjacent basis:
203.1000 +            new z = old z + delta z */
203.1001 +         if (kase < 0)
203.1002 +            *dn = mip->obj_val + dz;
203.1003 +         else
203.1004 +            *up = mip->obj_val + dz;
203.1005 +      }
203.1006 +      /*xprintf("obj = %g; dn = %g; up = %g\n",
203.1007 +         mip->obj_val, *dn, *up);*/
203.1008 +      return;
203.1009 +}
203.1010 +
203.1011 +/***********************************************************************
203.1012 +*  NAME
203.1013 +*
203.1014 +*  ios_round_bound - improve local bound by rounding
203.1015 +*
203.1016 +*  SYNOPSIS
203.1017 +*
203.1018 +*  #include "glpios.h"
203.1019 +*  double ios_round_bound(glp_tree *tree, double bound);
203.1020 +*
203.1021 +*  RETURNS
203.1022 +*
203.1023 +*  For the given local bound for any integer feasible solution to the
203.1024 +*  current subproblem the routine ios_round_bound returns an improved
203.1025 +*  local bound for the same integer feasible solution.
203.1026 +*
203.1027 +*  BACKGROUND
203.1028 +*
203.1029 +*  Let the current subproblem has the following objective function:
203.1030 +*
203.1031 +*     z =   sum  c[j] * x[j] + s >= b,                               (1)
203.1032 +*         j in J
203.1033 +*
203.1034 +*  where J = {j: c[j] is non-zero and integer, x[j] is integer}, s is
203.1035 +*  the sum of terms corresponding to fixed variables, b is an initial
203.1036 +*  local bound (minimization).
203.1037 +*
203.1038 +*  From (1) it follows that:
203.1039 +*
203.1040 +*     d *  sum  (c[j] / d) * x[j] + s >= b,                          (2)
203.1041 +*        j in J
203.1042 +*
203.1043 +*  or, equivalently,
203.1044 +*
203.1045 +*     sum  (c[j] / d) * x[j] >= (b - s) / d = h,                     (3)
203.1046 +*   j in J
203.1047 +*
203.1048 +*  where d = gcd(c[j]). Since the left-hand side of (3) is integer,
203.1049 +*  h = (b - s) / d can be rounded up to the nearest integer:
203.1050 +*
203.1051 +*     h' = ceil(h) = (b' - s) / d,                                   (4)
203.1052 +*
203.1053 +*  that gives an rounded, improved local bound:
203.1054 +*
203.1055 +*     b' = d * h' + s.                                               (5)
203.1056 +*
203.1057 +*  In case of maximization '>=' in (1) should be replaced by '<=' that
203.1058 +*  leads to the following formula:
203.1059 +*
203.1060 +*     h' = floor(h) = (b' - s) / d,                                  (6)
203.1061 +*
203.1062 +*  which should used in the same way as (4).
203.1063 +*
203.1064 +*  NOTE: If b is a valid local bound for a child of the current
203.1065 +*        subproblem, b' is also valid for that child subproblem. */
203.1066 +
203.1067 +double ios_round_bound(glp_tree *tree, double bound)
203.1068 +{     glp_prob *mip = tree->mip;
203.1069 +      int n = mip->n;
203.1070 +      int d, j, nn, *c = tree->iwrk;
203.1071 +      double s, h;
203.1072 +      /* determine c[j] and compute s */
203.1073 +      nn = 0, s = mip->c0, d = 0;
203.1074 +      for (j = 1; j <= n; j++)
203.1075 +      {  GLPCOL *col = mip->col[j];
203.1076 +         if (col->coef == 0.0) continue;
203.1077 +         if (col->type == GLP_FX)
203.1078 +         {  /* fixed variable */
203.1079 +            s += col->coef * col->prim;
203.1080 +         }
203.1081 +         else
203.1082 +         {  /* non-fixed variable */
203.1083 +            if (col->kind != GLP_IV) goto skip;
203.1084 +            if (col->coef != floor(col->coef)) goto skip;
203.1085 +            if (fabs(col->coef) <= (double)INT_MAX)
203.1086 +               c[++nn] = (int)fabs(col->coef);
203.1087 +            else
203.1088 +               d = 1;
203.1089 +         }
203.1090 +      }
203.1091 +      /* compute d = gcd(c[1],...c[nn]) */
203.1092 +      if (d == 0)
203.1093 +      {  if (nn == 0) goto skip;
203.1094 +         d = gcdn(nn, c);
203.1095 +      }
203.1096 +      xassert(d > 0);
203.1097 +      /* compute new local bound */
203.1098 +      if (mip->dir == GLP_MIN)
203.1099 +      {  if (bound != +DBL_MAX)
203.1100 +         {  h = (bound - s) / (double)d;
203.1101 +            if (h >= floor(h) + 0.001)
203.1102 +            {  /* round up */
203.1103 +               h = ceil(h);
203.1104 +               /*xprintf("d = %d; old = %g; ", d, bound);*/
203.1105 +               bound = (double)d * h + s;
203.1106 +               /*xprintf("new = %g\n", bound);*/
203.1107 +            }
203.1108 +         }
203.1109 +      }
203.1110 +      else if (mip->dir == GLP_MAX)
203.1111 +      {  if (bound != -DBL_MAX)
203.1112 +         {  h = (bound - s) / (double)d;
203.1113 +            if (h <= ceil(h) - 0.001)
203.1114 +            {  /* round down */
203.1115 +               h = floor(h);
203.1116 +               bound = (double)d * h + s;
203.1117 +            }
203.1118 +         }
203.1119 +      }
203.1120 +      else
203.1121 +         xassert(mip != mip);
203.1122 +skip: return bound;
203.1123 +}
203.1124 +
203.1125 +/***********************************************************************
203.1126 +*  NAME
203.1127 +*
203.1128 +*  ios_is_hopeful - check if subproblem is hopeful
203.1129 +*
203.1130 +*  SYNOPSIS
203.1131 +*
203.1132 +*  #include "glpios.h"
203.1133 +*  int ios_is_hopeful(glp_tree *tree, double bound);
203.1134 +*
203.1135 +*  DESCRIPTION
203.1136 +*
203.1137 +*  Given the local bound of a subproblem the routine ios_is_hopeful
203.1138 +*  checks if the subproblem can have an integer optimal solution which
203.1139 +*  is better than the best one currently known.
203.1140 +*
203.1141 +*  RETURNS
203.1142 +*
203.1143 +*  If the subproblem can have a better integer optimal solution, the
203.1144 +*  routine returns non-zero; otherwise, if the corresponding branch can
203.1145 +*  be pruned, the routine returns zero. */
203.1146 +
203.1147 +int ios_is_hopeful(glp_tree *tree, double bound)
203.1148 +{     glp_prob *mip = tree->mip;
203.1149 +      int ret = 1;
203.1150 +      double eps;
203.1151 +      if (mip->mip_stat == GLP_FEAS)
203.1152 +      {  eps = tree->parm->tol_obj * (1.0 + fabs(mip->mip_obj));
203.1153 +         switch (mip->dir)
203.1154 +         {  case GLP_MIN:
203.1155 +               if (bound >= mip->mip_obj - eps) ret = 0;
203.1156 +               break;
203.1157 +            case GLP_MAX:
203.1158 +               if (bound <= mip->mip_obj + eps) ret = 0;
203.1159 +               break;
203.1160 +            default:
203.1161 +               xassert(mip != mip);
203.1162 +         }
203.1163 +      }
203.1164 +      else
203.1165 +      {  switch (mip->dir)
203.1166 +         {  case GLP_MIN:
203.1167 +               if (bound == +DBL_MAX) ret = 0;
203.1168 +               break;
203.1169 +            case GLP_MAX:
203.1170 +               if (bound == -DBL_MAX) ret = 0;
203.1171 +               break;
203.1172 +            default:
203.1173 +               xassert(mip != mip);
203.1174 +         }
203.1175 +      }
203.1176 +      return ret;
203.1177 +}
203.1178 +
203.1179 +/***********************************************************************
203.1180 +*  NAME
203.1181 +*
203.1182 +*  ios_best_node - find active node with best local bound
203.1183 +*
203.1184 +*  SYNOPSIS
203.1185 +*
203.1186 +*  #include "glpios.h"
203.1187 +*  int ios_best_node(glp_tree *tree);
203.1188 +*
203.1189 +*  DESCRIPTION
203.1190 +*
203.1191 +*  The routine ios_best_node finds an active node whose local bound is
203.1192 +*  best among other active nodes.
203.1193 +*
203.1194 +*  It is understood that the integer optimal solution of the original
203.1195 +*  mip problem cannot be better than the best bound, so the best bound
203.1196 +*  is an lower (minimization) or upper (maximization) global bound for
203.1197 +*  the original problem.
203.1198 +*
203.1199 +*  RETURNS
203.1200 +*
203.1201 +*  The routine ios_best_node returns the subproblem reference number
203.1202 +*  for the best node. However, if the tree is empty, it returns zero. */
203.1203 +
203.1204 +int ios_best_node(glp_tree *tree)
203.1205 +{     IOSNPD *node, *best = NULL;
203.1206 +      switch (tree->mip->dir)
203.1207 +      {  case GLP_MIN:
203.1208 +            /* minimization */
203.1209 +            for (node = tree->head; node != NULL; node = node->next)
203.1210 +               if (best == NULL || best->bound > node->bound)
203.1211 +                  best = node;
203.1212 +            break;
203.1213 +         case GLP_MAX:
203.1214 +            /* maximization */
203.1215 +            for (node = tree->head; node != NULL; node = node->next)
203.1216 +               if (best == NULL || best->bound < node->bound)
203.1217 +                  best = node;
203.1218 +            break;
203.1219 +         default:
203.1220 +            xassert(tree != tree);
203.1221 +      }
203.1222 +      return best == NULL ? 0 : best->p;
203.1223 +}
203.1224 +
203.1225 +/***********************************************************************
203.1226 +*  NAME
203.1227 +*
203.1228 +*  ios_relative_gap - compute relative mip gap
203.1229 +*
203.1230 +*  SYNOPSIS
203.1231 +*
203.1232 +*  #include "glpios.h"
203.1233 +*  double ios_relative_gap(glp_tree *tree);
203.1234 +*
203.1235 +*  DESCRIPTION
203.1236 +*
203.1237 +*  The routine ios_relative_gap computes the relative mip gap using the
203.1238 +*  formula:
203.1239 +*
203.1240 +*     gap = |best_mip - best_bnd| / (|best_mip| + DBL_EPSILON),
203.1241 +*
203.1242 +*  where best_mip is the best integer feasible solution found so far,
203.1243 +*  best_bnd is the best (global) bound. If no integer feasible solution
203.1244 +*  has been found yet, rel_gap is set to DBL_MAX.
203.1245 +*
203.1246 +*  RETURNS
203.1247 +*
203.1248 +*  The routine ios_relative_gap returns the relative mip gap. */
203.1249 +
203.1250 +double ios_relative_gap(glp_tree *tree)
203.1251 +{     glp_prob *mip = tree->mip;
203.1252 +      int p;
203.1253 +      double best_mip, best_bnd, gap;
203.1254 +      if (mip->mip_stat == GLP_FEAS)
203.1255 +      {  best_mip = mip->mip_obj;
203.1256 +         p = ios_best_node(tree);
203.1257 +         if (p == 0)
203.1258 +         {  /* the tree is empty */
203.1259 +            gap = 0.0;
203.1260 +         }
203.1261 +         else
203.1262 +         {  best_bnd = tree->slot[p].node->bound;
203.1263 +            gap = fabs(best_mip - best_bnd) / (fabs(best_mip) +
203.1264 +               DBL_EPSILON);
203.1265 +         }
203.1266 +      }
203.1267 +      else
203.1268 +      {  /* no integer feasible solution has been found yet */
203.1269 +         gap = DBL_MAX;
203.1270 +      }
203.1271 +      return gap;
203.1272 +}
203.1273 +
203.1274 +/***********************************************************************
203.1275 +*  NAME
203.1276 +*
203.1277 +*  ios_solve_node - solve LP relaxation of current subproblem
203.1278 +*
203.1279 +*  SYNOPSIS
203.1280 +*
203.1281 +*  #include "glpios.h"
203.1282 +*  int ios_solve_node(glp_tree *tree);
203.1283 +*
203.1284 +*  DESCRIPTION
203.1285 +*
203.1286 +*  The routine ios_solve_node re-optimizes LP relaxation of the current
203.1287 +*  subproblem using the dual simplex method.
203.1288 +*
203.1289 +*  RETURNS
203.1290 +*
203.1291 +*  The routine returns the code which is reported by glp_simplex. */
203.1292 +
203.1293 +int ios_solve_node(glp_tree *tree)
203.1294 +{     glp_prob *mip = tree->mip;
203.1295 +      glp_smcp parm;
203.1296 +      int ret;
203.1297 +      /* the current subproblem must exist */
203.1298 +      xassert(tree->curr != NULL);
203.1299 +      /* set some control parameters */
203.1300 +      glp_init_smcp(&parm);
203.1301 +      switch (tree->parm->msg_lev)
203.1302 +      {  case GLP_MSG_OFF:
203.1303 +            parm.msg_lev = GLP_MSG_OFF; break;
203.1304 +         case GLP_MSG_ERR:
203.1305 +            parm.msg_lev = GLP_MSG_ERR; break;
203.1306 +         case GLP_MSG_ON:
203.1307 +         case GLP_MSG_ALL:
203.1308 +            parm.msg_lev = GLP_MSG_ON; break;
203.1309 +         case GLP_MSG_DBG:
203.1310 +            parm.msg_lev = GLP_MSG_ALL; break;
203.1311 +         default:
203.1312 +            xassert(tree != tree);
203.1313 +      }
203.1314 +      parm.meth = GLP_DUALP;
203.1315 +      if (tree->parm->msg_lev < GLP_MSG_DBG)
203.1316 +         parm.out_dly = tree->parm->out_dly;
203.1317 +      else
203.1318 +         parm.out_dly = 0;
203.1319 +      /* if the incumbent objective value is already known, use it to
203.1320 +         prematurely terminate the dual simplex search */
203.1321 +      if (mip->mip_stat == GLP_FEAS)
203.1322 +      {  switch (tree->mip->dir)
203.1323 +         {  case GLP_MIN:
203.1324 +               parm.obj_ul = mip->mip_obj;
203.1325 +               break;
203.1326 +            case GLP_MAX:
203.1327 +               parm.obj_ll = mip->mip_obj;
203.1328 +               break;
203.1329 +            default:
203.1330 +               xassert(mip != mip);
203.1331 +         }
203.1332 +      }
203.1333 +      /* try to solve/re-optimize the LP relaxation */
203.1334 +      ret = glp_simplex(mip, &parm);
203.1335 +      tree->curr->solved++;
203.1336 +#if 0
203.1337 +      xprintf("ret = %d; status = %d; pbs = %d; dbs = %d; some = %d\n",
203.1338 +         ret, glp_get_status(mip), mip->pbs_stat, mip->dbs_stat,
203.1339 +         mip->some);
203.1340 +      lpx_print_sol(mip, "sol");
203.1341 +#endif
203.1342 +      return ret;
203.1343 +}
203.1344 +
203.1345 +/**********************************************************************/
203.1346 +
203.1347 +IOSPOOL *ios_create_pool(glp_tree *tree)
203.1348 +{     /* create cut pool */
203.1349 +      IOSPOOL *pool;
203.1350 +#if 0
203.1351 +      pool = dmp_get_atom(tree->pool, sizeof(IOSPOOL));
203.1352 +#else
203.1353 +      xassert(tree == tree);
203.1354 +      pool = xmalloc(sizeof(IOSPOOL));
203.1355 +#endif
203.1356 +      pool->size = 0;
203.1357 +      pool->head = pool->tail = NULL;
203.1358 +      pool->ord = 0, pool->curr = NULL;
203.1359 +      return pool;
203.1360 +}
203.1361 +
203.1362 +int ios_add_row(glp_tree *tree, IOSPOOL *pool,
203.1363 +      const char *name, int klass, int flags, int len, const int ind[],
203.1364 +      const double val[], int type, double rhs)
203.1365 +{     /* add row (constraint) to the cut pool */
203.1366 +      IOSCUT *cut;
203.1367 +      IOSAIJ *aij;
203.1368 +      int k;
203.1369 +      xassert(pool != NULL);
203.1370 +      cut = dmp_get_atom(tree->pool, sizeof(IOSCUT));
203.1371 +      if (name == NULL || name[0] == '\0')
203.1372 +         cut->name = NULL;
203.1373 +      else
203.1374 +      {  for (k = 0; name[k] != '\0'; k++)
203.1375 +         {  if (k == 256)
203.1376 +               xerror("glp_ios_add_row: cut name too long\n");
203.1377 +            if (iscntrl((unsigned char)name[k]))
203.1378 +               xerror("glp_ios_add_row: cut name contains invalid chara"
203.1379 +                  "cter(s)\n");
203.1380 +         }
203.1381 +         cut->name = dmp_get_atom(tree->pool, strlen(name)+1);
203.1382 +         strcpy(cut->name, name);
203.1383 +      }
203.1384 +      if (!(0 <= klass && klass <= 255))
203.1385 +         xerror("glp_ios_add_row: klass = %d; invalid cut class\n",
203.1386 +            klass);
203.1387 +      cut->klass = (unsigned char)klass;
203.1388 +      if (flags != 0)
203.1389 +         xerror("glp_ios_add_row: flags = %d; invalid cut flags\n",
203.1390 +            flags);
203.1391 +      cut->ptr = NULL;
203.1392 +      if (!(0 <= len && len <= tree->n))
203.1393 +         xerror("glp_ios_add_row: len = %d; invalid cut length\n",
203.1394 +            len);
203.1395 +      for (k = 1; k <= len; k++)
203.1396 +      {  aij = dmp_get_atom(tree->pool, sizeof(IOSAIJ));
203.1397 +         if (!(1 <= ind[k] && ind[k] <= tree->n))
203.1398 +            xerror("glp_ios_add_row: ind[%d] = %d; column index out of "
203.1399 +               "range\n", k, ind[k]);
203.1400 +         aij->j = ind[k];
203.1401 +         aij->val = val[k];
203.1402 +         aij->next = cut->ptr;
203.1403 +         cut->ptr = aij;
203.1404 +      }
203.1405 +      if (!(type == GLP_LO || type == GLP_UP || type == GLP_FX))
203.1406 +         xerror("glp_ios_add_row: type = %d; invalid cut type\n",
203.1407 +            type);
203.1408 +      cut->type = (unsigned char)type;
203.1409 +      cut->rhs = rhs;
203.1410 +      cut->prev = pool->tail;
203.1411 +      cut->next = NULL;
203.1412 +      if (cut->prev == NULL)
203.1413 +         pool->head = cut;
203.1414 +      else
203.1415 +         cut->prev->next = cut;
203.1416 +      pool->tail = cut;
203.1417 +      pool->size++;
203.1418 +      return pool->size;
203.1419 +}
203.1420 +
203.1421 +IOSCUT *ios_find_row(IOSPOOL *pool, int i)
203.1422 +{     /* find row (constraint) in the cut pool */
203.1423 +      /* (smart linear search) */
203.1424 +      xassert(pool != NULL);
203.1425 +      xassert(1 <= i && i <= pool->size);
203.1426 +      if (pool->ord == 0)
203.1427 +      {  xassert(pool->curr == NULL);
203.1428 +         pool->ord = 1;
203.1429 +         pool->curr = pool->head;
203.1430 +      }
203.1431 +      xassert(pool->curr != NULL);
203.1432 +      if (i < pool->ord)
203.1433 +      {  if (i < pool->ord - i)
203.1434 +         {  pool->ord = 1;
203.1435 +            pool->curr = pool->head;
203.1436 +            while (pool->ord != i)
203.1437 +            {  pool->ord++;
203.1438 +               xassert(pool->curr != NULL);
203.1439 +               pool->curr = pool->curr->next;
203.1440 +            }
203.1441 +         }
203.1442 +         else
203.1443 +         {  while (pool->ord != i)
203.1444 +            {  pool->ord--;
203.1445 +               xassert(pool->curr != NULL);
203.1446 +               pool->curr = pool->curr->prev;
203.1447 +            }
203.1448 +         }
203.1449 +      }
203.1450 +      else if (i > pool->ord)
203.1451 +      {  if (i - pool->ord < pool->size - i)
203.1452 +         {  while (pool->ord != i)
203.1453 +            {  pool->ord++;
203.1454 +               xassert(pool->curr != NULL);
203.1455 +               pool->curr = pool->curr->next;
203.1456 +            }
203.1457 +         }
203.1458 +         else
203.1459 +         {  pool->ord = pool->size;
203.1460 +            pool->curr = pool->tail;
203.1461 +            while (pool->ord != i)
203.1462 +            {  pool->ord--;
203.1463 +               xassert(pool->curr != NULL);
203.1464 +               pool->curr = pool->curr->prev;
203.1465 +            }
203.1466 +         }
203.1467 +      }
203.1468 +      xassert(pool->ord == i);
203.1469 +      xassert(pool->curr != NULL);
203.1470 +      return pool->curr;
203.1471 +}
203.1472 +
203.1473 +void ios_del_row(glp_tree *tree, IOSPOOL *pool, int i)
203.1474 +{     /* remove row (constraint) from the cut pool */
203.1475 +      IOSCUT *cut;
203.1476 +      IOSAIJ *aij;
203.1477 +      xassert(pool != NULL);
203.1478 +      if (!(1 <= i && i <= pool->size))
203.1479 +         xerror("glp_ios_del_row: i = %d; cut number out of range\n",
203.1480 +            i);
203.1481 +      cut = ios_find_row(pool, i);
203.1482 +      xassert(pool->curr == cut);
203.1483 +      if (cut->next != NULL)
203.1484 +         pool->curr = cut->next;
203.1485 +      else if (cut->prev != NULL)
203.1486 +         pool->ord--, pool->curr = cut->prev;
203.1487 +      else
203.1488 +         pool->ord = 0, pool->curr = NULL;
203.1489 +      if (cut->name != NULL)
203.1490 +         dmp_free_atom(tree->pool, cut->name, strlen(cut->name)+1);
203.1491 +      if (cut->prev == NULL)
203.1492 +      {  xassert(pool->head == cut);
203.1493 +         pool->head = cut->next;
203.1494 +      }
203.1495 +      else
203.1496 +      {  xassert(cut->prev->next == cut);
203.1497 +         cut->prev->next = cut->next;
203.1498 +      }
203.1499 +      if (cut->next == NULL)
203.1500 +      {  xassert(pool->tail == cut);
203.1501 +         pool->tail = cut->prev;
203.1502 +      }
203.1503 +      else
203.1504 +      {  xassert(cut->next->prev == cut);
203.1505 +         cut->next->prev = cut->prev;
203.1506 +      }
203.1507 +      while (cut->ptr != NULL)
203.1508 +      {  aij = cut->ptr;
203.1509 +         cut->ptr = aij->next;
203.1510 +         dmp_free_atom(tree->pool, aij, sizeof(IOSAIJ));
203.1511 +      }
203.1512 +      dmp_free_atom(tree->pool, cut, sizeof(IOSCUT));
203.1513 +      pool->size--;
203.1514 +      return;
203.1515 +}
203.1516 +
203.1517 +void ios_clear_pool(glp_tree *tree, IOSPOOL *pool)
203.1518 +{     /* remove all rows (constraints) from the cut pool */
203.1519 +      xassert(pool != NULL);
203.1520 +      while (pool->head != NULL)
203.1521 +      {  IOSCUT *cut = pool->head;
203.1522 +         pool->head = cut->next;
203.1523 +         if (cut->name != NULL)
203.1524 +            dmp_free_atom(tree->pool, cut->name, strlen(cut->name)+1);
203.1525 +         while (cut->ptr != NULL)
203.1526 +         {  IOSAIJ *aij = cut->ptr;
203.1527 +            cut->ptr = aij->next;
203.1528 +            dmp_free_atom(tree->pool, aij, sizeof(IOSAIJ));
203.1529 +         }
203.1530 +         dmp_free_atom(tree->pool, cut, sizeof(IOSCUT));
203.1531 +      }
203.1532 +      pool->size = 0;
203.1533 +      pool->head = pool->tail = NULL;
203.1534 +      pool->ord = 0, pool->curr = NULL;
203.1535 +      return;
203.1536 +}
203.1537 +
203.1538 +void ios_delete_pool(glp_tree *tree, IOSPOOL *pool)
203.1539 +{     /* delete cut pool */
203.1540 +      xassert(pool != NULL);
203.1541 +      ios_clear_pool(tree, pool);
203.1542 +      xfree(pool);
203.1543 +      return;
203.1544 +}
203.1545 +
203.1546 +/**********************************************************************/
203.1547 +
203.1548 +#if 0
203.1549 +static int refer_to_node(glp_tree *tree, int j)
203.1550 +{     /* determine node number corresponding to binary variable x[j] or
203.1551 +         its complement */
203.1552 +      glp_prob *mip = tree->mip;
203.1553 +      int n = mip->n;
203.1554 +      int *ref;
203.1555 +      if (j > 0)
203.1556 +         ref = tree->n_ref;
203.1557 +      else
203.1558 +         ref = tree->c_ref, j = - j;
203.1559 +      xassert(1 <= j && j <= n);
203.1560 +      if (ref[j] == 0)
203.1561 +      {  /* new node is needed */
203.1562 +         SCG *g = tree->g;
203.1563 +         int n_max = g->n_max;
203.1564 +         ref[j] = scg_add_nodes(g, 1);
203.1565 +         if (g->n_max > n_max)
203.1566 +         {  int *save = tree->j_ref;
203.1567 +            tree->j_ref = xcalloc(1+g->n_max, sizeof(int));
203.1568 +            memcpy(&tree->j_ref[1], &save[1], g->n * sizeof(int));
203.1569 +            xfree(save);
203.1570 +         }
203.1571 +         xassert(ref[j] == g->n);
203.1572 +         tree->j_ref[ref[j]] = j;
203.1573 +         xassert(tree->curr != NULL);
203.1574 +         if (tree->curr->level > 0) tree->curr->own_nn++;
203.1575 +      }
203.1576 +      return ref[j];
203.1577 +}
203.1578 +#endif
203.1579 +
203.1580 +#if 0
203.1581 +void ios_add_edge(glp_tree *tree, int j1, int j2)
203.1582 +{     /* add new edge to the conflict graph */
203.1583 +      glp_prob *mip = tree->mip;
203.1584 +      int n = mip->n;
203.1585 +      SCGRIB *e;
203.1586 +      int first, i1, i2;
203.1587 +      xassert(-n <= j1 && j1 <= +n && j1 != 0);
203.1588 +      xassert(-n <= j2 && j2 <= +n && j2 != 0);
203.1589 +      xassert(j1 != j2);
203.1590 +      /* determine number of the first node, which was added for the
203.1591 +         current subproblem */
203.1592 +      xassert(tree->curr != NULL);
203.1593 +      first = tree->g->n - tree->curr->own_nn + 1;
203.1594 +      /* determine node numbers for both endpoints */
203.1595 +      i1 = refer_to_node(tree, j1);
203.1596 +      i2 = refer_to_node(tree, j2);
203.1597 +      /* add edge (i1,i2) to the conflict graph */
203.1598 +      e = scg_add_edge(tree->g, i1, i2);
203.1599 +      /* if the current subproblem is not the root and both endpoints
203.1600 +         were created on some previous levels, save the edge */
203.1601 +      if (tree->curr->level > 0 && i1 < first && i2 < first)
203.1602 +      {  IOSRIB *rib;
203.1603 +         rib = dmp_get_atom(tree->pool, sizeof(IOSRIB));
203.1604 +         rib->j1 = j1;
203.1605 +         rib->j2 = j2;
203.1606 +         rib->e = e;
203.1607 +         rib->next = tree->curr->e_ptr;
203.1608 +         tree->curr->e_ptr = rib;
203.1609 +      }
203.1610 +      return;
203.1611 +}
203.1612 +#endif
203.1613 +
203.1614 +/* eof */
   204.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   204.2 +++ b/src/glpios02.c	Mon Dec 06 13:09:21 2010 +0100
   204.3 @@ -0,0 +1,825 @@
   204.4 +/* glpios02.c (preprocess current subproblem) */
   204.5 +
   204.6 +/***********************************************************************
   204.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   204.8 +*
   204.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  204.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  204.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  204.12 +*  E-mail: <mao@gnu.org>.
  204.13 +*
  204.14 +*  GLPK is free software: you can redistribute it and/or modify it
  204.15 +*  under the terms of the GNU General Public License as published by
  204.16 +*  the Free Software Foundation, either version 3 of the License, or
  204.17 +*  (at your option) any later version.
  204.18 +*
  204.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  204.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  204.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  204.22 +*  License for more details.
  204.23 +*
  204.24 +*  You should have received a copy of the GNU General Public License
  204.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  204.26 +***********************************************************************/
  204.27 +
  204.28 +#include "glpios.h"
  204.29 +
  204.30 +/***********************************************************************
  204.31 +*  prepare_row_info - prepare row info to determine implied bounds
  204.32 +*
  204.33 +*  Given a row (linear form)
  204.34 +*
  204.35 +*      n
  204.36 +*     sum a[j] * x[j]                                                (1)
  204.37 +*     j=1
  204.38 +*
  204.39 +*  and bounds of columns (variables)
  204.40 +*
  204.41 +*     l[j] <= x[j] <= u[j]                                           (2)
  204.42 +*
  204.43 +*  this routine computes f_min, j_min, f_max, j_max needed to determine
  204.44 +*  implied bounds.
  204.45 +*
  204.46 +*  ALGORITHM
  204.47 +*
  204.48 +*  Let J+ = {j : a[j] > 0} and J- = {j : a[j] < 0}.
  204.49 +*
  204.50 +*  Parameters f_min and j_min are computed as follows:
  204.51 +*
  204.52 +*  1) if there is no x[k] such that k in J+ and l[k] = -inf or k in J-
  204.53 +*     and u[k] = +inf, then
  204.54 +*
  204.55 +*     f_min :=   sum   a[j] * l[j] +   sum   a[j] * u[j]
  204.56 +*              j in J+               j in J-
  204.57 +*                                                                    (3)
  204.58 +*     j_min := 0
  204.59 +*
  204.60 +*  2) if there is exactly one x[k] such that k in J+ and l[k] = -inf
  204.61 +*     or k in J- and u[k] = +inf, then
  204.62 +*
  204.63 +*     f_min :=   sum       a[j] * l[j] +   sum       a[j] * u[j]
  204.64 +*              j in J+\{k}               j in J-\{k}
  204.65 +*                                                                    (4)
  204.66 +*     j_min := k
  204.67 +*
  204.68 +*  3) if there are two or more x[k] such that k in J+ and l[k] = -inf
  204.69 +*     or k in J- and u[k] = +inf, then
  204.70 +*
  204.71 +*     f_min := -inf
  204.72 +*                                                                    (5)
  204.73 +*     j_min := 0
  204.74 +*
  204.75 +*  Parameters f_max and j_max are computed in a similar way as follows:
  204.76 +*
  204.77 +*  1) if there is no x[k] such that k in J+ and u[k] = +inf or k in J-
  204.78 +*     and l[k] = -inf, then
  204.79 +*
  204.80 +*     f_max :=   sum   a[j] * u[j] +   sum   a[j] * l[j]
  204.81 +*              j in J+               j in J-
  204.82 +*                                                                    (6)
  204.83 +*     j_max := 0
  204.84 +*
  204.85 +*  2) if there is exactly one x[k] such that k in J+ and u[k] = +inf
  204.86 +*     or k in J- and l[k] = -inf, then
  204.87 +*
  204.88 +*     f_max :=   sum       a[j] * u[j] +   sum       a[j] * l[j]
  204.89 +*              j in J+\{k}               j in J-\{k}
  204.90 +*                                                                    (7)
  204.91 +*     j_max := k
  204.92 +*
  204.93 +*  3) if there are two or more x[k] such that k in J+ and u[k] = +inf
  204.94 +*     or k in J- and l[k] = -inf, then
  204.95 +*
  204.96 +*     f_max := +inf
  204.97 +*                                                                    (8)
  204.98 +*     j_max := 0                                                      */
  204.99 +
 204.100 +struct f_info
 204.101 +{     int j_min, j_max;
 204.102 +      double f_min, f_max;
 204.103 +};
 204.104 +
 204.105 +static void prepare_row_info(int n, const double a[], const double l[],
 204.106 +      const double u[], struct f_info *f)
 204.107 +{     int j, j_min, j_max;
 204.108 +      double f_min, f_max;
 204.109 +      xassert(n >= 0);
 204.110 +      /* determine f_min and j_min */
 204.111 +      f_min = 0.0, j_min = 0;
 204.112 +      for (j = 1; j <= n; j++)
 204.113 +      {  if (a[j] > 0.0)
 204.114 +         {  if (l[j] == -DBL_MAX)
 204.115 +            {  if (j_min == 0)
 204.116 +                  j_min = j;
 204.117 +               else
 204.118 +               {  f_min = -DBL_MAX, j_min = 0;
 204.119 +                  break;
 204.120 +               }
 204.121 +            }
 204.122 +            else
 204.123 +               f_min += a[j] * l[j];
 204.124 +         }
 204.125 +         else if (a[j] < 0.0)
 204.126 +         {  if (u[j] == +DBL_MAX)
 204.127 +            {  if (j_min == 0)
 204.128 +                  j_min = j;
 204.129 +               else
 204.130 +               {  f_min = -DBL_MAX, j_min = 0;
 204.131 +                  break;
 204.132 +               }
 204.133 +            }
 204.134 +            else
 204.135 +               f_min += a[j] * u[j];
 204.136 +         }
 204.137 +         else
 204.138 +            xassert(a != a);
 204.139 +      }
 204.140 +      f->f_min = f_min, f->j_min = j_min;
 204.141 +      /* determine f_max and j_max */
 204.142 +      f_max = 0.0, j_max = 0;
 204.143 +      for (j = 1; j <= n; j++)
 204.144 +      {  if (a[j] > 0.0)
 204.145 +         {  if (u[j] == +DBL_MAX)
 204.146 +            {  if (j_max == 0)
 204.147 +                  j_max = j;
 204.148 +               else
 204.149 +               {  f_max = +DBL_MAX, j_max = 0;
 204.150 +                  break;
 204.151 +               }
 204.152 +            }
 204.153 +            else
 204.154 +               f_max += a[j] * u[j];
 204.155 +         }
 204.156 +         else if (a[j] < 0.0)
 204.157 +         {  if (l[j] == -DBL_MAX)
 204.158 +            {  if (j_max == 0)
 204.159 +                  j_max = j;
 204.160 +               else
 204.161 +               {  f_max = +DBL_MAX, j_max = 0;
 204.162 +                  break;
 204.163 +               }
 204.164 +            }
 204.165 +            else
 204.166 +               f_max += a[j] * l[j];
 204.167 +         }
 204.168 +         else
 204.169 +            xassert(a != a);
 204.170 +      }
 204.171 +      f->f_max = f_max, f->j_max = j_max;
 204.172 +      return;
 204.173 +}
 204.174 +
 204.175 +/***********************************************************************
 204.176 +*  row_implied_bounds - determine row implied bounds
 204.177 +*
 204.178 +*  Given a row (linear form)
 204.179 +*
 204.180 +*      n
 204.181 +*     sum a[j] * x[j]
 204.182 +*     j=1
 204.183 +*
 204.184 +*  and bounds of columns (variables)
 204.185 +*
 204.186 +*     l[j] <= x[j] <= u[j]
 204.187 +*
 204.188 +*  this routine determines implied bounds of the row.
 204.189 +*
 204.190 +*  ALGORITHM
 204.191 +*
 204.192 +*  Let J+ = {j : a[j] > 0} and J- = {j : a[j] < 0}.
 204.193 +*
 204.194 +*  The implied lower bound of the row is computed as follows:
 204.195 +*
 204.196 +*     L' :=   sum   a[j] * l[j] +   sum   a[j] * u[j]                (9)
 204.197 +*           j in J+               j in J-
 204.198 +*
 204.199 +*  and as it follows from (3), (4), and (5):
 204.200 +*
 204.201 +*     L' := if j_min = 0 then f_min else -inf                       (10)
 204.202 +*
 204.203 +*  The implied upper bound of the row is computed as follows:
 204.204 +*
 204.205 +*     U' :=   sum   a[j] * u[j] +   sum   a[j] * l[j]               (11)
 204.206 +*           j in J+               j in J-
 204.207 +*
 204.208 +*  and as it follows from (6), (7), and (8):
 204.209 +*
 204.210 +*     U' := if j_max = 0 then f_max else +inf                       (12)
 204.211 +*
 204.212 +*  The implied bounds are stored in locations LL and UU. */
 204.213 +
 204.214 +static void row_implied_bounds(const struct f_info *f, double *LL,
 204.215 +      double *UU)
 204.216 +{     *LL = (f->j_min == 0 ? f->f_min : -DBL_MAX);
 204.217 +      *UU = (f->j_max == 0 ? f->f_max : +DBL_MAX);
 204.218 +      return;
 204.219 +}
 204.220 +
 204.221 +/***********************************************************************
 204.222 +*  col_implied_bounds - determine column implied bounds
 204.223 +*
 204.224 +*  Given a row (constraint)
 204.225 +*
 204.226 +*           n
 204.227 +*     L <= sum a[j] * x[j] <= U                                     (13)
 204.228 +*          j=1
 204.229 +*
 204.230 +*  and bounds of columns (variables)
 204.231 +*
 204.232 +*     l[j] <= x[j] <= u[j]
 204.233 +*
 204.234 +*  this routine determines implied bounds of variable x[k].
 204.235 +*
 204.236 +*  It is assumed that if L != -inf, the lower bound of the row can be
 204.237 +*  active, and if U != +inf, the upper bound of the row can be active.
 204.238 +*
 204.239 +*  ALGORITHM
 204.240 +*
 204.241 +*  From (13) it follows that
 204.242 +*
 204.243 +*     L <= sum a[j] * x[j] + a[k] * x[k] <= U
 204.244 +*          j!=k
 204.245 +*  or
 204.246 +*
 204.247 +*     L - sum a[j] * x[j] <= a[k] * x[k] <= U - sum a[j] * x[j]
 204.248 +*         j!=k                                  j!=k
 204.249 +*
 204.250 +*  Thus, if the row lower bound L can be active, implied lower bound of
 204.251 +*  term a[k] * x[k] can be determined as follows:
 204.252 +*
 204.253 +*     ilb(a[k] * x[k]) = min(L - sum a[j] * x[j]) =
 204.254 +*                                j!=k
 204.255 +*                                                                   (14)
 204.256 +*                      = L - max sum a[j] * x[j]
 204.257 +*                            j!=k
 204.258 +*
 204.259 +*  where, as it follows from (6), (7), and (8)
 204.260 +*
 204.261 +*                           / f_max - a[k] * u[k], j_max = 0, a[k] > 0
 204.262 +*                           |
 204.263 +*                           | f_max - a[k] * l[k], j_max = 0, a[k] < 0
 204.264 +*     max sum a[j] * x[j] = {
 204.265 +*         j!=k              | f_max,               j_max = k
 204.266 +*                           |
 204.267 +*                           \ +inf,                j_max != 0
 204.268 +*
 204.269 +*  and if the upper bound U can be active, implied upper bound of term
 204.270 +*  a[k] * x[k] can be determined as follows:
 204.271 +*
 204.272 +*     iub(a[k] * x[k]) = max(U - sum a[j] * x[j]) =
 204.273 +*                                j!=k
 204.274 +*                                                                   (15)
 204.275 +*                      = U - min sum a[j] * x[j]
 204.276 +*                            j!=k
 204.277 +*
 204.278 +*  where, as it follows from (3), (4), and (5)
 204.279 +*
 204.280 +*                           / f_min - a[k] * l[k], j_min = 0, a[k] > 0
 204.281 +*                           |
 204.282 +*                           | f_min - a[k] * u[k], j_min = 0, a[k] < 0
 204.283 +*     min sum a[j] * x[j] = {
 204.284 +*         j!=k              | f_min,               j_min = k
 204.285 +*                           |
 204.286 +*                           \ -inf,                j_min != 0
 204.287 +*
 204.288 +*  Since
 204.289 +*
 204.290 +*     ilb(a[k] * x[k]) <= a[k] * x[k] <= iub(a[k] * x[k])
 204.291 +*
 204.292 +*  implied lower and upper bounds of x[k] are determined as follows:
 204.293 +*
 204.294 +*     l'[k] := if a[k] > 0 then ilb / a[k] else ulb / a[k]          (16)
 204.295 +*
 204.296 +*     u'[k] := if a[k] > 0 then ulb / a[k] else ilb / a[k]          (17)
 204.297 +*
 204.298 +*  The implied bounds are stored in locations ll and uu. */
 204.299 +
 204.300 +static void col_implied_bounds(const struct f_info *f, int n,
 204.301 +      const double a[], double L, double U, const double l[],
 204.302 +      const double u[], int k, double *ll, double *uu)
 204.303 +{     double ilb, iub;
 204.304 +      xassert(n >= 0);
 204.305 +      xassert(1 <= k && k <= n);
 204.306 +      /* determine implied lower bound of term a[k] * x[k] (14) */
 204.307 +      if (L == -DBL_MAX || f->f_max == +DBL_MAX)
 204.308 +         ilb = -DBL_MAX;
 204.309 +      else if (f->j_max == 0)
 204.310 +      {  if (a[k] > 0.0)
 204.311 +         {  xassert(u[k] != +DBL_MAX);
 204.312 +            ilb = L - (f->f_max - a[k] * u[k]);
 204.313 +         }
 204.314 +         else if (a[k] < 0.0)
 204.315 +         {  xassert(l[k] != -DBL_MAX);
 204.316 +            ilb = L - (f->f_max - a[k] * l[k]);
 204.317 +         }
 204.318 +         else
 204.319 +            xassert(a != a);
 204.320 +      }
 204.321 +      else if (f->j_max == k)
 204.322 +         ilb = L - f->f_max;
 204.323 +      else
 204.324 +         ilb = -DBL_MAX;
 204.325 +      /* determine implied upper bound of term a[k] * x[k] (15) */
 204.326 +      if (U == +DBL_MAX || f->f_min == -DBL_MAX)
 204.327 +         iub = +DBL_MAX;
 204.328 +      else if (f->j_min == 0)
 204.329 +      {  if (a[k] > 0.0)
 204.330 +         {  xassert(l[k] != -DBL_MAX);
 204.331 +            iub = U - (f->f_min - a[k] * l[k]);
 204.332 +         }
 204.333 +         else if (a[k] < 0.0)
 204.334 +         {  xassert(u[k] != +DBL_MAX);
 204.335 +            iub = U - (f->f_min - a[k] * u[k]);
 204.336 +         }
 204.337 +         else
 204.338 +            xassert(a != a);
 204.339 +      }
 204.340 +      else if (f->j_min == k)
 204.341 +         iub = U - f->f_min;
 204.342 +      else
 204.343 +         iub = +DBL_MAX;
 204.344 +      /* determine implied bounds of x[k] (16) and (17) */
 204.345 +#if 1
 204.346 +      /* do not use a[k] if it has small magnitude to prevent wrong
 204.347 +         implied bounds; for example, 1e-15 * x1 >= x2 + x3, where
 204.348 +         x1 >= -10, x2, x3 >= 0, would lead to wrong conclusion that
 204.349 +         x1 >= 0 */
 204.350 +      if (fabs(a[k]) < 1e-6)
 204.351 +         *ll = -DBL_MAX, *uu = +DBL_MAX; else
 204.352 +#endif
 204.353 +      if (a[k] > 0.0)
 204.354 +      {  *ll = (ilb == -DBL_MAX ? -DBL_MAX : ilb / a[k]);
 204.355 +         *uu = (iub == +DBL_MAX ? +DBL_MAX : iub / a[k]);
 204.356 +      }
 204.357 +      else if (a[k] < 0.0)
 204.358 +      {  *ll = (iub == +DBL_MAX ? -DBL_MAX : iub / a[k]);
 204.359 +         *uu = (ilb == -DBL_MAX ? +DBL_MAX : ilb / a[k]);
 204.360 +      }
 204.361 +      else
 204.362 +         xassert(a != a);
 204.363 +      return;
 204.364 +}
 204.365 +
 204.366 +/***********************************************************************
 204.367 +*  check_row_bounds - check and relax original row bounds
 204.368 +*
 204.369 +*  Given a row (constraint)
 204.370 +*
 204.371 +*           n
 204.372 +*     L <= sum a[j] * x[j] <= U
 204.373 +*          j=1
 204.374 +*
 204.375 +*  and bounds of columns (variables)
 204.376 +*
 204.377 +*     l[j] <= x[j] <= u[j]
 204.378 +*
 204.379 +*  this routine checks the original row bounds L and U for feasibility
 204.380 +*  and redundancy. If the original lower bound L or/and upper bound U
 204.381 +*  cannot be active due to bounds of variables, the routine remove them
 204.382 +*  replacing by -inf or/and +inf, respectively.
 204.383 +*
 204.384 +*  If no primal infeasibility is detected, the routine returns zero,
 204.385 +*  otherwise non-zero. */
 204.386 +
 204.387 +static int check_row_bounds(const struct f_info *f, double *L_,
 204.388 +      double *U_)
 204.389 +{     int ret = 0;
 204.390 +      double L = *L_, U = *U_, LL, UU;
 204.391 +      /* determine implied bounds of the row */
 204.392 +      row_implied_bounds(f, &LL, &UU);
 204.393 +      /* check if the original lower bound is infeasible */
 204.394 +      if (L != -DBL_MAX)
 204.395 +      {  double eps = 1e-3 * (1.0 + fabs(L));
 204.396 +         if (UU < L - eps)
 204.397 +         {  ret = 1;
 204.398 +            goto done;
 204.399 +         }
 204.400 +      }
 204.401 +      /* check if the original upper bound is infeasible */
 204.402 +      if (U != +DBL_MAX)
 204.403 +      {  double eps = 1e-3 * (1.0 + fabs(U));
 204.404 +         if (LL > U + eps)
 204.405 +         {  ret = 1;
 204.406 +            goto done;
 204.407 +         }
 204.408 +      }
 204.409 +      /* check if the original lower bound is redundant */
 204.410 +      if (L != -DBL_MAX)
 204.411 +      {  double eps = 1e-12 * (1.0 + fabs(L));
 204.412 +         if (LL > L - eps)
 204.413 +         {  /* it cannot be active, so remove it */
 204.414 +            *L_ = -DBL_MAX;
 204.415 +         }
 204.416 +      }
 204.417 +      /* check if the original upper bound is redundant */
 204.418 +      if (U != +DBL_MAX)
 204.419 +      {  double eps = 1e-12 * (1.0 + fabs(U));
 204.420 +         if (UU < U + eps)
 204.421 +         {  /* it cannot be active, so remove it */
 204.422 +            *U_ = +DBL_MAX;
 204.423 +         }
 204.424 +      }
 204.425 +done: return ret;
 204.426 +}
 204.427 +
 204.428 +/***********************************************************************
 204.429 +*  check_col_bounds - check and tighten original column bounds
 204.430 +*
 204.431 +*  Given a row (constraint)
 204.432 +*
 204.433 +*           n
 204.434 +*     L <= sum a[j] * x[j] <= U
 204.435 +*          j=1
 204.436 +*
 204.437 +*  and bounds of columns (variables)
 204.438 +*
 204.439 +*     l[j] <= x[j] <= u[j]
 204.440 +*
 204.441 +*  for column (variable) x[j] this routine checks the original column
 204.442 +*  bounds l[j] and u[j] for feasibility and redundancy. If the original
 204.443 +*  lower bound l[j] or/and upper bound u[j] cannot be active due to
 204.444 +*  bounds of the constraint and other variables, the routine tighten
 204.445 +*  them replacing by corresponding implied bounds, if possible.
 204.446 +*
 204.447 +*  NOTE: It is assumed that if L != -inf, the row lower bound can be
 204.448 +*        active, and if U != +inf, the row upper bound can be active.
 204.449 +*
 204.450 +*  The flag means that variable x[j] is required to be integer.
 204.451 +*
 204.452 +*  New actual bounds for x[j] are stored in locations lj and uj.
 204.453 +*
 204.454 +*  If no primal infeasibility is detected, the routine returns zero,
 204.455 +*  otherwise non-zero. */
 204.456 +
 204.457 +static int check_col_bounds(const struct f_info *f, int n,
 204.458 +      const double a[], double L, double U, const double l[],
 204.459 +      const double u[], int flag, int j, double *_lj, double *_uj)
 204.460 +{     int ret = 0;
 204.461 +      double lj, uj, ll, uu;
 204.462 +      xassert(n >= 0);
 204.463 +      xassert(1 <= j && j <= n);
 204.464 +      lj = l[j], uj = u[j];
 204.465 +      /* determine implied bounds of the column */
 204.466 +      col_implied_bounds(f, n, a, L, U, l, u, j, &ll, &uu);
 204.467 +      /* if x[j] is integral, round its implied bounds */
 204.468 +      if (flag)
 204.469 +      {  if (ll != -DBL_MAX)
 204.470 +            ll = (ll - floor(ll) < 1e-3 ? floor(ll) : ceil(ll));
 204.471 +         if (uu != +DBL_MAX)
 204.472 +            uu = (ceil(uu) - uu < 1e-3 ? ceil(uu) : floor(uu));
 204.473 +      }
 204.474 +      /* check if the original lower bound is infeasible */
 204.475 +      if (lj != -DBL_MAX)
 204.476 +      {  double eps = 1e-3 * (1.0 + fabs(lj));
 204.477 +         if (uu < lj - eps)
 204.478 +         {  ret = 1;
 204.479 +            goto done;
 204.480 +         }
 204.481 +      }
 204.482 +      /* check if the original upper bound is infeasible */
 204.483 +      if (uj != +DBL_MAX)
 204.484 +      {  double eps = 1e-3 * (1.0 + fabs(uj));
 204.485 +         if (ll > uj + eps)
 204.486 +         {  ret = 1;
 204.487 +            goto done;
 204.488 +         }
 204.489 +      }
 204.490 +      /* check if the original lower bound is redundant */
 204.491 +      if (ll != -DBL_MAX)
 204.492 +      {  double eps = 1e-3 * (1.0 + fabs(ll));
 204.493 +         if (lj < ll - eps)
 204.494 +         {  /* it cannot be active, so tighten it */
 204.495 +            lj = ll;
 204.496 +         }
 204.497 +      }
 204.498 +      /* check if the original upper bound is redundant */
 204.499 +      if (uu != +DBL_MAX)
 204.500 +      {  double eps = 1e-3 * (1.0 + fabs(uu));
 204.501 +         if (uj > uu + eps)
 204.502 +         {  /* it cannot be active, so tighten it */
 204.503 +            uj = uu;
 204.504 +         }
 204.505 +      }
 204.506 +      /* due to round-off errors it may happen that lj > uj (although
 204.507 +         lj < uj + eps, since no primal infeasibility is detected), so
 204.508 +         adjuct the new actual bounds to provide lj <= uj */
 204.509 +      if (!(lj == -DBL_MAX || uj == +DBL_MAX))
 204.510 +      {  double t1 = fabs(lj), t2 = fabs(uj);
 204.511 +         double eps = 1e-10 * (1.0 + (t1 <= t2 ? t1 : t2));
 204.512 +         if (lj > uj - eps)
 204.513 +         {  if (lj == l[j])
 204.514 +               uj = lj;
 204.515 +            else if (uj == u[j])
 204.516 +               lj = uj;
 204.517 +            else if (t1 <= t2)
 204.518 +               uj = lj;
 204.519 +            else
 204.520 +               lj = uj;
 204.521 +         }
 204.522 +      }
 204.523 +      *_lj = lj, *_uj = uj;
 204.524 +done: return ret;
 204.525 +}
 204.526 +
 204.527 +/***********************************************************************
 204.528 +*  check_efficiency - check if change in column bounds is efficient
 204.529 +*
 204.530 +*  Given the original bounds of a column l and u and its new actual
 204.531 +*  bounds l' and u' (possibly tighten by the routine check_col_bounds)
 204.532 +*  this routine checks if the change in the column bounds is efficient
 204.533 +*  enough. If so, the routine returns non-zero, otherwise zero.
 204.534 +*
 204.535 +*  The flag means that the variable is required to be integer. */
 204.536 +
 204.537 +static int check_efficiency(int flag, double l, double u, double ll,
 204.538 +      double uu)
 204.539 +{     int eff = 0;
 204.540 +      /* check efficiency for lower bound */
 204.541 +      if (l < ll)
 204.542 +      {  if (flag || l == -DBL_MAX)
 204.543 +            eff++;
 204.544 +         else
 204.545 +         {  double r;
 204.546 +            if (u == +DBL_MAX)
 204.547 +               r = 1.0 + fabs(l);
 204.548 +            else
 204.549 +               r = 1.0 + (u - l);
 204.550 +            if (ll - l >= 0.25 * r)
 204.551 +               eff++;
 204.552 +         }
 204.553 +      }
 204.554 +      /* check efficiency for upper bound */
 204.555 +      if (u > uu)
 204.556 +      {  if (flag || u == +DBL_MAX)
 204.557 +            eff++;
 204.558 +         else
 204.559 +         {  double r;
 204.560 +            if (l == -DBL_MAX)
 204.561 +               r = 1.0 + fabs(u);
 204.562 +            else
 204.563 +               r = 1.0 + (u - l);
 204.564 +            if (u - uu >= 0.25 * r)
 204.565 +               eff++;
 204.566 +         }
 204.567 +      }
 204.568 +      return eff;
 204.569 +}
 204.570 +
 204.571 +/***********************************************************************
 204.572 +*  basic_preprocessing - perform basic preprocessing
 204.573 +*
 204.574 +*  This routine performs basic preprocessing of the specified MIP that
 204.575 +*  includes relaxing some row bounds and tightening some column bounds.
 204.576 +*
 204.577 +*  On entry the arrays L and U contains original row bounds, and the
 204.578 +*  arrays l and u contains original column bounds:
 204.579 +*
 204.580 +*  L[0] is the lower bound of the objective row;
 204.581 +*  L[i], i = 1,...,m, is the lower bound of i-th row;
 204.582 +*  U[0] is the upper bound of the objective row;
 204.583 +*  U[i], i = 1,...,m, is the upper bound of i-th row;
 204.584 +*  l[0] is not used;
 204.585 +*  l[j], j = 1,...,n, is the lower bound of j-th column;
 204.586 +*  u[0] is not used;
 204.587 +*  u[j], j = 1,...,n, is the upper bound of j-th column.
 204.588 +*
 204.589 +*  On exit the arrays L, U, l, and u contain new actual bounds of rows
 204.590 +*  and column in the same locations.
 204.591 +*
 204.592 +*  The parameters nrs and num specify an initial list of rows to be
 204.593 +*  processed:
 204.594 +*
 204.595 +*  nrs is the number of rows in the initial list, 0 <= nrs <= m+1;
 204.596 +*  num[0] is not used;
 204.597 +*  num[1,...,nrs] are row numbers (0 means the objective row).
 204.598 +*
 204.599 +*  The parameter max_pass specifies the maximal number of times that
 204.600 +*  each row can be processed, max_pass > 0.
 204.601 +*
 204.602 +*  If no primal infeasibility is detected, the routine returns zero,
 204.603 +*  otherwise non-zero. */
 204.604 +
 204.605 +static int basic_preprocessing(glp_prob *mip, double L[], double U[],
 204.606 +      double l[], double u[], int nrs, const int num[], int max_pass)
 204.607 +{     int m = mip->m;
 204.608 +      int n = mip->n;
 204.609 +      struct f_info f;
 204.610 +      int i, j, k, len, size, ret = 0;
 204.611 +      int *ind, *list, *mark, *pass;
 204.612 +      double *val, *lb, *ub;
 204.613 +      xassert(0 <= nrs && nrs <= m+1);
 204.614 +      xassert(max_pass > 0);
 204.615 +      /* allocate working arrays */
 204.616 +      ind = xcalloc(1+n, sizeof(int));
 204.617 +      list = xcalloc(1+m+1, sizeof(int));
 204.618 +      mark = xcalloc(1+m+1, sizeof(int));
 204.619 +      memset(&mark[0], 0, (m+1) * sizeof(int));
 204.620 +      pass = xcalloc(1+m+1, sizeof(int));
 204.621 +      memset(&pass[0], 0, (m+1) * sizeof(int));
 204.622 +      val = xcalloc(1+n, sizeof(double));
 204.623 +      lb = xcalloc(1+n, sizeof(double));
 204.624 +      ub = xcalloc(1+n, sizeof(double));
 204.625 +      /* initialize the list of rows to be processed */
 204.626 +      size = 0;
 204.627 +      for (k = 1; k <= nrs; k++)
 204.628 +      {  i = num[k];
 204.629 +         xassert(0 <= i && i <= m);
 204.630 +         /* duplicate row numbers are not allowed */
 204.631 +         xassert(!mark[i]);
 204.632 +         list[++size] = i, mark[i] = 1;
 204.633 +      }
 204.634 +      xassert(size == nrs);
 204.635 +      /* process rows in the list until it becomes empty */
 204.636 +      while (size > 0)
 204.637 +      {  /* get a next row from the list */
 204.638 +         i = list[size--], mark[i] = 0;
 204.639 +         /* increase the row processing count */
 204.640 +         pass[i]++;
 204.641 +         /* if the row is free, skip it */
 204.642 +         if (L[i] == -DBL_MAX && U[i] == +DBL_MAX) continue;
 204.643 +         /* obtain coefficients of the row */
 204.644 +         len = 0;
 204.645 +         if (i == 0)
 204.646 +         {  for (j = 1; j <= n; j++)
 204.647 +            {  GLPCOL *col = mip->col[j];
 204.648 +               if (col->coef != 0.0)
 204.649 +                  len++, ind[len] = j, val[len] = col->coef;
 204.650 +            }
 204.651 +         }
 204.652 +         else
 204.653 +         {  GLPROW *row = mip->row[i];
 204.654 +            GLPAIJ *aij;
 204.655 +            for (aij = row->ptr; aij != NULL; aij = aij->r_next)
 204.656 +               len++, ind[len] = aij->col->j, val[len] = aij->val;
 204.657 +         }
 204.658 +         /* determine lower and upper bounds of columns corresponding
 204.659 +            to non-zero row coefficients */
 204.660 +         for (k = 1; k <= len; k++)
 204.661 +            j = ind[k], lb[k] = l[j], ub[k] = u[j];
 204.662 +         /* prepare the row info to determine implied bounds */
 204.663 +         prepare_row_info(len, val, lb, ub, &f);
 204.664 +         /* check and relax bounds of the row */
 204.665 +         if (check_row_bounds(&f, &L[i], &U[i]))
 204.666 +         {  /* the feasible region is empty */
 204.667 +            ret = 1;
 204.668 +            goto done;
 204.669 +         }
 204.670 +         /* if the row became free, drop it */
 204.671 +         if (L[i] == -DBL_MAX && U[i] == +DBL_MAX) continue;
 204.672 +         /* process columns having non-zero coefficients in the row */
 204.673 +         for (k = 1; k <= len; k++)
 204.674 +         {  GLPCOL *col;
 204.675 +            int flag, eff;
 204.676 +            double ll, uu;
 204.677 +            /* take a next column in the row */
 204.678 +            j = ind[k], col = mip->col[j];
 204.679 +            flag = col->kind != GLP_CV;
 204.680 +            /* check and tighten bounds of the column */
 204.681 +            if (check_col_bounds(&f, len, val, L[i], U[i], lb, ub,
 204.682 +                flag, k, &ll, &uu))
 204.683 +            {  /* the feasible region is empty */
 204.684 +               ret = 1;
 204.685 +               goto done;
 204.686 +            }
 204.687 +            /* check if change in the column bounds is efficient */
 204.688 +            eff = check_efficiency(flag, l[j], u[j], ll, uu);
 204.689 +            /* set new actual bounds of the column */
 204.690 +            l[j] = ll, u[j] = uu;
 204.691 +            /* if the change is efficient, add all rows affected by the
 204.692 +               corresponding column, to the list */
 204.693 +            if (eff > 0)
 204.694 +            {  GLPAIJ *aij;
 204.695 +               for (aij = col->ptr; aij != NULL; aij = aij->c_next)
 204.696 +               {  int ii = aij->row->i;
 204.697 +                  /* if the row was processed maximal number of times,
 204.698 +                     skip it */
 204.699 +                  if (pass[ii] >= max_pass) continue;
 204.700 +                  /* if the row is free, skip it */
 204.701 +                  if (L[ii] == -DBL_MAX && U[ii] == +DBL_MAX) continue;
 204.702 +                  /* put the row into the list */
 204.703 +                  if (mark[ii] == 0)
 204.704 +                  {  xassert(size <= m);
 204.705 +                     list[++size] = ii, mark[ii] = 1;
 204.706 +                  }
 204.707 +               }
 204.708 +            }
 204.709 +         }
 204.710 +      }
 204.711 +done: /* free working arrays */
 204.712 +      xfree(ind);
 204.713 +      xfree(list);
 204.714 +      xfree(mark);
 204.715 +      xfree(pass);
 204.716 +      xfree(val);
 204.717 +      xfree(lb);
 204.718 +      xfree(ub);
 204.719 +      return ret;
 204.720 +}
 204.721 +
 204.722 +/***********************************************************************
 204.723 +*  NAME
 204.724 +*
 204.725 +*  ios_preprocess_node - preprocess current subproblem
 204.726 +*
 204.727 +*  SYNOPSIS
 204.728 +*
 204.729 +*  #include "glpios.h"
 204.730 +*  int ios_preprocess_node(glp_tree *tree, int max_pass);
 204.731 +*
 204.732 +*  DESCRIPTION
 204.733 +*
 204.734 +*  The routine ios_preprocess_node performs basic preprocessing of the
 204.735 +*  current subproblem.
 204.736 +*
 204.737 +*  RETURNS
 204.738 +*
 204.739 +*  If no primal infeasibility is detected, the routine returns zero,
 204.740 +*  otherwise non-zero. */
 204.741 +
 204.742 +int ios_preprocess_node(glp_tree *tree, int max_pass)
 204.743 +{     glp_prob *mip = tree->mip;
 204.744 +      int m = mip->m;
 204.745 +      int n = mip->n;
 204.746 +      int i, j, nrs, *num, ret = 0;
 204.747 +      double *L, *U, *l, *u;
 204.748 +      /* the current subproblem must exist */
 204.749 +      xassert(tree->curr != NULL);
 204.750 +      /* determine original row bounds */
 204.751 +      L = xcalloc(1+m, sizeof(double));
 204.752 +      U = xcalloc(1+m, sizeof(double));
 204.753 +      switch (mip->mip_stat)
 204.754 +      {  case GLP_UNDEF:
 204.755 +            L[0] = -DBL_MAX, U[0] = +DBL_MAX;
 204.756 +            break;
 204.757 +         case GLP_FEAS:
 204.758 +            switch (mip->dir)
 204.759 +            {  case GLP_MIN:
 204.760 +                  L[0] = -DBL_MAX, U[0] = mip->mip_obj - mip->c0;
 204.761 +                  break;
 204.762 +               case GLP_MAX:
 204.763 +                  L[0] = mip->mip_obj - mip->c0, U[0] = +DBL_MAX;
 204.764 +                  break;
 204.765 +               default:
 204.766 +                  xassert(mip != mip);
 204.767 +            }
 204.768 +            break;
 204.769 +         default:
 204.770 +            xassert(mip != mip);
 204.771 +      }
 204.772 +      for (i = 1; i <= m; i++)
 204.773 +      {  L[i] = glp_get_row_lb(mip, i);
 204.774 +         U[i] = glp_get_row_ub(mip, i);
 204.775 +      }
 204.776 +      /* determine original column bounds */
 204.777 +      l = xcalloc(1+n, sizeof(double));
 204.778 +      u = xcalloc(1+n, sizeof(double));
 204.779 +      for (j = 1; j <= n; j++)
 204.780 +      {  l[j] = glp_get_col_lb(mip, j);
 204.781 +         u[j] = glp_get_col_ub(mip, j);
 204.782 +      }
 204.783 +      /* build the initial list of rows to be analyzed */
 204.784 +      nrs = m + 1;
 204.785 +      num = xcalloc(1+nrs, sizeof(int));
 204.786 +      for (i = 1; i <= nrs; i++) num[i] = i - 1;
 204.787 +      /* perform basic preprocessing */
 204.788 +      if (basic_preprocessing(mip , L, U, l, u, nrs, num, max_pass))
 204.789 +      {  ret = 1;
 204.790 +         goto done;
 204.791 +      }
 204.792 +      /* set new actual (relaxed) row bounds */
 204.793 +      for (i = 1; i <= m; i++)
 204.794 +      {  /* consider only non-active rows to keep dual feasibility */
 204.795 +         if (glp_get_row_stat(mip, i) == GLP_BS)
 204.796 +         {  if (L[i] == -DBL_MAX && U[i] == +DBL_MAX)
 204.797 +               glp_set_row_bnds(mip, i, GLP_FR, 0.0, 0.0);
 204.798 +            else if (U[i] == +DBL_MAX)
 204.799 +               glp_set_row_bnds(mip, i, GLP_LO, L[i], 0.0);
 204.800 +            else if (L[i] == -DBL_MAX)
 204.801 +               glp_set_row_bnds(mip, i, GLP_UP, 0.0, U[i]);
 204.802 +         }
 204.803 +      }
 204.804 +      /* set new actual (tightened) column bounds */
 204.805 +      for (j = 1; j <= n; j++)
 204.806 +      {  int type;
 204.807 +         if (l[j] == -DBL_MAX && u[j] == +DBL_MAX)
 204.808 +            type = GLP_FR;
 204.809 +         else if (u[j] == +DBL_MAX)
 204.810 +            type = GLP_LO;
 204.811 +         else if (l[j] == -DBL_MAX)
 204.812 +            type = GLP_UP;
 204.813 +         else if (l[j] != u[j])
 204.814 +            type = GLP_DB;
 204.815 +         else
 204.816 +            type = GLP_FX;
 204.817 +         glp_set_col_bnds(mip, j, type, l[j], u[j]);
 204.818 +      }
 204.819 +done: /* free working arrays and return */
 204.820 +      xfree(L);
 204.821 +      xfree(U);
 204.822 +      xfree(l);
 204.823 +      xfree(u);
 204.824 +      xfree(num);
 204.825 +      return ret;
 204.826 +}
 204.827 +
 204.828 +/* eof */
   205.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   205.2 +++ b/src/glpios03.c	Mon Dec 06 13:09:21 2010 +0100
   205.3 @@ -0,0 +1,1155 @@
   205.4 +/* glpios03.c (branch-and-cut driver) */
   205.5 +
   205.6 +/***********************************************************************
   205.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   205.8 +*
   205.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  205.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  205.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  205.12 +*  E-mail: <mao@gnu.org>.
  205.13 +*
  205.14 +*  GLPK is free software: you can redistribute it and/or modify it
  205.15 +*  under the terms of the GNU General Public License as published by
  205.16 +*  the Free Software Foundation, either version 3 of the License, or
  205.17 +*  (at your option) any later version.
  205.18 +*
  205.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  205.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  205.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  205.22 +*  License for more details.
  205.23 +*
  205.24 +*  You should have received a copy of the GNU General Public License
  205.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  205.26 +***********************************************************************/
  205.27 +
  205.28 +#include "glpios.h"
  205.29 +
  205.30 +/***********************************************************************
  205.31 +*  show_progress - display current progress of the search
  205.32 +*
  205.33 +*  This routine displays some information about current progress of the
  205.34 +*  search.
  205.35 +*
  205.36 +*  The information includes:
  205.37 +*
  205.38 +*  the current number of iterations performed by the simplex solver;
  205.39 +*
  205.40 +*  the objective value for the best known integer feasible solution,
  205.41 +*  which is upper (minimization) or lower (maximization) global bound
  205.42 +*  for optimal solution of the original mip problem;
  205.43 +*
  205.44 +*  the best local bound for active nodes, which is lower (minimization)
  205.45 +*  or upper (maximization) global bound for optimal solution of the
  205.46 +*  original mip problem;
  205.47 +*
  205.48 +*  the relative mip gap, in percents;
  205.49 +*
  205.50 +*  the number of open (active) subproblems;
  205.51 +*
  205.52 +*  the number of completely explored subproblems, i.e. whose nodes have
  205.53 +*  been removed from the tree. */
  205.54 +
  205.55 +static void show_progress(glp_tree *T, int bingo)
  205.56 +{     int p;
  205.57 +      double temp;
  205.58 +      char best_mip[50], best_bound[50], *rho, rel_gap[50];
  205.59 +      /* format the best known integer feasible solution */
  205.60 +      if (T->mip->mip_stat == GLP_FEAS)
  205.61 +         sprintf(best_mip, "%17.9e", T->mip->mip_obj);
  205.62 +      else
  205.63 +         sprintf(best_mip, "%17s", "not found yet");
  205.64 +      /* determine reference number of an active subproblem whose local
  205.65 +         bound is best */
  205.66 +      p = ios_best_node(T);
  205.67 +      /* format the best bound */
  205.68 +      if (p == 0)
  205.69 +         sprintf(best_bound, "%17s", "tree is empty");
  205.70 +      else
  205.71 +      {  temp = T->slot[p].node->bound;
  205.72 +         if (temp == -DBL_MAX)
  205.73 +            sprintf(best_bound, "%17s", "-inf");
  205.74 +         else if (temp == +DBL_MAX)
  205.75 +            sprintf(best_bound, "%17s", "+inf");
  205.76 +         else
  205.77 +            sprintf(best_bound, "%17.9e", temp);
  205.78 +      }
  205.79 +      /* choose the relation sign between global bounds */
  205.80 +      if (T->mip->dir == GLP_MIN)
  205.81 +         rho = ">=";
  205.82 +      else if (T->mip->dir == GLP_MAX)
  205.83 +         rho = "<=";
  205.84 +      else
  205.85 +         xassert(T != T);
  205.86 +      /* format the relative mip gap */
  205.87 +      temp = ios_relative_gap(T);
  205.88 +      if (temp == 0.0)
  205.89 +         sprintf(rel_gap, "  0.0%%");
  205.90 +      else if (temp < 0.001)
  205.91 +         sprintf(rel_gap, "< 0.1%%");
  205.92 +      else if (temp <= 9.999)
  205.93 +         sprintf(rel_gap, "%5.1f%%", 100.0 * temp);
  205.94 +      else
  205.95 +         sprintf(rel_gap, "%6s", "");
  205.96 +      /* display progress of the search */
  205.97 +      xprintf("+%6d: %s %s %s %s %s (%d; %d)\n",
  205.98 +         T->mip->it_cnt, bingo ? ">>>>>" : "mip =", best_mip, rho,
  205.99 +         best_bound, rel_gap, T->a_cnt, T->t_cnt - T->n_cnt);
 205.100 +      T->tm_lag = xtime();
 205.101 +      return;
 205.102 +}
 205.103 +
 205.104 +/***********************************************************************
 205.105 +*  is_branch_hopeful - check if specified branch is hopeful
 205.106 +*
 205.107 +*  This routine checks if the specified subproblem can have an integer
 205.108 +*  optimal solution which is better than the best known one.
 205.109 +*
 205.110 +*  The check is based on comparison of the local objective bound stored
 205.111 +*  in the subproblem descriptor and the incumbent objective value which
 205.112 +*  is the global objective bound.
 205.113 +*
 205.114 +*  If there is a chance that the specified subproblem can have a better
 205.115 +*  integer optimal solution, the routine returns non-zero. Otherwise, if
 205.116 +*  the corresponding branch can pruned, zero is returned. */
 205.117 +
 205.118 +static int is_branch_hopeful(glp_tree *T, int p)
 205.119 +{     xassert(1 <= p && p <= T->nslots);
 205.120 +      xassert(T->slot[p].node != NULL);
 205.121 +      return ios_is_hopeful(T, T->slot[p].node->bound);
 205.122 +}
 205.123 +
 205.124 +/***********************************************************************
 205.125 +*  check_integrality - check integrality of basic solution
 205.126 +*
 205.127 +*  This routine checks if the basic solution of LP relaxation of the
 205.128 +*  current subproblem satisfies to integrality conditions, i.e. that all
 205.129 +*  variables of integer kind have integral primal values. (The solution
 205.130 +*  is assumed to be optimal.)
 205.131 +*
 205.132 +*  For each variable of integer kind the routine computes the following
 205.133 +*  quantity:
 205.134 +*
 205.135 +*     ii(x[j]) = min(x[j] - floor(x[j]), ceil(x[j]) - x[j]),         (1)
 205.136 +*
 205.137 +*  which is a measure of the integer infeasibility (non-integrality) of
 205.138 +*  x[j] (for example, ii(2.1) = 0.1, ii(3.7) = 0.3, ii(5.0) = 0). It is
 205.139 +*  understood that 0 <= ii(x[j]) <= 0.5, and variable x[j] is integer
 205.140 +*  feasible if ii(x[j]) = 0. However, due to floating-point arithmetic
 205.141 +*  the routine checks less restrictive condition:
 205.142 +*
 205.143 +*     ii(x[j]) <= tol_int,                                           (2)
 205.144 +*
 205.145 +*  where tol_int is a given tolerance (small positive number) and marks
 205.146 +*  each variable which does not satisfy to (2) as integer infeasible by
 205.147 +*  setting its fractionality flag.
 205.148 +*
 205.149 +*  In order to characterize integer infeasibility of the basic solution
 205.150 +*  in the whole the routine computes two parameters: ii_cnt, which is
 205.151 +*  the number of variables with the fractionality flag set, and ii_sum,
 205.152 +*  which is the sum of integer infeasibilities (1). */
 205.153 +
 205.154 +static void check_integrality(glp_tree *T)
 205.155 +{     glp_prob *mip = T->mip;
 205.156 +      int j, type, ii_cnt = 0;
 205.157 +      double lb, ub, x, temp1, temp2, ii_sum = 0.0;
 205.158 +      /* walk through the set of columns (structural variables) */
 205.159 +      for (j = 1; j <= mip->n; j++)
 205.160 +      {  GLPCOL *col = mip->col[j];
 205.161 +         T->non_int[j] = 0;
 205.162 +         /* if the column is not integer, skip it */
 205.163 +         if (col->kind != GLP_IV) continue;
 205.164 +         /* if the column is non-basic, it is integer feasible */
 205.165 +         if (col->stat != GLP_BS) continue;
 205.166 +         /* obtain the type and bounds of the column */
 205.167 +         type = col->type, lb = col->lb, ub = col->ub;
 205.168 +         /* obtain value of the column in optimal basic solution */
 205.169 +         x = col->prim;
 205.170 +         /* if the column's primal value is close to the lower bound,
 205.171 +            the column is integer feasible within given tolerance */
 205.172 +         if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
 205.173 +         {  temp1 = lb - T->parm->tol_int;
 205.174 +            temp2 = lb + T->parm->tol_int;
 205.175 +            if (temp1 <= x && x <= temp2) continue;
 205.176 +#if 0
 205.177 +            /* the lower bound must not be violated */
 205.178 +            xassert(x >= lb);
 205.179 +#else
 205.180 +            if (x < lb) continue;
 205.181 +#endif
 205.182 +         }
 205.183 +         /* if the column's primal value is close to the upper bound,
 205.184 +            the column is integer feasible within given tolerance */
 205.185 +         if (type == GLP_UP || type == GLP_DB || type == GLP_FX)
 205.186 +         {  temp1 = ub - T->parm->tol_int;
 205.187 +            temp2 = ub + T->parm->tol_int;
 205.188 +            if (temp1 <= x && x <= temp2) continue;
 205.189 +#if 0
 205.190 +            /* the upper bound must not be violated */
 205.191 +            xassert(x <= ub);
 205.192 +#else
 205.193 +            if (x > ub) continue;
 205.194 +#endif
 205.195 +         }
 205.196 +         /* if the column's primal value is close to nearest integer,
 205.197 +            the column is integer feasible within given tolerance */
 205.198 +         temp1 = floor(x + 0.5) - T->parm->tol_int;
 205.199 +         temp2 = floor(x + 0.5) + T->parm->tol_int;
 205.200 +         if (temp1 <= x && x <= temp2) continue;
 205.201 +         /* otherwise the column is integer infeasible */
 205.202 +         T->non_int[j] = 1;
 205.203 +         /* increase the number of fractional-valued columns */
 205.204 +         ii_cnt++;
 205.205 +         /* compute the sum of integer infeasibilities */
 205.206 +         temp1 = x - floor(x);
 205.207 +         temp2 = ceil(x) - x;
 205.208 +         xassert(temp1 > 0.0 && temp2 > 0.0);
 205.209 +         ii_sum += (temp1 <= temp2 ? temp1 : temp2);
 205.210 +      }
 205.211 +      /* store ii_cnt and ii_sum to the current problem descriptor */
 205.212 +      xassert(T->curr != NULL);
 205.213 +      T->curr->ii_cnt = ii_cnt;
 205.214 +      T->curr->ii_sum = ii_sum;
 205.215 +      /* and also display these parameters */
 205.216 +      if (T->parm->msg_lev >= GLP_MSG_DBG)
 205.217 +      {  if (ii_cnt == 0)
 205.218 +            xprintf("There are no fractional columns\n");
 205.219 +         else if (ii_cnt == 1)
 205.220 +            xprintf("There is one fractional column, integer infeasibil"
 205.221 +               "ity is %.3e\n", ii_sum);
 205.222 +         else
 205.223 +            xprintf("There are %d fractional columns, integer infeasibi"
 205.224 +               "lity is %.3e\n", ii_cnt, ii_sum);
 205.225 +      }
 205.226 +      return;
 205.227 +}
 205.228 +
 205.229 +/***********************************************************************
 205.230 +*  record_solution - record better integer feasible solution
 205.231 +*
 205.232 +*  This routine records optimal basic solution of LP relaxation of the
 205.233 +*  current subproblem, which being integer feasible is better than the
 205.234 +*  best known integer feasible solution. */
 205.235 +
 205.236 +static void record_solution(glp_tree *T)
 205.237 +{     glp_prob *mip = T->mip;
 205.238 +      int i, j;
 205.239 +      mip->mip_stat = GLP_FEAS;
 205.240 +      mip->mip_obj = mip->obj_val;
 205.241 +      for (i = 1; i <= mip->m; i++)
 205.242 +      {  GLPROW *row = mip->row[i];
 205.243 +         row->mipx = row->prim;
 205.244 +      }
 205.245 +      for (j = 1; j <= mip->n; j++)
 205.246 +      {  GLPCOL *col = mip->col[j];
 205.247 +         if (col->kind == GLP_CV)
 205.248 +            col->mipx = col->prim;
 205.249 +         else if (col->kind == GLP_IV)
 205.250 +         {  /* value of the integer column must be integral */
 205.251 +            col->mipx = floor(col->prim + 0.5);
 205.252 +         }
 205.253 +         else
 205.254 +            xassert(col != col);
 205.255 +      }
 205.256 +      T->sol_cnt++;
 205.257 +      return;
 205.258 +}
 205.259 +
 205.260 +/***********************************************************************
 205.261 +*  fix_by_red_cost - fix non-basic integer columns by reduced costs
 205.262 +*
 205.263 +*  This routine fixes some non-basic integer columns if their reduced
 205.264 +*  costs indicate that increasing (decreasing) the column at least by
 205.265 +*  one involves the objective value becoming worse than the incumbent
 205.266 +*  objective value. */
 205.267 +
 205.268 +static void fix_by_red_cost(glp_tree *T)
 205.269 +{     glp_prob *mip = T->mip;
 205.270 +      int j, stat, fixed = 0;
 205.271 +      double obj, lb, ub, dj;
 205.272 +      /* the global bound must exist */
 205.273 +      xassert(T->mip->mip_stat == GLP_FEAS);
 205.274 +      /* basic solution of LP relaxation must be optimal */
 205.275 +      xassert(mip->pbs_stat == GLP_FEAS && mip->dbs_stat == GLP_FEAS);
 205.276 +      /* determine the objective function value */
 205.277 +      obj = mip->obj_val;
 205.278 +      /* walk through the column list */
 205.279 +      for (j = 1; j <= mip->n; j++)
 205.280 +      {  GLPCOL *col = mip->col[j];
 205.281 +         /* if the column is not integer, skip it */
 205.282 +         if (col->kind != GLP_IV) continue;
 205.283 +         /* obtain bounds of j-th column */
 205.284 +         lb = col->lb, ub = col->ub;
 205.285 +         /* and determine its status and reduced cost */
 205.286 +         stat = col->stat, dj = col->dual;
 205.287 +         /* analyze the reduced cost */
 205.288 +         switch (mip->dir)
 205.289 +         {  case GLP_MIN:
 205.290 +               /* minimization */
 205.291 +               if (stat == GLP_NL)
 205.292 +               {  /* j-th column is non-basic on its lower bound */
 205.293 +                  if (dj < 0.0) dj = 0.0;
 205.294 +                  if (obj + dj >= mip->mip_obj)
 205.295 +                     glp_set_col_bnds(mip, j, GLP_FX, lb, lb), fixed++;
 205.296 +               }
 205.297 +               else if (stat == GLP_NU)
 205.298 +               {  /* j-th column is non-basic on its upper bound */
 205.299 +                  if (dj > 0.0) dj = 0.0;
 205.300 +                  if (obj - dj >= mip->mip_obj)
 205.301 +                     glp_set_col_bnds(mip, j, GLP_FX, ub, ub), fixed++;
 205.302 +               }
 205.303 +               break;
 205.304 +            case GLP_MAX:
 205.305 +               /* maximization */
 205.306 +               if (stat == GLP_NL)
 205.307 +               {  /* j-th column is non-basic on its lower bound */
 205.308 +                  if (dj > 0.0) dj = 0.0;
 205.309 +                  if (obj + dj <= mip->mip_obj)
 205.310 +                     glp_set_col_bnds(mip, j, GLP_FX, lb, lb), fixed++;
 205.311 +               }
 205.312 +               else if (stat == GLP_NU)
 205.313 +               {  /* j-th column is non-basic on its upper bound */
 205.314 +                  if (dj < 0.0) dj = 0.0;
 205.315 +                  if (obj - dj <= mip->mip_obj)
 205.316 +                     glp_set_col_bnds(mip, j, GLP_FX, ub, ub), fixed++;
 205.317 +               }
 205.318 +               break;
 205.319 +            default:
 205.320 +               xassert(T != T);
 205.321 +         }
 205.322 +      }
 205.323 +      if (T->parm->msg_lev >= GLP_MSG_DBG)
 205.324 +      {  if (fixed == 0)
 205.325 +            /* nothing to say */;
 205.326 +         else if (fixed == 1)
 205.327 +            xprintf("One column has been fixed by reduced cost\n");
 205.328 +         else
 205.329 +            xprintf("%d columns have been fixed by reduced costs\n",
 205.330 +               fixed);
 205.331 +      }
 205.332 +      /* fixing non-basic columns on their current bounds does not
 205.333 +         change the basic solution */
 205.334 +      xassert(mip->pbs_stat == GLP_FEAS && mip->dbs_stat == GLP_FEAS);
 205.335 +      return;
 205.336 +}
 205.337 +
 205.338 +/***********************************************************************
 205.339 +*  branch_on - perform branching on specified variable
 205.340 +*
 205.341 +*  This routine performs branching on j-th column (structural variable)
 205.342 +*  of the current subproblem. The specified column must be of integer
 205.343 +*  kind and must have a fractional value in optimal basic solution of
 205.344 +*  LP relaxation of the current subproblem (i.e. only columns for which
 205.345 +*  the flag non_int[j] is set are valid candidates to branch on).
 205.346 +*
 205.347 +*  Let x be j-th structural variable, and beta be its primal fractional
 205.348 +*  value in the current basic solution. Branching on j-th variable is
 205.349 +*  dividing the current subproblem into two new subproblems, which are
 205.350 +*  identical to the current subproblem with the following exception: in
 205.351 +*  the first subproblem that begins the down-branch x has a new upper
 205.352 +*  bound x <= floor(beta), and in the second subproblem that begins the
 205.353 +*  up-branch x has a new lower bound x >= ceil(beta).
 205.354 +*
 205.355 +*  Depending on estimation of local bounds for down- and up-branches
 205.356 +*  this routine returns the following:
 205.357 +*
 205.358 +*  0 - both branches have been created;
 205.359 +*  1 - one branch is hopeless and has been pruned, so now the current
 205.360 +*      subproblem is other branch;
 205.361 +*  2 - both branches are hopeless and have been pruned; new subproblem
 205.362 +*      selection is needed to continue the search. */
 205.363 +
 205.364 +static int branch_on(glp_tree *T, int j, int next)
 205.365 +{     glp_prob *mip = T->mip;
 205.366 +      IOSNPD *node;
 205.367 +      int m = mip->m;
 205.368 +      int n = mip->n;
 205.369 +      int type, dn_type, up_type, dn_bad, up_bad, p, ret, clone[1+2];
 205.370 +      double lb, ub, beta, new_ub, new_lb, dn_lp, up_lp, dn_bnd, up_bnd;
 205.371 +      /* determine bounds and value of x[j] in optimal solution to LP
 205.372 +         relaxation of the current subproblem */
 205.373 +      xassert(1 <= j && j <= n);
 205.374 +      type = mip->col[j]->type;
 205.375 +      lb = mip->col[j]->lb;
 205.376 +      ub = mip->col[j]->ub;
 205.377 +      beta = mip->col[j]->prim;
 205.378 +      /* determine new bounds of x[j] for down- and up-branches */
 205.379 +      new_ub = floor(beta);
 205.380 +      new_lb = ceil(beta);
 205.381 +      switch (type)
 205.382 +      {  case GLP_FR:
 205.383 +            dn_type = GLP_UP;
 205.384 +            up_type = GLP_LO;
 205.385 +            break;
 205.386 +         case GLP_LO:
 205.387 +            xassert(lb <= new_ub);
 205.388 +            dn_type = (lb == new_ub ? GLP_FX : GLP_DB);
 205.389 +            xassert(lb + 1.0 <= new_lb);
 205.390 +            up_type = GLP_LO;
 205.391 +            break;
 205.392 +         case GLP_UP:
 205.393 +            xassert(new_ub <= ub - 1.0);
 205.394 +            dn_type = GLP_UP;
 205.395 +            xassert(new_lb <= ub);
 205.396 +            up_type = (new_lb == ub ? GLP_FX : GLP_DB);
 205.397 +            break;
 205.398 +         case GLP_DB:
 205.399 +            xassert(lb <= new_ub && new_ub <= ub - 1.0);
 205.400 +            dn_type = (lb == new_ub ? GLP_FX : GLP_DB);
 205.401 +            xassert(lb + 1.0 <= new_lb && new_lb <= ub);
 205.402 +            up_type = (new_lb == ub ? GLP_FX : GLP_DB);
 205.403 +            break;
 205.404 +         default:
 205.405 +            xassert(type != type);
 205.406 +      }
 205.407 +      /* compute local bounds to LP relaxation for both branches */
 205.408 +      ios_eval_degrad(T, j, &dn_lp, &up_lp);
 205.409 +      /* and improve them by rounding */
 205.410 +      dn_bnd = ios_round_bound(T, dn_lp);
 205.411 +      up_bnd = ios_round_bound(T, up_lp);
 205.412 +      /* check local bounds for down- and up-branches */
 205.413 +      dn_bad = !ios_is_hopeful(T, dn_bnd);
 205.414 +      up_bad = !ios_is_hopeful(T, up_bnd);
 205.415 +      if (dn_bad && up_bad)
 205.416 +      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
 205.417 +            xprintf("Both down- and up-branches are hopeless\n");
 205.418 +         ret = 2;
 205.419 +         goto done;
 205.420 +      }
 205.421 +      else if (up_bad)
 205.422 +      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
 205.423 +            xprintf("Up-branch is hopeless\n");
 205.424 +         glp_set_col_bnds(mip, j, dn_type, lb, new_ub);
 205.425 +         T->curr->lp_obj = dn_lp;
 205.426 +         if (mip->dir == GLP_MIN)
 205.427 +         {  if (T->curr->bound < dn_bnd)
 205.428 +                T->curr->bound = dn_bnd;
 205.429 +         }
 205.430 +         else if (mip->dir == GLP_MAX)
 205.431 +         {  if (T->curr->bound > dn_bnd)
 205.432 +                T->curr->bound = dn_bnd;
 205.433 +         }
 205.434 +         else
 205.435 +            xassert(mip != mip);
 205.436 +         ret = 1;
 205.437 +         goto done;
 205.438 +      }
 205.439 +      else if (dn_bad)
 205.440 +      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
 205.441 +            xprintf("Down-branch is hopeless\n");
 205.442 +         glp_set_col_bnds(mip, j, up_type, new_lb, ub);
 205.443 +         T->curr->lp_obj = up_lp;
 205.444 +         if (mip->dir == GLP_MIN)
 205.445 +         {  if (T->curr->bound < up_bnd)
 205.446 +                T->curr->bound = up_bnd;
 205.447 +         }
 205.448 +         else if (mip->dir == GLP_MAX)
 205.449 +         {  if (T->curr->bound > up_bnd)
 205.450 +                T->curr->bound = up_bnd;
 205.451 +         }
 205.452 +         else
 205.453 +            xassert(mip != mip);
 205.454 +         ret = 1;
 205.455 +         goto done;
 205.456 +      }
 205.457 +      /* both down- and up-branches seem to be hopeful */
 205.458 +      if (T->parm->msg_lev >= GLP_MSG_DBG)
 205.459 +         xprintf("Branching on column %d, primal value is %.9e\n",
 205.460 +            j, beta);
 205.461 +      /* determine the reference number of the current subproblem */
 205.462 +      xassert(T->curr != NULL);
 205.463 +      p = T->curr->p;
 205.464 +      T->curr->br_var = j;
 205.465 +      T->curr->br_val = beta;
 205.466 +      /* freeze the current subproblem */
 205.467 +      ios_freeze_node(T);
 205.468 +      /* create two clones of the current subproblem; the first clone
 205.469 +         begins the down-branch, the second one begins the up-branch */
 205.470 +      ios_clone_node(T, p, 2, clone);
 205.471 +      if (T->parm->msg_lev >= GLP_MSG_DBG)
 205.472 +         xprintf("Node %d begins down branch, node %d begins up branch "
 205.473 +            "\n", clone[1], clone[2]);
 205.474 +      /* set new upper bound of j-th column in the down-branch */
 205.475 +      node = T->slot[clone[1]].node;
 205.476 +      xassert(node != NULL);
 205.477 +      xassert(node->up != NULL);
 205.478 +      xassert(node->b_ptr == NULL);
 205.479 +      node->b_ptr = dmp_get_atom(T->pool, sizeof(IOSBND));
 205.480 +      node->b_ptr->k = m + j;
 205.481 +      node->b_ptr->type = (unsigned char)dn_type;
 205.482 +      node->b_ptr->lb = lb;
 205.483 +      node->b_ptr->ub = new_ub;
 205.484 +      node->b_ptr->next = NULL;
 205.485 +      node->lp_obj = dn_lp;
 205.486 +      if (mip->dir == GLP_MIN)
 205.487 +      {  if (node->bound < dn_bnd)
 205.488 +             node->bound = dn_bnd;
 205.489 +      }
 205.490 +      else if (mip->dir == GLP_MAX)
 205.491 +      {  if (node->bound > dn_bnd)
 205.492 +             node->bound = dn_bnd;
 205.493 +      }
 205.494 +      else
 205.495 +         xassert(mip != mip);
 205.496 +      /* set new lower bound of j-th column in the up-branch */
 205.497 +      node = T->slot[clone[2]].node;
 205.498 +      xassert(node != NULL);
 205.499 +      xassert(node->up != NULL);
 205.500 +      xassert(node->b_ptr == NULL);
 205.501 +      node->b_ptr = dmp_get_atom(T->pool, sizeof(IOSBND));
 205.502 +      node->b_ptr->k = m + j;
 205.503 +      node->b_ptr->type = (unsigned char)up_type;
 205.504 +      node->b_ptr->lb = new_lb;
 205.505 +      node->b_ptr->ub = ub;
 205.506 +      node->b_ptr->next = NULL;
 205.507 +      node->lp_obj = up_lp;
 205.508 +      if (mip->dir == GLP_MIN)
 205.509 +      {  if (node->bound < up_bnd)
 205.510 +             node->bound = up_bnd;
 205.511 +      }
 205.512 +      else if (mip->dir == GLP_MAX)
 205.513 +      {  if (node->bound > up_bnd)
 205.514 +             node->bound = up_bnd;
 205.515 +      }
 205.516 +      else
 205.517 +         xassert(mip != mip);
 205.518 +      /* suggest the subproblem to be solved next */
 205.519 +      xassert(T->child == 0);
 205.520 +      if (next == GLP_NO_BRNCH)
 205.521 +         T->child = 0;
 205.522 +      else if (next == GLP_DN_BRNCH)
 205.523 +         T->child = clone[1];
 205.524 +      else if (next == GLP_UP_BRNCH)
 205.525 +         T->child = clone[2];
 205.526 +      else
 205.527 +         xassert(next != next);
 205.528 +      ret = 0;
 205.529 +done: return ret;
 205.530 +}
 205.531 +
 205.532 +/***********************************************************************
 205.533 +*  cleanup_the_tree - prune hopeless branches from the tree
 205.534 +*
 205.535 +*  This routine walks through the active list and checks the local
 205.536 +*  bound for every active subproblem. If the local bound indicates that
 205.537 +*  the subproblem cannot have integer optimal solution better than the
 205.538 +*  incumbent objective value, the routine deletes such subproblem that,
 205.539 +*  in turn, involves pruning the corresponding branch of the tree. */
 205.540 +
 205.541 +static void cleanup_the_tree(glp_tree *T)
 205.542 +{     IOSNPD *node, *next_node;
 205.543 +      int count = 0;
 205.544 +      /* the global bound must exist */
 205.545 +      xassert(T->mip->mip_stat == GLP_FEAS);
 205.546 +      /* walk through the list of active subproblems */
 205.547 +      for (node = T->head; node != NULL; node = next_node)
 205.548 +      {  /* deleting some active problem node may involve deleting its
 205.549 +            parents recursively; however, all its parents being created
 205.550 +            *before* it are always *precede* it in the node list, so
 205.551 +            the next problem node is never affected by such deletion */
 205.552 +         next_node = node->next;
 205.553 +         /* if the branch is hopeless, prune it */
 205.554 +         if (!is_branch_hopeful(T, node->p))
 205.555 +            ios_delete_node(T, node->p), count++;
 205.556 +      }
 205.557 +      if (T->parm->msg_lev >= GLP_MSG_DBG)
 205.558 +      {  if (count == 1)
 205.559 +            xprintf("One hopeless branch has been pruned\n");
 205.560 +         else if (count > 1)
 205.561 +            xprintf("%d hopeless branches have been pruned\n", count);
 205.562 +      }
 205.563 +      return;
 205.564 +}
 205.565 +
 205.566 +/**********************************************************************/
 205.567 +
 205.568 +static void generate_cuts(glp_tree *T)
 205.569 +{     /* generate generic cuts with built-in generators */
 205.570 +      if (!(T->parm->mir_cuts == GLP_ON ||
 205.571 +            T->parm->gmi_cuts == GLP_ON ||
 205.572 +            T->parm->cov_cuts == GLP_ON ||
 205.573 +            T->parm->clq_cuts == GLP_ON)) goto done;
 205.574 +#if 1 /* 20/IX-2008 */
 205.575 +      {  int i, max_cuts, added_cuts;
 205.576 +         max_cuts = T->n;
 205.577 +         if (max_cuts < 1000) max_cuts = 1000;
 205.578 +         added_cuts = 0;
 205.579 +         for (i = T->orig_m+1; i <= T->mip->m; i++)
 205.580 +         {  if (T->mip->row[i]->origin == GLP_RF_CUT)
 205.581 +               added_cuts++;
 205.582 +         }
 205.583 +         /* xprintf("added_cuts = %d\n", added_cuts); */
 205.584 +         if (added_cuts >= max_cuts) goto done;
 205.585 +      }
 205.586 +#endif
 205.587 +      /* generate and add to POOL all cuts violated by x* */
 205.588 +      if (T->parm->gmi_cuts == GLP_ON)
 205.589 +      {  if (T->curr->changed < 5)
 205.590 +            ios_gmi_gen(T);
 205.591 +      }
 205.592 +      if (T->parm->mir_cuts == GLP_ON)
 205.593 +      {  xassert(T->mir_gen != NULL);
 205.594 +         ios_mir_gen(T, T->mir_gen);
 205.595 +      }
 205.596 +      if (T->parm->cov_cuts == GLP_ON)
 205.597 +      {  /* cover cuts works well along with mir cuts */
 205.598 +         /*if (T->round <= 5)*/
 205.599 +            ios_cov_gen(T);
 205.600 +      }
 205.601 +      if (T->parm->clq_cuts == GLP_ON)
 205.602 +      {  if (T->clq_gen != NULL)
 205.603 +         {  if (T->curr->level == 0 && T->curr->changed < 50 ||
 205.604 +                T->curr->level >  0 && T->curr->changed < 5)
 205.605 +               ios_clq_gen(T, T->clq_gen);
 205.606 +         }
 205.607 +      }
 205.608 +done: return;
 205.609 +}
 205.610 +
 205.611 +/**********************************************************************/
 205.612 +
 205.613 +static void remove_cuts(glp_tree *T)
 205.614 +{     /* remove inactive cuts (some valueable globally valid cut might
 205.615 +         be saved in the global cut pool) */
 205.616 +      int i, cnt = 0, *num = NULL;
 205.617 +      xassert(T->curr != NULL);
 205.618 +      for (i = T->orig_m+1; i <= T->mip->m; i++)
 205.619 +      {  if (T->mip->row[i]->origin == GLP_RF_CUT &&
 205.620 +             T->mip->row[i]->level == T->curr->level &&
 205.621 +             T->mip->row[i]->stat == GLP_BS)
 205.622 +         {  if (num == NULL)
 205.623 +               num = xcalloc(1+T->mip->m, sizeof(int));
 205.624 +            num[++cnt] = i;
 205.625 +         }
 205.626 +      }
 205.627 +      if (cnt > 0)
 205.628 +      {  glp_del_rows(T->mip, cnt, num);
 205.629 +#if 0
 205.630 +         xprintf("%d inactive cut(s) removed\n", cnt);
 205.631 +#endif
 205.632 +         xfree(num);
 205.633 +         xassert(glp_factorize(T->mip) == 0);
 205.634 +      }
 205.635 +      return;
 205.636 +}
 205.637 +
 205.638 +/**********************************************************************/
 205.639 +
 205.640 +static void display_cut_info(glp_tree *T)
 205.641 +{     glp_prob *mip = T->mip;
 205.642 +      int i, gmi = 0, mir = 0, cov = 0, clq = 0, app = 0;
 205.643 +      for (i = mip->m; i > 0; i--)
 205.644 +      {  GLPROW *row;
 205.645 +         row = mip->row[i];
 205.646 +         /* if (row->level < T->curr->level) break; */
 205.647 +         if (row->origin == GLP_RF_CUT)
 205.648 +         {  if (row->klass == GLP_RF_GMI)
 205.649 +               gmi++;
 205.650 +            else if (row->klass == GLP_RF_MIR)
 205.651 +               mir++;
 205.652 +            else if (row->klass == GLP_RF_COV)
 205.653 +               cov++;
 205.654 +            else if (row->klass == GLP_RF_CLQ)
 205.655 +               clq++;
 205.656 +            else
 205.657 +               app++;
 205.658 +         }
 205.659 +      }
 205.660 +      xassert(T->curr != NULL);
 205.661 +      if (gmi + mir + cov + clq + app > 0)
 205.662 +      {  xprintf("Cuts on level %d:", T->curr->level);
 205.663 +         if (gmi > 0) xprintf(" gmi = %d;", gmi);
 205.664 +         if (mir > 0) xprintf(" mir = %d;", mir);
 205.665 +         if (cov > 0) xprintf(" cov = %d;", cov);
 205.666 +         if (clq > 0) xprintf(" clq = %d;", clq);
 205.667 +         if (app > 0) xprintf(" app = %d;", app);
 205.668 +         xprintf("\n");
 205.669 +      }
 205.670 +      return;
 205.671 +}
 205.672 +
 205.673 +/***********************************************************************
 205.674 +*  NAME
 205.675 +*
 205.676 +*  ios_driver - branch-and-cut driver
 205.677 +*
 205.678 +*  SYNOPSIS
 205.679 +*
 205.680 +*  #include "glpios.h"
 205.681 +*  int ios_driver(glp_tree *T);
 205.682 +*
 205.683 +*  DESCRIPTION
 205.684 +*
 205.685 +*  The routine ios_driver is a branch-and-cut driver. It controls the
 205.686 +*  MIP solution process.
 205.687 +*
 205.688 +*  RETURNS
 205.689 +*
 205.690 +*  0  The MIP problem instance has been successfully solved. This code
 205.691 +*     does not necessarily mean that the solver has found optimal
 205.692 +*     solution. It only means that the solution process was successful.
 205.693 +*
 205.694 +*  GLP_EFAIL
 205.695 +*     The search was prematurely terminated due to the solver failure.
 205.696 +*
 205.697 +*  GLP_EMIPGAP
 205.698 +*     The search was prematurely terminated, because the relative mip
 205.699 +*     gap tolerance has been reached.
 205.700 +*
 205.701 +*  GLP_ETMLIM
 205.702 +*     The search was prematurely terminated, because the time limit has
 205.703 +*     been exceeded.
 205.704 +*
 205.705 +*  GLP_ESTOP
 205.706 +*     The search was prematurely terminated by application. */
 205.707 +
 205.708 +int ios_driver(glp_tree *T)
 205.709 +{     int p, curr_p, p_stat, d_stat, ret;
 205.710 +#if 1 /* carry out to glp_tree */
 205.711 +      int pred_p = 0;
 205.712 +      /* if the current subproblem has been just created due to
 205.713 +         branching, pred_p is the reference number of its parent
 205.714 +         subproblem, otherwise pred_p is zero */
 205.715 +#endif
 205.716 +      glp_long ttt = T->tm_beg;
 205.717 +#if 0
 205.718 +      ((glp_iocp *)T->parm)->msg_lev = GLP_MSG_DBG;
 205.719 +#endif
 205.720 +      /* on entry to the B&B driver it is assumed that the active list
 205.721 +         contains the only active (i.e. root) subproblem, which is the
 205.722 +         original MIP problem to be solved */
 205.723 +loop: /* main loop starts here */
 205.724 +      /* at this point the current subproblem does not exist */
 205.725 +      xassert(T->curr == NULL);
 205.726 +      /* if the active list is empty, the search is finished */
 205.727 +      if (T->head == NULL)
 205.728 +      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
 205.729 +            xprintf("Active list is empty!\n");
 205.730 +         xassert(dmp_in_use(T->pool).lo == 0);
 205.731 +         ret = 0;
 205.732 +         goto done;
 205.733 +      }
 205.734 +      /* select some active subproblem to continue the search */
 205.735 +      xassert(T->next_p == 0);
 205.736 +      /* let the application program select subproblem */
 205.737 +      if (T->parm->cb_func != NULL)
 205.738 +      {  xassert(T->reason == 0);
 205.739 +         T->reason = GLP_ISELECT;
 205.740 +         T->parm->cb_func(T, T->parm->cb_info);
 205.741 +         T->reason = 0;
 205.742 +         if (T->stop)
 205.743 +         {  ret = GLP_ESTOP;
 205.744 +            goto done;
 205.745 +         }
 205.746 +      }
 205.747 +      if (T->next_p != 0)
 205.748 +      {  /* the application program has selected something */
 205.749 +         ;
 205.750 +      }
 205.751 +      else if (T->a_cnt == 1)
 205.752 +      {  /* the only active subproblem exists, so select it */
 205.753 +         xassert(T->head->next == NULL);
 205.754 +         T->next_p = T->head->p;
 205.755 +      }
 205.756 +      else if (T->child != 0)
 205.757 +      {  /* select one of branching childs suggested by the branching
 205.758 +            heuristic */
 205.759 +         T->next_p = T->child;
 205.760 +      }
 205.761 +      else
 205.762 +      {  /* select active subproblem as specified by the backtracking
 205.763 +            technique option */
 205.764 +         T->next_p = ios_choose_node(T);
 205.765 +      }
 205.766 +      /* the active subproblem just selected becomes current */
 205.767 +      ios_revive_node(T, T->next_p);
 205.768 +      T->next_p = T->child = 0;
 205.769 +      /* invalidate pred_p, if it is not the reference number of the
 205.770 +         parent of the current subproblem */
 205.771 +      if (T->curr->up != NULL && T->curr->up->p != pred_p) pred_p = 0;
 205.772 +      /* determine the reference number of the current subproblem */
 205.773 +      p = T->curr->p;
 205.774 +      if (T->parm->msg_lev >= GLP_MSG_DBG)
 205.775 +      {  xprintf("-----------------------------------------------------"
 205.776 +            "-------------------\n");
 205.777 +         xprintf("Processing node %d at level %d\n", p, T->curr->level);
 205.778 +      }
 205.779 +      /* if it is the root subproblem, initialize cut generators */
 205.780 +      if (p == 1)
 205.781 +      {  if (T->parm->gmi_cuts == GLP_ON)
 205.782 +         {  if (T->parm->msg_lev >= GLP_MSG_ALL)
 205.783 +               xprintf("Gomory's cuts enabled\n");
 205.784 +         }
 205.785 +         if (T->parm->mir_cuts == GLP_ON)
 205.786 +         {  if (T->parm->msg_lev >= GLP_MSG_ALL)
 205.787 +               xprintf("MIR cuts enabled\n");
 205.788 +            xassert(T->mir_gen == NULL);
 205.789 +            T->mir_gen = ios_mir_init(T);
 205.790 +         }
 205.791 +         if (T->parm->cov_cuts == GLP_ON)
 205.792 +         {  if (T->parm->msg_lev >= GLP_MSG_ALL)
 205.793 +               xprintf("Cover cuts enabled\n");
 205.794 +         }
 205.795 +         if (T->parm->clq_cuts == GLP_ON)
 205.796 +         {  xassert(T->clq_gen == NULL);
 205.797 +            if (T->parm->msg_lev >= GLP_MSG_ALL)
 205.798 +               xprintf("Clique cuts enabled\n");
 205.799 +            T->clq_gen = ios_clq_init(T);
 205.800 +         }
 205.801 +      }
 205.802 +more: /* minor loop starts here */
 205.803 +      /* at this point the current subproblem needs either to be solved
 205.804 +         for the first time or re-optimized due to reformulation */
 205.805 +      /* display current progress of the search */
 205.806 +      if (T->parm->msg_lev >= GLP_MSG_DBG ||
 205.807 +          T->parm->msg_lev >= GLP_MSG_ON &&
 205.808 +        (double)(T->parm->out_frq - 1) <=
 205.809 +            1000.0 * xdifftime(xtime(), T->tm_lag))
 205.810 +         show_progress(T, 0);
 205.811 +      if (T->parm->msg_lev >= GLP_MSG_ALL &&
 205.812 +            xdifftime(xtime(), ttt) >= 60.0)
 205.813 +      {  glp_long total;
 205.814 +         glp_mem_usage(NULL, NULL, &total, NULL);
 205.815 +         xprintf("Time used: %.1f secs.  Memory used: %.1f Mb.\n",
 205.816 +            xdifftime(xtime(), T->tm_beg), xltod(total) / 1048576.0);
 205.817 +         ttt = xtime();
 205.818 +      }
 205.819 +      /* check the mip gap */
 205.820 +      if (T->parm->mip_gap > 0.0 &&
 205.821 +          ios_relative_gap(T) <= T->parm->mip_gap)
 205.822 +      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
 205.823 +            xprintf("Relative gap tolerance reached; search terminated "
 205.824 +               "\n");
 205.825 +         ret = GLP_EMIPGAP;
 205.826 +         goto done;
 205.827 +      }
 205.828 +      /* check if the time limit has been exhausted */
 205.829 +      if (T->parm->tm_lim < INT_MAX &&
 205.830 +         (double)(T->parm->tm_lim - 1) <=
 205.831 +         1000.0 * xdifftime(xtime(), T->tm_beg))
 205.832 +      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
 205.833 +            xprintf("Time limit exhausted; search terminated\n");
 205.834 +         ret = GLP_ETMLIM;
 205.835 +         goto done;
 205.836 +      }
 205.837 +      /* let the application program preprocess the subproblem */
 205.838 +      if (T->parm->cb_func != NULL)
 205.839 +      {  xassert(T->reason == 0);
 205.840 +         T->reason = GLP_IPREPRO;
 205.841 +         T->parm->cb_func(T, T->parm->cb_info);
 205.842 +         T->reason = 0;
 205.843 +         if (T->stop)
 205.844 +         {  ret = GLP_ESTOP;
 205.845 +            goto done;
 205.846 +         }
 205.847 +      }
 205.848 +      /* perform basic preprocessing */
 205.849 +      if (T->parm->pp_tech == GLP_PP_NONE)
 205.850 +         ;
 205.851 +      else if (T->parm->pp_tech == GLP_PP_ROOT)
 205.852 +      {  if (T->curr->level == 0)
 205.853 +         {  if (ios_preprocess_node(T, 100))
 205.854 +               goto fath;
 205.855 +         }
 205.856 +      }
 205.857 +      else if (T->parm->pp_tech == GLP_PP_ALL)
 205.858 +      {  if (ios_preprocess_node(T, T->curr->level == 0 ? 100 : 10))
 205.859 +            goto fath;
 205.860 +      }
 205.861 +      else
 205.862 +         xassert(T != T);
 205.863 +      /* preprocessing may improve the global bound */
 205.864 +      if (!is_branch_hopeful(T, p))
 205.865 +      {  xprintf("*** not tested yet ***\n");
 205.866 +         goto fath;
 205.867 +      }
 205.868 +      /* solve LP relaxation of the current subproblem */
 205.869 +      if (T->parm->msg_lev >= GLP_MSG_DBG)
 205.870 +         xprintf("Solving LP relaxation...\n");
 205.871 +      ret = ios_solve_node(T);
 205.872 +      if (!(ret == 0 || ret == GLP_EOBJLL || ret == GLP_EOBJUL))
 205.873 +      {  if (T->parm->msg_lev >= GLP_MSG_ERR)
 205.874 +            xprintf("ios_driver: unable to solve current LP relaxation;"
 205.875 +               " glp_simplex returned %d\n", ret);
 205.876 +         ret = GLP_EFAIL;
 205.877 +         goto done;
 205.878 +      }
 205.879 +      /* analyze status of the basic solution to LP relaxation found */
 205.880 +      p_stat = T->mip->pbs_stat;
 205.881 +      d_stat = T->mip->dbs_stat;
 205.882 +      if (p_stat == GLP_FEAS && d_stat == GLP_FEAS)
 205.883 +      {  /* LP relaxation has optimal solution */
 205.884 +         if (T->parm->msg_lev >= GLP_MSG_DBG)
 205.885 +            xprintf("Found optimal solution to LP relaxation\n");
 205.886 +      }
 205.887 +      else if (d_stat == GLP_NOFEAS)
 205.888 +      {  /* LP relaxation has no dual feasible solution */
 205.889 +         /* since the current subproblem cannot have a larger feasible
 205.890 +            region than its parent, there is something wrong */
 205.891 +         if (T->parm->msg_lev >= GLP_MSG_ERR)
 205.892 +            xprintf("ios_driver: current LP relaxation has no dual feas"
 205.893 +               "ible solution\n");
 205.894 +         ret = GLP_EFAIL;
 205.895 +         goto done;
 205.896 +      }
 205.897 +      else if (p_stat == GLP_INFEAS && d_stat == GLP_FEAS)
 205.898 +      {  /* LP relaxation has no primal solution which is better than
 205.899 +            the incumbent objective value */
 205.900 +         xassert(T->mip->mip_stat == GLP_FEAS);
 205.901 +         if (T->parm->msg_lev >= GLP_MSG_DBG)
 205.902 +            xprintf("LP relaxation has no solution better than incumben"
 205.903 +               "t objective value\n");
 205.904 +         /* prune the branch */
 205.905 +         goto fath;
 205.906 +      }
 205.907 +      else if (p_stat == GLP_NOFEAS)
 205.908 +      {  /* LP relaxation has no primal feasible solution */
 205.909 +         if (T->parm->msg_lev >= GLP_MSG_DBG)
 205.910 +            xprintf("LP relaxation has no feasible solution\n");
 205.911 +         /* prune the branch */
 205.912 +         goto fath;
 205.913 +      }
 205.914 +      else
 205.915 +      {  /* other cases cannot appear */
 205.916 +         xassert(T->mip != T->mip);
 205.917 +      }
 205.918 +      /* at this point basic solution to LP relaxation of the current
 205.919 +         subproblem is optimal */
 205.920 +      xassert(p_stat == GLP_FEAS && d_stat == GLP_FEAS);
 205.921 +      xassert(T->curr != NULL);
 205.922 +      T->curr->lp_obj = T->mip->obj_val;
 205.923 +      /* thus, it defines a local bound to integer optimal solution of
 205.924 +         the current subproblem */
 205.925 +      {  double bound = T->mip->obj_val;
 205.926 +         /* some local bound to the current subproblem could be already
 205.927 +            set before, so we should only improve it */
 205.928 +         bound = ios_round_bound(T, bound);
 205.929 +         if (T->mip->dir == GLP_MIN)
 205.930 +         {  if (T->curr->bound < bound)
 205.931 +               T->curr->bound = bound;
 205.932 +         }
 205.933 +         else if (T->mip->dir == GLP_MAX)
 205.934 +         {  if (T->curr->bound > bound)
 205.935 +               T->curr->bound = bound;
 205.936 +         }
 205.937 +         else
 205.938 +            xassert(T->mip != T->mip);
 205.939 +         if (T->parm->msg_lev >= GLP_MSG_DBG)
 205.940 +            xprintf("Local bound is %.9e\n", bound);
 205.941 +      }
 205.942 +      /* if the local bound indicates that integer optimal solution of
 205.943 +         the current subproblem cannot be better than the global bound,
 205.944 +         prune the branch */
 205.945 +      if (!is_branch_hopeful(T, p))
 205.946 +      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
 205.947 +            xprintf("Current branch is hopeless and can be pruned\n");
 205.948 +         goto fath;
 205.949 +      }
 205.950 +      /* let the application program generate additional rows ("lazy"
 205.951 +         constraints) */
 205.952 +      xassert(T->reopt == 0);
 205.953 +      xassert(T->reinv == 0);
 205.954 +      if (T->parm->cb_func != NULL)
 205.955 +      {  xassert(T->reason == 0);
 205.956 +         T->reason = GLP_IROWGEN;
 205.957 +         T->parm->cb_func(T, T->parm->cb_info);
 205.958 +         T->reason = 0;
 205.959 +         if (T->stop)
 205.960 +         {  ret = GLP_ESTOP;
 205.961 +            goto done;
 205.962 +         }
 205.963 +         if (T->reopt)
 205.964 +         {  /* some rows were added; re-optimization is needed */
 205.965 +            T->reopt = T->reinv = 0;
 205.966 +            goto more;
 205.967 +         }
 205.968 +         if (T->reinv)
 205.969 +         {  /* no rows were added, however, some inactive rows were
 205.970 +               removed */
 205.971 +            T->reinv = 0;
 205.972 +            xassert(glp_factorize(T->mip) == 0);
 205.973 +         }
 205.974 +      }
 205.975 +      /* check if the basic solution is integer feasible */
 205.976 +      check_integrality(T);
 205.977 +      /* if the basic solution satisfies to all integrality conditions,
 205.978 +         it is a new, better integer feasible solution */
 205.979 +      if (T->curr->ii_cnt == 0)
 205.980 +      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
 205.981 +            xprintf("New integer feasible solution found\n");
 205.982 +         if (T->parm->msg_lev >= GLP_MSG_ALL)
 205.983 +            display_cut_info(T);
 205.984 +         record_solution(T);
 205.985 +         if (T->parm->msg_lev >= GLP_MSG_ON)
 205.986 +            show_progress(T, 1);
 205.987 +         /* make the application program happy */
 205.988 +         if (T->parm->cb_func != NULL)
 205.989 +         {  xassert(T->reason == 0);
 205.990 +            T->reason = GLP_IBINGO;
 205.991 +            T->parm->cb_func(T, T->parm->cb_info);
 205.992 +            T->reason = 0;
 205.993 +            if (T->stop)
 205.994 +            {  ret = GLP_ESTOP;
 205.995 +               goto done;
 205.996 +            }
 205.997 +         }
 205.998 +         /* since the current subproblem has been fathomed, prune its
 205.999 +            branch */
205.1000 +         goto fath;
205.1001 +      }
205.1002 +      /* at this point basic solution to LP relaxation of the current
205.1003 +         subproblem is optimal, but integer infeasible */
205.1004 +      /* try to fix some non-basic structural variables of integer kind
205.1005 +         on their current bounds due to reduced costs */
205.1006 +      if (T->mip->mip_stat == GLP_FEAS)
205.1007 +         fix_by_red_cost(T);
205.1008 +      /* let the application program try to find some solution to the
205.1009 +         original MIP with a primal heuristic */
205.1010 +      if (T->parm->cb_func != NULL)
205.1011 +      {  xassert(T->reason == 0);
205.1012 +         T->reason = GLP_IHEUR;
205.1013 +         T->parm->cb_func(T, T->parm->cb_info);
205.1014 +         T->reason = 0;
205.1015 +         if (T->stop)
205.1016 +         {  ret = GLP_ESTOP;
205.1017 +            goto done;
205.1018 +         }
205.1019 +         /* check if the current branch became hopeless */
205.1020 +         if (!is_branch_hopeful(T, p))
205.1021 +         {  if (T->parm->msg_lev >= GLP_MSG_DBG)
205.1022 +               xprintf("Current branch became hopeless and can be prune"
205.1023 +                  "d\n");
205.1024 +            goto fath;
205.1025 +         }
205.1026 +      }
205.1027 +      /* try to find solution with the feasibility pump heuristic */
205.1028 +      if (T->parm->fp_heur)
205.1029 +      {  xassert(T->reason == 0);
205.1030 +         T->reason = GLP_IHEUR;
205.1031 +         ios_feas_pump(T);
205.1032 +         T->reason = 0;
205.1033 +         /* check if the current branch became hopeless */
205.1034 +         if (!is_branch_hopeful(T, p))
205.1035 +         {  if (T->parm->msg_lev >= GLP_MSG_DBG)
205.1036 +               xprintf("Current branch became hopeless and can be prune"
205.1037 +                  "d\n");
205.1038 +            goto fath;
205.1039 +         }
205.1040 +      }
205.1041 +      /* it's time to generate cutting planes */
205.1042 +      xassert(T->local != NULL);
205.1043 +      xassert(T->local->size == 0);
205.1044 +      /* let the application program generate some cuts; note that it
205.1045 +         can add cuts either to the local cut pool or directly to the
205.1046 +         current subproblem */
205.1047 +      if (T->parm->cb_func != NULL)
205.1048 +      {  xassert(T->reason == 0);
205.1049 +         T->reason = GLP_ICUTGEN;
205.1050 +         T->parm->cb_func(T, T->parm->cb_info);
205.1051 +         T->reason = 0;
205.1052 +         if (T->stop)
205.1053 +         {  ret = GLP_ESTOP;
205.1054 +            goto done;
205.1055 +         }
205.1056 +      }
205.1057 +      /* try to generate generic cuts with built-in generators
205.1058 +         (as suggested by Matteo Fischetti et al. the built-in cuts
205.1059 +         are not generated at each branching node; an intense attempt
205.1060 +         of generating new cuts is only made at the root node, and then
205.1061 +         a moderate effort is spent after each backtracking step) */
205.1062 +      if (T->curr->level == 0 || pred_p == 0)
205.1063 +      {  xassert(T->reason == 0);
205.1064 +         T->reason = GLP_ICUTGEN;
205.1065 +         generate_cuts(T);
205.1066 +         T->reason = 0;
205.1067 +      }
205.1068 +      /* if the local cut pool is not empty, select useful cuts and add
205.1069 +         them to the current subproblem */
205.1070 +      if (T->local->size > 0)
205.1071 +      {  xassert(T->reason == 0);
205.1072 +         T->reason = GLP_ICUTGEN;
205.1073 +         ios_process_cuts(T);
205.1074 +         T->reason = 0;
205.1075 +      }
205.1076 +      /* clear the local cut pool */
205.1077 +      ios_clear_pool(T, T->local);
205.1078 +      /* perform re-optimization, if necessary */
205.1079 +      if (T->reopt)
205.1080 +      {  T->reopt = 0;
205.1081 +         T->curr->changed++;
205.1082 +         goto more;
205.1083 +      }
205.1084 +      /* no cuts were generated; remove inactive cuts */
205.1085 +      remove_cuts(T);
205.1086 +      if (T->parm->msg_lev >= GLP_MSG_ALL && T->curr->level == 0)
205.1087 +         display_cut_info(T);
205.1088 +      /* update history information used on pseudocost branching */
205.1089 +      if (T->pcost != NULL) ios_pcost_update(T);
205.1090 +      /* it's time to perform branching */
205.1091 +      xassert(T->br_var == 0);
205.1092 +      xassert(T->br_sel == 0);
205.1093 +      /* let the application program choose variable to branch on */
205.1094 +      if (T->parm->cb_func != NULL)
205.1095 +      {  xassert(T->reason == 0);
205.1096 +         xassert(T->br_var == 0);
205.1097 +         xassert(T->br_sel == 0);
205.1098 +         T->reason = GLP_IBRANCH;
205.1099 +         T->parm->cb_func(T, T->parm->cb_info);
205.1100 +         T->reason = 0;
205.1101 +         if (T->stop)
205.1102 +         {  ret = GLP_ESTOP;
205.1103 +            goto done;
205.1104 +         }
205.1105 +      }
205.1106 +      /* if nothing has been chosen, choose some variable as specified
205.1107 +         by the branching technique option */
205.1108 +      if (T->br_var == 0)
205.1109 +         T->br_var = ios_choose_var(T, &T->br_sel);
205.1110 +      /* perform actual branching */
205.1111 +      curr_p = T->curr->p;
205.1112 +      ret = branch_on(T, T->br_var, T->br_sel);
205.1113 +      T->br_var = T->br_sel = 0;
205.1114 +      if (ret == 0)
205.1115 +      {  /* both branches have been created */
205.1116 +         pred_p = curr_p;
205.1117 +         goto loop;
205.1118 +      }
205.1119 +      else if (ret == 1)
205.1120 +      {  /* one branch is hopeless and has been pruned, so now the
205.1121 +            current subproblem is other branch */
205.1122 +         /* the current subproblem should be considered as a new one,
205.1123 +            since one bound of the branching variable was changed */
205.1124 +         T->curr->solved = T->curr->changed = 0;
205.1125 +         goto more;
205.1126 +      }
205.1127 +      else if (ret == 2)
205.1128 +      {  /* both branches are hopeless and have been pruned; new
205.1129 +            subproblem selection is needed to continue the search */
205.1130 +         goto fath;
205.1131 +      }
205.1132 +      else
205.1133 +         xassert(ret != ret);
205.1134 +fath: /* the current subproblem has been fathomed */
205.1135 +      if (T->parm->msg_lev >= GLP_MSG_DBG)
205.1136 +         xprintf("Node %d fathomed\n", p);
205.1137 +      /* freeze the current subproblem */
205.1138 +      ios_freeze_node(T);
205.1139 +      /* and prune the corresponding branch of the tree */
205.1140 +      ios_delete_node(T, p);
205.1141 +      /* if a new integer feasible solution has just been found, other
205.1142 +         branches may become hopeless and therefore must be pruned */
205.1143 +      if (T->mip->mip_stat == GLP_FEAS) cleanup_the_tree(T);
205.1144 +      /* new subproblem selection is needed due to backtracking */
205.1145 +      pred_p = 0;
205.1146 +      goto loop;
205.1147 +done: /* display progress of the search on exit from the solver */
205.1148 +      if (T->parm->msg_lev >= GLP_MSG_ON)
205.1149 +         show_progress(T, 0);
205.1150 +      if (T->mir_gen != NULL)
205.1151 +         ios_mir_term(T->mir_gen), T->mir_gen = NULL;
205.1152 +      if (T->clq_gen != NULL)
205.1153 +         ios_clq_term(T->clq_gen), T->clq_gen = NULL;
205.1154 +      /* return to the calling program */
205.1155 +      return ret;
205.1156 +}
205.1157 +
205.1158 +/* eof */
   206.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   206.2 +++ b/src/glpios04.c	Mon Dec 06 13:09:21 2010 +0100
   206.3 @@ -0,0 +1,303 @@
   206.4 +/* glpios04.c (operations on sparse vectors) */
   206.5 +
   206.6 +/***********************************************************************
   206.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   206.8 +*
   206.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  206.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  206.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  206.12 +*  E-mail: <mao@gnu.org>.
  206.13 +*
  206.14 +*  GLPK is free software: you can redistribute it and/or modify it
  206.15 +*  under the terms of the GNU General Public License as published by
  206.16 +*  the Free Software Foundation, either version 3 of the License, or
  206.17 +*  (at your option) any later version.
  206.18 +*
  206.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  206.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  206.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  206.22 +*  License for more details.
  206.23 +*
  206.24 +*  You should have received a copy of the GNU General Public License
  206.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  206.26 +***********************************************************************/
  206.27 +
  206.28 +#include "glpios.h"
  206.29 +
  206.30 +/***********************************************************************
  206.31 +*  NAME
  206.32 +*
  206.33 +*  ios_create_vec - create sparse vector
  206.34 +*
  206.35 +*  SYNOPSIS
  206.36 +*
  206.37 +*  #include "glpios.h"
  206.38 +*  IOSVEC *ios_create_vec(int n);
  206.39 +*
  206.40 +*  DESCRIPTION
  206.41 +*
  206.42 +*  The routine ios_create_vec creates a sparse vector of dimension n,
  206.43 +*  which initially is a null vector.
  206.44 +*
  206.45 +*  RETURNS
  206.46 +*
  206.47 +*  The routine returns a pointer to the vector created. */
  206.48 +
  206.49 +IOSVEC *ios_create_vec(int n)
  206.50 +{     IOSVEC *v;
  206.51 +      xassert(n >= 0);
  206.52 +      v = xmalloc(sizeof(IOSVEC));
  206.53 +      v->n = n;
  206.54 +      v->nnz = 0;
  206.55 +      v->pos = xcalloc(1+n, sizeof(int));
  206.56 +      memset(&v->pos[1], 0, n * sizeof(int));
  206.57 +      v->ind = xcalloc(1+n, sizeof(int));
  206.58 +      v->val = xcalloc(1+n, sizeof(double));
  206.59 +      return v;
  206.60 +}
  206.61 +
  206.62 +/***********************************************************************
  206.63 +*  NAME
  206.64 +*
  206.65 +*  ios_check_vec - check that sparse vector has correct representation
  206.66 +*
  206.67 +*  SYNOPSIS
  206.68 +*
  206.69 +*  #include "glpios.h"
  206.70 +*  void ios_check_vec(IOSVEC *v);
  206.71 +*
  206.72 +*  DESCRIPTION
  206.73 +*
  206.74 +*  The routine ios_check_vec checks that a sparse vector specified by
  206.75 +*  the parameter v has correct representation.
  206.76 +*
  206.77 +*  NOTE
  206.78 +*
  206.79 +*  Complexity of this operation is O(n). */
  206.80 +
  206.81 +void ios_check_vec(IOSVEC *v)
  206.82 +{     int j, k, nnz;
  206.83 +      xassert(v->n >= 0);
  206.84 +      nnz = 0;
  206.85 +      for (j = v->n; j >= 1; j--)
  206.86 +      {  k = v->pos[j];
  206.87 +         xassert(0 <= k && k <= v->nnz);
  206.88 +         if (k != 0)
  206.89 +         {  xassert(v->ind[k] == j);
  206.90 +            nnz++;
  206.91 +         }
  206.92 +      }
  206.93 +      xassert(v->nnz == nnz);
  206.94 +      return;
  206.95 +}
  206.96 +
  206.97 +/***********************************************************************
  206.98 +*  NAME
  206.99 +*
 206.100 +*  ios_get_vj - retrieve component of sparse vector
 206.101 +*
 206.102 +*  SYNOPSIS
 206.103 +*
 206.104 +*  #include "glpios.h"
 206.105 +*  double ios_get_vj(IOSVEC *v, int j);
 206.106 +*
 206.107 +*  RETURNS
 206.108 +*
 206.109 +*  The routine ios_get_vj returns j-th component of a sparse vector
 206.110 +*  specified by the parameter v. */
 206.111 +
 206.112 +double ios_get_vj(IOSVEC *v, int j)
 206.113 +{     int k;
 206.114 +      xassert(1 <= j && j <= v->n);
 206.115 +      k = v->pos[j];
 206.116 +      xassert(0 <= k && k <= v->nnz);
 206.117 +      return (k == 0 ? 0.0 : v->val[k]);
 206.118 +}
 206.119 +
 206.120 +/***********************************************************************
 206.121 +*  NAME
 206.122 +*
 206.123 +*  ios_set_vj - set/change component of sparse vector
 206.124 +*
 206.125 +*  SYNOPSIS
 206.126 +*
 206.127 +*  #include "glpios.h"
 206.128 +*  void ios_set_vj(IOSVEC *v, int j, double val);
 206.129 +*
 206.130 +*  DESCRIPTION
 206.131 +*
 206.132 +*  The routine ios_set_vj assigns val to j-th component of a sparse
 206.133 +*  vector specified by the parameter v. */
 206.134 +
 206.135 +void ios_set_vj(IOSVEC *v, int j, double val)
 206.136 +{     int k;
 206.137 +      xassert(1 <= j && j <= v->n);
 206.138 +      k = v->pos[j];
 206.139 +      if (val == 0.0)
 206.140 +      {  if (k != 0)
 206.141 +         {  /* remove j-th component */
 206.142 +            v->pos[j] = 0;
 206.143 +            if (k < v->nnz)
 206.144 +            {  v->pos[v->ind[v->nnz]] = k;
 206.145 +               v->ind[k] = v->ind[v->nnz];
 206.146 +               v->val[k] = v->val[v->nnz];
 206.147 +            }
 206.148 +            v->nnz--;
 206.149 +         }
 206.150 +      }
 206.151 +      else
 206.152 +      {  if (k == 0)
 206.153 +         {  /* create j-th component */
 206.154 +            k = ++(v->nnz);
 206.155 +            v->pos[j] = k;
 206.156 +            v->ind[k] = j;
 206.157 +         }
 206.158 +         v->val[k] = val;
 206.159 +      }
 206.160 +      return;
 206.161 +}
 206.162 +
 206.163 +/***********************************************************************
 206.164 +*  NAME
 206.165 +*
 206.166 +*  ios_clear_vec - set all components of sparse vector to zero
 206.167 +*
 206.168 +*  SYNOPSIS
 206.169 +*
 206.170 +*  #include "glpios.h"
 206.171 +*  void ios_clear_vec(IOSVEC *v);
 206.172 +*
 206.173 +*  DESCRIPTION
 206.174 +*
 206.175 +*  The routine ios_clear_vec sets all components of a sparse vector
 206.176 +*  specified by the parameter v to zero. */
 206.177 +
 206.178 +void ios_clear_vec(IOSVEC *v)
 206.179 +{     int k;
 206.180 +      for (k = 1; k <= v->nnz; k++)
 206.181 +         v->pos[v->ind[k]] = 0;
 206.182 +      v->nnz = 0;
 206.183 +      return;
 206.184 +}
 206.185 +
 206.186 +/***********************************************************************
 206.187 +*  NAME
 206.188 +*
 206.189 +*  ios_clean_vec - remove zero or small components from sparse vector
 206.190 +*
 206.191 +*  SYNOPSIS
 206.192 +*
 206.193 +*  #include "glpios.h"
 206.194 +*  void ios_clean_vec(IOSVEC *v, double eps);
 206.195 +*
 206.196 +*  DESCRIPTION
 206.197 +*
 206.198 +*  The routine ios_clean_vec removes zero components and components
 206.199 +*  whose magnitude is less than eps from a sparse vector specified by
 206.200 +*  the parameter v. If eps is 0.0, only zero components are removed. */
 206.201 +
 206.202 +void ios_clean_vec(IOSVEC *v, double eps)
 206.203 +{     int k, nnz;
 206.204 +      nnz = 0;
 206.205 +      for (k = 1; k <= v->nnz; k++)
 206.206 +      {  if (fabs(v->val[k]) == 0.0 || fabs(v->val[k]) < eps)
 206.207 +         {  /* remove component */
 206.208 +            v->pos[v->ind[k]] = 0;
 206.209 +         }
 206.210 +         else
 206.211 +         {  /* keep component */
 206.212 +            nnz++;
 206.213 +            v->pos[v->ind[k]] = nnz;
 206.214 +            v->ind[nnz] = v->ind[k];
 206.215 +            v->val[nnz] = v->val[k];
 206.216 +         }
 206.217 +      }
 206.218 +      v->nnz = nnz;
 206.219 +      return;
 206.220 +}
 206.221 +
 206.222 +/***********************************************************************
 206.223 +*  NAME
 206.224 +*
 206.225 +*  ios_copy_vec - copy sparse vector (x := y)
 206.226 +*
 206.227 +*  SYNOPSIS
 206.228 +*
 206.229 +*  #include "glpios.h"
 206.230 +*  void ios_copy_vec(IOSVEC *x, IOSVEC *y);
 206.231 +*
 206.232 +*  DESCRIPTION
 206.233 +*
 206.234 +*  The routine ios_copy_vec copies a sparse vector specified by the
 206.235 +*  parameter y to a sparse vector specified by the parameter x. */
 206.236 +
 206.237 +void ios_copy_vec(IOSVEC *x, IOSVEC *y)
 206.238 +{     int j;
 206.239 +      xassert(x != y);
 206.240 +      xassert(x->n == y->n);
 206.241 +      ios_clear_vec(x);
 206.242 +      x->nnz = y->nnz;
 206.243 +      memcpy(&x->ind[1], &y->ind[1], x->nnz * sizeof(int));
 206.244 +      memcpy(&x->val[1], &y->val[1], x->nnz * sizeof(double));
 206.245 +      for (j = 1; j <= x->nnz; j++)
 206.246 +         x->pos[x->ind[j]] = j;
 206.247 +      return;
 206.248 +}
 206.249 +
 206.250 +/***********************************************************************
 206.251 +*  NAME
 206.252 +*
 206.253 +*  ios_linear_comb - compute linear combination (x := x + a * y)
 206.254 +*
 206.255 +*  SYNOPSIS
 206.256 +*
 206.257 +*  #include "glpios.h"
 206.258 +*  void ios_linear_comb(IOSVEC *x, double a, IOSVEC *y);
 206.259 +*
 206.260 +*  DESCRIPTION
 206.261 +*
 206.262 +*  The routine ios_linear_comb computes the linear combination
 206.263 +*
 206.264 +*     x := x + a * y,
 206.265 +*
 206.266 +*  where x and y are sparse vectors, a is a scalar. */
 206.267 +
 206.268 +void ios_linear_comb(IOSVEC *x, double a, IOSVEC *y)
 206.269 +{     int j, k;
 206.270 +      double xj, yj;
 206.271 +      xassert(x != y);
 206.272 +      xassert(x->n == y->n);
 206.273 +      for (k = 1; k <= y->nnz; k++)
 206.274 +      {  j = y->ind[k];
 206.275 +         xj = ios_get_vj(x, j);
 206.276 +         yj = y->val[k];
 206.277 +         ios_set_vj(x, j, xj + a * yj);
 206.278 +      }
 206.279 +      return;
 206.280 +}
 206.281 +
 206.282 +/***********************************************************************
 206.283 +*  NAME
 206.284 +*
 206.285 +*  ios_delete_vec - delete sparse vector
 206.286 +*
 206.287 +*  SYNOPSIS
 206.288 +*
 206.289 +*  #include "glpios.h"
 206.290 +*  void ios_delete_vec(IOSVEC *v);
 206.291 +*
 206.292 +*  DESCRIPTION
 206.293 +*
 206.294 +*  The routine ios_delete_vec deletes a sparse vector specified by the
 206.295 +*  parameter v freeing all the memory allocated to this object. */
 206.296 +
 206.297 +void ios_delete_vec(IOSVEC *v)
 206.298 +{     /* delete sparse vector */
 206.299 +      xfree(v->pos);
 206.300 +      xfree(v->ind);
 206.301 +      xfree(v->val);
 206.302 +      xfree(v);
 206.303 +      return;
 206.304 +}
 206.305 +
 206.306 +/* eof */
   207.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   207.2 +++ b/src/glpios05.c	Mon Dec 06 13:09:21 2010 +0100
   207.3 @@ -0,0 +1,281 @@
   207.4 +/* glpios05.c (Gomory's mixed integer cut generator) */
   207.5 +
   207.6 +/***********************************************************************
   207.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   207.8 +*
   207.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  207.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  207.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  207.12 +*  E-mail: <mao@gnu.org>.
  207.13 +*
  207.14 +*  GLPK is free software: you can redistribute it and/or modify it
  207.15 +*  under the terms of the GNU General Public License as published by
  207.16 +*  the Free Software Foundation, either version 3 of the License, or
  207.17 +*  (at your option) any later version.
  207.18 +*
  207.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  207.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  207.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  207.22 +*  License for more details.
  207.23 +*
  207.24 +*  You should have received a copy of the GNU General Public License
  207.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  207.26 +***********************************************************************/
  207.27 +
  207.28 +#include "glpios.h"
  207.29 +
  207.30 +/***********************************************************************
  207.31 +*  NAME
  207.32 +*
  207.33 +*  ios_gmi_gen - generate Gomory's mixed integer cuts.
  207.34 +*
  207.35 +*  SYNOPSIS
  207.36 +*
  207.37 +*  #include "glpios.h"
  207.38 +*  void ios_gmi_gen(glp_tree *tree, IOSPOOL *pool);
  207.39 +*
  207.40 +*  DESCRIPTION
  207.41 +*
  207.42 +*  The routine ios_gmi_gen generates Gomory's mixed integer cuts for
  207.43 +*  the current point and adds them to the cut pool. */
  207.44 +
  207.45 +#define MAXCUTS 50
  207.46 +/* maximal number of cuts to be generated for one round */
  207.47 +
  207.48 +struct worka
  207.49 +{     /* Gomory's cut generator working area */
  207.50 +      int *ind; /* int ind[1+n]; */
  207.51 +      double *val; /* double val[1+n]; */
  207.52 +      double *phi; /* double phi[1+m+n]; */
  207.53 +};
  207.54 +
  207.55 +#define f(x) ((x) - floor(x))
  207.56 +/* compute fractional part of x */
  207.57 +
  207.58 +static void gen_cut(glp_tree *tree, struct worka *worka, int j)
  207.59 +{     /* this routine tries to generate Gomory's mixed integer cut for
  207.60 +         specified structural variable x[m+j] of integer kind, which is
  207.61 +         basic and has fractional value in optimal solution to current
  207.62 +         LP relaxation */
  207.63 +      glp_prob *mip = tree->mip;
  207.64 +      int m = mip->m;
  207.65 +      int n = mip->n;
  207.66 +      int *ind = worka->ind;
  207.67 +      double *val = worka->val;
  207.68 +      double *phi = worka->phi;
  207.69 +      int i, k, len, kind, stat;
  207.70 +      double lb, ub, alfa, beta, ksi, phi1, rhs;
  207.71 +      /* compute row of the simplex tableau, which (row) corresponds
  207.72 +         to specified basic variable xB[i] = x[m+j]; see (23) */
  207.73 +      len = glp_eval_tab_row(mip, m+j, ind, val);
  207.74 +      /* determine beta[i], which a value of xB[i] in optimal solution
  207.75 +         to current LP relaxation; note that this value is the same as
  207.76 +         if it would be computed with formula (27); it is assumed that
  207.77 +         beta[i] is fractional enough */
  207.78 +      beta = mip->col[j]->prim;
  207.79 +      /* compute cut coefficients phi and right-hand side rho, which
  207.80 +         correspond to formula (30); dense format is used, because rows
  207.81 +         of the simplex tableau is usually dense */
  207.82 +      for (k = 1; k <= m+n; k++) phi[k] = 0.0;
  207.83 +      rhs = f(beta); /* initial value of rho; see (28), (32) */
  207.84 +      for (j = 1; j <= len; j++)
  207.85 +      {  /* determine original number of non-basic variable xN[j] */
  207.86 +         k = ind[j];
  207.87 +         xassert(1 <= k && k <= m+n);
  207.88 +         /* determine the kind, bounds and current status of xN[j] in
  207.89 +            optimal solution to LP relaxation */
  207.90 +         if (k <= m)
  207.91 +         {  /* auxiliary variable */
  207.92 +            GLPROW *row = mip->row[k];
  207.93 +            kind = GLP_CV;
  207.94 +            lb = row->lb;
  207.95 +            ub = row->ub;
  207.96 +            stat = row->stat;
  207.97 +         }
  207.98 +         else
  207.99 +         {  /* structural variable */
 207.100 +            GLPCOL *col = mip->col[k-m];
 207.101 +            kind = col->kind;
 207.102 +            lb = col->lb;
 207.103 +            ub = col->ub;
 207.104 +            stat = col->stat;
 207.105 +         }
 207.106 +         /* xN[j] cannot be basic */
 207.107 +         xassert(stat != GLP_BS);
 207.108 +         /* determine row coefficient ksi[i,j] at xN[j]; see (23) */
 207.109 +         ksi = val[j];
 207.110 +         /* if ksi[i,j] is too large in the magnitude, do not generate
 207.111 +            the cut */
 207.112 +         if (fabs(ksi) > 1e+05) goto fini;
 207.113 +         /* if ksi[i,j] is too small in the magnitude, skip it */
 207.114 +         if (fabs(ksi) < 1e-10) goto skip;
 207.115 +         /* compute row coefficient alfa[i,j] at y[j]; see (26) */
 207.116 +         switch (stat)
 207.117 +         {  case GLP_NF:
 207.118 +               /* xN[j] is free (unbounded) having non-zero ksi[i,j];
 207.119 +                  do not generate the cut */
 207.120 +               goto fini;
 207.121 +            case GLP_NL:
 207.122 +               /* xN[j] has active lower bound */
 207.123 +               alfa = - ksi;
 207.124 +               break;
 207.125 +            case GLP_NU:
 207.126 +               /* xN[j] has active upper bound */
 207.127 +               alfa = + ksi;
 207.128 +               break;
 207.129 +            case GLP_NS:
 207.130 +               /* xN[j] is fixed; skip it */
 207.131 +               goto skip;
 207.132 +            default:
 207.133 +               xassert(stat != stat);
 207.134 +         }
 207.135 +         /* compute cut coefficient phi'[j] at y[j]; see (21), (28) */
 207.136 +         switch (kind)
 207.137 +         {  case GLP_IV:
 207.138 +               /* y[j] is integer */
 207.139 +               if (fabs(alfa - floor(alfa + 0.5)) < 1e-10)
 207.140 +               {  /* alfa[i,j] is close to nearest integer; skip it */
 207.141 +                  goto skip;
 207.142 +               }
 207.143 +               else if (f(alfa) <= f(beta))
 207.144 +                  phi1 = f(alfa);
 207.145 +               else
 207.146 +                  phi1 = (f(beta) / (1.0 - f(beta))) * (1.0 - f(alfa));
 207.147 +               break;
 207.148 +            case GLP_CV:
 207.149 +               /* y[j] is continuous */
 207.150 +               if (alfa >= 0.0)
 207.151 +                  phi1 = + alfa;
 207.152 +               else
 207.153 +                  phi1 = (f(beta) / (1.0 - f(beta))) * (- alfa);
 207.154 +               break;
 207.155 +            default:
 207.156 +               xassert(kind != kind);
 207.157 +         }
 207.158 +         /* compute cut coefficient phi[j] at xN[j] and update right-
 207.159 +            hand side rho; see (31), (32) */
 207.160 +         switch (stat)
 207.161 +         {  case GLP_NL:
 207.162 +               /* xN[j] has active lower bound */
 207.163 +               phi[k] = + phi1;
 207.164 +               rhs += phi1 * lb;
 207.165 +               break;
 207.166 +            case GLP_NU:
 207.167 +               /* xN[j] has active upper bound */
 207.168 +               phi[k] = - phi1;
 207.169 +               rhs -= phi1 * ub;
 207.170 +               break;
 207.171 +            default:
 207.172 +               xassert(stat != stat);
 207.173 +         }
 207.174 +skip:    ;
 207.175 +      }
 207.176 +      /* now the cut has the form sum_k phi[k] * x[k] >= rho, where cut
 207.177 +         coefficients are stored in the array phi in dense format;
 207.178 +         x[1,...,m] are auxiliary variables, x[m+1,...,m+n] are struc-
 207.179 +         tural variables; see (30) */
 207.180 +      /* eliminate auxiliary variables in order to express the cut only
 207.181 +         through structural variables; see (33) */
 207.182 +      for (i = 1; i <= m; i++)
 207.183 +      {  GLPROW *row;
 207.184 +         GLPAIJ *aij;
 207.185 +         if (fabs(phi[i]) < 1e-10) continue;
 207.186 +         /* auxiliary variable x[i] has non-zero cut coefficient */
 207.187 +         row = mip->row[i];
 207.188 +         /* x[i] cannot be fixed */
 207.189 +         xassert(row->type != GLP_FX);
 207.190 +         /* substitute x[i] = sum_j a[i,j] * x[m+j] */
 207.191 +         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
 207.192 +            phi[m+aij->col->j] += phi[i] * aij->val;
 207.193 +      }
 207.194 +      /* convert the final cut to sparse format and substitute fixed
 207.195 +         (structural) variables */
 207.196 +      len = 0;
 207.197 +      for (j = 1; j <= n; j++)
 207.198 +      {  GLPCOL *col;
 207.199 +         if (fabs(phi[m+j]) < 1e-10) continue;
 207.200 +         /* structural variable x[m+j] has non-zero cut coefficient */
 207.201 +         col = mip->col[j];
 207.202 +         if (col->type == GLP_FX)
 207.203 +         {  /* eliminate x[m+j] */
 207.204 +            rhs -= phi[m+j] * col->lb;
 207.205 +         }
 207.206 +         else
 207.207 +         {  len++;
 207.208 +            ind[len] = j;
 207.209 +            val[len] = phi[m+j];
 207.210 +         }
 207.211 +      }
 207.212 +      if (fabs(rhs) < 1e-12) rhs = 0.0;
 207.213 +      /* if the cut inequality seems to be badly scaled, reject it to
 207.214 +         avoid numeric difficulties */
 207.215 +      for (k = 1; k <= len; k++)
 207.216 +      {  if (fabs(val[k]) < 1e-03) goto fini;
 207.217 +         if (fabs(val[k]) > 1e+03) goto fini;
 207.218 +      }
 207.219 +      /* add the cut to the cut pool for further consideration */
 207.220 +#if 0
 207.221 +      ios_add_cut_row(tree, pool, GLP_RF_GMI, len, ind, val, GLP_LO,
 207.222 +         rhs);
 207.223 +#else
 207.224 +      glp_ios_add_row(tree, NULL, GLP_RF_GMI, 0, len, ind, val, GLP_LO,
 207.225 +         rhs);
 207.226 +#endif
 207.227 +fini: return;
 207.228 +}
 207.229 +
 207.230 +struct var { int j; double f; };
 207.231 +
 207.232 +static int fcmp(const void *p1, const void *p2)
 207.233 +{     const struct var *v1 = p1, *v2 = p2;
 207.234 +      if (v1->f > v2->f) return -1;
 207.235 +      if (v1->f < v2->f) return +1;
 207.236 +      return 0;
 207.237 +}
 207.238 +
 207.239 +void ios_gmi_gen(glp_tree *tree)
 207.240 +{     /* main routine to generate Gomory's cuts */
 207.241 +      glp_prob *mip = tree->mip;
 207.242 +      int m = mip->m;
 207.243 +      int n = mip->n;
 207.244 +      struct var *var;
 207.245 +      int k, nv, j, size;
 207.246 +      struct worka _worka, *worka = &_worka;
 207.247 +      /* allocate working arrays */
 207.248 +      var = xcalloc(1+n, sizeof(struct var));
 207.249 +      worka->ind = xcalloc(1+n, sizeof(int));
 207.250 +      worka->val = xcalloc(1+n, sizeof(double));
 207.251 +      worka->phi = xcalloc(1+m+n, sizeof(double));
 207.252 +      /* build the list of integer structural variables, which are
 207.253 +         basic and have fractional value in optimal solution to current
 207.254 +         LP relaxation */
 207.255 +      nv = 0;
 207.256 +      for (j = 1; j <= n; j++)
 207.257 +      {  GLPCOL *col = mip->col[j];
 207.258 +         double frac;
 207.259 +         if (col->kind != GLP_IV) continue;
 207.260 +         if (col->type == GLP_FX) continue;
 207.261 +         if (col->stat != GLP_BS) continue;
 207.262 +         frac = f(col->prim);
 207.263 +         if (!(0.05 <= frac && frac <= 0.95)) continue;
 207.264 +         /* add variable to the list */
 207.265 +         nv++, var[nv].j = j, var[nv].f = frac;
 207.266 +      }
 207.267 +      /* order the list by descending fractionality */
 207.268 +      qsort(&var[1], nv, sizeof(struct var), fcmp);
 207.269 +      /* try to generate cuts by one for each variable in the list, but
 207.270 +         not more than MAXCUTS cuts */
 207.271 +      size = glp_ios_pool_size(tree);
 207.272 +      for (k = 1; k <= nv; k++)
 207.273 +      {  if (glp_ios_pool_size(tree) - size >= MAXCUTS) break;
 207.274 +         gen_cut(tree, worka, var[k].j);
 207.275 +      }
 207.276 +      /* free working arrays */
 207.277 +      xfree(var);
 207.278 +      xfree(worka->ind);
 207.279 +      xfree(worka->val);
 207.280 +      xfree(worka->phi);
 207.281 +      return;
 207.282 +}
 207.283 +
 207.284 +/* eof */
   208.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   208.2 +++ b/src/glpios06.c	Mon Dec 06 13:09:21 2010 +0100
   208.3 @@ -0,0 +1,1447 @@
   208.4 +/* glpios06.c (MIR cut generator) */
   208.5 +
   208.6 +/***********************************************************************
   208.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   208.8 +*
   208.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  208.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  208.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  208.12 +*  E-mail: <mao@gnu.org>.
  208.13 +*
  208.14 +*  GLPK is free software: you can redistribute it and/or modify it
  208.15 +*  under the terms of the GNU General Public License as published by
  208.16 +*  the Free Software Foundation, either version 3 of the License, or
  208.17 +*  (at your option) any later version.
  208.18 +*
  208.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  208.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  208.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  208.22 +*  License for more details.
  208.23 +*
  208.24 +*  You should have received a copy of the GNU General Public License
  208.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  208.26 +***********************************************************************/
  208.27 +
  208.28 +#include "glpios.h"
  208.29 +
  208.30 +#define _MIR_DEBUG 0
  208.31 +
  208.32 +#define MAXAGGR 5
  208.33 +/* maximal number of rows which can be aggregated */
  208.34 +
  208.35 +struct MIR
  208.36 +{     /* MIR cut generator working area */
  208.37 +      /*--------------------------------------------------------------*/
  208.38 +      /* global information valid for the root subproblem */
  208.39 +      int m;
  208.40 +      /* number of rows (in the root subproblem) */
  208.41 +      int n;
  208.42 +      /* number of columns */
  208.43 +      char *skip; /* char skip[1+m]; */
  208.44 +      /* skip[i], 1 <= i <= m, is a flag that means that row i should
  208.45 +         not be used because (1) it is not suitable, or (2) because it
  208.46 +         has been used in the aggregated constraint */
  208.47 +      char *isint; /* char isint[1+m+n]; */
  208.48 +      /* isint[k], 1 <= k <= m+n, is a flag that means that variable
  208.49 +         x[k] is integer (otherwise, continuous) */
  208.50 +      double *lb; /* double lb[1+m+n]; */
  208.51 +      /* lb[k], 1 <= k <= m+n, is lower bound of x[k]; -DBL_MAX means
  208.52 +         that x[k] has no lower bound */
  208.53 +      int *vlb; /* int vlb[1+m+n]; */
  208.54 +      /* vlb[k] = k', 1 <= k <= m+n, is the number of integer variable,
  208.55 +         which defines variable lower bound x[k] >= lb[k] * x[k']; zero
  208.56 +         means that x[k] has simple lower bound */
  208.57 +      double *ub; /* double ub[1+m+n]; */
  208.58 +      /* ub[k], 1 <= k <= m+n, is upper bound of x[k]; +DBL_MAX means
  208.59 +         that x[k] has no upper bound */
  208.60 +      int *vub; /* int vub[1+m+n]; */
  208.61 +      /* vub[k] = k', 1 <= k <= m+n, is the number of integer variable,
  208.62 +         which defines variable upper bound x[k] <= ub[k] * x[k']; zero
  208.63 +         means that x[k] has simple upper bound */
  208.64 +      /*--------------------------------------------------------------*/
  208.65 +      /* current (fractional) point to be separated */
  208.66 +      double *x; /* double x[1+m+n]; */
  208.67 +      /* x[k] is current value of auxiliary (1 <= k <= m) or structural
  208.68 +         (m+1 <= k <= m+n) variable */
  208.69 +      /*--------------------------------------------------------------*/
  208.70 +      /* aggregated constraint sum a[k] * x[k] = b, which is a linear
  208.71 +         combination of original constraints transformed to equalities
  208.72 +         by introducing auxiliary variables */
  208.73 +      int agg_cnt;
  208.74 +      /* number of rows (original constraints) used to build aggregated
  208.75 +         constraint, 1 <= agg_cnt <= MAXAGGR */
  208.76 +      int *agg_row; /* int agg_row[1+MAXAGGR]; */
  208.77 +      /* agg_row[k], 1 <= k <= agg_cnt, is the row number used to build
  208.78 +         aggregated constraint */
  208.79 +      IOSVEC *agg_vec; /* IOSVEC agg_vec[1:m+n]; */
  208.80 +      /* sparse vector of aggregated constraint coefficients, a[k] */
  208.81 +      double agg_rhs;
  208.82 +      /* right-hand side of the aggregated constraint, b */
  208.83 +      /*--------------------------------------------------------------*/
  208.84 +      /* bound substitution flags for modified constraint */
  208.85 +      char *subst; /* char subst[1+m+n]; */
  208.86 +      /* subst[k], 1 <= k <= m+n, is a bound substitution flag used for
  208.87 +         variable x[k]:
  208.88 +         '?' - x[k] is missing in modified constraint
  208.89 +         'L' - x[k] = (lower bound) + x'[k]
  208.90 +         'U' - x[k] = (upper bound) - x'[k] */
  208.91 +      /*--------------------------------------------------------------*/
  208.92 +      /* modified constraint sum a'[k] * x'[k] = b', where x'[k] >= 0,
  208.93 +         derived from aggregated constraint by substituting bounds;
  208.94 +         note that due to substitution of variable bounds there may be
  208.95 +         additional terms in the modified constraint */
  208.96 +      IOSVEC *mod_vec; /* IOSVEC mod_vec[1:m+n]; */
  208.97 +      /* sparse vector of modified constraint coefficients, a'[k] */
  208.98 +      double mod_rhs;
  208.99 +      /* right-hand side of the modified constraint, b' */
 208.100 +      /*--------------------------------------------------------------*/
 208.101 +      /* cutting plane sum alpha[k] * x[k] <= beta */
 208.102 +      IOSVEC *cut_vec; /* IOSVEC cut_vec[1:m+n]; */
 208.103 +      /* sparse vector of cutting plane coefficients, alpha[k] */
 208.104 +      double cut_rhs;
 208.105 +      /* right-hand size of the cutting plane, beta */
 208.106 +};
 208.107 +
 208.108 +/***********************************************************************
 208.109 +*  NAME
 208.110 +*
 208.111 +*  ios_mir_init - initialize MIR cut generator
 208.112 +*
 208.113 +*  SYNOPSIS
 208.114 +*
 208.115 +*  #include "glpios.h"
 208.116 +*  void *ios_mir_init(glp_tree *tree);
 208.117 +*
 208.118 +*  DESCRIPTION
 208.119 +*
 208.120 +*  The routine ios_mir_init initializes the MIR cut generator assuming
 208.121 +*  that the current subproblem is the root subproblem.
 208.122 +*
 208.123 +*  RETURNS
 208.124 +*
 208.125 +*  The routine ios_mir_init returns a pointer to the MIR cut generator
 208.126 +*  working area. */
 208.127 +
 208.128 +static void set_row_attrib(glp_tree *tree, struct MIR *mir)
 208.129 +{     /* set global row attributes */
 208.130 +      glp_prob *mip = tree->mip;
 208.131 +      int m = mir->m;
 208.132 +      int k;
 208.133 +      for (k = 1; k <= m; k++)
 208.134 +      {  GLPROW *row = mip->row[k];
 208.135 +         mir->skip[k] = 0;
 208.136 +         mir->isint[k] = 0;
 208.137 +         switch (row->type)
 208.138 +         {  case GLP_FR:
 208.139 +               mir->lb[k] = -DBL_MAX, mir->ub[k] = +DBL_MAX; break;
 208.140 +            case GLP_LO:
 208.141 +               mir->lb[k] = row->lb, mir->ub[k] = +DBL_MAX; break;
 208.142 +            case GLP_UP:
 208.143 +               mir->lb[k] = -DBL_MAX, mir->ub[k] = row->ub; break;
 208.144 +            case GLP_DB:
 208.145 +               mir->lb[k] = row->lb, mir->ub[k] = row->ub; break;
 208.146 +            case GLP_FX:
 208.147 +               mir->lb[k] = mir->ub[k] = row->lb; break;
 208.148 +            default:
 208.149 +               xassert(row != row);
 208.150 +         }
 208.151 +         mir->vlb[k] = mir->vub[k] = 0;
 208.152 +      }
 208.153 +      return;
 208.154 +}
 208.155 +
 208.156 +static void set_col_attrib(glp_tree *tree, struct MIR *mir)
 208.157 +{     /* set global column attributes */
 208.158 +      glp_prob *mip = tree->mip;
 208.159 +      int m = mir->m;
 208.160 +      int n = mir->n;
 208.161 +      int k;
 208.162 +      for (k = m+1; k <= m+n; k++)
 208.163 +      {  GLPCOL *col = mip->col[k-m];
 208.164 +         switch (col->kind)
 208.165 +         {  case GLP_CV:
 208.166 +               mir->isint[k] = 0; break;
 208.167 +            case GLP_IV:
 208.168 +               mir->isint[k] = 1; break;
 208.169 +            default:
 208.170 +               xassert(col != col);
 208.171 +         }
 208.172 +         switch (col->type)
 208.173 +         {  case GLP_FR:
 208.174 +               mir->lb[k] = -DBL_MAX, mir->ub[k] = +DBL_MAX; break;
 208.175 +            case GLP_LO:
 208.176 +               mir->lb[k] = col->lb, mir->ub[k] = +DBL_MAX; break;
 208.177 +            case GLP_UP:
 208.178 +               mir->lb[k] = -DBL_MAX, mir->ub[k] = col->ub; break;
 208.179 +            case GLP_DB:
 208.180 +               mir->lb[k] = col->lb, mir->ub[k] = col->ub; break;
 208.181 +            case GLP_FX:
 208.182 +               mir->lb[k] = mir->ub[k] = col->lb; break;
 208.183 +            default:
 208.184 +               xassert(col != col);
 208.185 +         }
 208.186 +         mir->vlb[k] = mir->vub[k] = 0;
 208.187 +      }
 208.188 +      return;
 208.189 +}
 208.190 +
 208.191 +static void set_var_bounds(glp_tree *tree, struct MIR *mir)
 208.192 +{     /* set variable bounds */
 208.193 +      glp_prob *mip = tree->mip;
 208.194 +      int m = mir->m;
 208.195 +      GLPAIJ *aij;
 208.196 +      int i, k1, k2;
 208.197 +      double a1, a2;
 208.198 +      for (i = 1; i <= m; i++)
 208.199 +      {  /* we need the row to be '>= 0' or '<= 0' */
 208.200 +         if (!(mir->lb[i] == 0.0 && mir->ub[i] == +DBL_MAX ||
 208.201 +               mir->lb[i] == -DBL_MAX && mir->ub[i] == 0.0)) continue;
 208.202 +         /* take first term */
 208.203 +         aij = mip->row[i]->ptr;
 208.204 +         if (aij == NULL) continue;
 208.205 +         k1 = m + aij->col->j, a1 = aij->val;
 208.206 +         /* take second term */
 208.207 +         aij = aij->r_next;
 208.208 +         if (aij == NULL) continue;
 208.209 +         k2 = m + aij->col->j, a2 = aij->val;
 208.210 +         /* there must be only two terms */
 208.211 +         if (aij->r_next != NULL) continue;
 208.212 +         /* interchange terms, if needed */
 208.213 +         if (!mir->isint[k1] && mir->isint[k2])
 208.214 +            ;
 208.215 +         else if (mir->isint[k1] && !mir->isint[k2])
 208.216 +         {  k2 = k1, a2 = a1;
 208.217 +            k1 = m + aij->col->j, a1 = aij->val;
 208.218 +         }
 208.219 +         else
 208.220 +         {  /* both terms are either continuous or integer */
 208.221 +            continue;
 208.222 +         }
 208.223 +         /* x[k2] should be double-bounded */
 208.224 +         if (mir->lb[k2] == -DBL_MAX || mir->ub[k2] == +DBL_MAX ||
 208.225 +             mir->lb[k2] == mir->ub[k2]) continue;
 208.226 +         /* change signs, if necessary */
 208.227 +         if (mir->ub[i] == 0.0) a1 = - a1, a2 = - a2;
 208.228 +         /* now the row has the form a1 * x1 + a2 * x2 >= 0, where x1
 208.229 +            is continuous, x2 is integer */
 208.230 +         if (a1 > 0.0)
 208.231 +         {  /* x1 >= - (a2 / a1) * x2 */
 208.232 +            if (mir->vlb[k1] == 0)
 208.233 +            {  /* set variable lower bound for x1 */
 208.234 +               mir->lb[k1] = - a2 / a1;
 208.235 +               mir->vlb[k1] = k2;
 208.236 +               /* the row should not be used */
 208.237 +               mir->skip[i] = 1;
 208.238 +            }
 208.239 +         }
 208.240 +         else /* a1 < 0.0 */
 208.241 +         {  /* x1 <= - (a2 / a1) * x2 */
 208.242 +            if (mir->vub[k1] == 0)
 208.243 +            {  /* set variable upper bound for x1 */
 208.244 +               mir->ub[k1] = - a2 / a1;
 208.245 +               mir->vub[k1] = k2;
 208.246 +               /* the row should not be used */
 208.247 +               mir->skip[i] = 1;
 208.248 +            }
 208.249 +         }
 208.250 +      }
 208.251 +      return;
 208.252 +}
 208.253 +
 208.254 +static void mark_useless_rows(glp_tree *tree, struct MIR *mir)
 208.255 +{     /* mark rows which should not be used */
 208.256 +      glp_prob *mip = tree->mip;
 208.257 +      int m = mir->m;
 208.258 +      GLPAIJ *aij;
 208.259 +      int i, k, nv;
 208.260 +      for (i = 1; i <= m; i++)
 208.261 +      {  /* free rows should not be used */
 208.262 +         if (mir->lb[i] == -DBL_MAX && mir->ub[i] == +DBL_MAX)
 208.263 +         {  mir->skip[i] = 1;
 208.264 +            continue;
 208.265 +         }
 208.266 +         nv = 0;
 208.267 +         for (aij = mip->row[i]->ptr; aij != NULL; aij = aij->r_next)
 208.268 +         {  k = m + aij->col->j;
 208.269 +            /* rows with free variables should not be used */
 208.270 +            if (mir->lb[k] == -DBL_MAX && mir->ub[k] == +DBL_MAX)
 208.271 +            {  mir->skip[i] = 1;
 208.272 +               break;
 208.273 +            }
 208.274 +            /* rows with integer variables having infinite (lower or
 208.275 +               upper) bound should not be used */
 208.276 +            if (mir->isint[k] && mir->lb[k] == -DBL_MAX ||
 208.277 +                mir->isint[k] && mir->ub[k] == +DBL_MAX)
 208.278 +            {  mir->skip[i] = 1;
 208.279 +               break;
 208.280 +            }
 208.281 +            /* count non-fixed variables */
 208.282 +            if (!(mir->vlb[k] == 0 && mir->vub[k] == 0 &&
 208.283 +                  mir->lb[k] == mir->ub[k])) nv++;
 208.284 +         }
 208.285 +         /* rows with all variables fixed should not be used */
 208.286 +         if (nv == 0)
 208.287 +         {  mir->skip[i] = 1;
 208.288 +            continue;
 208.289 +         }
 208.290 +      }
 208.291 +      return;
 208.292 +}
 208.293 +
 208.294 +void *ios_mir_init(glp_tree *tree)
 208.295 +{     /* initialize MIR cut generator */
 208.296 +      glp_prob *mip = tree->mip;
 208.297 +      int m = mip->m;
 208.298 +      int n = mip->n;
 208.299 +      struct MIR *mir;
 208.300 +#if _MIR_DEBUG
 208.301 +      xprintf("ios_mir_init: warning: debug mode enabled\n");
 208.302 +#endif
 208.303 +      /* allocate working area */
 208.304 +      mir = xmalloc(sizeof(struct MIR));
 208.305 +      mir->m = m;
 208.306 +      mir->n = n;
 208.307 +      mir->skip = xcalloc(1+m, sizeof(char));
 208.308 +      mir->isint = xcalloc(1+m+n, sizeof(char));
 208.309 +      mir->lb = xcalloc(1+m+n, sizeof(double));
 208.310 +      mir->vlb = xcalloc(1+m+n, sizeof(int));
 208.311 +      mir->ub = xcalloc(1+m+n, sizeof(double));
 208.312 +      mir->vub = xcalloc(1+m+n, sizeof(int));
 208.313 +      mir->x = xcalloc(1+m+n, sizeof(double));
 208.314 +      mir->agg_row = xcalloc(1+MAXAGGR, sizeof(int));
 208.315 +      mir->agg_vec = ios_create_vec(m+n);
 208.316 +      mir->subst = xcalloc(1+m+n, sizeof(char));
 208.317 +      mir->mod_vec = ios_create_vec(m+n);
 208.318 +      mir->cut_vec = ios_create_vec(m+n);
 208.319 +      /* set global row attributes */
 208.320 +      set_row_attrib(tree, mir);
 208.321 +      /* set global column attributes */
 208.322 +      set_col_attrib(tree, mir);
 208.323 +      /* set variable bounds */
 208.324 +      set_var_bounds(tree, mir);
 208.325 +      /* mark rows which should not be used */
 208.326 +      mark_useless_rows(tree, mir);
 208.327 +      return mir;
 208.328 +}
 208.329 +
 208.330 +/***********************************************************************
 208.331 +*  NAME
 208.332 +*
 208.333 +*  ios_mir_gen - generate MIR cuts
 208.334 +*
 208.335 +*  SYNOPSIS
 208.336 +*
 208.337 +*  #include "glpios.h"
 208.338 +*  void ios_mir_gen(glp_tree *tree, void *gen, IOSPOOL *pool);
 208.339 +*
 208.340 +*  DESCRIPTION
 208.341 +*
 208.342 +*  The routine ios_mir_gen generates MIR cuts for the current point and
 208.343 +*  adds them to the cut pool. */
 208.344 +
 208.345 +static void get_current_point(glp_tree *tree, struct MIR *mir)
 208.346 +{     /* obtain current point */
 208.347 +      glp_prob *mip = tree->mip;
 208.348 +      int m = mir->m;
 208.349 +      int n = mir->n;
 208.350 +      int k;
 208.351 +      for (k = 1; k <= m; k++)
 208.352 +         mir->x[k] = mip->row[k]->prim;
 208.353 +      for (k = m+1; k <= m+n; k++)
 208.354 +         mir->x[k] = mip->col[k-m]->prim;
 208.355 +      return;
 208.356 +}
 208.357 +
 208.358 +#if _MIR_DEBUG
 208.359 +static void check_current_point(struct MIR *mir)
 208.360 +{     /* check current point */
 208.361 +      int m = mir->m;
 208.362 +      int n = mir->n;
 208.363 +      int k, kk;
 208.364 +      double lb, ub, eps;
 208.365 +      for (k = 1; k <= m+n; k++)
 208.366 +      {  /* determine lower bound */
 208.367 +         lb = mir->lb[k];
 208.368 +         kk = mir->vlb[k];
 208.369 +         if (kk != 0)
 208.370 +         {  xassert(lb != -DBL_MAX);
 208.371 +            xassert(!mir->isint[k]);
 208.372 +            xassert(mir->isint[kk]);
 208.373 +            lb *= mir->x[kk];
 208.374 +         }
 208.375 +         /* check lower bound */
 208.376 +         if (lb != -DBL_MAX)
 208.377 +         {  eps = 1e-6 * (1.0 + fabs(lb));
 208.378 +            xassert(mir->x[k] >= lb - eps);
 208.379 +         }
 208.380 +         /* determine upper bound */
 208.381 +         ub = mir->ub[k];
 208.382 +         kk = mir->vub[k];
 208.383 +         if (kk != 0)
 208.384 +         {  xassert(ub != +DBL_MAX);
 208.385 +            xassert(!mir->isint[k]);
 208.386 +            xassert(mir->isint[kk]);
 208.387 +            ub *= mir->x[kk];
 208.388 +         }
 208.389 +         /* check upper bound */
 208.390 +         if (ub != +DBL_MAX)
 208.391 +         {  eps = 1e-6 * (1.0 + fabs(ub));
 208.392 +            xassert(mir->x[k] <= ub + eps);
 208.393 +         }
 208.394 +      }
 208.395 +      return;
 208.396 +}
 208.397 +#endif
 208.398 +
 208.399 +static void initial_agg_row(glp_tree *tree, struct MIR *mir, int i)
 208.400 +{     /* use original i-th row as initial aggregated constraint */
 208.401 +      glp_prob *mip = tree->mip;
 208.402 +      int m = mir->m;
 208.403 +      GLPAIJ *aij;
 208.404 +      xassert(1 <= i && i <= m);
 208.405 +      xassert(!mir->skip[i]);
 208.406 +      /* mark i-th row in order not to use it in the same aggregated
 208.407 +         constraint */
 208.408 +      mir->skip[i] = 2;
 208.409 +      mir->agg_cnt = 1;
 208.410 +      mir->agg_row[1] = i;
 208.411 +      /* use x[i] - sum a[i,j] * x[m+j] = 0, where x[i] is auxiliary
 208.412 +         variable of row i, x[m+j] are structural variables */
 208.413 +      ios_clear_vec(mir->agg_vec);
 208.414 +      ios_set_vj(mir->agg_vec, i, 1.0);
 208.415 +      for (aij = mip->row[i]->ptr; aij != NULL; aij = aij->r_next)
 208.416 +         ios_set_vj(mir->agg_vec, m + aij->col->j, - aij->val);
 208.417 +      mir->agg_rhs = 0.0;
 208.418 +#if _MIR_DEBUG
 208.419 +      ios_check_vec(mir->agg_vec);
 208.420 +#endif
 208.421 +      return;
 208.422 +}
 208.423 +
 208.424 +#if _MIR_DEBUG
 208.425 +static void check_agg_row(struct MIR *mir)
 208.426 +{     /* check aggregated constraint */
 208.427 +      int m = mir->m;
 208.428 +      int n = mir->n;
 208.429 +      int j, k;
 208.430 +      double r, big;
 208.431 +      /* compute the residual r = sum a[k] * x[k] - b and determine
 208.432 +         big = max(1, |a[k]|, |b|) */
 208.433 +      r = 0.0, big = 1.0;
 208.434 +      for (j = 1; j <= mir->agg_vec->nnz; j++)
 208.435 +      {  k = mir->agg_vec->ind[j];
 208.436 +         xassert(1 <= k && k <= m+n);
 208.437 +         r += mir->agg_vec->val[j] * mir->x[k];
 208.438 +         if (big < fabs(mir->agg_vec->val[j]))
 208.439 +            big = fabs(mir->agg_vec->val[j]);
 208.440 +      }
 208.441 +      r -= mir->agg_rhs;
 208.442 +      if (big < fabs(mir->agg_rhs))
 208.443 +         big = fabs(mir->agg_rhs);
 208.444 +      /* the residual must be close to zero */
 208.445 +      xassert(fabs(r) <= 1e-6 * big);
 208.446 +      return;
 208.447 +}
 208.448 +#endif
 208.449 +
 208.450 +static void subst_fixed_vars(struct MIR *mir)
 208.451 +{     /* substitute fixed variables into aggregated constraint */
 208.452 +      int m = mir->m;
 208.453 +      int n = mir->n;
 208.454 +      int j, k;
 208.455 +      for (j = 1; j <= mir->agg_vec->nnz; j++)
 208.456 +      {  k = mir->agg_vec->ind[j];
 208.457 +         xassert(1 <= k && k <= m+n);
 208.458 +         if (mir->vlb[k] == 0 && mir->vub[k] == 0 &&
 208.459 +             mir->lb[k] == mir->ub[k])
 208.460 +         {  /* x[k] is fixed */
 208.461 +            mir->agg_rhs -= mir->agg_vec->val[j] * mir->lb[k];
 208.462 +            mir->agg_vec->val[j] = 0.0;
 208.463 +         }
 208.464 +      }
 208.465 +      /* remove terms corresponding to fixed variables */
 208.466 +      ios_clean_vec(mir->agg_vec, DBL_EPSILON);
 208.467 +#if _MIR_DEBUG
 208.468 +      ios_check_vec(mir->agg_vec);
 208.469 +#endif
 208.470 +      return;
 208.471 +}
 208.472 +
 208.473 +static void bound_subst_heur(struct MIR *mir)
 208.474 +{     /* bound substitution heuristic */
 208.475 +      int m = mir->m;
 208.476 +      int n = mir->n;
 208.477 +      int j, k, kk;
 208.478 +      double d1, d2;
 208.479 +      for (j = 1; j <= mir->agg_vec->nnz; j++)
 208.480 +      {  k = mir->agg_vec->ind[j];
 208.481 +         xassert(1 <= k && k <= m+n);
 208.482 +         if (mir->isint[k]) continue; /* skip integer variable */
 208.483 +         /* compute distance from x[k] to its lower bound */
 208.484 +         kk = mir->vlb[k];
 208.485 +         if (kk == 0)
 208.486 +         {  if (mir->lb[k] == -DBL_MAX)
 208.487 +               d1 = DBL_MAX;
 208.488 +            else
 208.489 +               d1 = mir->x[k] - mir->lb[k];
 208.490 +         }
 208.491 +         else
 208.492 +         {  xassert(1 <= kk && kk <= m+n);
 208.493 +            xassert(mir->isint[kk]);
 208.494 +            xassert(mir->lb[k] != -DBL_MAX);
 208.495 +            d1 = mir->x[k] - mir->lb[k] * mir->x[kk];
 208.496 +         }
 208.497 +         /* compute distance from x[k] to its upper bound */
 208.498 +         kk = mir->vub[k];
 208.499 +         if (kk == 0)
 208.500 +         {  if (mir->vub[k] == +DBL_MAX)
 208.501 +               d2 = DBL_MAX;
 208.502 +            else
 208.503 +               d2 = mir->ub[k] - mir->x[k];
 208.504 +         }
 208.505 +         else
 208.506 +         {  xassert(1 <= kk && kk <= m+n);
 208.507 +            xassert(mir->isint[kk]);
 208.508 +            xassert(mir->ub[k] != +DBL_MAX);
 208.509 +            d2 = mir->ub[k] * mir->x[kk] - mir->x[k];
 208.510 +         }
 208.511 +         /* x[k] cannot be free */
 208.512 +         xassert(d1 != DBL_MAX || d2 != DBL_MAX);
 208.513 +         /* choose the bound which is closer to x[k] */
 208.514 +         xassert(mir->subst[k] == '?');
 208.515 +         if (d1 <= d2)
 208.516 +            mir->subst[k] = 'L';
 208.517 +         else
 208.518 +            mir->subst[k] = 'U';
 208.519 +      }
 208.520 +      return;
 208.521 +}
 208.522 +
 208.523 +static void build_mod_row(struct MIR *mir)
 208.524 +{     /* substitute bounds and build modified constraint */
 208.525 +      int m = mir->m;
 208.526 +      int n = mir->n;
 208.527 +      int j, jj, k, kk;
 208.528 +      /* initially modified constraint is aggregated constraint */
 208.529 +      ios_copy_vec(mir->mod_vec, mir->agg_vec);
 208.530 +      mir->mod_rhs = mir->agg_rhs;
 208.531 +#if _MIR_DEBUG
 208.532 +      ios_check_vec(mir->mod_vec);
 208.533 +#endif
 208.534 +      /* substitute bounds for continuous variables; note that due to
 208.535 +         substitution of variable bounds additional terms may appear in
 208.536 +         modified constraint */
 208.537 +      for (j = mir->mod_vec->nnz; j >= 1; j--)
 208.538 +      {  k = mir->mod_vec->ind[j];
 208.539 +         xassert(1 <= k && k <= m+n);
 208.540 +         if (mir->isint[k]) continue; /* skip integer variable */
 208.541 +         if (mir->subst[k] == 'L')
 208.542 +         {  /* x[k] = (lower bound) + x'[k] */
 208.543 +            xassert(mir->lb[k] != -DBL_MAX);
 208.544 +            kk = mir->vlb[k];
 208.545 +            if (kk == 0)
 208.546 +            {  /* x[k] = lb[k] + x'[k] */
 208.547 +               mir->mod_rhs -= mir->mod_vec->val[j] * mir->lb[k];
 208.548 +            }
 208.549 +            else
 208.550 +            {  /* x[k] = lb[k] * x[kk] + x'[k] */
 208.551 +               xassert(mir->isint[kk]);
 208.552 +               jj = mir->mod_vec->pos[kk];
 208.553 +               if (jj == 0)
 208.554 +               {  ios_set_vj(mir->mod_vec, kk, 1.0);
 208.555 +                  jj = mir->mod_vec->pos[kk];
 208.556 +                  mir->mod_vec->val[jj] = 0.0;
 208.557 +               }
 208.558 +               mir->mod_vec->val[jj] +=
 208.559 +                  mir->mod_vec->val[j] * mir->lb[k];
 208.560 +            }
 208.561 +         }
 208.562 +         else if (mir->subst[k] == 'U')
 208.563 +         {  /* x[k] = (upper bound) - x'[k] */
 208.564 +            xassert(mir->ub[k] != +DBL_MAX);
 208.565 +            kk = mir->vub[k];
 208.566 +            if (kk == 0)
 208.567 +            {  /* x[k] = ub[k] - x'[k] */
 208.568 +               mir->mod_rhs -= mir->mod_vec->val[j] * mir->ub[k];
 208.569 +            }
 208.570 +            else
 208.571 +            {  /* x[k] = ub[k] * x[kk] - x'[k] */
 208.572 +               xassert(mir->isint[kk]);
 208.573 +               jj = mir->mod_vec->pos[kk];
 208.574 +               if (jj == 0)
 208.575 +               {  ios_set_vj(mir->mod_vec, kk, 1.0);
 208.576 +                  jj = mir->mod_vec->pos[kk];
 208.577 +                  mir->mod_vec->val[jj] = 0.0;
 208.578 +               }
 208.579 +               mir->mod_vec->val[jj] +=
 208.580 +                  mir->mod_vec->val[j] * mir->ub[k];
 208.581 +            }
 208.582 +            mir->mod_vec->val[j] = - mir->mod_vec->val[j];
 208.583 +         }
 208.584 +         else
 208.585 +            xassert(k != k);
 208.586 +      }
 208.587 +#if _MIR_DEBUG
 208.588 +      ios_check_vec(mir->mod_vec);
 208.589 +#endif
 208.590 +      /* substitute bounds for integer variables */
 208.591 +      for (j = 1; j <= mir->mod_vec->nnz; j++)
 208.592 +      {  k = mir->mod_vec->ind[j];
 208.593 +         xassert(1 <= k && k <= m+n);
 208.594 +         if (!mir->isint[k]) continue; /* skip continuous variable */
 208.595 +         xassert(mir->subst[k] == '?');
 208.596 +         xassert(mir->vlb[k] == 0 && mir->vub[k] == 0);
 208.597 +         xassert(mir->lb[k] != -DBL_MAX && mir->ub[k] != +DBL_MAX);
 208.598 +         if (fabs(mir->lb[k]) <= fabs(mir->ub[k]))
 208.599 +         {  /* x[k] = lb[k] + x'[k] */
 208.600 +            mir->subst[k] = 'L';
 208.601 +            mir->mod_rhs -= mir->mod_vec->val[j] * mir->lb[k];
 208.602 +         }
 208.603 +         else
 208.604 +         {  /* x[k] = ub[k] - x'[k] */
 208.605 +            mir->subst[k] = 'U';
 208.606 +            mir->mod_rhs -= mir->mod_vec->val[j] * mir->ub[k];
 208.607 +            mir->mod_vec->val[j] = - mir->mod_vec->val[j];
 208.608 +         }
 208.609 +      }
 208.610 +#if _MIR_DEBUG
 208.611 +      ios_check_vec(mir->mod_vec);
 208.612 +#endif
 208.613 +      return;
 208.614 +}
 208.615 +
 208.616 +#if _MIR_DEBUG
 208.617 +static void check_mod_row(struct MIR *mir)
 208.618 +{     /* check modified constraint */
 208.619 +      int m = mir->m;
 208.620 +      int n = mir->n;
 208.621 +      int j, k, kk;
 208.622 +      double r, big, x;
 208.623 +      /* compute the residual r = sum a'[k] * x'[k] - b' and determine
 208.624 +         big = max(1, |a[k]|, |b|) */
 208.625 +      r = 0.0, big = 1.0;
 208.626 +      for (j = 1; j <= mir->mod_vec->nnz; j++)
 208.627 +      {  k = mir->mod_vec->ind[j];
 208.628 +         xassert(1 <= k && k <= m+n);
 208.629 +         if (mir->subst[k] == 'L')
 208.630 +         {  /* x'[k] = x[k] - (lower bound) */
 208.631 +            xassert(mir->lb[k] != -DBL_MAX);
 208.632 +            kk = mir->vlb[k];
 208.633 +            if (kk == 0)
 208.634 +               x = mir->x[k] - mir->lb[k];
 208.635 +            else
 208.636 +               x = mir->x[k] - mir->lb[k] * mir->x[kk];
 208.637 +         }
 208.638 +         else if (mir->subst[k] == 'U')
 208.639 +         {  /* x'[k] = (upper bound) - x[k] */
 208.640 +            xassert(mir->ub[k] != +DBL_MAX);
 208.641 +            kk = mir->vub[k];
 208.642 +            if (kk == 0)
 208.643 +               x = mir->ub[k] - mir->x[k];
 208.644 +            else
 208.645 +               x = mir->ub[k] * mir->x[kk] - mir->x[k];
 208.646 +         }
 208.647 +         else
 208.648 +            xassert(k != k);
 208.649 +         r += mir->mod_vec->val[j] * x;
 208.650 +         if (big < fabs(mir->mod_vec->val[j]))
 208.651 +            big = fabs(mir->mod_vec->val[j]);
 208.652 +      }
 208.653 +      r -= mir->mod_rhs;
 208.654 +      if (big < fabs(mir->mod_rhs))
 208.655 +         big = fabs(mir->mod_rhs);
 208.656 +      /* the residual must be close to zero */
 208.657 +      xassert(fabs(r) <= 1e-6 * big);
 208.658 +      return;
 208.659 +}
 208.660 +#endif
 208.661 +
 208.662 +/***********************************************************************
 208.663 +*  mir_ineq - construct MIR inequality
 208.664 +*
 208.665 +*  Given the single constraint mixed integer set
 208.666 +*
 208.667 +*                    |N|
 208.668 +*     X = {(x,s) in Z    x R  : sum   a[j] * x[j] <= b + s},
 208.669 +*                    +      +  j in N
 208.670 +*
 208.671 +*  this routine constructs the mixed integer rounding (MIR) inequality
 208.672 +*
 208.673 +*     sum   alpha[j] * x[j] <= beta + gamma * s,
 208.674 +*    j in N
 208.675 +*
 208.676 +*  which is valid for X.
 208.677 +*
 208.678 +*  If the MIR inequality has been successfully constructed, the routine
 208.679 +*  returns zero. Otherwise, if b is close to nearest integer, there may
 208.680 +*  be numeric difficulties due to big coefficients; so in this case the
 208.681 +*  routine returns non-zero. */
 208.682 +
 208.683 +static int mir_ineq(const int n, const double a[], const double b,
 208.684 +      double alpha[], double *beta, double *gamma)
 208.685 +{     int j;
 208.686 +      double f, t;
 208.687 +      if (fabs(b - floor(b + .5)) < 0.01)
 208.688 +         return 1;
 208.689 +      f = b - floor(b);
 208.690 +      for (j = 1; j <= n; j++)
 208.691 +      {  t = (a[j] - floor(a[j])) - f;
 208.692 +         if (t <= 0.0)
 208.693 +            alpha[j] = floor(a[j]);
 208.694 +         else
 208.695 +            alpha[j] = floor(a[j]) + t / (1.0 - f);
 208.696 +      }
 208.697 +      *beta = floor(b);
 208.698 +      *gamma = 1.0 / (1.0 - f);
 208.699 +      return 0;
 208.700 +}
 208.701 +
 208.702 +/***********************************************************************
 208.703 +*  cmir_ineq - construct c-MIR inequality
 208.704 +*
 208.705 +*  Given the mixed knapsack set
 208.706 +*
 208.707 +*      MK              |N|
 208.708 +*     X   = {(x,s) in Z    x R  : sum   a[j] * x[j] <= b + s,
 208.709 +*                      +      +  j in N
 208.710 +*
 208.711 +*             x[j] <= u[j]},
 208.712 +*
 208.713 +*  a subset C of variables to be complemented, and a divisor delta > 0,
 208.714 +*  this routine constructs the complemented MIR (c-MIR) inequality
 208.715 +*
 208.716 +*     sum   alpha[j] * x[j] <= beta + gamma * s,
 208.717 +*    j in N
 208.718 +*                      MK
 208.719 +*  which is valid for X  .
 208.720 +*
 208.721 +*  If the c-MIR inequality has been successfully constructed, the
 208.722 +*  routine returns zero. Otherwise, if there is a risk of numerical
 208.723 +*  difficulties due to big coefficients (see comments to the routine
 208.724 +*  mir_ineq), the routine cmir_ineq returns non-zero. */
 208.725 +
 208.726 +static int cmir_ineq(const int n, const double a[], const double b,
 208.727 +      const double u[], const char cset[], const double delta,
 208.728 +      double alpha[], double *beta, double *gamma)
 208.729 +{     int j;
 208.730 +      double *aa, bb;
 208.731 +      aa = alpha, bb = b;
 208.732 +      for (j = 1; j <= n; j++)
 208.733 +      {  aa[j] = a[j] / delta;
 208.734 +         if (cset[j])
 208.735 +            aa[j] = - aa[j], bb -= a[j] * u[j];
 208.736 +      }
 208.737 +      bb /= delta;
 208.738 +      if (mir_ineq(n, aa, bb, alpha, beta, gamma)) return 1;
 208.739 +      for (j = 1; j <= n; j++)
 208.740 +      {  if (cset[j])
 208.741 +            alpha[j] = - alpha[j], *beta += alpha[j] * u[j];
 208.742 +      }
 208.743 +      *gamma /= delta;
 208.744 +      return 0;
 208.745 +}
 208.746 +
 208.747 +/***********************************************************************
 208.748 +*  cmir_sep - c-MIR separation heuristic
 208.749 +*
 208.750 +*  Given the mixed knapsack set
 208.751 +*
 208.752 +*      MK              |N|
 208.753 +*     X   = {(x,s) in Z    x R  : sum   a[j] * x[j] <= b + s,
 208.754 +*                      +      +  j in N
 208.755 +*
 208.756 +*             x[j] <= u[j]}
 208.757 +*
 208.758 +*                           *   *
 208.759 +*  and a fractional point (x , s ), this routine tries to construct
 208.760 +*  c-MIR inequality
 208.761 +*
 208.762 +*     sum   alpha[j] * x[j] <= beta + gamma * s,
 208.763 +*    j in N
 208.764 +*                      MK
 208.765 +*  which is valid for X   and has (desirably maximal) violation at the
 208.766 +*  fractional point given. This is attained by choosing an appropriate
 208.767 +*  set C of variables to be complemented and a divisor delta > 0, which
 208.768 +*  together define corresponding c-MIR inequality.
 208.769 +*
 208.770 +*  If a violated c-MIR inequality has been successfully constructed,
 208.771 +*  the routine returns its violation:
 208.772 +*
 208.773 +*                       *                      *
 208.774 +*     sum   alpha[j] * x [j] - beta - gamma * s ,
 208.775 +*    j in N
 208.776 +*
 208.777 +*  which is positive. In case of failure the routine returns zero. */
 208.778 +
 208.779 +struct vset { int j; double v; };
 208.780 +
 208.781 +static int cmir_cmp(const void *p1, const void *p2)
 208.782 +{     const struct vset *v1 = p1, *v2 = p2;
 208.783 +      if (v1->v < v2->v) return -1;
 208.784 +      if (v1->v > v2->v) return +1;
 208.785 +      return 0;
 208.786 +}
 208.787 +
 208.788 +static double cmir_sep(const int n, const double a[], const double b,
 208.789 +      const double u[], const double x[], const double s,
 208.790 +      double alpha[], double *beta, double *gamma)
 208.791 +{     int fail, j, k, nv, v;
 208.792 +      double delta, eps, d_try[1+3], r, r_best;
 208.793 +      char *cset;
 208.794 +      struct vset *vset;
 208.795 +      /* allocate working arrays */
 208.796 +      cset = xcalloc(1+n, sizeof(char));
 208.797 +      vset = xcalloc(1+n, sizeof(struct vset));
 208.798 +      /* choose initial C */
 208.799 +      for (j = 1; j <= n; j++)
 208.800 +         cset[j] = (char)(x[j] >= 0.5 * u[j]);
 208.801 +      /* choose initial delta */
 208.802 +      r_best = delta = 0.0;
 208.803 +      for (j = 1; j <= n; j++)
 208.804 +      {  xassert(a[j] != 0.0);
 208.805 +         /* if x[j] is close to its bounds, skip it */
 208.806 +         eps = 1e-9 * (1.0 + fabs(u[j]));
 208.807 +         if (x[j] < eps || x[j] > u[j] - eps) continue;
 208.808 +         /* try delta = |a[j]| to construct c-MIR inequality */
 208.809 +         fail = cmir_ineq(n, a, b, u, cset, fabs(a[j]), alpha, beta,
 208.810 +            gamma);
 208.811 +         if (fail) continue;
 208.812 +         /* compute violation */
 208.813 +         r = - (*beta) - (*gamma) * s;
 208.814 +         for (k = 1; k <= n; k++) r += alpha[k] * x[k];
 208.815 +         if (r_best < r) r_best = r, delta = fabs(a[j]);
 208.816 +      }
 208.817 +      if (r_best < 0.001) r_best = 0.0;
 208.818 +      if (r_best == 0.0) goto done;
 208.819 +      xassert(delta > 0.0);
 208.820 +      /* try to increase violation by dividing delta by 2, 4, and 8,
 208.821 +         respectively */
 208.822 +      d_try[1] = delta / 2.0;
 208.823 +      d_try[2] = delta / 4.0;
 208.824 +      d_try[3] = delta / 8.0;
 208.825 +      for (j = 1; j <= 3; j++)
 208.826 +      {  /* construct c-MIR inequality */
 208.827 +         fail = cmir_ineq(n, a, b, u, cset, d_try[j], alpha, beta,
 208.828 +            gamma);
 208.829 +         if (fail) continue;
 208.830 +         /* compute violation */
 208.831 +         r = - (*beta) - (*gamma) * s;
 208.832 +         for (k = 1; k <= n; k++) r += alpha[k] * x[k];
 208.833 +         if (r_best < r) r_best = r, delta = d_try[j];
 208.834 +      }
 208.835 +      /* build subset of variables lying strictly between their bounds
 208.836 +         and order it by nondecreasing values of |x[j] - u[j]/2| */
 208.837 +      nv = 0;
 208.838 +      for (j = 1; j <= n; j++)
 208.839 +      {  /* if x[j] is close to its bounds, skip it */
 208.840 +         eps = 1e-9 * (1.0 + fabs(u[j]));
 208.841 +         if (x[j] < eps || x[j] > u[j] - eps) continue;
 208.842 +         /* add x[j] to the subset */
 208.843 +         nv++;
 208.844 +         vset[nv].j = j;
 208.845 +         vset[nv].v = fabs(x[j] - 0.5 * u[j]);
 208.846 +      }
 208.847 +      qsort(&vset[1], nv, sizeof(struct vset), cmir_cmp);
 208.848 +      /* try to increase violation by successively complementing each
 208.849 +         variable in the subset */
 208.850 +      for (v = 1; v <= nv; v++)
 208.851 +      {  j = vset[v].j;
 208.852 +         /* replace x[j] by its complement or vice versa */
 208.853 +         cset[j] = (char)!cset[j];
 208.854 +         /* construct c-MIR inequality */
 208.855 +         fail = cmir_ineq(n, a, b, u, cset, delta, alpha, beta, gamma);
 208.856 +         /* restore the variable */
 208.857 +         cset[j] = (char)!cset[j];
 208.858 +         /* do not replace the variable in case of failure */
 208.859 +         if (fail) continue;
 208.860 +         /* compute violation */
 208.861 +         r = - (*beta) - (*gamma) * s;
 208.862 +         for (k = 1; k <= n; k++) r += alpha[k] * x[k];
 208.863 +         if (r_best < r) r_best = r, cset[j] = (char)!cset[j];
 208.864 +      }
 208.865 +      /* construct the best c-MIR inequality chosen */
 208.866 +      fail = cmir_ineq(n, a, b, u, cset, delta, alpha, beta, gamma);
 208.867 +      xassert(!fail);
 208.868 +done: /* free working arrays */
 208.869 +      xfree(cset);
 208.870 +      xfree(vset);
 208.871 +      /* return to the calling routine */
 208.872 +      return r_best;
 208.873 +}
 208.874 +
 208.875 +static double generate(struct MIR *mir)
 208.876 +{     /* try to generate violated c-MIR cut for modified constraint */
 208.877 +      int m = mir->m;
 208.878 +      int n = mir->n;
 208.879 +      int j, k, kk, nint;
 208.880 +      double s, *u, *x, *alpha, r_best = 0.0, b, beta, gamma;
 208.881 +      ios_copy_vec(mir->cut_vec, mir->mod_vec);
 208.882 +      mir->cut_rhs = mir->mod_rhs;
 208.883 +      /* remove small terms, which can appear due to substitution of
 208.884 +         variable bounds */
 208.885 +      ios_clean_vec(mir->cut_vec, DBL_EPSILON);
 208.886 +#if _MIR_DEBUG
 208.887 +      ios_check_vec(mir->cut_vec);
 208.888 +#endif
 208.889 +      /* remove positive continuous terms to obtain MK relaxation */
 208.890 +      for (j = 1; j <= mir->cut_vec->nnz; j++)
 208.891 +      {  k = mir->cut_vec->ind[j];
 208.892 +         xassert(1 <= k && k <= m+n);
 208.893 +         if (!mir->isint[k] && mir->cut_vec->val[j] > 0.0)
 208.894 +            mir->cut_vec->val[j] = 0.0;
 208.895 +      }
 208.896 +      ios_clean_vec(mir->cut_vec, 0.0);
 208.897 +#if _MIR_DEBUG
 208.898 +      ios_check_vec(mir->cut_vec);
 208.899 +#endif
 208.900 +      /* move integer terms to the beginning of the sparse vector and
 208.901 +         determine the number of integer variables */
 208.902 +      nint = 0;
 208.903 +      for (j = 1; j <= mir->cut_vec->nnz; j++)
 208.904 +      {  k = mir->cut_vec->ind[j];
 208.905 +         xassert(1 <= k && k <= m+n);
 208.906 +         if (mir->isint[k])
 208.907 +         {  double temp;
 208.908 +            nint++;
 208.909 +            /* interchange elements [nint] and [j] */
 208.910 +            kk = mir->cut_vec->ind[nint];
 208.911 +            mir->cut_vec->pos[k] = nint;
 208.912 +            mir->cut_vec->pos[kk] = j;
 208.913 +            mir->cut_vec->ind[nint] = k;
 208.914 +            mir->cut_vec->ind[j] = kk;
 208.915 +            temp = mir->cut_vec->val[nint];
 208.916 +            mir->cut_vec->val[nint] = mir->cut_vec->val[j];
 208.917 +            mir->cut_vec->val[j] = temp;
 208.918 +         }
 208.919 +      }
 208.920 +#if _MIR_DEBUG
 208.921 +      ios_check_vec(mir->cut_vec);
 208.922 +#endif
 208.923 +      /* if there is no integer variable, nothing to generate */
 208.924 +      if (nint == 0) goto done;
 208.925 +      /* allocate working arrays */
 208.926 +      u = xcalloc(1+nint, sizeof(double));
 208.927 +      x = xcalloc(1+nint, sizeof(double));
 208.928 +      alpha = xcalloc(1+nint, sizeof(double));
 208.929 +      /* determine u and x */
 208.930 +      for (j = 1; j <= nint; j++)
 208.931 +      {  k = mir->cut_vec->ind[j];
 208.932 +         xassert(m+1 <= k && k <= m+n);
 208.933 +         xassert(mir->isint[k]);
 208.934 +         u[j] = mir->ub[k] - mir->lb[k];
 208.935 +         xassert(u[j] >= 1.0);
 208.936 +         if (mir->subst[k] == 'L')
 208.937 +            x[j] = mir->x[k] - mir->lb[k];
 208.938 +         else if (mir->subst[k] == 'U')
 208.939 +            x[j] = mir->ub[k] - mir->x[k];
 208.940 +         else
 208.941 +            xassert(k != k);
 208.942 +         xassert(x[j] >= -0.001);
 208.943 +         if (x[j] < 0.0) x[j] = 0.0;
 208.944 +      }
 208.945 +      /* compute s = - sum of continuous terms */
 208.946 +      s = 0.0;
 208.947 +      for (j = nint+1; j <= mir->cut_vec->nnz; j++)
 208.948 +      {  double x;
 208.949 +         k = mir->cut_vec->ind[j];
 208.950 +         xassert(1 <= k && k <= m+n);
 208.951 +         /* must be continuous */
 208.952 +         xassert(!mir->isint[k]);
 208.953 +         if (mir->subst[k] == 'L')
 208.954 +         {  xassert(mir->lb[k] != -DBL_MAX);
 208.955 +            kk = mir->vlb[k];
 208.956 +            if (kk == 0)
 208.957 +               x = mir->x[k] - mir->lb[k];
 208.958 +            else
 208.959 +               x = mir->x[k] - mir->lb[k] * mir->x[kk];
 208.960 +         }
 208.961 +         else if (mir->subst[k] == 'U')
 208.962 +         {  xassert(mir->ub[k] != +DBL_MAX);
 208.963 +            kk = mir->vub[k];
 208.964 +            if (kk == 0)
 208.965 +               x = mir->ub[k] - mir->x[k];
 208.966 +            else
 208.967 +               x = mir->ub[k] * mir->x[kk] - mir->x[k];
 208.968 +         }
 208.969 +         else
 208.970 +            xassert(k != k);
 208.971 +         xassert(x >= -0.001);
 208.972 +         if (x < 0.0) x = 0.0;
 208.973 +         s -= mir->cut_vec->val[j] * x;
 208.974 +      }
 208.975 +      xassert(s >= 0.0);
 208.976 +      /* apply heuristic to obtain most violated c-MIR inequality */
 208.977 +      b = mir->cut_rhs;
 208.978 +      r_best = cmir_sep(nint, mir->cut_vec->val, b, u, x, s, alpha,
 208.979 +         &beta, &gamma);
 208.980 +      if (r_best == 0.0) goto skip;
 208.981 +      xassert(r_best > 0.0);
 208.982 +      /* convert to raw cut */
 208.983 +      /* sum alpha[j] * x[j] <= beta + gamma * s */
 208.984 +      for (j = 1; j <= nint; j++)
 208.985 +         mir->cut_vec->val[j] = alpha[j];
 208.986 +      for (j = nint+1; j <= mir->cut_vec->nnz; j++)
 208.987 +      {  k = mir->cut_vec->ind[j];
 208.988 +         if (k <= m+n) mir->cut_vec->val[j] *= gamma;
 208.989 +      }
 208.990 +      mir->cut_rhs = beta;
 208.991 +#if _MIR_DEBUG
 208.992 +      ios_check_vec(mir->cut_vec);
 208.993 +#endif
 208.994 +skip: /* free working arrays */
 208.995 +      xfree(u);
 208.996 +      xfree(x);
 208.997 +      xfree(alpha);
 208.998 +done: return r_best;
 208.999 +}
208.1000 +
208.1001 +#if _MIR_DEBUG
208.1002 +static void check_raw_cut(struct MIR *mir, double r_best)
208.1003 +{     /* check raw cut before back bound substitution */
208.1004 +      int m = mir->m;
208.1005 +      int n = mir->n;
208.1006 +      int j, k, kk;
208.1007 +      double r, big, x;
208.1008 +      /* compute the residual r = sum a[k] * x[k] - b and determine
208.1009 +         big = max(1, |a[k]|, |b|) */
208.1010 +      r = 0.0, big = 1.0;
208.1011 +      for (j = 1; j <= mir->cut_vec->nnz; j++)
208.1012 +      {  k = mir->cut_vec->ind[j];
208.1013 +         xassert(1 <= k && k <= m+n);
208.1014 +         if (mir->subst[k] == 'L')
208.1015 +         {  xassert(mir->lb[k] != -DBL_MAX);
208.1016 +            kk = mir->vlb[k];
208.1017 +            if (kk == 0)
208.1018 +               x = mir->x[k] - mir->lb[k];
208.1019 +            else
208.1020 +               x = mir->x[k] - mir->lb[k] * mir->x[kk];
208.1021 +         }
208.1022 +         else if (mir->subst[k] == 'U')
208.1023 +         {  xassert(mir->ub[k] != +DBL_MAX);
208.1024 +            kk = mir->vub[k];
208.1025 +            if (kk == 0)
208.1026 +               x = mir->ub[k] - mir->x[k];
208.1027 +            else
208.1028 +               x = mir->ub[k] * mir->x[kk] - mir->x[k];
208.1029 +         }
208.1030 +         else
208.1031 +            xassert(k != k);
208.1032 +         r += mir->cut_vec->val[j] * x;
208.1033 +         if (big < fabs(mir->cut_vec->val[j]))
208.1034 +            big = fabs(mir->cut_vec->val[j]);
208.1035 +      }
208.1036 +      r -= mir->cut_rhs;
208.1037 +      if (big < fabs(mir->cut_rhs))
208.1038 +         big = fabs(mir->cut_rhs);
208.1039 +      /* the residual must be close to r_best */
208.1040 +      xassert(fabs(r - r_best) <= 1e-6 * big);
208.1041 +      return;
208.1042 +}
208.1043 +#endif
208.1044 +
208.1045 +static void back_subst(struct MIR *mir)
208.1046 +{     /* back substitution of original bounds */
208.1047 +      int m = mir->m;
208.1048 +      int n = mir->n;
208.1049 +      int j, jj, k, kk;
208.1050 +      /* at first, restore bounds of integer variables (because on
208.1051 +         restoring variable bounds of continuous variables we need
208.1052 +         original, not shifted, bounds of integer variables) */
208.1053 +      for (j = 1; j <= mir->cut_vec->nnz; j++)
208.1054 +      {  k = mir->cut_vec->ind[j];
208.1055 +         xassert(1 <= k && k <= m+n);
208.1056 +         if (!mir->isint[k]) continue; /* skip continuous */
208.1057 +         if (mir->subst[k] == 'L')
208.1058 +         {  /* x'[k] = x[k] - lb[k] */
208.1059 +            xassert(mir->lb[k] != -DBL_MAX);
208.1060 +            xassert(mir->vlb[k] == 0);
208.1061 +            mir->cut_rhs += mir->cut_vec->val[j] * mir->lb[k];
208.1062 +         }
208.1063 +         else if (mir->subst[k] == 'U')
208.1064 +         {  /* x'[k] = ub[k] - x[k] */
208.1065 +            xassert(mir->ub[k] != +DBL_MAX);
208.1066 +            xassert(mir->vub[k] == 0);
208.1067 +            mir->cut_rhs -= mir->cut_vec->val[j] * mir->ub[k];
208.1068 +            mir->cut_vec->val[j] = - mir->cut_vec->val[j];
208.1069 +         }
208.1070 +         else
208.1071 +            xassert(k != k);
208.1072 +      }
208.1073 +      /* now restore bounds of continuous variables */
208.1074 +      for (j = 1; j <= mir->cut_vec->nnz; j++)
208.1075 +      {  k = mir->cut_vec->ind[j];
208.1076 +         xassert(1 <= k && k <= m+n);
208.1077 +         if (mir->isint[k]) continue; /* skip integer */
208.1078 +         if (mir->subst[k] == 'L')
208.1079 +         {  /* x'[k] = x[k] - (lower bound) */
208.1080 +            xassert(mir->lb[k] != -DBL_MAX);
208.1081 +            kk = mir->vlb[k];
208.1082 +            if (kk == 0)
208.1083 +            {  /* x'[k] = x[k] - lb[k] */
208.1084 +               mir->cut_rhs += mir->cut_vec->val[j] * mir->lb[k];
208.1085 +            }
208.1086 +            else
208.1087 +            {  /* x'[k] = x[k] - lb[k] * x[kk] */
208.1088 +               jj = mir->cut_vec->pos[kk];
208.1089 +#if 0
208.1090 +               xassert(jj != 0);
208.1091 +#else
208.1092 +               if (jj == 0)
208.1093 +               {  ios_set_vj(mir->cut_vec, kk, 1.0);
208.1094 +                  jj = mir->cut_vec->pos[kk];
208.1095 +                  xassert(jj != 0);
208.1096 +                  mir->cut_vec->val[jj] = 0.0;
208.1097 +               }
208.1098 +#endif
208.1099 +               mir->cut_vec->val[jj] -= mir->cut_vec->val[j] *
208.1100 +                  mir->lb[k];
208.1101 +            }
208.1102 +         }
208.1103 +         else if (mir->subst[k] == 'U')
208.1104 +         {  /* x'[k] = (upper bound) - x[k] */
208.1105 +            xassert(mir->ub[k] != +DBL_MAX);
208.1106 +            kk = mir->vub[k];
208.1107 +            if (kk == 0)
208.1108 +            {  /* x'[k] = ub[k] - x[k] */
208.1109 +               mir->cut_rhs -= mir->cut_vec->val[j] * mir->ub[k];
208.1110 +            }
208.1111 +            else
208.1112 +            {  /* x'[k] = ub[k] * x[kk] - x[k] */
208.1113 +               jj = mir->cut_vec->pos[kk];
208.1114 +               if (jj == 0)
208.1115 +               {  ios_set_vj(mir->cut_vec, kk, 1.0);
208.1116 +                  jj = mir->cut_vec->pos[kk];
208.1117 +                  xassert(jj != 0);
208.1118 +                  mir->cut_vec->val[jj] = 0.0;
208.1119 +               }
208.1120 +               mir->cut_vec->val[jj] += mir->cut_vec->val[j] *
208.1121 +                  mir->ub[k];
208.1122 +            }
208.1123 +            mir->cut_vec->val[j] = - mir->cut_vec->val[j];
208.1124 +         }
208.1125 +         else
208.1126 +            xassert(k != k);
208.1127 +      }
208.1128 +#if _MIR_DEBUG
208.1129 +      ios_check_vec(mir->cut_vec);
208.1130 +#endif
208.1131 +      return;
208.1132 +}
208.1133 +
208.1134 +#if _MIR_DEBUG
208.1135 +static void check_cut_row(struct MIR *mir, double r_best)
208.1136 +{     /* check the cut after back bound substitution or elimination of
208.1137 +         auxiliary variables */
208.1138 +      int m = mir->m;
208.1139 +      int n = mir->n;
208.1140 +      int j, k;
208.1141 +      double r, big;
208.1142 +      /* compute the residual r = sum a[k] * x[k] - b and determine
208.1143 +         big = max(1, |a[k]|, |b|) */
208.1144 +      r = 0.0, big = 1.0;
208.1145 +      for (j = 1; j <= mir->cut_vec->nnz; j++)
208.1146 +      {  k = mir->cut_vec->ind[j];
208.1147 +         xassert(1 <= k && k <= m+n);
208.1148 +         r += mir->cut_vec->val[j] * mir->x[k];
208.1149 +         if (big < fabs(mir->cut_vec->val[j]))
208.1150 +            big = fabs(mir->cut_vec->val[j]);
208.1151 +      }
208.1152 +      r -= mir->cut_rhs;
208.1153 +      if (big < fabs(mir->cut_rhs))
208.1154 +         big = fabs(mir->cut_rhs);
208.1155 +      /* the residual must be close to r_best */
208.1156 +      xassert(fabs(r - r_best) <= 1e-6 * big);
208.1157 +      return;
208.1158 +}
208.1159 +#endif
208.1160 +
208.1161 +static void subst_aux_vars(glp_tree *tree, struct MIR *mir)
208.1162 +{     /* final substitution to eliminate auxiliary variables */
208.1163 +      glp_prob *mip = tree->mip;
208.1164 +      int m = mir->m;
208.1165 +      int n = mir->n;
208.1166 +      GLPAIJ *aij;
208.1167 +      int j, k, kk, jj;
208.1168 +      for (j = mir->cut_vec->nnz; j >= 1; j--)
208.1169 +      {  k = mir->cut_vec->ind[j];
208.1170 +         xassert(1 <= k && k <= m+n);
208.1171 +         if (k > m) continue; /* skip structurals */
208.1172 +         for (aij = mip->row[k]->ptr; aij != NULL; aij = aij->r_next)
208.1173 +         {  kk = m + aij->col->j; /* structural */
208.1174 +            jj = mir->cut_vec->pos[kk];
208.1175 +            if (jj == 0)
208.1176 +            {  ios_set_vj(mir->cut_vec, kk, 1.0);
208.1177 +               jj = mir->cut_vec->pos[kk];
208.1178 +               mir->cut_vec->val[jj] = 0.0;
208.1179 +            }
208.1180 +            mir->cut_vec->val[jj] += mir->cut_vec->val[j] * aij->val;
208.1181 +         }
208.1182 +         mir->cut_vec->val[j] = 0.0;
208.1183 +      }
208.1184 +      ios_clean_vec(mir->cut_vec, 0.0);
208.1185 +      return;
208.1186 +}
208.1187 +
208.1188 +static void add_cut(glp_tree *tree, struct MIR *mir)
208.1189 +{     /* add constructed cut inequality to the cut pool */
208.1190 +      int m = mir->m;
208.1191 +      int n = mir->n;
208.1192 +      int j, k, len;
208.1193 +      int *ind = xcalloc(1+n, sizeof(int));
208.1194 +      double *val = xcalloc(1+n, sizeof(double));
208.1195 +      len = 0;
208.1196 +      for (j = mir->cut_vec->nnz; j >= 1; j--)
208.1197 +      {  k = mir->cut_vec->ind[j];
208.1198 +         xassert(m+1 <= k && k <= m+n);
208.1199 +         len++, ind[len] = k - m, val[len] = mir->cut_vec->val[j];
208.1200 +      }
208.1201 +#if 0
208.1202 +      ios_add_cut_row(tree, pool, GLP_RF_MIR, len, ind, val, GLP_UP,
208.1203 +         mir->cut_rhs);
208.1204 +#else
208.1205 +      glp_ios_add_row(tree, NULL, GLP_RF_MIR, 0, len, ind, val, GLP_UP,
208.1206 +         mir->cut_rhs);
208.1207 +#endif
208.1208 +      xfree(ind);
208.1209 +      xfree(val);
208.1210 +      return;
208.1211 +}
208.1212 +
208.1213 +static int aggregate_row(glp_tree *tree, struct MIR *mir)
208.1214 +{     /* try to aggregate another row */
208.1215 +      glp_prob *mip = tree->mip;
208.1216 +      int m = mir->m;
208.1217 +      int n = mir->n;
208.1218 +      GLPAIJ *aij;
208.1219 +      IOSVEC *v;
208.1220 +      int ii, j, jj, k, kk, kappa = 0, ret = 0;
208.1221 +      double d1, d2, d, d_max = 0.0;
208.1222 +      /* choose appropriate structural variable in the aggregated row
208.1223 +         to be substituted */
208.1224 +      for (j = 1; j <= mir->agg_vec->nnz; j++)
208.1225 +      {  k = mir->agg_vec->ind[j];
208.1226 +         xassert(1 <= k && k <= m+n);
208.1227 +         if (k <= m) continue; /* skip auxiliary var */
208.1228 +         if (mir->isint[k]) continue; /* skip integer var */
208.1229 +         if (fabs(mir->agg_vec->val[j]) < 0.001) continue;
208.1230 +         /* compute distance from x[k] to its lower bound */
208.1231 +         kk = mir->vlb[k];
208.1232 +         if (kk == 0)
208.1233 +         {  if (mir->lb[k] == -DBL_MAX)
208.1234 +               d1 = DBL_MAX;
208.1235 +            else
208.1236 +               d1 = mir->x[k] - mir->lb[k];
208.1237 +         }
208.1238 +         else
208.1239 +         {  xassert(1 <= kk && kk <= m+n);
208.1240 +            xassert(mir->isint[kk]);
208.1241 +            xassert(mir->lb[k] != -DBL_MAX);
208.1242 +            d1 = mir->x[k] - mir->lb[k] * mir->x[kk];
208.1243 +         }
208.1244 +         /* compute distance from x[k] to its upper bound */
208.1245 +         kk = mir->vub[k];
208.1246 +         if (kk == 0)
208.1247 +         {  if (mir->vub[k] == +DBL_MAX)
208.1248 +               d2 = DBL_MAX;
208.1249 +            else
208.1250 +               d2 = mir->ub[k] - mir->x[k];
208.1251 +         }
208.1252 +         else
208.1253 +         {  xassert(1 <= kk && kk <= m+n);
208.1254 +            xassert(mir->isint[kk]);
208.1255 +            xassert(mir->ub[k] != +DBL_MAX);
208.1256 +            d2 = mir->ub[k] * mir->x[kk] - mir->x[k];
208.1257 +         }
208.1258 +         /* x[k] cannot be free */
208.1259 +         xassert(d1 != DBL_MAX || d2 != DBL_MAX);
208.1260 +         /* d = min(d1, d2) */
208.1261 +         d = (d1 <= d2 ? d1 : d2);
208.1262 +         xassert(d != DBL_MAX);
208.1263 +         /* should not be close to corresponding bound */
208.1264 +         if (d < 0.001) continue;
208.1265 +         if (d_max < d) d_max = d, kappa = k;
208.1266 +      }
208.1267 +      if (kappa == 0)
208.1268 +      {  /* nothing chosen */
208.1269 +         ret = 1;
208.1270 +         goto done;
208.1271 +      }
208.1272 +      /* x[kappa] has been chosen */
208.1273 +      xassert(m+1 <= kappa && kappa <= m+n);
208.1274 +      xassert(!mir->isint[kappa]);
208.1275 +      /* find another row, which have not been used yet, to eliminate
208.1276 +         x[kappa] from the aggregated row */
208.1277 +      for (ii = 1; ii <= m; ii++)
208.1278 +      {  if (mir->skip[ii]) continue;
208.1279 +         for (aij = mip->row[ii]->ptr; aij != NULL; aij = aij->r_next)
208.1280 +            if (aij->col->j == kappa - m) break;
208.1281 +         if (aij != NULL && fabs(aij->val) >= 0.001) break;
208.1282 +      }
208.1283 +      if (ii > m)
208.1284 +      {  /* nothing found */
208.1285 +         ret = 2;
208.1286 +         goto done;
208.1287 +      }
208.1288 +      /* row ii has been found; include it in the aggregated list */
208.1289 +      mir->agg_cnt++;
208.1290 +      xassert(mir->agg_cnt <= MAXAGGR);
208.1291 +      mir->agg_row[mir->agg_cnt] = ii;
208.1292 +      mir->skip[ii] = 2;
208.1293 +      /* v := new row */
208.1294 +      v = ios_create_vec(m+n);
208.1295 +      ios_set_vj(v, ii, 1.0);
208.1296 +      for (aij = mip->row[ii]->ptr; aij != NULL; aij = aij->r_next)
208.1297 +         ios_set_vj(v, m + aij->col->j, - aij->val);
208.1298 +#if _MIR_DEBUG
208.1299 +      ios_check_vec(v);
208.1300 +#endif
208.1301 +      /* perform gaussian elimination to remove x[kappa] */
208.1302 +      j = mir->agg_vec->pos[kappa];
208.1303 +      xassert(j != 0);
208.1304 +      jj = v->pos[kappa];
208.1305 +      xassert(jj != 0);
208.1306 +      ios_linear_comb(mir->agg_vec,
208.1307 +         - mir->agg_vec->val[j] / v->val[jj], v);
208.1308 +      ios_delete_vec(v);
208.1309 +      ios_set_vj(mir->agg_vec, kappa, 0.0);
208.1310 +#if _MIR_DEBUG
208.1311 +      ios_check_vec(mir->agg_vec);
208.1312 +#endif
208.1313 +done: return ret;
208.1314 +}
208.1315 +
208.1316 +void ios_mir_gen(glp_tree *tree, void *gen)
208.1317 +{     /* main routine to generate MIR cuts */
208.1318 +      glp_prob *mip = tree->mip;
208.1319 +      struct MIR *mir = gen;
208.1320 +      int m = mir->m;
208.1321 +      int n = mir->n;
208.1322 +      int i;
208.1323 +      double r_best;
208.1324 +      xassert(mip->m >= m);
208.1325 +      xassert(mip->n == n);
208.1326 +      /* obtain current point */
208.1327 +      get_current_point(tree, mir);
208.1328 +#if _MIR_DEBUG
208.1329 +      /* check current point */
208.1330 +      check_current_point(mir);
208.1331 +#endif
208.1332 +      /* reset bound substitution flags */
208.1333 +      memset(&mir->subst[1], '?', m+n);
208.1334 +      /* try to generate a set of violated MIR cuts */
208.1335 +      for (i = 1; i <= m; i++)
208.1336 +      {  if (mir->skip[i]) continue;
208.1337 +         /* use original i-th row as initial aggregated constraint */
208.1338 +         initial_agg_row(tree, mir, i);
208.1339 +loop:    ;
208.1340 +#if _MIR_DEBUG
208.1341 +         /* check aggregated row */
208.1342 +         check_agg_row(mir);
208.1343 +#endif
208.1344 +         /* substitute fixed variables into aggregated constraint */
208.1345 +         subst_fixed_vars(mir);
208.1346 +#if _MIR_DEBUG
208.1347 +         /* check aggregated row */
208.1348 +         check_agg_row(mir);
208.1349 +#endif
208.1350 +#if _MIR_DEBUG
208.1351 +         /* check bound substitution flags */
208.1352 +         {  int k;
208.1353 +            for (k = 1; k <= m+n; k++)
208.1354 +               xassert(mir->subst[k] == '?');
208.1355 +         }
208.1356 +#endif
208.1357 +         /* apply bound substitution heuristic */
208.1358 +         bound_subst_heur(mir);
208.1359 +         /* substitute bounds and build modified constraint */
208.1360 +         build_mod_row(mir);
208.1361 +#if _MIR_DEBUG
208.1362 +         /* check modified row */
208.1363 +         check_mod_row(mir);
208.1364 +#endif
208.1365 +         /* try to generate violated c-MIR cut for modified row */
208.1366 +         r_best = generate(mir);
208.1367 +         if (r_best > 0.0)
208.1368 +         {  /* success */
208.1369 +#if _MIR_DEBUG
208.1370 +            /* check raw cut before back bound substitution */
208.1371 +            check_raw_cut(mir, r_best);
208.1372 +#endif
208.1373 +            /* back substitution of original bounds */
208.1374 +            back_subst(mir);
208.1375 +#if _MIR_DEBUG
208.1376 +            /* check the cut after back bound substitution */
208.1377 +            check_cut_row(mir, r_best);
208.1378 +#endif
208.1379 +            /* final substitution to eliminate auxiliary variables */
208.1380 +            subst_aux_vars(tree, mir);
208.1381 +#if _MIR_DEBUG
208.1382 +            /* check the cut after elimination of auxiliaries */
208.1383 +            check_cut_row(mir, r_best);
208.1384 +#endif
208.1385 +            /* add constructed cut inequality to the cut pool */
208.1386 +            add_cut(tree, mir);
208.1387 +         }
208.1388 +         /* reset bound substitution flags */
208.1389 +         {  int j, k;
208.1390 +            for (j = 1; j <= mir->mod_vec->nnz; j++)
208.1391 +            {  k = mir->mod_vec->ind[j];
208.1392 +               xassert(1 <= k && k <= m+n);
208.1393 +               xassert(mir->subst[k] != '?');
208.1394 +               mir->subst[k] = '?';
208.1395 +            }
208.1396 +         }
208.1397 +         if (r_best == 0.0)
208.1398 +         {  /* failure */
208.1399 +            if (mir->agg_cnt < MAXAGGR)
208.1400 +            {  /* try to aggregate another row */
208.1401 +               if (aggregate_row(tree, mir) == 0) goto loop;
208.1402 +            }
208.1403 +         }
208.1404 +         /* unmark rows used in the aggregated constraint */
208.1405 +         {  int k, ii;
208.1406 +            for (k = 1; k <= mir->agg_cnt; k++)
208.1407 +            {  ii = mir->agg_row[k];
208.1408 +               xassert(1 <= ii && ii <= m);
208.1409 +               xassert(mir->skip[ii] == 2);
208.1410 +               mir->skip[ii] = 0;
208.1411 +            }
208.1412 +         }
208.1413 +      }
208.1414 +      return;
208.1415 +}
208.1416 +
208.1417 +/***********************************************************************
208.1418 +*  NAME
208.1419 +*
208.1420 +*  ios_mir_term - terminate MIR cut generator
208.1421 +*
208.1422 +*  SYNOPSIS
208.1423 +*
208.1424 +*  #include "glpios.h"
208.1425 +*  void ios_mir_term(void *gen);
208.1426 +*
208.1427 +*  DESCRIPTION
208.1428 +*
208.1429 +*  The routine ios_mir_term deletes the MIR cut generator working area
208.1430 +*  freeing all the memory allocated to it. */
208.1431 +
208.1432 +void ios_mir_term(void *gen)
208.1433 +{     struct MIR *mir = gen;
208.1434 +      xfree(mir->skip);
208.1435 +      xfree(mir->isint);
208.1436 +      xfree(mir->lb);
208.1437 +      xfree(mir->vlb);
208.1438 +      xfree(mir->ub);
208.1439 +      xfree(mir->vub);
208.1440 +      xfree(mir->x);
208.1441 +      xfree(mir->agg_row);
208.1442 +      ios_delete_vec(mir->agg_vec);
208.1443 +      xfree(mir->subst);
208.1444 +      ios_delete_vec(mir->mod_vec);
208.1445 +      ios_delete_vec(mir->cut_vec);
208.1446 +      xfree(mir);
208.1447 +      return;
208.1448 +}
208.1449 +
208.1450 +/* eof */
   209.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   209.2 +++ b/src/glpios07.c	Mon Dec 06 13:09:21 2010 +0100
   209.3 @@ -0,0 +1,554 @@
   209.4 +/* glpios07.c (mixed cover cut generator) */
   209.5 +
   209.6 +/***********************************************************************
   209.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   209.8 +*
   209.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  209.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  209.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  209.12 +*  E-mail: <mao@gnu.org>.
  209.13 +*
  209.14 +*  GLPK is free software: you can redistribute it and/or modify it
  209.15 +*  under the terms of the GNU General Public License as published by
  209.16 +*  the Free Software Foundation, either version 3 of the License, or
  209.17 +*  (at your option) any later version.
  209.18 +*
  209.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  209.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  209.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  209.22 +*  License for more details.
  209.23 +*
  209.24 +*  You should have received a copy of the GNU General Public License
  209.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  209.26 +***********************************************************************/
  209.27 +
  209.28 +#include "glpios.h"
  209.29 +
  209.30 +/*----------------------------------------------------------------------
  209.31 +-- COVER INEQUALITIES
  209.32 +--
  209.33 +-- Consider the set of feasible solutions to 0-1 knapsack problem:
  209.34 +--
  209.35 +--    sum a[j]*x[j] <= b,                                            (1)
  209.36 +--  j in J
  209.37 +--
  209.38 +--    x[j] is binary,                                                (2)
  209.39 +--
  209.40 +-- where, wlog, we assume that a[j] > 0 (since 0-1 variables can be
  209.41 +-- complemented) and a[j] <= b (since a[j] > b implies x[j] = 0).
  209.42 +--
  209.43 +-- A set C within J is called a cover if
  209.44 +--
  209.45 +--    sum a[j] > b.                                                  (3)
  209.46 +--  j in C
  209.47 +--
  209.48 +-- For any cover C the inequality
  209.49 +--
  209.50 +--    sum x[j] <= |C| - 1                                            (4)
  209.51 +--  j in C
  209.52 +--
  209.53 +-- is called a cover inequality and is valid for (1)-(2).
  209.54 +--
  209.55 +-- MIXED COVER INEQUALITIES
  209.56 +--
  209.57 +-- Consider the set of feasible solutions to mixed knapsack problem:
  209.58 +--
  209.59 +--    sum a[j]*x[j] + y <= b,                                        (5)
  209.60 +--  j in J
  209.61 +--
  209.62 +--    x[j] is binary,                                                (6)
  209.63 +--
  209.64 +--    0 <= y <= u is continuous,                                     (7)
  209.65 +--
  209.66 +-- where again we assume that a[j] > 0.
  209.67 +--
  209.68 +-- Let C within J be some set. From (1)-(4) it follows that
  209.69 +--
  209.70 +--    sum a[j] > b - y                                               (8)
  209.71 +--  j in C
  209.72 +--
  209.73 +-- implies
  209.74 +--
  209.75 +--    sum x[j] <= |C| - 1.                                           (9)
  209.76 +--  j in C
  209.77 +--
  209.78 +-- Thus, we need to modify the inequality (9) in such a way that it be
  209.79 +-- a constraint only if the condition (8) is satisfied.
  209.80 +--
  209.81 +-- Consider the following inequality:
  209.82 +--
  209.83 +--    sum x[j] <= |C| - t.                                          (10)
  209.84 +--  j in C
  209.85 +--
  209.86 +-- If 0 < t <= 1, then (10) is equivalent to (9), because all x[j] are
  209.87 +-- binary variables. On the other hand, if t <= 0, (10) being satisfied
  209.88 +-- for any values of x[j] is not a constraint.
  209.89 +--
  209.90 +-- Let
  209.91 +--
  209.92 +--    t' = sum a[j] + y - b.                                        (11)
  209.93 +--       j in C
  209.94 +--
  209.95 +-- It is understood that the condition t' > 0 is equivalent to (8).
  209.96 +-- Besides, from (6)-(7) it follows that t' has an implied upper bound:
  209.97 +--
  209.98 +--    t'max = sum a[j] + u - b.                                     (12)
  209.99 +--          j in C
 209.100 +--
 209.101 +-- This allows to express the parameter t having desired properties:
 209.102 +--
 209.103 +--    t = t' / t'max.                                               (13)
 209.104 +--
 209.105 +-- In fact, t <= 1 by definition, and t > 0 being equivalent to t' > 0
 209.106 +-- is equivalent to (8).
 209.107 +--
 209.108 +-- Thus, the inequality (10), where t is given by formula (13) is valid
 209.109 +-- for (5)-(7).
 209.110 +--
 209.111 +-- Note that if u = 0, then y = 0, so t = 1, and the conditions (8) and
 209.112 +-- (10) is transformed to the conditions (3) and (4).
 209.113 +--
 209.114 +-- GENERATING MIXED COVER CUTS
 209.115 +--
 209.116 +-- To generate a mixed cover cut in the form (10) we need to find such
 209.117 +-- set C which satisfies to the inequality (8) and for which, in turn,
 209.118 +-- the inequality (10) is violated in the current point.
 209.119 +--
 209.120 +-- Substituting t from (13) to (10) gives:
 209.121 +--
 209.122 +--                        1
 209.123 +--    sum x[j] <= |C| - -----  (sum a[j] + y - b),                  (14)
 209.124 +--  j in C              t'max j in C
 209.125 +--
 209.126 +-- and finally we have the cut inequality in the standard form:
 209.127 +--
 209.128 +--    sum x[j] + alfa * y <= beta,                                  (15)
 209.129 +--  j in C
 209.130 +--
 209.131 +-- where:
 209.132 +--
 209.133 +--    alfa = 1 / t'max,                                             (16)
 209.134 +--
 209.135 +--    beta = |C| - alfa *  (sum a[j] - b).                          (17)
 209.136 +--                        j in C                                      */
 209.137 +
 209.138 +#if 1
 209.139 +#define MAXTRY 1000
 209.140 +#else
 209.141 +#define MAXTRY 10000
 209.142 +#endif
 209.143 +
 209.144 +static int cover2(int n, double a[], double b, double u, double x[],
 209.145 +      double y, int cov[], double *_alfa, double *_beta)
 209.146 +{     /* try to generate mixed cover cut using two-element cover */
 209.147 +      int i, j, try = 0, ret = 0;
 209.148 +      double eps, alfa, beta, temp, rmax = 0.001;
 209.149 +      eps = 0.001 * (1.0 + fabs(b));
 209.150 +      for (i = 0+1; i <= n; i++)
 209.151 +      for (j = i+1; j <= n; j++)
 209.152 +      {  /* C = {i, j} */
 209.153 +         try++;
 209.154 +         if (try > MAXTRY) goto done;
 209.155 +         /* check if condition (8) is satisfied */
 209.156 +         if (a[i] + a[j] + y > b + eps)
 209.157 +         {  /* compute parameters for inequality (15) */
 209.158 +            temp = a[i] + a[j] - b;
 209.159 +            alfa = 1.0 / (temp + u);
 209.160 +            beta = 2.0 - alfa * temp;
 209.161 +            /* compute violation of inequality (15) */
 209.162 +            temp = x[i] + x[j] + alfa * y - beta;
 209.163 +            /* choose C providing maximum violation */
 209.164 +            if (rmax < temp)
 209.165 +            {  rmax = temp;
 209.166 +               cov[1] = i;
 209.167 +               cov[2] = j;
 209.168 +               *_alfa = alfa;
 209.169 +               *_beta = beta;
 209.170 +               ret = 1;
 209.171 +            }
 209.172 +         }
 209.173 +      }
 209.174 +done: return ret;
 209.175 +}
 209.176 +
 209.177 +static int cover3(int n, double a[], double b, double u, double x[],
 209.178 +      double y, int cov[], double *_alfa, double *_beta)
 209.179 +{     /* try to generate mixed cover cut using three-element cover */
 209.180 +      int i, j, k, try = 0, ret = 0;
 209.181 +      double eps, alfa, beta, temp, rmax = 0.001;
 209.182 +      eps = 0.001 * (1.0 + fabs(b));
 209.183 +      for (i = 0+1; i <= n; i++)
 209.184 +      for (j = i+1; j <= n; j++)
 209.185 +      for (k = j+1; k <= n; k++)
 209.186 +      {  /* C = {i, j, k} */
 209.187 +         try++;
 209.188 +         if (try > MAXTRY) goto done;
 209.189 +         /* check if condition (8) is satisfied */
 209.190 +         if (a[i] + a[j] + a[k] + y > b + eps)
 209.191 +         {  /* compute parameters for inequality (15) */
 209.192 +            temp = a[i] + a[j] + a[k] - b;
 209.193 +            alfa = 1.0 / (temp + u);
 209.194 +            beta = 3.0 - alfa * temp;
 209.195 +            /* compute violation of inequality (15) */
 209.196 +            temp = x[i] + x[j] + x[k] + alfa * y - beta;
 209.197 +            /* choose C providing maximum violation */
 209.198 +            if (rmax < temp)
 209.199 +            {  rmax = temp;
 209.200 +               cov[1] = i;
 209.201 +               cov[2] = j;
 209.202 +               cov[3] = k;
 209.203 +               *_alfa = alfa;
 209.204 +               *_beta = beta;
 209.205 +               ret = 1;
 209.206 +            }
 209.207 +         }
 209.208 +      }
 209.209 +done: return ret;
 209.210 +}
 209.211 +
 209.212 +static int cover4(int n, double a[], double b, double u, double x[],
 209.213 +      double y, int cov[], double *_alfa, double *_beta)
 209.214 +{     /* try to generate mixed cover cut using four-element cover */
 209.215 +      int i, j, k, l, try = 0, ret = 0;
 209.216 +      double eps, alfa, beta, temp, rmax = 0.001;
 209.217 +      eps = 0.001 * (1.0 + fabs(b));
 209.218 +      for (i = 0+1; i <= n; i++)
 209.219 +      for (j = i+1; j <= n; j++)
 209.220 +      for (k = j+1; k <= n; k++)
 209.221 +      for (l = k+1; l <= n; l++)
 209.222 +      {  /* C = {i, j, k, l} */
 209.223 +         try++;
 209.224 +         if (try > MAXTRY) goto done;
 209.225 +         /* check if condition (8) is satisfied */
 209.226 +         if (a[i] + a[j] + a[k] + a[l] + y > b + eps)
 209.227 +         {  /* compute parameters for inequality (15) */
 209.228 +            temp = a[i] + a[j] + a[k] + a[l] - b;
 209.229 +            alfa = 1.0 / (temp + u);
 209.230 +            beta = 4.0 - alfa * temp;
 209.231 +            /* compute violation of inequality (15) */
 209.232 +            temp = x[i] + x[j] + x[k] + x[l] + alfa * y - beta;
 209.233 +            /* choose C providing maximum violation */
 209.234 +            if (rmax < temp)
 209.235 +            {  rmax = temp;
 209.236 +               cov[1] = i;
 209.237 +               cov[2] = j;
 209.238 +               cov[3] = k;
 209.239 +               cov[4] = l;
 209.240 +               *_alfa = alfa;
 209.241 +               *_beta = beta;
 209.242 +               ret = 1;
 209.243 +            }
 209.244 +         }
 209.245 +      }
 209.246 +done: return ret;
 209.247 +}
 209.248 +
 209.249 +static int cover(int n, double a[], double b, double u, double x[],
 209.250 +      double y, int cov[], double *alfa, double *beta)
 209.251 +{     /* try to generate mixed cover cut;
 209.252 +         input (see (5)):
 209.253 +         n        is the number of binary variables;
 209.254 +         a[1:n]   are coefficients at binary variables;
 209.255 +         b        is the right-hand side;
 209.256 +         u        is upper bound of continuous variable;
 209.257 +         x[1:n]   are values of binary variables at current point;
 209.258 +         y        is value of continuous variable at current point;
 209.259 +         output (see (15), (16), (17)):
 209.260 +         cov[1:r] are indices of binary variables included in cover C,
 209.261 +                  where r is the set cardinality returned on exit;
 209.262 +         alfa     coefficient at continuous variable;
 209.263 +         beta     is the right-hand side; */
 209.264 +      int j;
 209.265 +      /* perform some sanity checks */
 209.266 +      xassert(n >= 2);
 209.267 +      for (j = 1; j <= n; j++) xassert(a[j] > 0.0);
 209.268 +#if 1 /* ??? */
 209.269 +      xassert(b > -1e-5);
 209.270 +#else
 209.271 +      xassert(b > 0.0);
 209.272 +#endif
 209.273 +      xassert(u >= 0.0);
 209.274 +      for (j = 1; j <= n; j++) xassert(0.0 <= x[j] && x[j] <= 1.0);
 209.275 +      xassert(0.0 <= y && y <= u);
 209.276 +      /* try to generate mixed cover cut */
 209.277 +      if (cover2(n, a, b, u, x, y, cov, alfa, beta)) return 2;
 209.278 +      if (cover3(n, a, b, u, x, y, cov, alfa, beta)) return 3;
 209.279 +      if (cover4(n, a, b, u, x, y, cov, alfa, beta)) return 4;
 209.280 +      return 0;
 209.281 +}
 209.282 +
 209.283 +/*----------------------------------------------------------------------
 209.284 +-- lpx_cover_cut - generate mixed cover cut.
 209.285 +--
 209.286 +-- SYNOPSIS
 209.287 +--
 209.288 +-- #include "glplpx.h"
 209.289 +-- int lpx_cover_cut(LPX *lp, int len, int ind[], double val[],
 209.290 +--    double work[]);
 209.291 +--
 209.292 +-- DESCRIPTION
 209.293 +--
 209.294 +-- The routine lpx_cover_cut generates a mixed cover cut for a given
 209.295 +-- row of the MIP problem.
 209.296 +--
 209.297 +-- The given row of the MIP problem should be explicitly specified in
 209.298 +-- the form:
 209.299 +--
 209.300 +--    sum{j in J} a[j]*x[j] <= b.                                    (1)
 209.301 +--
 209.302 +-- On entry indices (ordinal numbers) of structural variables, which
 209.303 +-- have non-zero constraint coefficients, should be placed in locations
 209.304 +-- ind[1], ..., ind[len], and corresponding constraint coefficients
 209.305 +-- should be placed in locations val[1], ..., val[len]. The right-hand
 209.306 +-- side b should be stored in location val[0].
 209.307 +--
 209.308 +-- The working array work should have at least nb locations, where nb
 209.309 +-- is the number of binary variables in (1).
 209.310 +--
 209.311 +-- The routine generates a mixed cover cut in the same form as (1) and
 209.312 +-- stores the cut coefficients and right-hand side in the same way as
 209.313 +-- just described above.
 209.314 +--
 209.315 +-- RETURNS
 209.316 +--
 209.317 +-- If the cutting plane has been successfully generated, the routine
 209.318 +-- returns 1 <= len' <= n, which is the number of non-zero coefficients
 209.319 +-- in the inequality constraint. Otherwise, the routine returns zero. */
 209.320 +
 209.321 +static int lpx_cover_cut(LPX *lp, int len, int ind[], double val[],
 209.322 +      double work[])
 209.323 +{     int cov[1+4], j, k, nb, newlen, r;
 209.324 +      double f_min, f_max, alfa, beta, u, *x = work, y;
 209.325 +      /* substitute and remove fixed variables */
 209.326 +      newlen = 0;
 209.327 +      for (k = 1; k <= len; k++)
 209.328 +      {  j = ind[k];
 209.329 +         if (lpx_get_col_type(lp, j) == LPX_FX)
 209.330 +            val[0] -= val[k] * lpx_get_col_lb(lp, j);
 209.331 +         else
 209.332 +         {  newlen++;
 209.333 +            ind[newlen] = ind[k];
 209.334 +            val[newlen] = val[k];
 209.335 +         }
 209.336 +      }
 209.337 +      len = newlen;
 209.338 +      /* move binary variables to the beginning of the list so that
 209.339 +         elements 1, 2, ..., nb correspond to binary variables, and
 209.340 +         elements nb+1, nb+2, ..., len correspond to rest variables */
 209.341 +      nb = 0;
 209.342 +      for (k = 1; k <= len; k++)
 209.343 +      {  j = ind[k];
 209.344 +         if (lpx_get_col_kind(lp, j) == LPX_IV &&
 209.345 +             lpx_get_col_type(lp, j) == LPX_DB &&
 209.346 +             lpx_get_col_lb(lp, j) == 0.0 &&
 209.347 +             lpx_get_col_ub(lp, j) == 1.0)
 209.348 +         {  /* binary variable */
 209.349 +            int ind_k;
 209.350 +            double val_k;
 209.351 +            nb++;
 209.352 +            ind_k = ind[nb], val_k = val[nb];
 209.353 +            ind[nb] = ind[k], val[nb] = val[k];
 209.354 +            ind[k] = ind_k, val[k] = val_k;
 209.355 +         }
 209.356 +      }
 209.357 +      /* now the specified row has the form:
 209.358 +         sum a[j]*x[j] + sum a[j]*y[j] <= b,
 209.359 +         where x[j] are binary variables, y[j] are rest variables */
 209.360 +      /* at least two binary variables are needed */
 209.361 +      if (nb < 2) return 0;
 209.362 +      /* compute implied lower and upper bounds for sum a[j]*y[j] */
 209.363 +      f_min = f_max = 0.0;
 209.364 +      for (k = nb+1; k <= len; k++)
 209.365 +      {  j = ind[k];
 209.366 +         /* both bounds must be finite */
 209.367 +         if (lpx_get_col_type(lp, j) != LPX_DB) return 0;
 209.368 +         if (val[k] > 0.0)
 209.369 +         {  f_min += val[k] * lpx_get_col_lb(lp, j);
 209.370 +            f_max += val[k] * lpx_get_col_ub(lp, j);
 209.371 +         }
 209.372 +         else
 209.373 +         {  f_min += val[k] * lpx_get_col_ub(lp, j);
 209.374 +            f_max += val[k] * lpx_get_col_lb(lp, j);
 209.375 +         }
 209.376 +      }
 209.377 +      /* sum a[j]*x[j] + sum a[j]*y[j] <= b ===>
 209.378 +         sum a[j]*x[j] + (sum a[j]*y[j] - f_min) <= b - f_min ===>
 209.379 +         sum a[j]*x[j] + y <= b - f_min,
 209.380 +         where y = sum a[j]*y[j] - f_min;
 209.381 +         note that 0 <= y <= u, u = f_max - f_min */
 209.382 +      /* determine upper bound of y */
 209.383 +      u = f_max - f_min;
 209.384 +      /* determine value of y at the current point */
 209.385 +      y = 0.0;
 209.386 +      for (k = nb+1; k <= len; k++)
 209.387 +      {  j = ind[k];
 209.388 +         y += val[k] * lpx_get_col_prim(lp, j);
 209.389 +      }
 209.390 +      y -= f_min;
 209.391 +      if (y < 0.0) y = 0.0;
 209.392 +      if (y > u) y = u;
 209.393 +      /* modify the right-hand side b */
 209.394 +      val[0] -= f_min;
 209.395 +      /* now the transformed row has the form:
 209.396 +         sum a[j]*x[j] + y <= b, where 0 <= y <= u */
 209.397 +      /* determine values of x[j] at the current point */
 209.398 +      for (k = 1; k <= nb; k++)
 209.399 +      {  j = ind[k];
 209.400 +         x[k] = lpx_get_col_prim(lp, j);
 209.401 +         if (x[k] < 0.0) x[k] = 0.0;
 209.402 +         if (x[k] > 1.0) x[k] = 1.0;
 209.403 +      }
 209.404 +      /* if a[j] < 0, replace x[j] by its complement 1 - x'[j] */
 209.405 +      for (k = 1; k <= nb; k++)
 209.406 +      {  if (val[k] < 0.0)
 209.407 +         {  ind[k] = - ind[k];
 209.408 +            val[k] = - val[k];
 209.409 +            val[0] += val[k];
 209.410 +            x[k] = 1.0 - x[k];
 209.411 +         }
 209.412 +      }
 209.413 +      /* try to generate a mixed cover cut for the transformed row */
 209.414 +      r = cover(nb, val, val[0], u, x, y, cov, &alfa, &beta);
 209.415 +      if (r == 0) return 0;
 209.416 +      xassert(2 <= r && r <= 4);
 209.417 +      /* now the cut is in the form:
 209.418 +         sum{j in C} x[j] + alfa * y <= beta */
 209.419 +      /* store the right-hand side beta */
 209.420 +      ind[0] = 0, val[0] = beta;
 209.421 +      /* restore the original ordinal numbers of x[j] */
 209.422 +      for (j = 1; j <= r; j++) cov[j] = ind[cov[j]];
 209.423 +      /* store cut coefficients at binary variables complementing back
 209.424 +         the variables having negative row coefficients */
 209.425 +      xassert(r <= nb);
 209.426 +      for (k = 1; k <= r; k++)
 209.427 +      {  if (cov[k] > 0)
 209.428 +         {  ind[k] = +cov[k];
 209.429 +            val[k] = +1.0;
 209.430 +         }
 209.431 +         else
 209.432 +         {  ind[k] = -cov[k];
 209.433 +            val[k] = -1.0;
 209.434 +            val[0] -= 1.0;
 209.435 +         }
 209.436 +      }
 209.437 +      /* substitute y = sum a[j]*y[j] - f_min */
 209.438 +      for (k = nb+1; k <= len; k++)
 209.439 +      {  r++;
 209.440 +         ind[r] = ind[k];
 209.441 +         val[r] = alfa * val[k];
 209.442 +      }
 209.443 +      val[0] += alfa * f_min;
 209.444 +      xassert(r <= len);
 209.445 +      len = r;
 209.446 +      return len;
 209.447 +}
 209.448 +
 209.449 +/*----------------------------------------------------------------------
 209.450 +-- lpx_eval_row - compute explictily specified row.
 209.451 +--
 209.452 +-- SYNOPSIS
 209.453 +--
 209.454 +-- #include "glplpx.h"
 209.455 +-- double lpx_eval_row(LPX *lp, int len, int ind[], double val[]);
 209.456 +--
 209.457 +-- DESCRIPTION
 209.458 +--
 209.459 +-- The routine lpx_eval_row computes the primal value of an explicitly
 209.460 +-- specified row using current values of structural variables.
 209.461 +--
 209.462 +-- The explicitly specified row may be thought as a linear form:
 209.463 +--
 209.464 +--    y = a[1]*x[m+1] + a[2]*x[m+2] + ... + a[n]*x[m+n],
 209.465 +--
 209.466 +-- where y is an auxiliary variable for this row, a[j] are coefficients
 209.467 +-- of the linear form, x[m+j] are structural variables.
 209.468 +--
 209.469 +-- On entry column indices and numerical values of non-zero elements of
 209.470 +-- the row should be stored in locations ind[1], ..., ind[len] and
 209.471 +-- val[1], ..., val[len], where len is the number of non-zero elements.
 209.472 +-- The array ind and val are not changed on exit.
 209.473 +--
 209.474 +-- RETURNS
 209.475 +--
 209.476 +-- The routine returns a computed value of y, the auxiliary variable of
 209.477 +-- the specified row. */
 209.478 +
 209.479 +static double lpx_eval_row(LPX *lp, int len, int ind[], double val[])
 209.480 +{     int n = lpx_get_num_cols(lp);
 209.481 +      int j, k;
 209.482 +      double sum = 0.0;
 209.483 +      if (len < 0)
 209.484 +         xerror("lpx_eval_row: len = %d; invalid row length\n", len);
 209.485 +      for (k = 1; k <= len; k++)
 209.486 +      {  j = ind[k];
 209.487 +         if (!(1 <= j && j <= n))
 209.488 +            xerror("lpx_eval_row: j = %d; column number out of range\n",
 209.489 +               j);
 209.490 +         sum += val[k] * lpx_get_col_prim(lp, j);
 209.491 +      }
 209.492 +      return sum;
 209.493 +}
 209.494 +
 209.495 +/***********************************************************************
 209.496 +*  NAME
 209.497 +*
 209.498 +*  ios_cov_gen - generate mixed cover cuts
 209.499 +*
 209.500 +*  SYNOPSIS
 209.501 +*
 209.502 +*  #include "glpios.h"
 209.503 +*  void ios_cov_gen(glp_tree *tree);
 209.504 +*
 209.505 +*  DESCRIPTION
 209.506 +*
 209.507 +*  The routine ios_cov_gen generates mixed cover cuts for the current
 209.508 +*  point and adds them to the cut pool. */
 209.509 +
 209.510 +void ios_cov_gen(glp_tree *tree)
 209.511 +{     glp_prob *prob = tree->mip;
 209.512 +      int m = lpx_get_num_rows(prob);
 209.513 +      int n = lpx_get_num_cols(prob);
 209.514 +      int i, k, type, kase, len, *ind;
 209.515 +      double r, *val, *work;
 209.516 +      xassert(lpx_get_status(prob) == LPX_OPT);
 209.517 +      /* allocate working arrays */
 209.518 +      ind = xcalloc(1+n, sizeof(int));
 209.519 +      val = xcalloc(1+n, sizeof(double));
 209.520 +      work = xcalloc(1+n, sizeof(double));
 209.521 +      /* look through all rows */
 209.522 +      for (i = 1; i <= m; i++)
 209.523 +      for (kase = 1; kase <= 2; kase++)
 209.524 +      {  type = lpx_get_row_type(prob, i);
 209.525 +         if (kase == 1)
 209.526 +         {  /* consider rows of '<=' type */
 209.527 +            if (!(type == LPX_UP || type == LPX_DB)) continue;
 209.528 +            len = lpx_get_mat_row(prob, i, ind, val);
 209.529 +            val[0] = lpx_get_row_ub(prob, i);
 209.530 +         }
 209.531 +         else
 209.532 +         {  /* consider rows of '>=' type */
 209.533 +            if (!(type == LPX_LO || type == LPX_DB)) continue;
 209.534 +            len = lpx_get_mat_row(prob, i, ind, val);
 209.535 +            for (k = 1; k <= len; k++) val[k] = - val[k];
 209.536 +            val[0] = - lpx_get_row_lb(prob, i);
 209.537 +         }
 209.538 +         /* generate mixed cover cut:
 209.539 +            sum{j in J} a[j] * x[j] <= b */
 209.540 +         len = lpx_cover_cut(prob, len, ind, val, work);
 209.541 +         if (len == 0) continue;
 209.542 +         /* at the current point the cut inequality is violated, i.e.
 209.543 +            sum{j in J} a[j] * x[j] - b > 0 */
 209.544 +         r = lpx_eval_row(prob, len, ind, val) - val[0];
 209.545 +         if (r < 1e-3) continue;
 209.546 +         /* add the cut to the cut pool */
 209.547 +         glp_ios_add_row(tree, NULL, GLP_RF_COV, 0, len, ind, val,
 209.548 +            GLP_UP, val[0]);
 209.549 +      }
 209.550 +      /* free working arrays */
 209.551 +      xfree(ind);
 209.552 +      xfree(val);
 209.553 +      xfree(work);
 209.554 +      return;
 209.555 +}
 209.556 +
 209.557 +/* eof */
   210.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   210.2 +++ b/src/glpios08.c	Mon Dec 06 13:09:21 2010 +0100
   210.3 @@ -0,0 +1,907 @@
   210.4 +/* glpios08.c (clique cut generator) */
   210.5 +
   210.6 +/***********************************************************************
   210.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   210.8 +*
   210.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  210.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  210.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  210.12 +*  E-mail: <mao@gnu.org>.
  210.13 +*
  210.14 +*  GLPK is free software: you can redistribute it and/or modify it
  210.15 +*  under the terms of the GNU General Public License as published by
  210.16 +*  the Free Software Foundation, either version 3 of the License, or
  210.17 +*  (at your option) any later version.
  210.18 +*
  210.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  210.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  210.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  210.22 +*  License for more details.
  210.23 +*
  210.24 +*  You should have received a copy of the GNU General Public License
  210.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  210.26 +***********************************************************************/
  210.27 +
  210.28 +#include "glpios.h"
  210.29 +
  210.30 +static double get_row_lb(LPX *lp, int i)
  210.31 +{     /* this routine returns lower bound of row i or -DBL_MAX if the
  210.32 +         row has no lower bound */
  210.33 +      double lb;
  210.34 +      switch (lpx_get_row_type(lp, i))
  210.35 +      {  case LPX_FR:
  210.36 +         case LPX_UP:
  210.37 +            lb = -DBL_MAX;
  210.38 +            break;
  210.39 +         case LPX_LO:
  210.40 +         case LPX_DB:
  210.41 +         case LPX_FX:
  210.42 +            lb = lpx_get_row_lb(lp, i);
  210.43 +            break;
  210.44 +         default:
  210.45 +            xassert(lp != lp);
  210.46 +      }
  210.47 +      return lb;
  210.48 +}
  210.49 +
  210.50 +static double get_row_ub(LPX *lp, int i)
  210.51 +{     /* this routine returns upper bound of row i or +DBL_MAX if the
  210.52 +         row has no upper bound */
  210.53 +      double ub;
  210.54 +      switch (lpx_get_row_type(lp, i))
  210.55 +      {  case LPX_FR:
  210.56 +         case LPX_LO:
  210.57 +            ub = +DBL_MAX;
  210.58 +            break;
  210.59 +         case LPX_UP:
  210.60 +         case LPX_DB:
  210.61 +         case LPX_FX:
  210.62 +            ub = lpx_get_row_ub(lp, i);
  210.63 +            break;
  210.64 +         default:
  210.65 +            xassert(lp != lp);
  210.66 +      }
  210.67 +      return ub;
  210.68 +}
  210.69 +
  210.70 +static double get_col_lb(LPX *lp, int j)
  210.71 +{     /* this routine returns lower bound of column j or -DBL_MAX if
  210.72 +         the column has no lower bound */
  210.73 +      double lb;
  210.74 +      switch (lpx_get_col_type(lp, j))
  210.75 +      {  case LPX_FR:
  210.76 +         case LPX_UP:
  210.77 +            lb = -DBL_MAX;
  210.78 +            break;
  210.79 +         case LPX_LO:
  210.80 +         case LPX_DB:
  210.81 +         case LPX_FX:
  210.82 +            lb = lpx_get_col_lb(lp, j);
  210.83 +            break;
  210.84 +         default:
  210.85 +            xassert(lp != lp);
  210.86 +      }
  210.87 +      return lb;
  210.88 +}
  210.89 +
  210.90 +static double get_col_ub(LPX *lp, int j)
  210.91 +{     /* this routine returns upper bound of column j or +DBL_MAX if
  210.92 +         the column has no upper bound */
  210.93 +      double ub;
  210.94 +      switch (lpx_get_col_type(lp, j))
  210.95 +      {  case LPX_FR:
  210.96 +         case LPX_LO:
  210.97 +            ub = +DBL_MAX;
  210.98 +            break;
  210.99 +         case LPX_UP:
 210.100 +         case LPX_DB:
 210.101 +         case LPX_FX:
 210.102 +            ub = lpx_get_col_ub(lp, j);
 210.103 +            break;
 210.104 +         default:
 210.105 +            xassert(lp != lp);
 210.106 +      }
 210.107 +      return ub;
 210.108 +}
 210.109 +
 210.110 +static int is_binary(LPX *lp, int j)
 210.111 +{     /* this routine checks if variable x[j] is binary */
 210.112 +      return
 210.113 +         lpx_get_col_kind(lp, j) == LPX_IV &&
 210.114 +         lpx_get_col_type(lp, j) == LPX_DB &&
 210.115 +         lpx_get_col_lb(lp, j) == 0.0 && lpx_get_col_ub(lp, j) == 1.0;
 210.116 +}
 210.117 +
 210.118 +static double eval_lf_min(LPX *lp, int len, int ind[], double val[])
 210.119 +{     /* this routine computes the minimum of a specified linear form
 210.120 +
 210.121 +            sum a[j]*x[j]
 210.122 +             j
 210.123 +
 210.124 +         using the formula:
 210.125 +
 210.126 +            min =   sum   a[j]*lb[j] +   sum   a[j]*ub[j],
 210.127 +                  j in J+              j in J-
 210.128 +
 210.129 +         where J+ = {j: a[j] > 0}, J- = {j: a[j] < 0}, lb[j] and ub[j]
 210.130 +         are lower and upper bound of variable x[j], resp. */
 210.131 +      int j, t;
 210.132 +      double lb, ub, sum;
 210.133 +      sum = 0.0;
 210.134 +      for (t = 1; t <= len; t++)
 210.135 +      {  j = ind[t];
 210.136 +         if (val[t] > 0.0)
 210.137 +         {  lb = get_col_lb(lp, j);
 210.138 +            if (lb == -DBL_MAX)
 210.139 +            {  sum = -DBL_MAX;
 210.140 +               break;
 210.141 +            }
 210.142 +            sum += val[t] * lb;
 210.143 +         }
 210.144 +         else if (val[t] < 0.0)
 210.145 +         {  ub = get_col_ub(lp, j);
 210.146 +            if (ub == +DBL_MAX)
 210.147 +            {  sum = -DBL_MAX;
 210.148 +               break;
 210.149 +            }
 210.150 +            sum += val[t] * ub;
 210.151 +         }
 210.152 +         else
 210.153 +            xassert(val != val);
 210.154 +      }
 210.155 +      return sum;
 210.156 +}
 210.157 +
 210.158 +static double eval_lf_max(LPX *lp, int len, int ind[], double val[])
 210.159 +{     /* this routine computes the maximum of a specified linear form
 210.160 +
 210.161 +            sum a[j]*x[j]
 210.162 +             j
 210.163 +
 210.164 +         using the formula:
 210.165 +
 210.166 +            max =   sum   a[j]*ub[j] +   sum   a[j]*lb[j],
 210.167 +                  j in J+              j in J-
 210.168 +
 210.169 +         where J+ = {j: a[j] > 0}, J- = {j: a[j] < 0}, lb[j] and ub[j]
 210.170 +         are lower and upper bound of variable x[j], resp. */
 210.171 +      int j, t;
 210.172 +      double lb, ub, sum;
 210.173 +      sum = 0.0;
 210.174 +      for (t = 1; t <= len; t++)
 210.175 +      {  j = ind[t];
 210.176 +         if (val[t] > 0.0)
 210.177 +         {  ub = get_col_ub(lp, j);
 210.178 +            if (ub == +DBL_MAX)
 210.179 +            {  sum = +DBL_MAX;
 210.180 +               break;
 210.181 +            }
 210.182 +            sum += val[t] * ub;
 210.183 +         }
 210.184 +         else if (val[t] < 0.0)
 210.185 +         {  lb = get_col_lb(lp, j);
 210.186 +            if (lb == -DBL_MAX)
 210.187 +            {  sum = +DBL_MAX;
 210.188 +               break;
 210.189 +            }
 210.190 +            sum += val[t] * lb;
 210.191 +         }
 210.192 +         else
 210.193 +            xassert(val != val);
 210.194 +      }
 210.195 +      return sum;
 210.196 +}
 210.197 +
 210.198 +/*----------------------------------------------------------------------
 210.199 +-- probing - determine logical relation between binary variables.
 210.200 +--
 210.201 +-- This routine tentatively sets a binary variable to 0 and then to 1
 210.202 +-- and examines whether another binary variable is caused to be fixed.
 210.203 +--
 210.204 +-- The examination is based only on one row (constraint), which is the
 210.205 +-- following:
 210.206 +--
 210.207 +--    L <= sum a[j]*x[j] <= U.                                       (1)
 210.208 +--          j
 210.209 +--
 210.210 +-- Let x[p] be a probing variable, x[q] be an examined variable. Then
 210.211 +-- (1) can be written as:
 210.212 +--
 210.213 +--    L <=   sum  a[j]*x[j] + a[p]*x[p] + a[q]*x[q] <= U,            (2)
 210.214 +--         j in J'
 210.215 +--
 210.216 +-- where J' = {j: j != p and j != q}.
 210.217 +--
 210.218 +-- Let
 210.219 +--
 210.220 +--    L' = L - a[p]*x[p],                                            (3)
 210.221 +--
 210.222 +--    U' = U - a[p]*x[p],                                            (4)
 210.223 +--
 210.224 +-- where x[p] is assumed to be fixed at 0 or 1. So (2) can be rewritten
 210.225 +-- as follows:
 210.226 +--
 210.227 +--    L' <=   sum  a[j]*x[j] + a[q]*x[q] <= U',                      (5)
 210.228 +--          j in J'
 210.229 +--
 210.230 +-- from where we have:
 210.231 +--
 210.232 +--    L' -  sum  a[j]*x[j] <= a[q]*x[q] <= U' -  sum  a[j]*x[j].     (6)
 210.233 +--        j in J'                              j in J'
 210.234 +--
 210.235 +-- Thus,
 210.236 +--
 210.237 +--    min a[q]*x[q] = L' - MAX,                                      (7)
 210.238 +--
 210.239 +--    max a[q]*x[q] = U' - MIN,                                      (8)
 210.240 +--
 210.241 +-- where
 210.242 +--
 210.243 +--    MIN = min  sum  a[j]*x[j],                                     (9)
 210.244 +--             j in J'
 210.245 +--
 210.246 +--    MAX = max  sum  a[j]*x[j].                                    (10)
 210.247 +--             j in J'
 210.248 +--
 210.249 +-- Formulae (7) and (8) allows determining implied lower and upper
 210.250 +-- bounds of x[q].
 210.251 +--
 210.252 +-- Parameters len, val, L and U specify the constraint (1).
 210.253 +--
 210.254 +-- Parameters lf_min and lf_max specify implied lower and upper bounds
 210.255 +-- of the linear form (1). It is assumed that these bounds are computed
 210.256 +-- with the routines eval_lf_min and eval_lf_max (see above).
 210.257 +--
 210.258 +-- Parameter p specifies the probing variable x[p], which is set to 0
 210.259 +-- (if set is 0) or to 1 (if set is 1).
 210.260 +--
 210.261 +-- Parameter q specifies the examined variable x[q].
 210.262 +--
 210.263 +-- On exit the routine returns one of the following codes:
 210.264 +--
 210.265 +-- 0 - there is no logical relation between x[p] and x[q];
 210.266 +-- 1 - x[q] can take only on value 0;
 210.267 +-- 2 - x[q] can take only on value 1. */
 210.268 +
 210.269 +static int probing(int len, double val[], double L, double U,
 210.270 +      double lf_min, double lf_max, int p, int set, int q)
 210.271 +{     double temp;
 210.272 +      xassert(1 <= p && p < q && q <= len);
 210.273 +      /* compute L' (3) */
 210.274 +      if (L != -DBL_MAX && set) L -= val[p];
 210.275 +      /* compute U' (4) */
 210.276 +      if (U != +DBL_MAX && set) U -= val[p];
 210.277 +      /* compute MIN (9) */
 210.278 +      if (lf_min != -DBL_MAX)
 210.279 +      {  if (val[p] < 0.0) lf_min -= val[p];
 210.280 +         if (val[q] < 0.0) lf_min -= val[q];
 210.281 +      }
 210.282 +      /* compute MAX (10) */
 210.283 +      if (lf_max != +DBL_MAX)
 210.284 +      {  if (val[p] > 0.0) lf_max -= val[p];
 210.285 +         if (val[q] > 0.0) lf_max -= val[q];
 210.286 +      }
 210.287 +      /* compute implied lower bound of x[q]; see (7), (8) */
 210.288 +      if (val[q] > 0.0)
 210.289 +      {  if (L == -DBL_MAX || lf_max == +DBL_MAX)
 210.290 +            temp = -DBL_MAX;
 210.291 +         else
 210.292 +            temp = (L - lf_max) / val[q];
 210.293 +      }
 210.294 +      else
 210.295 +      {  if (U == +DBL_MAX || lf_min == -DBL_MAX)
 210.296 +            temp = -DBL_MAX;
 210.297 +         else
 210.298 +            temp = (U - lf_min) / val[q];
 210.299 +      }
 210.300 +      if (temp > 0.001) return 2;
 210.301 +      /* compute implied upper bound of x[q]; see (7), (8) */
 210.302 +      if (val[q] > 0.0)
 210.303 +      {  if (U == +DBL_MAX || lf_min == -DBL_MAX)
 210.304 +            temp = +DBL_MAX;
 210.305 +         else
 210.306 +            temp = (U - lf_min) / val[q];
 210.307 +      }
 210.308 +      else
 210.309 +      {  if (L == -DBL_MAX || lf_max == +DBL_MAX)
 210.310 +            temp = +DBL_MAX;
 210.311 +         else
 210.312 +            temp = (L - lf_max) / val[q];
 210.313 +      }
 210.314 +      if (temp < 0.999) return 1;
 210.315 +      /* there is no logical relation between x[p] and x[q] */
 210.316 +      return 0;
 210.317 +}
 210.318 +
 210.319 +struct COG
 210.320 +{     /* conflict graph; it represents logical relations between binary
 210.321 +         variables and has a vertex for each binary variable and its
 210.322 +         complement, and an edge between two vertices when at most one
 210.323 +         of the variables represented by the vertices can equal one in
 210.324 +         an optimal solution */
 210.325 +      int n;
 210.326 +      /* number of variables */
 210.327 +      int nb;
 210.328 +      /* number of binary variables represented in the graph (note that
 210.329 +         not all binary variables can be represented); vertices which
 210.330 +         correspond to binary variables have numbers 1, ..., nb while
 210.331 +         vertices which correspond to complements of binary variables
 210.332 +         have numbers nb+1, ..., nb+nb */
 210.333 +      int ne;
 210.334 +      /* number of edges in the graph */
 210.335 +      int *vert; /* int vert[1+n]; */
 210.336 +      /* if x[j] is a binary variable represented in the graph, vert[j]
 210.337 +         is the vertex number corresponding to x[j]; otherwise vert[j]
 210.338 +         is zero */
 210.339 +      int *orig; /* int list[1:nb]; */
 210.340 +      /* if vert[j] = k > 0, then orig[k] = j */
 210.341 +      unsigned char *a;
 210.342 +      /* adjacency matrix of the graph having 2*nb rows and columns;
 210.343 +         only strict lower triangle is stored in dense packed form */
 210.344 +};
 210.345 +
 210.346 +/*----------------------------------------------------------------------
 210.347 +-- lpx_create_cog - create the conflict graph.
 210.348 +--
 210.349 +-- SYNOPSIS
 210.350 +--
 210.351 +-- #include "glplpx.h"
 210.352 +-- void *lpx_create_cog(LPX *lp);
 210.353 +--
 210.354 +-- DESCRIPTION
 210.355 +--
 210.356 +-- The routine lpx_create_cog creates the conflict graph for a given
 210.357 +-- problem instance.
 210.358 +--
 210.359 +-- RETURNS
 210.360 +--
 210.361 +-- If the graph has been created, the routine returns a pointer to it.
 210.362 +-- Otherwise the routine returns NULL. */
 210.363 +
 210.364 +#define MAX_NB 4000
 210.365 +#define MAX_ROW_LEN 500
 210.366 +
 210.367 +static void lpx_add_cog_edge(void *_cog, int i, int j);
 210.368 +
 210.369 +static void *lpx_create_cog(LPX *lp)
 210.370 +{     struct COG *cog = NULL;
 210.371 +      int m, n, nb, i, j, p, q, len, *ind, *vert, *orig;
 210.372 +      double L, U, lf_min, lf_max, *val;
 210.373 +      xprintf("Creating the conflict graph...\n");
 210.374 +      m = lpx_get_num_rows(lp);
 210.375 +      n = lpx_get_num_cols(lp);
 210.376 +      /* determine which binary variables should be included in the
 210.377 +         conflict graph */
 210.378 +      nb = 0;
 210.379 +      vert = xcalloc(1+n, sizeof(int));
 210.380 +      for (j = 1; j <= n; j++) vert[j] = 0;
 210.381 +      orig = xcalloc(1+n, sizeof(int));
 210.382 +      ind = xcalloc(1+n, sizeof(int));
 210.383 +      val = xcalloc(1+n, sizeof(double));
 210.384 +      for (i = 1; i <= m; i++)
 210.385 +      {  L = get_row_lb(lp, i);
 210.386 +         U = get_row_ub(lp, i);
 210.387 +         if (L == -DBL_MAX && U == +DBL_MAX) continue;
 210.388 +         len = lpx_get_mat_row(lp, i, ind, val);
 210.389 +         if (len > MAX_ROW_LEN) continue;
 210.390 +         lf_min = eval_lf_min(lp, len, ind, val);
 210.391 +         lf_max = eval_lf_max(lp, len, ind, val);
 210.392 +         for (p = 1; p <= len; p++)
 210.393 +         {  if (!is_binary(lp, ind[p])) continue;
 210.394 +            for (q = p+1; q <= len; q++)
 210.395 +            {  if (!is_binary(lp, ind[q])) continue;
 210.396 +               if (probing(len, val, L, U, lf_min, lf_max, p, 0, q) ||
 210.397 +                   probing(len, val, L, U, lf_min, lf_max, p, 1, q))
 210.398 +               {  /* there is a logical relation */
 210.399 +                  /* include the first variable in the graph */
 210.400 +                  j = ind[p];
 210.401 +                  if (vert[j] == 0) nb++, vert[j] = nb, orig[nb] = j;
 210.402 +                  /* incude the second variable in the graph */
 210.403 +                  j = ind[q];
 210.404 +                  if (vert[j] == 0) nb++, vert[j] = nb, orig[nb] = j;
 210.405 +               }
 210.406 +            }
 210.407 +         }
 210.408 +      }
 210.409 +      /* if the graph is either empty or has too many vertices, do not
 210.410 +         create it */
 210.411 +      if (nb == 0 || nb > MAX_NB)
 210.412 +      {  xprintf("The conflict graph is either empty or too big\n");
 210.413 +         xfree(vert);
 210.414 +         xfree(orig);
 210.415 +         goto done;
 210.416 +      }
 210.417 +      /* create the conflict graph */
 210.418 +      cog = xmalloc(sizeof(struct COG));
 210.419 +      cog->n = n;
 210.420 +      cog->nb = nb;
 210.421 +      cog->ne = 0;
 210.422 +      cog->vert = vert;
 210.423 +      cog->orig = orig;
 210.424 +      len = nb + nb; /* number of vertices */
 210.425 +      len = (len * (len - 1)) / 2; /* number of entries in triangle */
 210.426 +      len = (len + (CHAR_BIT - 1)) / CHAR_BIT; /* bytes needed */
 210.427 +      cog->a = xmalloc(len);
 210.428 +      memset(cog->a, 0, len);
 210.429 +      for (j = 1; j <= nb; j++)
 210.430 +      {  /* add edge between variable and its complement */
 210.431 +         lpx_add_cog_edge(cog, +orig[j], -orig[j]);
 210.432 +      }
 210.433 +      for (i = 1; i <= m; i++)
 210.434 +      {  L = get_row_lb(lp, i);
 210.435 +         U = get_row_ub(lp, i);
 210.436 +         if (L == -DBL_MAX && U == +DBL_MAX) continue;
 210.437 +         len = lpx_get_mat_row(lp, i, ind, val);
 210.438 +         if (len > MAX_ROW_LEN) continue;
 210.439 +         lf_min = eval_lf_min(lp, len, ind, val);
 210.440 +         lf_max = eval_lf_max(lp, len, ind, val);
 210.441 +         for (p = 1; p <= len; p++)
 210.442 +         {  if (!is_binary(lp, ind[p])) continue;
 210.443 +            for (q = p+1; q <= len; q++)
 210.444 +            {  if (!is_binary(lp, ind[q])) continue;
 210.445 +               /* set x[p] to 0 and examine x[q] */
 210.446 +               switch (probing(len, val, L, U, lf_min, lf_max, p, 0, q))
 210.447 +               {  case 0:
 210.448 +                     /* no logical relation */
 210.449 +                     break;
 210.450 +                  case 1:
 210.451 +                     /* x[p] = 0 implies x[q] = 0 */
 210.452 +                     lpx_add_cog_edge(cog, -ind[p], +ind[q]);
 210.453 +                     break;
 210.454 +                  case 2:
 210.455 +                     /* x[p] = 0 implies x[q] = 1 */
 210.456 +                     lpx_add_cog_edge(cog, -ind[p], -ind[q]);
 210.457 +                     break;
 210.458 +                  default:
 210.459 +                     xassert(lp != lp);
 210.460 +               }
 210.461 +               /* set x[p] to 1 and examine x[q] */
 210.462 +               switch (probing(len, val, L, U, lf_min, lf_max, p, 1, q))
 210.463 +               {  case 0:
 210.464 +                     /* no logical relation */
 210.465 +                     break;
 210.466 +                  case 1:
 210.467 +                     /* x[p] = 1 implies x[q] = 0 */
 210.468 +                     lpx_add_cog_edge(cog, +ind[p], +ind[q]);
 210.469 +                     break;
 210.470 +                  case 2:
 210.471 +                     /* x[p] = 1 implies x[q] = 1 */
 210.472 +                     lpx_add_cog_edge(cog, +ind[p], -ind[q]);
 210.473 +                     break;
 210.474 +                  default:
 210.475 +                     xassert(lp != lp);
 210.476 +               }
 210.477 +            }
 210.478 +         }
 210.479 +      }
 210.480 +      xprintf("The conflict graph has 2*%d vertices and %d edges\n",
 210.481 +         cog->nb, cog->ne);
 210.482 +done: xfree(ind);
 210.483 +      xfree(val);
 210.484 +      return cog;
 210.485 +}
 210.486 +
 210.487 +/*----------------------------------------------------------------------
 210.488 +-- lpx_add_cog_edge - add edge to the conflict graph.
 210.489 +--
 210.490 +-- SYNOPSIS
 210.491 +--
 210.492 +-- #include "glplpx.h"
 210.493 +-- void lpx_add_cog_edge(void *cog, int i, int j);
 210.494 +--
 210.495 +-- DESCRIPTION
 210.496 +--
 210.497 +-- The routine lpx_add_cog_edge adds an edge to the conflict graph.
 210.498 +-- The edge connects x[i] (if i > 0) or its complement (if i < 0) and
 210.499 +-- x[j] (if j > 0) or its complement (if j < 0), where i and j are
 210.500 +-- original ordinal numbers of corresponding variables. */
 210.501 +
 210.502 +static void lpx_add_cog_edge(void *_cog, int i, int j)
 210.503 +{     struct COG *cog = _cog;
 210.504 +      int k;
 210.505 +      xassert(i != j);
 210.506 +      /* determine indices of corresponding vertices */
 210.507 +      if (i > 0)
 210.508 +      {  xassert(1 <= i && i <= cog->n);
 210.509 +         i = cog->vert[i];
 210.510 +         xassert(i != 0);
 210.511 +      }
 210.512 +      else
 210.513 +      {  i = -i;
 210.514 +         xassert(1 <= i && i <= cog->n);
 210.515 +         i = cog->vert[i];
 210.516 +         xassert(i != 0);
 210.517 +         i += cog->nb;
 210.518 +      }
 210.519 +      if (j > 0)
 210.520 +      {  xassert(1 <= j && j <= cog->n);
 210.521 +         j = cog->vert[j];
 210.522 +         xassert(j != 0);
 210.523 +      }
 210.524 +      else
 210.525 +      {  j = -j;
 210.526 +         xassert(1 <= j && j <= cog->n);
 210.527 +         j = cog->vert[j];
 210.528 +         xassert(j != 0);
 210.529 +         j += cog->nb;
 210.530 +      }
 210.531 +      /* only lower triangle is stored, so we need i > j */
 210.532 +      if (i < j) k = i, i = j, j = k;
 210.533 +      k = ((i - 1) * (i - 2)) / 2 + (j - 1);
 210.534 +      cog->a[k / CHAR_BIT] |=
 210.535 +         (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT));
 210.536 +      cog->ne++;
 210.537 +      return;
 210.538 +}
 210.539 +
 210.540 +/*----------------------------------------------------------------------
 210.541 +-- MAXIMUM WEIGHT CLIQUE
 210.542 +--
 210.543 +-- Two subroutines sub() and wclique() below are intended to find a
 210.544 +-- maximum weight clique in a given undirected graph. These subroutines
 210.545 +-- are slightly modified version of the program WCLIQUE developed by
 210.546 +-- Patric Ostergard <http://www.tcs.hut.fi/~pat/wclique.html> and based
 210.547 +-- on ideas from the article "P. R. J. Ostergard, A new algorithm for
 210.548 +-- the maximum-weight clique problem, submitted for publication", which
 210.549 +-- in turn is a generalization of the algorithm for unweighted graphs
 210.550 +-- presented in "P. R. J. Ostergard, A fast algorithm for the maximum
 210.551 +-- clique problem, submitted for publication".
 210.552 +--
 210.553 +-- USED WITH PERMISSION OF THE AUTHOR OF THE ORIGINAL CODE. */
 210.554 +
 210.555 +struct dsa
 210.556 +{     /* dynamic storage area */
 210.557 +      int n;
 210.558 +      /* number of vertices */
 210.559 +      int *wt; /* int wt[0:n-1]; */
 210.560 +      /* weights */
 210.561 +      unsigned char *a;
 210.562 +      /* adjacency matrix (packed lower triangle without main diag.) */
 210.563 +      int record;
 210.564 +      /* weight of best clique */
 210.565 +      int rec_level;
 210.566 +      /* number of vertices in best clique */
 210.567 +      int *rec; /* int rec[0:n-1]; */
 210.568 +      /* best clique so far */
 210.569 +      int *clique; /* int clique[0:n-1]; */
 210.570 +      /* table for pruning */
 210.571 +      int *set; /* int set[0:n-1]; */
 210.572 +      /* current clique */
 210.573 +};
 210.574 +
 210.575 +#define n         (dsa->n)
 210.576 +#define wt        (dsa->wt)
 210.577 +#define a         (dsa->a)
 210.578 +#define record    (dsa->record)
 210.579 +#define rec_level (dsa->rec_level)
 210.580 +#define rec       (dsa->rec)
 210.581 +#define clique    (dsa->clique)
 210.582 +#define set       (dsa->set)
 210.583 +
 210.584 +#if 0
 210.585 +static int is_edge(struct dsa *dsa, int i, int j)
 210.586 +{     /* if there is arc (i,j), the routine returns true; otherwise
 210.587 +         false; 0 <= i, j < n */
 210.588 +      int k;
 210.589 +      xassert(0 <= i && i < n);
 210.590 +      xassert(0 <= j && j < n);
 210.591 +      if (i == j) return 0;
 210.592 +      if (i < j) k = i, i = j, j = k;
 210.593 +      k = (i * (i - 1)) / 2 + j;
 210.594 +      return a[k / CHAR_BIT] &
 210.595 +         (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT));
 210.596 +}
 210.597 +#else
 210.598 +#define is_edge(dsa, i, j) ((i) == (j) ? 0 : \
 210.599 +      (i) > (j) ? is_edge1(i, j) : is_edge1(j, i))
 210.600 +#define is_edge1(i, j) is_edge2(((i) * ((i) - 1)) / 2 + (j))
 210.601 +#define is_edge2(k) (a[(k) / CHAR_BIT] & \
 210.602 +      (unsigned char)(1 << ((CHAR_BIT - 1) - (k) % CHAR_BIT)))
 210.603 +#endif
 210.604 +
 210.605 +static void sub(struct dsa *dsa, int ct, int table[], int level,
 210.606 +      int weight, int l_weight)
 210.607 +{     int i, j, k, curr_weight, left_weight, *p1, *p2, *newtable;
 210.608 +      newtable = xcalloc(n, sizeof(int));
 210.609 +      if (ct <= 0)
 210.610 +      {  /* 0 or 1 elements left; include these */
 210.611 +         if (ct == 0)
 210.612 +         {  set[level++] = table[0];
 210.613 +            weight += l_weight;
 210.614 +         }
 210.615 +         if (weight > record)
 210.616 +         {  record = weight;
 210.617 +            rec_level = level;
 210.618 +            for (i = 0; i < level; i++) rec[i] = set[i];
 210.619 +         }
 210.620 +         goto done;
 210.621 +      }
 210.622 +      for (i = ct; i >= 0; i--)
 210.623 +      {  if ((level == 0) && (i < ct)) goto done;
 210.624 +         k = table[i];
 210.625 +         if ((level > 0) && (clique[k] <= (record - weight)))
 210.626 +            goto done; /* prune */
 210.627 +         set[level] = k;
 210.628 +         curr_weight = weight + wt[k];
 210.629 +         l_weight -= wt[k];
 210.630 +         if (l_weight <= (record - curr_weight))
 210.631 +            goto done; /* prune */
 210.632 +         p1 = newtable;
 210.633 +         p2 = table;
 210.634 +         left_weight = 0;
 210.635 +         while (p2 < table + i)
 210.636 +         {  j = *p2++;
 210.637 +            if (is_edge(dsa, j, k))
 210.638 +            {  *p1++ = j;
 210.639 +               left_weight += wt[j];
 210.640 +            }
 210.641 +         }
 210.642 +         if (left_weight <= (record - curr_weight)) continue;
 210.643 +         sub(dsa, p1 - newtable - 1, newtable, level + 1, curr_weight,
 210.644 +            left_weight);
 210.645 +      }
 210.646 +done: xfree(newtable);
 210.647 +      return;
 210.648 +}
 210.649 +
 210.650 +static int wclique(int _n, int w[], unsigned char _a[], int sol[])
 210.651 +{     struct dsa _dsa, *dsa = &_dsa;
 210.652 +      int i, j, p, max_wt, max_nwt, wth, *used, *nwt, *pos;
 210.653 +      glp_long timer;
 210.654 +      n = _n;
 210.655 +      wt = &w[1];
 210.656 +      a = _a;
 210.657 +      record = 0;
 210.658 +      rec_level = 0;
 210.659 +      rec = &sol[1];
 210.660 +      clique = xcalloc(n, sizeof(int));
 210.661 +      set = xcalloc(n, sizeof(int));
 210.662 +      used = xcalloc(n, sizeof(int));
 210.663 +      nwt = xcalloc(n, sizeof(int));
 210.664 +      pos = xcalloc(n, sizeof(int));
 210.665 +      /* start timer */
 210.666 +      timer = xtime();
 210.667 +      /* order vertices */
 210.668 +      for (i = 0; i < n; i++)
 210.669 +      {  nwt[i] = 0;
 210.670 +         for (j = 0; j < n; j++)
 210.671 +            if (is_edge(dsa, i, j)) nwt[i] += wt[j];
 210.672 +      }
 210.673 +      for (i = 0; i < n; i++)
 210.674 +         used[i] = 0;
 210.675 +      for (i = n-1; i >= 0; i--)
 210.676 +      {  max_wt = -1;
 210.677 +         max_nwt = -1;
 210.678 +         for (j = 0; j < n; j++)
 210.679 +         {  if ((!used[j]) && ((wt[j] > max_wt) || (wt[j] == max_wt
 210.680 +               && nwt[j] > max_nwt)))
 210.681 +            {  max_wt = wt[j];
 210.682 +               max_nwt = nwt[j];
 210.683 +               p = j;
 210.684 +            }
 210.685 +         }
 210.686 +         pos[i] = p;
 210.687 +         used[p] = 1;
 210.688 +         for (j = 0; j < n; j++)
 210.689 +            if ((!used[j]) && (j != p) && (is_edge(dsa, p, j)))
 210.690 +               nwt[j] -= wt[p];
 210.691 +      }
 210.692 +      /* main routine */
 210.693 +      wth = 0;
 210.694 +      for (i = 0; i < n; i++)
 210.695 +      {  wth += wt[pos[i]];
 210.696 +         sub(dsa, i, pos, 0, 0, wth);
 210.697 +         clique[pos[i]] = record;
 210.698 +#if 0
 210.699 +         if (utime() >= timer + 5.0)
 210.700 +#else
 210.701 +         if (xdifftime(xtime(), timer) >= 5.0 - 0.001)
 210.702 +#endif
 210.703 +         {  /* print current record and reset timer */
 210.704 +            xprintf("level = %d (%d); best = %d\n", i+1, n, record);
 210.705 +#if 0
 210.706 +            timer = utime();
 210.707 +#else
 210.708 +            timer = xtime();
 210.709 +#endif
 210.710 +         }
 210.711 +      }
 210.712 +      xfree(clique);
 210.713 +      xfree(set);
 210.714 +      xfree(used);
 210.715 +      xfree(nwt);
 210.716 +      xfree(pos);
 210.717 +      /* return the solution found */
 210.718 +      for (i = 1; i <= rec_level; i++) sol[i]++;
 210.719 +      return rec_level;
 210.720 +}
 210.721 +
 210.722 +#undef n
 210.723 +#undef wt
 210.724 +#undef a
 210.725 +#undef record
 210.726 +#undef rec_level
 210.727 +#undef rec
 210.728 +#undef clique
 210.729 +#undef set
 210.730 +
 210.731 +/*----------------------------------------------------------------------
 210.732 +-- lpx_clique_cut - generate cluque cut.
 210.733 +--
 210.734 +-- SYNOPSIS
 210.735 +--
 210.736 +-- #include "glplpx.h"
 210.737 +-- int lpx_clique_cut(LPX *lp, void *cog, int ind[], double val[]);
 210.738 +--
 210.739 +-- DESCRIPTION
 210.740 +--
 210.741 +-- The routine lpx_clique_cut generates a clique cut using the conflict
 210.742 +-- graph specified by the parameter cog.
 210.743 +--
 210.744 +-- If a violated clique cut has been found, it has the following form:
 210.745 +--
 210.746 +--    sum{j in J} a[j]*x[j] <= b.
 210.747 +--
 210.748 +-- Variable indices j in J are stored in elements ind[1], ..., ind[len]
 210.749 +-- while corresponding constraint coefficients are stored in elements
 210.750 +-- val[1], ..., val[len], where len is returned on exit. The right-hand
 210.751 +-- side b is stored in element val[0].
 210.752 +--
 210.753 +-- RETURNS
 210.754 +--
 210.755 +-- If the cutting plane has been successfully generated, the routine
 210.756 +-- returns 1 <= len <= n, which is the number of non-zero coefficients
 210.757 +-- in the inequality constraint. Otherwise, the routine returns zero. */
 210.758 +
 210.759 +static int lpx_clique_cut(LPX *lp, void *_cog, int ind[], double val[])
 210.760 +{     struct COG *cog = _cog;
 210.761 +      int n = lpx_get_num_cols(lp);
 210.762 +      int j, t, v, card, temp, len = 0, *w, *sol;
 210.763 +      double x, sum, b, *vec;
 210.764 +      /* allocate working arrays */
 210.765 +      w = xcalloc(1 + 2 * cog->nb, sizeof(int));
 210.766 +      sol = xcalloc(1 + 2 * cog->nb, sizeof(int));
 210.767 +      vec = xcalloc(1+n, sizeof(double));
 210.768 +      /* assign weights to vertices of the conflict graph */
 210.769 +      for (t = 1; t <= cog->nb; t++)
 210.770 +      {  j = cog->orig[t];
 210.771 +         x = lpx_get_col_prim(lp, j);
 210.772 +         temp = (int)(100.0 * x + 0.5);
 210.773 +         if (temp < 0) temp = 0;
 210.774 +         if (temp > 100) temp = 100;
 210.775 +         w[t] = temp;
 210.776 +         w[cog->nb + t] = 100 - temp;
 210.777 +      }
 210.778 +      /* find a clique of maximum weight */
 210.779 +      card = wclique(2 * cog->nb, w, cog->a, sol);
 210.780 +      /* compute the clique weight for unscaled values */
 210.781 +      sum = 0.0;
 210.782 +      for ( t = 1; t <= card; t++)
 210.783 +      {  v = sol[t];
 210.784 +         xassert(1 <= v && v <= 2 * cog->nb);
 210.785 +         if (v <= cog->nb)
 210.786 +         {  /* vertex v corresponds to binary variable x[j] */
 210.787 +            j = cog->orig[v];
 210.788 +            x = lpx_get_col_prim(lp, j);
 210.789 +            sum += x;
 210.790 +         }
 210.791 +         else
 210.792 +         {  /* vertex v corresponds to the complement of x[j] */
 210.793 +            j = cog->orig[v - cog->nb];
 210.794 +            x = lpx_get_col_prim(lp, j);
 210.795 +            sum += 1.0 - x;
 210.796 +         }
 210.797 +      }
 210.798 +      /* if the sum of binary variables and their complements in the
 210.799 +         clique greater than 1, the clique cut is violated */
 210.800 +      if (sum >= 1.01)
 210.801 +      {  /* construct the inquality */
 210.802 +         for (j = 1; j <= n; j++) vec[j] = 0;
 210.803 +         b = 1.0;
 210.804 +         for (t = 1; t <= card; t++)
 210.805 +         {  v = sol[t];
 210.806 +            if (v <= cog->nb)
 210.807 +            {  /* vertex v corresponds to binary variable x[j] */
 210.808 +               j = cog->orig[v];
 210.809 +               xassert(1 <= j && j <= n);
 210.810 +               vec[j] += 1.0;
 210.811 +            }
 210.812 +            else
 210.813 +            {  /* vertex v corresponds to the complement of x[j] */
 210.814 +               j = cog->orig[v - cog->nb];
 210.815 +               xassert(1 <= j && j <= n);
 210.816 +               vec[j] -= 1.0;
 210.817 +               b -= 1.0;
 210.818 +            }
 210.819 +         }
 210.820 +         xassert(len == 0);
 210.821 +         for (j = 1; j <= n; j++)
 210.822 +         {  if (vec[j] != 0.0)
 210.823 +            {  len++;
 210.824 +               ind[len] = j, val[len] = vec[j];
 210.825 +            }
 210.826 +         }
 210.827 +         ind[0] = 0, val[0] = b;
 210.828 +      }
 210.829 +      /* free working arrays */
 210.830 +      xfree(w);
 210.831 +      xfree(sol);
 210.832 +      xfree(vec);
 210.833 +      /* return to the calling program */
 210.834 +      return len;
 210.835 +}
 210.836 +
 210.837 +/*----------------------------------------------------------------------
 210.838 +-- lpx_delete_cog - delete the conflict graph.
 210.839 +--
 210.840 +-- SYNOPSIS
 210.841 +--
 210.842 +-- #include "glplpx.h"
 210.843 +-- void lpx_delete_cog(void *cog);
 210.844 +--
 210.845 +-- DESCRIPTION
 210.846 +--
 210.847 +-- The routine lpx_delete_cog deletes the conflict graph, which the
 210.848 +-- parameter cog points to, freeing all the memory allocated to this
 210.849 +-- object. */
 210.850 +
 210.851 +static void lpx_delete_cog(void *_cog)
 210.852 +{     struct COG *cog = _cog;
 210.853 +      xfree(cog->vert);
 210.854 +      xfree(cog->orig);
 210.855 +      xfree(cog->a);
 210.856 +      xfree(cog);
 210.857 +}
 210.858 +
 210.859 +/**********************************************************************/
 210.860 +
 210.861 +void *ios_clq_init(glp_tree *tree)
 210.862 +{     /* initialize clique cut generator */
 210.863 +      glp_prob *mip = tree->mip;
 210.864 +      xassert(mip != NULL);
 210.865 +      return lpx_create_cog(mip);
 210.866 +}
 210.867 +
 210.868 +/***********************************************************************
 210.869 +*  NAME
 210.870 +*
 210.871 +*  ios_clq_gen - generate clique cuts
 210.872 +*
 210.873 +*  SYNOPSIS
 210.874 +*
 210.875 +*  #include "glpios.h"
 210.876 +*  void ios_clq_gen(glp_tree *tree, void *gen);
 210.877 +*
 210.878 +*  DESCRIPTION
 210.879 +*
 210.880 +*  The routine ios_clq_gen generates clique cuts for the current point
 210.881 +*  and adds them to the clique pool. */
 210.882 +
 210.883 +void ios_clq_gen(glp_tree *tree, void *gen)
 210.884 +{     int n = lpx_get_num_cols(tree->mip);
 210.885 +      int len, *ind;
 210.886 +      double *val;
 210.887 +      xassert(gen != NULL);
 210.888 +      ind = xcalloc(1+n, sizeof(int));
 210.889 +      val = xcalloc(1+n, sizeof(double));
 210.890 +      len = lpx_clique_cut(tree->mip, gen, ind, val);
 210.891 +      if (len > 0)
 210.892 +      {  /* xprintf("len = %d\n", len); */
 210.893 +         glp_ios_add_row(tree, NULL, GLP_RF_CLQ, 0, len, ind, val,
 210.894 +            GLP_UP, val[0]);
 210.895 +      }
 210.896 +      xfree(ind);
 210.897 +      xfree(val);
 210.898 +      return;
 210.899 +}
 210.900 +
 210.901 +/**********************************************************************/
 210.902 +
 210.903 +void ios_clq_term(void *gen)
 210.904 +{     /* terminate clique cut generator */
 210.905 +      xassert(gen != NULL);
 210.906 +      lpx_delete_cog(gen);
 210.907 +      return;
 210.908 +}
 210.909 +
 210.910 +/* eof */
   211.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   211.2 +++ b/src/glpios09.c	Mon Dec 06 13:09:21 2010 +0100
   211.3 @@ -0,0 +1,659 @@
   211.4 +/* glpios09.c (branching heuristics) */
   211.5 +
   211.6 +/***********************************************************************
   211.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   211.8 +*
   211.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  211.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  211.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  211.12 +*  E-mail: <mao@gnu.org>.
  211.13 +*
  211.14 +*  GLPK is free software: you can redistribute it and/or modify it
  211.15 +*  under the terms of the GNU General Public License as published by
  211.16 +*  the Free Software Foundation, either version 3 of the License, or
  211.17 +*  (at your option) any later version.
  211.18 +*
  211.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  211.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  211.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  211.22 +*  License for more details.
  211.23 +*
  211.24 +*  You should have received a copy of the GNU General Public License
  211.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  211.26 +***********************************************************************/
  211.27 +
  211.28 +#include "glpios.h"
  211.29 +
  211.30 +/***********************************************************************
  211.31 +*  NAME
  211.32 +*
  211.33 +*  ios_choose_var - select variable to branch on
  211.34 +*
  211.35 +*  SYNOPSIS
  211.36 +*
  211.37 +*  #include "glpios.h"
  211.38 +*  int ios_choose_var(glp_tree *T, int *next);
  211.39 +*
  211.40 +*  The routine ios_choose_var chooses a variable from the candidate
  211.41 +*  list to branch on. Additionally the routine provides a flag stored
  211.42 +*  in the location next to suggests which of the child subproblems
  211.43 +*  should be solved next.
  211.44 +*
  211.45 +*  RETURNS
  211.46 +*
  211.47 +*  The routine ios_choose_var returns the ordinal number of the column
  211.48 +*  choosen. */
  211.49 +
  211.50 +static int branch_first(glp_tree *T, int *next);
  211.51 +static int branch_last(glp_tree *T, int *next);
  211.52 +static int branch_mostf(glp_tree *T, int *next);
  211.53 +static int branch_drtom(glp_tree *T, int *next);
  211.54 +
  211.55 +int ios_choose_var(glp_tree *T, int *next)
  211.56 +{     int j;
  211.57 +      if (T->parm->br_tech == GLP_BR_FFV)
  211.58 +      {  /* branch on first fractional variable */
  211.59 +         j = branch_first(T, next);
  211.60 +      }
  211.61 +      else if (T->parm->br_tech == GLP_BR_LFV)
  211.62 +      {  /* branch on last fractional variable */
  211.63 +         j = branch_last(T, next);
  211.64 +      }
  211.65 +      else if (T->parm->br_tech == GLP_BR_MFV)
  211.66 +      {  /* branch on most fractional variable */
  211.67 +         j = branch_mostf(T, next);
  211.68 +      }
  211.69 +      else if (T->parm->br_tech == GLP_BR_DTH)
  211.70 +      {  /* branch using the heuristic by Dreebeck and Tomlin */
  211.71 +         j = branch_drtom(T, next);
  211.72 +      }
  211.73 +      else if (T->parm->br_tech == GLP_BR_PCH)
  211.74 +      {  /* hybrid pseudocost heuristic */
  211.75 +         j = ios_pcost_branch(T, next);
  211.76 +      }
  211.77 +      else
  211.78 +         xassert(T != T);
  211.79 +      return j;
  211.80 +}
  211.81 +
  211.82 +/***********************************************************************
  211.83 +*  branch_first - choose first branching variable
  211.84 +*
  211.85 +*  This routine looks up the list of structural variables and chooses
  211.86 +*  the first one, which is of integer kind and has fractional value in
  211.87 +*  optimal solution to the current LP relaxation.
  211.88 +*
  211.89 +*  This routine also selects the branch to be solved next where integer
  211.90 +*  infeasibility of the chosen variable is less than in other one. */
  211.91 +
  211.92 +static int branch_first(glp_tree *T, int *_next)
  211.93 +{     int j, next;
  211.94 +      double beta;
  211.95 +      /* choose the column to branch on */
  211.96 +      for (j = 1; j <= T->n; j++)
  211.97 +         if (T->non_int[j]) break;
  211.98 +      xassert(1 <= j && j <= T->n);
  211.99 +      /* select the branch to be solved next */
 211.100 +      beta = glp_get_col_prim(T->mip, j);
 211.101 +      if (beta - floor(beta) < ceil(beta) - beta)
 211.102 +         next = GLP_DN_BRNCH;
 211.103 +      else
 211.104 +         next = GLP_UP_BRNCH;
 211.105 +      *_next = next;
 211.106 +      return j;
 211.107 +}
 211.108 +
 211.109 +/***********************************************************************
 211.110 +*  branch_last - choose last branching variable
 211.111 +*
 211.112 +*  This routine looks up the list of structural variables and chooses
 211.113 +*  the last one, which is of integer kind and has fractional value in
 211.114 +*  optimal solution to the current LP relaxation.
 211.115 +*
 211.116 +*  This routine also selects the branch to be solved next where integer
 211.117 +*  infeasibility of the chosen variable is less than in other one. */
 211.118 +
 211.119 +static int branch_last(glp_tree *T, int *_next)
 211.120 +{     int j, next;
 211.121 +      double beta;
 211.122 +      /* choose the column to branch on */
 211.123 +      for (j = T->n; j >= 1; j--)
 211.124 +         if (T->non_int[j]) break;
 211.125 +      xassert(1 <= j && j <= T->n);
 211.126 +      /* select the branch to be solved next */
 211.127 +      beta = glp_get_col_prim(T->mip, j);
 211.128 +      if (beta - floor(beta) < ceil(beta) - beta)
 211.129 +         next = GLP_DN_BRNCH;
 211.130 +      else
 211.131 +         next = GLP_UP_BRNCH;
 211.132 +      *_next = next;
 211.133 +      return j;
 211.134 +}
 211.135 +
 211.136 +/***********************************************************************
 211.137 +*  branch_mostf - choose most fractional branching variable
 211.138 +*
 211.139 +*  This routine looks up the list of structural variables and chooses
 211.140 +*  that one, which is of integer kind and has most fractional value in
 211.141 +*  optimal solution to the current LP relaxation.
 211.142 +*
 211.143 +*  This routine also selects the branch to be solved next where integer
 211.144 +*  infeasibility of the chosen variable is less than in other one.
 211.145 +*
 211.146 +*  (Alexander Martin notices that "...most infeasible is as good as
 211.147 +*  random...".) */
 211.148 +
 211.149 +static int branch_mostf(glp_tree *T, int *_next)
 211.150 +{     int j, jj, next;
 211.151 +      double beta, most, temp;
 211.152 +      /* choose the column to branch on */
 211.153 +      jj = 0, most = DBL_MAX;
 211.154 +      for (j = 1; j <= T->n; j++)
 211.155 +      {  if (T->non_int[j])
 211.156 +         {  beta = glp_get_col_prim(T->mip, j);
 211.157 +            temp = floor(beta) + 0.5;
 211.158 +            if (most > fabs(beta - temp))
 211.159 +            {  jj = j, most = fabs(beta - temp);
 211.160 +               if (beta < temp)
 211.161 +                  next = GLP_DN_BRNCH;
 211.162 +               else
 211.163 +                  next = GLP_UP_BRNCH;
 211.164 +            }
 211.165 +         }
 211.166 +      }
 211.167 +      *_next = next;
 211.168 +      return jj;
 211.169 +}
 211.170 +
 211.171 +/***********************************************************************
 211.172 +*  branch_drtom - choose branching var using Driebeck-Tomlin heuristic
 211.173 +*
 211.174 +*  This routine chooses a structural variable, which is required to be
 211.175 +*  integral and has fractional value in optimal solution of the current
 211.176 +*  LP relaxation, using a heuristic proposed by Driebeck and Tomlin.
 211.177 +*
 211.178 +*  The routine also selects the branch to be solved next, again due to
 211.179 +*  Driebeck and Tomlin.
 211.180 +*
 211.181 +*  This routine is based on the heuristic proposed in:
 211.182 +*
 211.183 +*  Driebeck N.J. An algorithm for the solution of mixed-integer
 211.184 +*  programming problems, Management Science, 12: 576-87 (1966);
 211.185 +*
 211.186 +*  and improved in:
 211.187 +*
 211.188 +*  Tomlin J.A. Branch and bound methods for integer and non-convex
 211.189 +*  programming, in J.Abadie (ed.), Integer and Nonlinear Programming,
 211.190 +*  North-Holland, Amsterdam, pp. 437-50 (1970).
 211.191 +*
 211.192 +*  Must note that this heuristic is time-expensive, because computing
 211.193 +*  one-step degradation (see the routine below) requires one BTRAN for
 211.194 +*  each fractional-valued structural variable. */
 211.195 +
 211.196 +static int branch_drtom(glp_tree *T, int *_next)
 211.197 +{     glp_prob *mip = T->mip;
 211.198 +      int m = mip->m;
 211.199 +      int n = mip->n;
 211.200 +      char *non_int = T->non_int;
 211.201 +      int j, jj, k, t, next, kase, len, stat, *ind;
 211.202 +      double x, dk, alfa, delta_j, delta_k, delta_z, dz_dn, dz_up,
 211.203 +         dd_dn, dd_up, degrad, *val;
 211.204 +      /* basic solution of LP relaxation must be optimal */
 211.205 +      xassert(glp_get_status(mip) == GLP_OPT);
 211.206 +      /* allocate working arrays */
 211.207 +      ind = xcalloc(1+n, sizeof(int));
 211.208 +      val = xcalloc(1+n, sizeof(double));
 211.209 +      /* nothing has been chosen so far */
 211.210 +      jj = 0, degrad = -1.0;
 211.211 +      /* walk through the list of columns (structural variables) */
 211.212 +      for (j = 1; j <= n; j++)
 211.213 +      {  /* if j-th column is not marked as fractional, skip it */
 211.214 +         if (!non_int[j]) continue;
 211.215 +         /* obtain (fractional) value of j-th column in basic solution
 211.216 +            of LP relaxation */
 211.217 +         x = glp_get_col_prim(mip, j);
 211.218 +         /* since the value of j-th column is fractional, the column is
 211.219 +            basic; compute corresponding row of the simplex table */
 211.220 +         len = glp_eval_tab_row(mip, m+j, ind, val);
 211.221 +         /* the following fragment computes a change in the objective
 211.222 +            function: delta Z = new Z - old Z, where old Z is the
 211.223 +            objective value in the current optimal basis, and new Z is
 211.224 +            the objective value in the adjacent basis, for two cases:
 211.225 +            1) if new upper bound ub' = floor(x[j]) is introduced for
 211.226 +               j-th column (down branch);
 211.227 +            2) if new lower bound lb' = ceil(x[j]) is introduced for
 211.228 +               j-th column (up branch);
 211.229 +            since in both cases the solution remaining dual feasible
 211.230 +            becomes primal infeasible, one implicit simplex iteration
 211.231 +            is performed to determine the change delta Z;
 211.232 +            it is obvious that new Z, which is never better than old Z,
 211.233 +            is a lower (minimization) or upper (maximization) bound of
 211.234 +            the objective function for down- and up-branches. */
 211.235 +         for (kase = -1; kase <= +1; kase += 2)
 211.236 +         {  /* if kase < 0, the new upper bound of x[j] is introduced;
 211.237 +               in this case x[j] should decrease in order to leave the
 211.238 +               basis and go to its new upper bound */
 211.239 +            /* if kase > 0, the new lower bound of x[j] is introduced;
 211.240 +               in this case x[j] should increase in order to leave the
 211.241 +               basis and go to its new lower bound */
 211.242 +            /* apply the dual ratio test in order to determine which
 211.243 +               auxiliary or structural variable should enter the basis
 211.244 +               to keep dual feasibility */
 211.245 +            k = glp_dual_rtest(mip, len, ind, val, kase, 1e-9);
 211.246 +            if (k != 0) k = ind[k];
 211.247 +            /* if no non-basic variable has been chosen, LP relaxation
 211.248 +               of corresponding branch being primal infeasible and dual
 211.249 +               unbounded has no primal feasible solution; in this case
 211.250 +               the change delta Z is formally set to infinity */
 211.251 +            if (k == 0)
 211.252 +            {  delta_z =
 211.253 +                  (T->mip->dir == GLP_MIN ? +DBL_MAX : -DBL_MAX);
 211.254 +               goto skip;
 211.255 +            }
 211.256 +            /* row of the simplex table that corresponds to non-basic
 211.257 +               variable x[k] choosen by the dual ratio test is:
 211.258 +                  x[j] = ... + alfa * x[k] + ...
 211.259 +               where alfa is the influence coefficient (an element of
 211.260 +               the simplex table row) */
 211.261 +            /* determine the coefficient alfa */
 211.262 +            for (t = 1; t <= len; t++) if (ind[t] == k) break;
 211.263 +            xassert(1 <= t && t <= len);
 211.264 +            alfa = val[t];
 211.265 +            /* since in the adjacent basis the variable x[j] becomes
 211.266 +               non-basic, knowing its value in the current basis we can
 211.267 +               determine its change delta x[j] = new x[j] - old x[j] */
 211.268 +            delta_j = (kase < 0 ? floor(x) : ceil(x)) - x;
 211.269 +            /* and knowing the coefficient alfa we can determine the
 211.270 +               corresponding change delta x[k] = new x[k] - old x[k],
 211.271 +               where old x[k] is a value of x[k] in the current basis,
 211.272 +               and new x[k] is a value of x[k] in the adjacent basis */
 211.273 +            delta_k = delta_j / alfa;
 211.274 +            /* Tomlin noticed that if the variable x[k] is of integer
 211.275 +               kind, its change cannot be less (eventually) than one in
 211.276 +               the magnitude */
 211.277 +            if (k > m && glp_get_col_kind(mip, k-m) != GLP_CV)
 211.278 +            {  /* x[k] is structural integer variable */
 211.279 +               if (fabs(delta_k - floor(delta_k + 0.5)) > 1e-3)
 211.280 +               {  if (delta_k > 0.0)
 211.281 +                     delta_k = ceil(delta_k);  /* +3.14 -> +4 */
 211.282 +                  else
 211.283 +                     delta_k = floor(delta_k); /* -3.14 -> -4 */
 211.284 +               }
 211.285 +            }
 211.286 +            /* now determine the status and reduced cost of x[k] in the
 211.287 +               current basis */
 211.288 +            if (k <= m)
 211.289 +            {  stat = glp_get_row_stat(mip, k);
 211.290 +               dk = glp_get_row_dual(mip, k);
 211.291 +            }
 211.292 +            else
 211.293 +            {  stat = glp_get_col_stat(mip, k-m);
 211.294 +               dk = glp_get_col_dual(mip, k-m);
 211.295 +            }
 211.296 +            /* if the current basis is dual degenerate, some reduced
 211.297 +               costs which are close to zero may have wrong sign due to
 211.298 +               round-off errors, so correct the sign of d[k] */
 211.299 +            switch (T->mip->dir)
 211.300 +            {  case GLP_MIN:
 211.301 +                  if (stat == GLP_NL && dk < 0.0 ||
 211.302 +                      stat == GLP_NU && dk > 0.0 ||
 211.303 +                      stat == GLP_NF) dk = 0.0;
 211.304 +                  break;
 211.305 +               case GLP_MAX:
 211.306 +                  if (stat == GLP_NL && dk > 0.0 ||
 211.307 +                      stat == GLP_NU && dk < 0.0 ||
 211.308 +                      stat == GLP_NF) dk = 0.0;
 211.309 +                  break;
 211.310 +               default:
 211.311 +                  xassert(T != T);
 211.312 +            }
 211.313 +            /* now knowing the change of x[k] and its reduced cost d[k]
 211.314 +               we can compute the corresponding change in the objective
 211.315 +               function delta Z = new Z - old Z = d[k] * delta x[k];
 211.316 +               note that due to Tomlin's modification new Z can be even
 211.317 +               worse than in the adjacent basis */
 211.318 +            delta_z = dk * delta_k;
 211.319 +skip:       /* new Z is never better than old Z, therefore the change
 211.320 +               delta Z is always non-negative (in case of minimization)
 211.321 +               or non-positive (in case of maximization) */
 211.322 +            switch (T->mip->dir)
 211.323 +            {  case GLP_MIN: xassert(delta_z >= 0.0); break;
 211.324 +               case GLP_MAX: xassert(delta_z <= 0.0); break;
 211.325 +               default: xassert(T != T);
 211.326 +            }
 211.327 +            /* save the change in the objective fnction for down- and
 211.328 +               up-branches, respectively */
 211.329 +            if (kase < 0) dz_dn = delta_z; else dz_up = delta_z;
 211.330 +         }
 211.331 +         /* thus, in down-branch no integer feasible solution can be
 211.332 +            better than Z + dz_dn, and in up-branch no integer feasible
 211.333 +            solution can be better than Z + dz_up, where Z is value of
 211.334 +            the objective function in the current basis */
 211.335 +         /* following the heuristic by Driebeck and Tomlin we choose a
 211.336 +            column (i.e. structural variable) which provides largest
 211.337 +            degradation of the objective function in some of branches;
 211.338 +            besides, we select the branch with smaller degradation to
 211.339 +            be solved next and keep other branch with larger degradation
 211.340 +            in the active list hoping to minimize the number of further
 211.341 +            backtrackings */
 211.342 +         if (degrad < fabs(dz_dn) || degrad < fabs(dz_up))
 211.343 +         {  jj = j;
 211.344 +            if (fabs(dz_dn) < fabs(dz_up))
 211.345 +            {  /* select down branch to be solved next */
 211.346 +               next = GLP_DN_BRNCH;
 211.347 +               degrad = fabs(dz_up);
 211.348 +            }
 211.349 +            else
 211.350 +            {  /* select up branch to be solved next */
 211.351 +               next = GLP_UP_BRNCH;
 211.352 +               degrad = fabs(dz_dn);
 211.353 +            }
 211.354 +            /* save the objective changes for printing */
 211.355 +            dd_dn = dz_dn, dd_up = dz_up;
 211.356 +            /* if down- or up-branch has no feasible solution, we does
 211.357 +               not need to consider other candidates (in principle, the
 211.358 +               corresponding branch could be pruned right now) */
 211.359 +            if (degrad == DBL_MAX) break;
 211.360 +         }
 211.361 +      }
 211.362 +      /* free working arrays */
 211.363 +      xfree(ind);
 211.364 +      xfree(val);
 211.365 +      /* something must be chosen */
 211.366 +      xassert(1 <= jj && jj <= n);
 211.367 +#if 1 /* 02/XI-2009 */
 211.368 +      if (degrad < 1e-6 * (1.0 + 0.001 * fabs(mip->obj_val)))
 211.369 +      {  jj = branch_mostf(T, &next);
 211.370 +         goto done;
 211.371 +      }
 211.372 +#endif
 211.373 +      if (T->parm->msg_lev >= GLP_MSG_DBG)
 211.374 +      {  xprintf("branch_drtom: column %d chosen to branch on\n", jj);
 211.375 +         if (fabs(dd_dn) == DBL_MAX)
 211.376 +            xprintf("branch_drtom: down-branch is infeasible\n");
 211.377 +         else
 211.378 +            xprintf("branch_drtom: down-branch bound is %.9e\n",
 211.379 +               lpx_get_obj_val(mip) + dd_dn);
 211.380 +         if (fabs(dd_up) == DBL_MAX)
 211.381 +            xprintf("branch_drtom: up-branch   is infeasible\n");
 211.382 +         else
 211.383 +            xprintf("branch_drtom: up-branch   bound is %.9e\n",
 211.384 +               lpx_get_obj_val(mip) + dd_up);
 211.385 +      }
 211.386 +done: *_next = next;
 211.387 +      return jj;
 211.388 +}
 211.389 +
 211.390 +/**********************************************************************/
 211.391 +
 211.392 +struct csa
 211.393 +{     /* common storage area */
 211.394 +      int *dn_cnt; /* int dn_cnt[1+n]; */
 211.395 +      /* dn_cnt[j] is the number of subproblems, whose LP relaxations
 211.396 +         have been solved and which are down-branches for variable x[j];
 211.397 +         dn_cnt[j] = 0 means the down pseudocost is uninitialized */
 211.398 +      double *dn_sum; /* double dn_sum[1+n]; */
 211.399 +      /* dn_sum[j] is the sum of per unit degradations of the objective
 211.400 +         over all dn_cnt[j] subproblems */
 211.401 +      int *up_cnt; /* int up_cnt[1+n]; */
 211.402 +      /* up_cnt[j] is the number of subproblems, whose LP relaxations
 211.403 +         have been solved and which are up-branches for variable x[j];
 211.404 +         up_cnt[j] = 0 means the up pseudocost is uninitialized */
 211.405 +      double *up_sum; /* double up_sum[1+n]; */
 211.406 +      /* up_sum[j] is the sum of per unit degradations of the objective
 211.407 +         over all up_cnt[j] subproblems */
 211.408 +};
 211.409 +
 211.410 +void *ios_pcost_init(glp_tree *tree)
 211.411 +{     /* initialize working data used on pseudocost branching */
 211.412 +      struct csa *csa;
 211.413 +      int n = tree->n, j;
 211.414 +      csa = xmalloc(sizeof(struct csa));
 211.415 +      csa->dn_cnt = xcalloc(1+n, sizeof(int));
 211.416 +      csa->dn_sum = xcalloc(1+n, sizeof(double));
 211.417 +      csa->up_cnt = xcalloc(1+n, sizeof(int));
 211.418 +      csa->up_sum = xcalloc(1+n, sizeof(double));
 211.419 +      for (j = 1; j <= n; j++)
 211.420 +      {  csa->dn_cnt[j] = csa->up_cnt[j] = 0;
 211.421 +         csa->dn_sum[j] = csa->up_sum[j] = 0.0;
 211.422 +      }
 211.423 +      return csa;
 211.424 +}
 211.425 +
 211.426 +static double eval_degrad(glp_prob *P, int j, double bnd)
 211.427 +{     /* compute degradation of the objective on fixing x[j] at given
 211.428 +         value with a limited number of dual simplex iterations */
 211.429 +      /* this routine fixes column x[j] at specified value bnd,
 211.430 +         solves resulting LP, and returns a lower bound to degradation
 211.431 +         of the objective, degrad >= 0 */
 211.432 +      glp_prob *lp;
 211.433 +      glp_smcp parm;
 211.434 +      int ret;
 211.435 +      double degrad;
 211.436 +      /* the current basis must be optimal */
 211.437 +      xassert(glp_get_status(P) == GLP_OPT);
 211.438 +      /* create a copy of P */
 211.439 +      lp = glp_create_prob();
 211.440 +      glp_copy_prob(lp, P, 0);
 211.441 +      /* fix column x[j] at specified value */
 211.442 +      glp_set_col_bnds(lp, j, GLP_FX, bnd, bnd);
 211.443 +      /* try to solve resulting LP */
 211.444 +      glp_init_smcp(&parm);
 211.445 +      parm.msg_lev = GLP_MSG_OFF;
 211.446 +      parm.meth = GLP_DUAL;
 211.447 +      parm.it_lim = 30;
 211.448 +      parm.out_dly = 1000;
 211.449 +      parm.meth = GLP_DUAL;
 211.450 +      ret = glp_simplex(lp, &parm);
 211.451 +      if (ret == 0 || ret == GLP_EITLIM)
 211.452 +      {  if (glp_get_prim_stat(lp) == GLP_NOFEAS)
 211.453 +         {  /* resulting LP has no primal feasible solution */
 211.454 +            degrad = DBL_MAX;
 211.455 +         }
 211.456 +         else if (glp_get_dual_stat(lp) == GLP_FEAS)
 211.457 +         {  /* resulting basis is optimal or at least dual feasible,
 211.458 +               so we have the correct lower bound to degradation */
 211.459 +            if (P->dir == GLP_MIN)
 211.460 +               degrad = lp->obj_val - P->obj_val;
 211.461 +            else if (P->dir == GLP_MAX)
 211.462 +               degrad = P->obj_val - lp->obj_val;
 211.463 +            else
 211.464 +               xassert(P != P);
 211.465 +            /* degradation cannot be negative by definition */
 211.466 +            /* note that the lower bound to degradation may be close
 211.467 +               to zero even if its exact value is zero due to round-off
 211.468 +               errors on computing the objective value */
 211.469 +            if (degrad < 1e-6 * (1.0 + 0.001 * fabs(P->obj_val)))
 211.470 +               degrad = 0.0;
 211.471 +         }
 211.472 +         else
 211.473 +         {  /* the final basis reported by the simplex solver is dual
 211.474 +               infeasible, so we cannot determine a non-trivial lower
 211.475 +               bound to degradation */
 211.476 +            degrad = 0.0;
 211.477 +         }
 211.478 +      }
 211.479 +      else
 211.480 +      {  /* the simplex solver failed */
 211.481 +         degrad = 0.0;
 211.482 +      }
 211.483 +      /* delete the copy of P */
 211.484 +      glp_delete_prob(lp);
 211.485 +      return degrad;
 211.486 +}
 211.487 +
 211.488 +void ios_pcost_update(glp_tree *tree)
 211.489 +{     /* update history information for pseudocost branching */
 211.490 +      /* this routine is called every time when LP relaxation of the
 211.491 +         current subproblem has been solved to optimality with all lazy
 211.492 +         and cutting plane constraints included */
 211.493 +      int j;
 211.494 +      double dx, dz, psi;
 211.495 +      struct csa *csa = tree->pcost;
 211.496 +      xassert(csa != NULL);
 211.497 +      xassert(tree->curr != NULL);
 211.498 +      /* if the current subproblem is the root, skip updating */
 211.499 +      if (tree->curr->up == NULL) goto skip;
 211.500 +      /* determine branching variable x[j], which was used in the
 211.501 +         parent subproblem to create the current subproblem */
 211.502 +      j = tree->curr->up->br_var;
 211.503 +      xassert(1 <= j && j <= tree->n);
 211.504 +      /* determine the change dx[j] = new x[j] - old x[j],
 211.505 +         where new x[j] is a value of x[j] in optimal solution to LP
 211.506 +         relaxation of the current subproblem, old x[j] is a value of
 211.507 +         x[j] in optimal solution to LP relaxation of the parent
 211.508 +         subproblem */
 211.509 +      dx = tree->mip->col[j]->prim - tree->curr->up->br_val;
 211.510 +      xassert(dx != 0.0);
 211.511 +      /* determine corresponding change dz = new dz - old dz in the
 211.512 +         objective function value */
 211.513 +      dz = tree->mip->obj_val - tree->curr->up->lp_obj;
 211.514 +      /* determine per unit degradation of the objective function */
 211.515 +      psi = fabs(dz / dx);
 211.516 +      /* update history information */
 211.517 +      if (dx < 0.0)
 211.518 +      {  /* the current subproblem is down-branch */
 211.519 +         csa->dn_cnt[j]++;
 211.520 +         csa->dn_sum[j] += psi;
 211.521 +      }
 211.522 +      else /* dx > 0.0 */
 211.523 +      {  /* the current subproblem is up-branch */
 211.524 +         csa->up_cnt[j]++;
 211.525 +         csa->up_sum[j] += psi;
 211.526 +      }
 211.527 +skip: return;
 211.528 +}
 211.529 +
 211.530 +void ios_pcost_free(glp_tree *tree)
 211.531 +{     /* free working area used on pseudocost branching */
 211.532 +      struct csa *csa = tree->pcost;
 211.533 +      xassert(csa != NULL);
 211.534 +      xfree(csa->dn_cnt);
 211.535 +      xfree(csa->dn_sum);
 211.536 +      xfree(csa->up_cnt);
 211.537 +      xfree(csa->up_sum);
 211.538 +      xfree(csa);
 211.539 +      tree->pcost = NULL;
 211.540 +      return;
 211.541 +}
 211.542 +
 211.543 +static double eval_psi(glp_tree *T, int j, int brnch)
 211.544 +{     /* compute estimation of pseudocost of variable x[j] for down-
 211.545 +         or up-branch */
 211.546 +      struct csa *csa = T->pcost;
 211.547 +      double beta, degrad, psi;
 211.548 +      xassert(csa != NULL);
 211.549 +      xassert(1 <= j && j <= T->n);
 211.550 +      if (brnch == GLP_DN_BRNCH)
 211.551 +      {  /* down-branch */
 211.552 +         if (csa->dn_cnt[j] == 0)
 211.553 +         {  /* initialize down pseudocost */
 211.554 +            beta = T->mip->col[j]->prim;
 211.555 +            degrad = eval_degrad(T->mip, j, floor(beta));
 211.556 +            if (degrad == DBL_MAX)
 211.557 +            {  psi = DBL_MAX;
 211.558 +               goto done;
 211.559 +            }
 211.560 +            csa->dn_cnt[j] = 1;
 211.561 +            csa->dn_sum[j] = degrad / (beta - floor(beta));
 211.562 +         }
 211.563 +         psi = csa->dn_sum[j] / (double)csa->dn_cnt[j];
 211.564 +      }
 211.565 +      else if (brnch == GLP_UP_BRNCH)
 211.566 +      {  /* up-branch */
 211.567 +         if (csa->up_cnt[j] == 0)
 211.568 +         {  /* initialize up pseudocost */
 211.569 +            beta = T->mip->col[j]->prim;
 211.570 +            degrad = eval_degrad(T->mip, j, ceil(beta));
 211.571 +            if (degrad == DBL_MAX)
 211.572 +            {  psi = DBL_MAX;
 211.573 +               goto done;
 211.574 +            }
 211.575 +            csa->up_cnt[j] = 1;
 211.576 +            csa->up_sum[j] = degrad / (ceil(beta) - beta);
 211.577 +         }
 211.578 +         psi = csa->up_sum[j] / (double)csa->up_cnt[j];
 211.579 +      }
 211.580 +      else
 211.581 +         xassert(brnch != brnch);
 211.582 +done: return psi;
 211.583 +}
 211.584 +
 211.585 +static void progress(glp_tree *T)
 211.586 +{     /* display progress of pseudocost initialization */
 211.587 +      struct csa *csa = T->pcost;
 211.588 +      int j, nv = 0, ni = 0;
 211.589 +      for (j = 1; j <= T->n; j++)
 211.590 +      {  if (glp_ios_can_branch(T, j))
 211.591 +         {  nv++;
 211.592 +            if (csa->dn_cnt[j] > 0 && csa->up_cnt[j] > 0) ni++;
 211.593 +         }
 211.594 +      }
 211.595 +      xprintf("Pseudocosts initialized for %d of %d variables\n",
 211.596 +         ni, nv);
 211.597 +      return;
 211.598 +}
 211.599 +
 211.600 +int ios_pcost_branch(glp_tree *T, int *_next)
 211.601 +{     /* choose branching variable with pseudocost branching */
 211.602 +      glp_long t = xtime();
 211.603 +      int j, jjj, sel;
 211.604 +      double beta, psi, d1, d2, d, dmax;
 211.605 +      /* initialize the working arrays */
 211.606 +      if (T->pcost == NULL)
 211.607 +         T->pcost = ios_pcost_init(T);
 211.608 +      /* nothing has been chosen so far */
 211.609 +      jjj = 0, dmax = -1.0;
 211.610 +      /* go through the list of branching candidates */
 211.611 +      for (j = 1; j <= T->n; j++)
 211.612 +      {  if (!glp_ios_can_branch(T, j)) continue;
 211.613 +         /* determine primal value of x[j] in optimal solution to LP
 211.614 +            relaxation of the current subproblem */
 211.615 +         beta = T->mip->col[j]->prim;
 211.616 +         /* estimate pseudocost of x[j] for down-branch */
 211.617 +         psi = eval_psi(T, j, GLP_DN_BRNCH);
 211.618 +         if (psi == DBL_MAX)
 211.619 +         {  /* down-branch has no primal feasible solution */
 211.620 +            jjj = j, sel = GLP_DN_BRNCH;
 211.621 +            goto done;
 211.622 +         }
 211.623 +         /* estimate degradation of the objective for down-branch */
 211.624 +         d1 = psi * (beta - floor(beta));
 211.625 +         /* estimate pseudocost of x[j] for up-branch */
 211.626 +         psi = eval_psi(T, j, GLP_UP_BRNCH);
 211.627 +         if (psi == DBL_MAX)
 211.628 +         {  /* up-branch has no primal feasible solution */
 211.629 +            jjj = j, sel = GLP_UP_BRNCH;
 211.630 +            goto done;
 211.631 +         }
 211.632 +         /* estimate degradation of the objective for up-branch */
 211.633 +         d2 = psi * (ceil(beta) - beta);
 211.634 +         /* determine d = max(d1, d2) */
 211.635 +         d = (d1 > d2 ? d1 : d2);
 211.636 +         /* choose x[j] which provides maximal estimated degradation of
 211.637 +            the objective either in down- or up-branch */
 211.638 +         if (dmax < d)
 211.639 +         {  dmax = d;
 211.640 +            jjj = j;
 211.641 +            /* continue the search from a subproblem, where degradation
 211.642 +               is less than in other one */
 211.643 +            sel = (d1 <= d2 ? GLP_DN_BRNCH : GLP_UP_BRNCH);
 211.644 +         }
 211.645 +         /* display progress of pseudocost initialization */
 211.646 +         if (T->parm->msg_lev >= GLP_ON)
 211.647 +         {  if (xdifftime(xtime(), t) >= 10.0)
 211.648 +            {  progress(T);
 211.649 +               t = xtime();
 211.650 +            }
 211.651 +         }
 211.652 +      }
 211.653 +      if (dmax == 0.0)
 211.654 +      {  /* no degradation is indicated; choose a variable having most
 211.655 +            fractional value */
 211.656 +         jjj = branch_mostf(T, &sel);
 211.657 +      }
 211.658 +done: *_next = sel;
 211.659 +      return jjj;
 211.660 +}
 211.661 +
 211.662 +/* eof */
   212.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   212.2 +++ b/src/glpios10.c	Mon Dec 06 13:09:21 2010 +0100
   212.3 @@ -0,0 +1,348 @@
   212.4 +/* glpios10.c (feasibility pump heuristic) */
   212.5 +
   212.6 +/***********************************************************************
   212.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   212.8 +*
   212.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  212.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  212.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  212.12 +*  E-mail: <mao@gnu.org>.
  212.13 +*
  212.14 +*  GLPK is free software: you can redistribute it and/or modify it
  212.15 +*  under the terms of the GNU General Public License as published by
  212.16 +*  the Free Software Foundation, either version 3 of the License, or
  212.17 +*  (at your option) any later version.
  212.18 +*
  212.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  212.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  212.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  212.22 +*  License for more details.
  212.23 +*
  212.24 +*  You should have received a copy of the GNU General Public License
  212.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  212.26 +***********************************************************************/
  212.27 +
  212.28 +#include "glpios.h"
  212.29 +#include "glprng.h"
  212.30 +
  212.31 +/***********************************************************************
  212.32 +*  NAME
  212.33 +*
  212.34 +*  ios_feas_pump - feasibility pump heuristic
  212.35 +*
  212.36 +*  SYNOPSIS
  212.37 +*
  212.38 +*  #include "glpios.h"
  212.39 +*  void ios_feas_pump(glp_tree *T);
  212.40 +*
  212.41 +*  DESCRIPTION
  212.42 +*
  212.43 +*  The routine ios_feas_pump is a simple implementation of the Feasi-
  212.44 +*  bility Pump heuristic.
  212.45 +*
  212.46 +*  REFERENCES
  212.47 +*
  212.48 +*  M.Fischetti, F.Glover, and A.Lodi. "The feasibility pump." Math.
  212.49 +*  Program., Ser. A 104, pp. 91-104 (2005). */
  212.50 +
  212.51 +struct VAR
  212.52 +{     /* binary variable */
  212.53 +      int j;
  212.54 +      /* ordinal number */
  212.55 +      int x;
  212.56 +      /* value in the rounded solution (0 or 1) */
  212.57 +      double d;
  212.58 +      /* sorting key */
  212.59 +};
  212.60 +
  212.61 +static int fcmp(const void *x, const void *y)
  212.62 +{     /* comparison routine */
  212.63 +      const struct VAR *vx = x, *vy = y;
  212.64 +      if (vx->d > vy->d)
  212.65 +         return -1;
  212.66 +      else if (vx->d < vy->d)
  212.67 +         return +1;
  212.68 +      else
  212.69 +         return 0;
  212.70 +}
  212.71 +
  212.72 +void ios_feas_pump(glp_tree *T)
  212.73 +{     glp_prob *P = T->mip;
  212.74 +      int n = P->n;
  212.75 +      glp_prob *lp = NULL;
  212.76 +      struct VAR *var = NULL;
  212.77 +      RNG *rand = NULL;
  212.78 +      GLPCOL *col;
  212.79 +      glp_smcp parm;
  212.80 +      int j, k, new_x, nfail, npass, nv, ret, stalling;
  212.81 +      double dist, tol;
  212.82 +      xassert(glp_get_status(P) == GLP_OPT);
  212.83 +      /* this heuristic is applied only once on the root level */
  212.84 +      if (!(T->curr->level == 0 && T->curr->solved == 1)) goto done;
  212.85 +      /* determine number of binary variables */
  212.86 +      nv = 0;
  212.87 +      for (j = 1; j <= n; j++)
  212.88 +      {  col = P->col[j];
  212.89 +         /* if x[j] is continuous, skip it */
  212.90 +         if (col->kind == GLP_CV) continue;
  212.91 +         /* if x[j] is fixed, skip it */
  212.92 +         if (col->type == GLP_FX) continue;
  212.93 +         /* x[j] is non-fixed integer */
  212.94 +         xassert(col->kind == GLP_IV);
  212.95 +         if (col->type == GLP_DB && col->lb == 0.0 && col->ub == 1.0)
  212.96 +         {  /* x[j] is binary */
  212.97 +            nv++;
  212.98 +         }
  212.99 +         else
 212.100 +         {  /* x[j] is general integer */
 212.101 +            if (T->parm->msg_lev >= GLP_MSG_ALL)
 212.102 +               xprintf("FPUMP heuristic cannot be applied due to genera"
 212.103 +                  "l integer variables\n");
 212.104 +            goto done;
 212.105 +         }
 212.106 +      }
 212.107 +      /* there must be at least one binary variable */
 212.108 +      if (nv == 0) goto done;
 212.109 +      if (T->parm->msg_lev >= GLP_MSG_ALL)
 212.110 +         xprintf("Applying FPUMP heuristic...\n");
 212.111 +      /* build the list of binary variables */
 212.112 +      var = xcalloc(1+nv, sizeof(struct VAR));
 212.113 +      k = 0;
 212.114 +      for (j = 1; j <= n; j++)
 212.115 +      {  col = P->col[j];
 212.116 +         if (col->kind == GLP_IV && col->type == GLP_DB)
 212.117 +            var[++k].j = j;
 212.118 +      }
 212.119 +      xassert(k == nv);
 212.120 +      /* create working problem object */
 212.121 +      lp = glp_create_prob();
 212.122 +more: /* copy the original problem object to keep it intact */
 212.123 +      glp_copy_prob(lp, P, GLP_OFF);
 212.124 +      /* we are interested to find an integer feasible solution, which
 212.125 +         is better than the best known one */
 212.126 +      if (P->mip_stat == GLP_FEAS)
 212.127 +      {  int *ind;
 212.128 +         double *val, bnd;
 212.129 +         /* add a row and make it identical to the objective row */
 212.130 +         glp_add_rows(lp, 1);
 212.131 +         ind = xcalloc(1+n, sizeof(int));
 212.132 +         val = xcalloc(1+n, sizeof(double));
 212.133 +         for (j = 1; j <= n; j++)
 212.134 +         {  ind[j] = j;
 212.135 +            val[j] = P->col[j]->coef;
 212.136 +         }
 212.137 +         glp_set_mat_row(lp, lp->m, n, ind, val);
 212.138 +         xfree(ind);
 212.139 +         xfree(val);
 212.140 +         /* introduce upper (minimization) or lower (maximization)
 212.141 +            bound to the original objective function; note that this
 212.142 +            additional constraint is not violated at the optimal point
 212.143 +            to LP relaxation */
 212.144 +#if 0 /* modified by xypron <xypron.glpk@gmx.de> */
 212.145 +         if (P->dir == GLP_MIN)
 212.146 +         {  bnd = P->mip_obj - 0.10 * (1.0 + fabs(P->mip_obj));
 212.147 +            if (bnd < P->obj_val) bnd = P->obj_val;
 212.148 +            glp_set_row_bnds(lp, lp->m, GLP_UP, 0.0, bnd - P->c0);
 212.149 +         }
 212.150 +         else if (P->dir == GLP_MAX)
 212.151 +         {  bnd = P->mip_obj + 0.10 * (1.0 + fabs(P->mip_obj));
 212.152 +            if (bnd > P->obj_val) bnd = P->obj_val;
 212.153 +            glp_set_row_bnds(lp, lp->m, GLP_LO, bnd - P->c0, 0.0);
 212.154 +         }
 212.155 +         else
 212.156 +            xassert(P != P);
 212.157 +#else
 212.158 +         bnd = 0.1 * P->obj_val + 0.9 * P->mip_obj;
 212.159 +         /* xprintf("bnd = %f\n", bnd); */
 212.160 +         if (P->dir == GLP_MIN)
 212.161 +            glp_set_row_bnds(lp, lp->m, GLP_UP, 0.0, bnd - P->c0);
 212.162 +         else if (P->dir == GLP_MAX)
 212.163 +            glp_set_row_bnds(lp, lp->m, GLP_LO, bnd - P->c0, 0.0);
 212.164 +         else
 212.165 +            xassert(P != P);
 212.166 +#endif
 212.167 +      }
 212.168 +      /* reset pass count */
 212.169 +      npass = 0;
 212.170 +      /* invalidate the rounded point */
 212.171 +      for (k = 1; k <= nv; k++)
 212.172 +         var[k].x = -1;
 212.173 +pass: /* next pass starts here */
 212.174 +      npass++;
 212.175 +      if (T->parm->msg_lev >= GLP_MSG_ALL)
 212.176 +         xprintf("Pass %d\n", npass);
 212.177 +      /* initialize minimal distance between the basic point and the
 212.178 +         rounded one obtained during this pass */
 212.179 +      dist = DBL_MAX;
 212.180 +      /* reset failure count (the number of succeeded iterations failed
 212.181 +         to improve the distance) */
 212.182 +      nfail = 0;
 212.183 +      /* if it is not the first pass, perturb the last rounded point
 212.184 +         rather than construct it from the basic solution */
 212.185 +      if (npass > 1)
 212.186 +      {  double rho, temp;
 212.187 +         if (rand == NULL)
 212.188 +            rand = rng_create_rand();
 212.189 +         for (k = 1; k <= nv; k++)
 212.190 +         {  j = var[k].j;
 212.191 +            col = lp->col[j];
 212.192 +            rho = rng_uniform(rand, -0.3, 0.7);
 212.193 +            if (rho < 0.0) rho = 0.0;
 212.194 +            temp = fabs((double)var[k].x - col->prim);
 212.195 +            if (temp + rho > 0.5) var[k].x = 1 - var[k].x;
 212.196 +         }
 212.197 +         goto skip;
 212.198 +      }
 212.199 +loop: /* innermost loop begins here */
 212.200 +      /* round basic solution (which is assumed primal feasible) */
 212.201 +      stalling = 1;
 212.202 +      for (k = 1; k <= nv; k++)
 212.203 +      {  col = lp->col[var[k].j];
 212.204 +         if (col->prim < 0.5)
 212.205 +         {  /* rounded value is 0 */
 212.206 +            new_x = 0;
 212.207 +         }
 212.208 +         else
 212.209 +         {  /* rounded value is 1 */
 212.210 +            new_x = 1;
 212.211 +         }
 212.212 +         if (var[k].x != new_x)
 212.213 +         {  stalling = 0;
 212.214 +            var[k].x = new_x;
 212.215 +         }
 212.216 +      }
 212.217 +      /* if the rounded point has not changed (stalling), choose and
 212.218 +         flip some its entries heuristically */
 212.219 +      if (stalling)
 212.220 +      {  /* compute d[j] = |x[j] - round(x[j])| */
 212.221 +         for (k = 1; k <= nv; k++)
 212.222 +         {  col = lp->col[var[k].j];
 212.223 +            var[k].d = fabs(col->prim - (double)var[k].x);
 212.224 +         }
 212.225 +         /* sort the list of binary variables by descending d[j] */
 212.226 +         qsort(&var[1], nv, sizeof(struct VAR), fcmp);
 212.227 +         /* choose and flip some rounded components */
 212.228 +         for (k = 1; k <= nv; k++)
 212.229 +         {  if (k >= 5 && var[k].d < 0.35 || k >= 10) break;
 212.230 +            var[k].x = 1 - var[k].x;
 212.231 +         }
 212.232 +      }
 212.233 +skip: /* check if the time limit has been exhausted */
 212.234 +      if (T->parm->tm_lim < INT_MAX &&
 212.235 +         (double)(T->parm->tm_lim - 1) <=
 212.236 +         1000.0 * xdifftime(xtime(), T->tm_beg)) goto done;
 212.237 +      /* build the objective, which is the distance between the current
 212.238 +         (basic) point and the rounded one */
 212.239 +      lp->dir = GLP_MIN;
 212.240 +      lp->c0 = 0.0;
 212.241 +      for (j = 1; j <= n; j++)
 212.242 +         lp->col[j]->coef = 0.0;
 212.243 +      for (k = 1; k <= nv; k++)
 212.244 +      {  j = var[k].j;
 212.245 +         if (var[k].x == 0)
 212.246 +            lp->col[j]->coef = +1.0;
 212.247 +         else
 212.248 +         {  lp->col[j]->coef = -1.0;
 212.249 +            lp->c0 += 1.0;
 212.250 +         }
 212.251 +      }
 212.252 +      /* minimize the distance with the simplex method */
 212.253 +      glp_init_smcp(&parm);
 212.254 +      if (T->parm->msg_lev <= GLP_MSG_ERR)
 212.255 +         parm.msg_lev = T->parm->msg_lev;
 212.256 +      else if (T->parm->msg_lev <= GLP_MSG_ALL)
 212.257 +      {  parm.msg_lev = GLP_MSG_ON;
 212.258 +         parm.out_dly = 10000;
 212.259 +      }
 212.260 +      ret = glp_simplex(lp, &parm);
 212.261 +      if (ret != 0)
 212.262 +      {  if (T->parm->msg_lev >= GLP_MSG_ERR)
 212.263 +            xprintf("Warning: glp_simplex returned %d\n", ret);
 212.264 +         goto done;
 212.265 +      }
 212.266 +      ret = glp_get_status(lp);
 212.267 +      if (ret != GLP_OPT)
 212.268 +      {  if (T->parm->msg_lev >= GLP_MSG_ERR)
 212.269 +            xprintf("Warning: glp_get_status returned %d\n", ret);
 212.270 +         goto done;
 212.271 +      }
 212.272 +      if (T->parm->msg_lev >= GLP_MSG_DBG)
 212.273 +         xprintf("delta = %g\n", lp->obj_val);
 212.274 +      /* check if the basic solution is integer feasible; note that it
 212.275 +         may be so even if the minimial distance is positive */
 212.276 +      tol = 0.3 * T->parm->tol_int;
 212.277 +      for (k = 1; k <= nv; k++)
 212.278 +      {  col = lp->col[var[k].j];
 212.279 +         if (tol < col->prim && col->prim < 1.0 - tol) break;
 212.280 +      }
 212.281 +      if (k > nv)
 212.282 +      {  /* okay; the basic solution seems to be integer feasible */
 212.283 +         double *x = xcalloc(1+n, sizeof(double));
 212.284 +         for (j = 1; j <= n; j++)
 212.285 +         {  x[j] = lp->col[j]->prim;
 212.286 +            if (P->col[j]->kind == GLP_IV) x[j] = floor(x[j] + 0.5);
 212.287 +         }
 212.288 +#if 1 /* modified by xypron <xypron.glpk@gmx.de> */
 212.289 +         /* reset direction and right-hand side of objective */
 212.290 +         lp->c0  = P->c0;
 212.291 +         lp->dir = P->dir;
 212.292 +         /* fix integer variables */
 212.293 +         for (k = 1; k <= nv; k++)
 212.294 +         {  lp->col[var[k].j]->lb   = x[var[k].j];
 212.295 +            lp->col[var[k].j]->ub   = x[var[k].j];
 212.296 +            lp->col[var[k].j]->type = GLP_FX;
 212.297 +         }
 212.298 +         /* copy original objective function */
 212.299 +         for (j = 1; j <= n; j++)
 212.300 +            lp->col[j]->coef = P->col[j]->coef;
 212.301 +         /* solve original LP and copy result */
 212.302 +         ret = glp_simplex(lp, &parm);
 212.303 +         if (ret != 0)
 212.304 +         {  if (T->parm->msg_lev >= GLP_MSG_ERR)
 212.305 +               xprintf("Warning: glp_simplex returned %d\n", ret);
 212.306 +            goto done;
 212.307 +         }
 212.308 +         ret = glp_get_status(lp);
 212.309 +         if (ret != GLP_OPT)
 212.310 +         {  if (T->parm->msg_lev >= GLP_MSG_ERR)
 212.311 +               xprintf("Warning: glp_get_status returned %d\n", ret);
 212.312 +            goto done;
 212.313 +         }
 212.314 +         for (j = 1; j <= n; j++)
 212.315 +            if (P->col[j]->kind != GLP_IV) x[j] = lp->col[j]->prim;
 212.316 +#endif
 212.317 +         ret = glp_ios_heur_sol(T, x);
 212.318 +         xfree(x);
 212.319 +         if (ret == 0)
 212.320 +         {  /* the integer solution is accepted */
 212.321 +            if (ios_is_hopeful(T, T->curr->bound))
 212.322 +            {  /* it is reasonable to apply the heuristic once again */
 212.323 +               goto more;
 212.324 +            }
 212.325 +            else
 212.326 +            {  /* the best known integer feasible solution just found
 212.327 +                  is close to optimal solution to LP relaxation */
 212.328 +               goto done;
 212.329 +            }
 212.330 +         }
 212.331 +      }
 212.332 +      /* the basic solution is fractional */
 212.333 +      if (dist == DBL_MAX ||
 212.334 +          lp->obj_val <= dist - 1e-6 * (1.0 + dist))
 212.335 +      {  /* the distance is reducing */
 212.336 +         nfail = 0, dist = lp->obj_val;
 212.337 +      }
 212.338 +      else
 212.339 +      {  /* improving the distance failed */
 212.340 +         nfail++;
 212.341 +      }
 212.342 +      if (nfail < 3) goto loop;
 212.343 +      if (npass < 5) goto pass;
 212.344 +done: /* delete working objects */
 212.345 +      if (lp != NULL) glp_delete_prob(lp);
 212.346 +      if (var != NULL) xfree(var);
 212.347 +      if (rand != NULL) rng_delete_rand(rand);
 212.348 +      return;
 212.349 +}
 212.350 +
 212.351 +/* eof */
   213.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   213.2 +++ b/src/glpios11.c	Mon Dec 06 13:09:21 2010 +0100
   213.3 @@ -0,0 +1,280 @@
   213.4 +/* glpios11.c (process cuts stored in the local cut pool) */
   213.5 +
   213.6 +/***********************************************************************
   213.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   213.8 +*
   213.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  213.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  213.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  213.12 +*  E-mail: <mao@gnu.org>.
  213.13 +*
  213.14 +*  GLPK is free software: you can redistribute it and/or modify it
  213.15 +*  under the terms of the GNU General Public License as published by
  213.16 +*  the Free Software Foundation, either version 3 of the License, or
  213.17 +*  (at your option) any later version.
  213.18 +*
  213.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  213.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  213.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  213.22 +*  License for more details.
  213.23 +*
  213.24 +*  You should have received a copy of the GNU General Public License
  213.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  213.26 +***********************************************************************/
  213.27 +
  213.28 +#include "glpios.h"
  213.29 +
  213.30 +/***********************************************************************
  213.31 +*  NAME
  213.32 +*
  213.33 +*  ios_process_cuts - process cuts stored in the local cut pool
  213.34 +*
  213.35 +*  SYNOPSIS
  213.36 +*
  213.37 +*  #include "glpios.h"
  213.38 +*  void ios_process_cuts(glp_tree *T);
  213.39 +*
  213.40 +*  DESCRIPTION
  213.41 +*
  213.42 +*  The routine ios_process_cuts analyzes each cut currently stored in
  213.43 +*  the local cut pool, which must be non-empty, and either adds the cut
  213.44 +*  to the current subproblem or just discards it. All cuts are assumed
  213.45 +*  to be locally valid. On exit the local cut pool remains unchanged.
  213.46 +*
  213.47 +*  REFERENCES
  213.48 +*
  213.49 +*  1. E.Balas, S.Ceria, G.Cornuejols, "Mixed 0-1 Programming by
  213.50 +*     Lift-and-Project in a Branch-and-Cut Framework", Management Sc.,
  213.51 +*     42 (1996) 1229-1246.
  213.52 +*
  213.53 +*  2. G.Andreello, A.Caprara, and M.Fischetti, "Embedding Cuts in
  213.54 +*     a Branch&Cut Framework: a Computational Study with {0,1/2}-Cuts",
  213.55 +*     Preliminary Draft, October 28, 2003, pp.6-8. */
  213.56 +
  213.57 +struct info
  213.58 +{     /* estimated cut efficiency */
  213.59 +      IOSCUT *cut;
  213.60 +      /* pointer to cut in the cut pool */
  213.61 +      char flag;
  213.62 +      /* if this flag is set, the cut is included into the current
  213.63 +         subproblem */
  213.64 +      double eff;
  213.65 +      /* cut efficacy (normalized residual) */
  213.66 +      double deg;
  213.67 +      /* lower bound to objective degradation */
  213.68 +};
  213.69 +
  213.70 +static int fcmp(const void *arg1, const void *arg2)
  213.71 +{     const struct info *info1 = arg1, *info2 = arg2;
  213.72 +      if (info1->deg == 0.0 && info2->deg == 0.0)
  213.73 +      {  if (info1->eff > info2->eff) return -1;
  213.74 +         if (info1->eff < info2->eff) return +1;
  213.75 +      }
  213.76 +      else
  213.77 +      {  if (info1->deg > info2->deg) return -1;
  213.78 +         if (info1->deg < info2->deg) return +1;
  213.79 +      }
  213.80 +      return 0;
  213.81 +}
  213.82 +
  213.83 +static double parallel(IOSCUT *a, IOSCUT *b, double work[]);
  213.84 +
  213.85 +void ios_process_cuts(glp_tree *T)
  213.86 +{     IOSPOOL *pool;
  213.87 +      IOSCUT *cut;
  213.88 +      IOSAIJ *aij;
  213.89 +      struct info *info;
  213.90 +      int k, kk, max_cuts, len, ret, *ind;
  213.91 +      double *val, *work;
  213.92 +      /* the current subproblem must exist */
  213.93 +      xassert(T->curr != NULL);
  213.94 +      /* the pool must exist and be non-empty */
  213.95 +      pool = T->local;
  213.96 +      xassert(pool != NULL);
  213.97 +      xassert(pool->size > 0);
  213.98 +      /* allocate working arrays */
  213.99 +      info = xcalloc(1+pool->size, sizeof(struct info));
 213.100 +      ind = xcalloc(1+T->n, sizeof(int));
 213.101 +      val = xcalloc(1+T->n, sizeof(double));
 213.102 +      work = xcalloc(1+T->n, sizeof(double));
 213.103 +      for (k = 1; k <= T->n; k++) work[k] = 0.0;
 213.104 +      /* build the list of cuts stored in the cut pool */
 213.105 +      for (k = 0, cut = pool->head; cut != NULL; cut = cut->next)
 213.106 +         k++, info[k].cut = cut, info[k].flag = 0;
 213.107 +      xassert(k == pool->size);
 213.108 +      /* estimate efficiency of all cuts in the cut pool */
 213.109 +      for (k = 1; k <= pool->size; k++)
 213.110 +      {  double temp, dy, dz;
 213.111 +         cut = info[k].cut;
 213.112 +         /* build the vector of cut coefficients and compute its
 213.113 +            Euclidean norm */
 213.114 +         len = 0; temp = 0.0;
 213.115 +         for (aij = cut->ptr; aij != NULL; aij = aij->next)
 213.116 +         {  xassert(1 <= aij->j && aij->j <= T->n);
 213.117 +            len++, ind[len] = aij->j, val[len] = aij->val;
 213.118 +            temp += aij->val * aij->val;
 213.119 +         }
 213.120 +         if (temp < DBL_EPSILON * DBL_EPSILON) temp = DBL_EPSILON;
 213.121 +         /* transform the cut to express it only through non-basic
 213.122 +            (auxiliary and structural) variables */
 213.123 +         len = glp_transform_row(T->mip, len, ind, val);
 213.124 +         /* determine change in the cut value and in the objective
 213.125 +            value for the adjacent basis by simulating one step of the
 213.126 +            dual simplex */
 213.127 +         ret = _glp_analyze_row(T->mip, len, ind, val, cut->type,
 213.128 +            cut->rhs, 1e-9, NULL, NULL, NULL, NULL, &dy, &dz);
 213.129 +         /* determine normalized residual and lower bound to objective
 213.130 +            degradation */
 213.131 +         if (ret == 0)
 213.132 +         {  info[k].eff = fabs(dy) / sqrt(temp);
 213.133 +            /* if some reduced costs violates (slightly) their zero
 213.134 +               bounds (i.e. have wrong signs) due to round-off errors,
 213.135 +               dz also may have wrong sign being close to zero */
 213.136 +            if (T->mip->dir == GLP_MIN)
 213.137 +            {  if (dz < 0.0) dz = 0.0;
 213.138 +               info[k].deg = + dz;
 213.139 +            }
 213.140 +            else /* GLP_MAX */
 213.141 +            {  if (dz > 0.0) dz = 0.0;
 213.142 +               info[k].deg = - dz;
 213.143 +            }
 213.144 +         }
 213.145 +         else if (ret == 1)
 213.146 +         {  /* the constraint is not violated at the current point */
 213.147 +            info[k].eff = info[k].deg = 0.0;
 213.148 +         }
 213.149 +         else if (ret == 2)
 213.150 +         {  /* no dual feasible adjacent basis exists */
 213.151 +            info[k].eff = 1.0;
 213.152 +            info[k].deg = DBL_MAX;
 213.153 +         }
 213.154 +         else
 213.155 +            xassert(ret != ret);
 213.156 +         /* if the degradation is too small, just ignore it */
 213.157 +         if (info[k].deg < 0.01) info[k].deg = 0.0;
 213.158 +      }
 213.159 +      /* sort the list of cuts by decreasing objective degradation and
 213.160 +         then by decreasing efficacy */
 213.161 +      qsort(&info[1], pool->size, sizeof(struct info), fcmp);
 213.162 +      /* only first (most efficient) max_cuts in the list are qualified
 213.163 +         as candidates to be added to the current subproblem */
 213.164 +      max_cuts = (T->curr->level == 0 ? 90 : 10);
 213.165 +      if (max_cuts > pool->size) max_cuts = pool->size;
 213.166 +      /* add cuts to the current subproblem */
 213.167 +#if 0
 213.168 +      xprintf("*** adding cuts ***\n");
 213.169 +#endif
 213.170 +      for (k = 1; k <= max_cuts; k++)
 213.171 +      {  int i, len;
 213.172 +         /* if this cut seems to be inefficient, skip it */
 213.173 +         if (info[k].deg < 0.01 && info[k].eff < 0.01) continue;
 213.174 +         /* if the angle between this cut and every other cut included
 213.175 +            in the current subproblem is small, skip this cut */
 213.176 +         for (kk = 1; kk < k; kk++)
 213.177 +         {  if (info[kk].flag)
 213.178 +            {  if (parallel(info[k].cut, info[kk].cut, work) > 0.90)
 213.179 +                  break;
 213.180 +            }
 213.181 +         }
 213.182 +         if (kk < k) continue;
 213.183 +         /* add this cut to the current subproblem */
 213.184 +#if 0
 213.185 +         xprintf("eff = %g; deg = %g\n", info[k].eff, info[k].deg);
 213.186 +#endif
 213.187 +         cut = info[k].cut, info[k].flag = 1;
 213.188 +         i = glp_add_rows(T->mip, 1);
 213.189 +         if (cut->name != NULL)
 213.190 +            glp_set_row_name(T->mip, i, cut->name);
 213.191 +         xassert(T->mip->row[i]->origin == GLP_RF_CUT);
 213.192 +         T->mip->row[i]->klass = cut->klass;
 213.193 +         len = 0;
 213.194 +         for (aij = cut->ptr; aij != NULL; aij = aij->next)
 213.195 +            len++, ind[len] = aij->j, val[len] = aij->val;
 213.196 +         glp_set_mat_row(T->mip, i, len, ind, val);
 213.197 +         xassert(cut->type == GLP_LO || cut->type == GLP_UP);
 213.198 +         glp_set_row_bnds(T->mip, i, cut->type, cut->rhs, cut->rhs);
 213.199 +      }
 213.200 +      /* free working arrays */
 213.201 +      xfree(info);
 213.202 +      xfree(ind);
 213.203 +      xfree(val);
 213.204 +      xfree(work);
 213.205 +      return;
 213.206 +}
 213.207 +
 213.208 +#if 0
 213.209 +/***********************************************************************
 213.210 +*  Given a cut a * x >= b (<= b) the routine efficacy computes the cut
 213.211 +*  efficacy as follows:
 213.212 +*
 213.213 +*     eff = d * (a * x~ - b) / ||a||,
 213.214 +*
 213.215 +*  where d is -1 (in case of '>= b') or +1 (in case of '<= b'), x~ is
 213.216 +*  the vector of values of structural variables in optimal solution to
 213.217 +*  LP relaxation of the current subproblem, ||a|| is the Euclidean norm
 213.218 +*  of the vector of cut coefficients.
 213.219 +*
 213.220 +*  If the cut is violated at point x~, the efficacy eff is positive,
 213.221 +*  and its value is the Euclidean distance between x~ and the cut plane
 213.222 +*  a * x = b in the space of structural variables.
 213.223 +*
 213.224 +*  Following geometrical intuition, it is quite natural to consider
 213.225 +*  this distance as a first-order measure of the expected efficacy of
 213.226 +*  the cut: the larger the distance the better the cut [1]. */
 213.227 +
 213.228 +static double efficacy(glp_tree *T, IOSCUT *cut)
 213.229 +{     glp_prob *mip = T->mip;
 213.230 +      IOSAIJ *aij;
 213.231 +      double s = 0.0, t = 0.0, temp;
 213.232 +      for (aij = cut->ptr; aij != NULL; aij = aij->next)
 213.233 +      {  xassert(1 <= aij->j && aij->j <= mip->n);
 213.234 +         s += aij->val * mip->col[aij->j]->prim;
 213.235 +         t += aij->val * aij->val;
 213.236 +      }
 213.237 +      temp = sqrt(t);
 213.238 +      if (temp < DBL_EPSILON) temp = DBL_EPSILON;
 213.239 +      if (cut->type == GLP_LO)
 213.240 +         temp = (s >= cut->rhs ? 0.0 : (cut->rhs - s) / temp);
 213.241 +      else if (cut->type == GLP_UP)
 213.242 +         temp = (s <= cut->rhs ? 0.0 : (s - cut->rhs) / temp);
 213.243 +      else
 213.244 +         xassert(cut != cut);
 213.245 +      return temp;
 213.246 +}
 213.247 +#endif
 213.248 +
 213.249 +/***********************************************************************
 213.250 +*  Given two cuts a1 * x >= b1 (<= b1) and a2 * x >= b2 (<= b2) the
 213.251 +*  routine parallel computes the cosine of angle between the cut planes
 213.252 +*  a1 * x = b1 and a2 * x = b2 (which is the acute angle between two
 213.253 +*  normals to these planes) in the space of structural variables as
 213.254 +*  follows:
 213.255 +*
 213.256 +*     cos phi = (a1' * a2) / (||a1|| * ||a2||),
 213.257 +*
 213.258 +*  where (a1' * a2) is a dot product of vectors of cut coefficients,
 213.259 +*  ||a1|| and ||a2|| are Euclidean norms of vectors a1 and a2.
 213.260 +*
 213.261 +*  Note that requirement cos phi = 0 forces the cuts to be orthogonal,
 213.262 +*  i.e. with disjoint support, while requirement cos phi <= 0.999 means
 213.263 +*  only avoiding duplicate (parallel) cuts [1]. */
 213.264 +
 213.265 +static double parallel(IOSCUT *a, IOSCUT *b, double work[])
 213.266 +{     IOSAIJ *aij;
 213.267 +      double s = 0.0, sa = 0.0, sb = 0.0, temp;
 213.268 +      for (aij = a->ptr; aij != NULL; aij = aij->next)
 213.269 +      {  work[aij->j] = aij->val;
 213.270 +         sa += aij->val * aij->val;
 213.271 +      }
 213.272 +      for (aij = b->ptr; aij != NULL; aij = aij->next)
 213.273 +      {  s += work[aij->j] * aij->val;
 213.274 +         sb += aij->val * aij->val;
 213.275 +      }
 213.276 +      for (aij = a->ptr; aij != NULL; aij = aij->next)
 213.277 +         work[aij->j] = 0.0;
 213.278 +      temp = sqrt(sa) * sqrt(sb);
 213.279 +      if (temp < DBL_EPSILON * DBL_EPSILON) temp = DBL_EPSILON;
 213.280 +      return s / temp;
 213.281 +}
 213.282 +
 213.283 +/* eof */
   214.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   214.2 +++ b/src/glpios12.c	Mon Dec 06 13:09:21 2010 +0100
   214.3 @@ -0,0 +1,176 @@
   214.4 +/* glpios12.c (node selection heuristics) */
   214.5 +
   214.6 +/***********************************************************************
   214.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   214.8 +*
   214.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  214.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  214.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  214.12 +*  E-mail: <mao@gnu.org>.
  214.13 +*
  214.14 +*  GLPK is free software: you can redistribute it and/or modify it
  214.15 +*  under the terms of the GNU General Public License as published by
  214.16 +*  the Free Software Foundation, either version 3 of the License, or
  214.17 +*  (at your option) any later version.
  214.18 +*
  214.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  214.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  214.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  214.22 +*  License for more details.
  214.23 +*
  214.24 +*  You should have received a copy of the GNU General Public License
  214.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  214.26 +***********************************************************************/
  214.27 +
  214.28 +#include "glpios.h"
  214.29 +
  214.30 +/***********************************************************************
  214.31 +*  NAME
  214.32 +*
  214.33 +*  ios_choose_node - select subproblem to continue the search
  214.34 +*
  214.35 +*  SYNOPSIS
  214.36 +*
  214.37 +*  #include "glpios.h"
  214.38 +*  int ios_choose_node(glp_tree *T);
  214.39 +*
  214.40 +*  DESCRIPTION
  214.41 +*
  214.42 +*  The routine ios_choose_node selects a subproblem from the active
  214.43 +*  list to continue the search. The choice depends on the backtracking
  214.44 +*  technique option.
  214.45 +*
  214.46 +*  RETURNS
  214.47 +*
  214.48 +*  The routine ios_choose_node return the reference number of the
  214.49 +*  subproblem selected. */
  214.50 +
  214.51 +static int most_feas(glp_tree *T);
  214.52 +static int best_proj(glp_tree *T);
  214.53 +static int best_node(glp_tree *T);
  214.54 +
  214.55 +int ios_choose_node(glp_tree *T)
  214.56 +{     int p;
  214.57 +      if (T->parm->bt_tech == GLP_BT_DFS)
  214.58 +      {  /* depth first search */
  214.59 +         xassert(T->tail != NULL);
  214.60 +         p = T->tail->p;
  214.61 +      }
  214.62 +      else if (T->parm->bt_tech == GLP_BT_BFS)
  214.63 +      {  /* breadth first search */
  214.64 +         xassert(T->head != NULL);
  214.65 +         p = T->head->p;
  214.66 +      }
  214.67 +      else if (T->parm->bt_tech == GLP_BT_BLB)
  214.68 +      {  /* select node with best local bound */
  214.69 +         p = best_node(T);
  214.70 +      }
  214.71 +      else if (T->parm->bt_tech == GLP_BT_BPH)
  214.72 +      {  if (T->mip->mip_stat == GLP_UNDEF)
  214.73 +         {  /* "most integer feasible" subproblem */
  214.74 +            p = most_feas(T);
  214.75 +         }
  214.76 +         else
  214.77 +         {  /* best projection heuristic */
  214.78 +            p = best_proj(T);
  214.79 +         }
  214.80 +      }
  214.81 +      else
  214.82 +         xassert(T != T);
  214.83 +      return p;
  214.84 +}
  214.85 +
  214.86 +static int most_feas(glp_tree *T)
  214.87 +{     /* select subproblem whose parent has minimal sum of integer
  214.88 +         infeasibilities */
  214.89 +      IOSNPD *node;
  214.90 +      int p;
  214.91 +      double best;
  214.92 +      p = 0, best = DBL_MAX;
  214.93 +      for (node = T->head; node != NULL; node = node->next)
  214.94 +      {  xassert(node->up != NULL);
  214.95 +         if (best > node->up->ii_sum)
  214.96 +            p = node->p, best = node->up->ii_sum;
  214.97 +      }
  214.98 +      return p;
  214.99 +}
 214.100 +
 214.101 +static int best_proj(glp_tree *T)
 214.102 +{     /* select subproblem using the best projection heuristic */
 214.103 +      IOSNPD *root, *node;
 214.104 +      int p;
 214.105 +      double best, deg, obj;
 214.106 +      /* the global bound must exist */
 214.107 +      xassert(T->mip->mip_stat == GLP_FEAS);
 214.108 +      /* obtain pointer to the root node, which must exist */
 214.109 +      root = T->slot[1].node;
 214.110 +      xassert(root != NULL);
 214.111 +      /* deg estimates degradation of the objective function per unit
 214.112 +         of the sum of integer infeasibilities */
 214.113 +      xassert(root->ii_sum > 0.0);
 214.114 +      deg = (T->mip->mip_obj - root->bound) / root->ii_sum;
 214.115 +      /* nothing has been selected so far */
 214.116 +      p = 0, best = DBL_MAX;
 214.117 +      /* walk through the list of active subproblems */
 214.118 +      for (node = T->head; node != NULL; node = node->next)
 214.119 +      {  xassert(node->up != NULL);
 214.120 +         /* obj estimates optimal objective value if the sum of integer
 214.121 +            infeasibilities were zero */
 214.122 +         obj = node->up->bound + deg * node->up->ii_sum;
 214.123 +         if (T->mip->dir == GLP_MAX) obj = - obj;
 214.124 +         /* select the subproblem which has the best estimated optimal
 214.125 +            objective value */
 214.126 +         if (best > obj) p = node->p, best = obj;
 214.127 +      }
 214.128 +      return p;
 214.129 +}
 214.130 +
 214.131 +static int best_node(glp_tree *T)
 214.132 +{     /* select subproblem with best local bound */
 214.133 +      IOSNPD *node, *best = NULL;
 214.134 +      double bound, eps;
 214.135 +      switch (T->mip->dir)
 214.136 +      {  case GLP_MIN:
 214.137 +            bound = +DBL_MAX;
 214.138 +            for (node = T->head; node != NULL; node = node->next)
 214.139 +               if (bound > node->bound) bound = node->bound;
 214.140 +            xassert(bound != +DBL_MAX);
 214.141 +            eps = 0.001 * (1.0 + fabs(bound));
 214.142 +            for (node = T->head; node != NULL; node = node->next)
 214.143 +            {  if (node->bound <= bound + eps)
 214.144 +               {  xassert(node->up != NULL);
 214.145 +                  if (best == NULL ||
 214.146 +#if 1
 214.147 +                  best->up->ii_sum > node->up->ii_sum) best = node;
 214.148 +#else
 214.149 +                  best->lp_obj > node->lp_obj) best = node;
 214.150 +#endif
 214.151 +               }
 214.152 +            }
 214.153 +            break;
 214.154 +         case GLP_MAX:
 214.155 +            bound = -DBL_MAX;
 214.156 +            for (node = T->head; node != NULL; node = node->next)
 214.157 +               if (bound < node->bound) bound = node->bound;
 214.158 +            xassert(bound != -DBL_MAX);
 214.159 +            eps = 0.001 * (1.0 + fabs(bound));
 214.160 +            for (node = T->head; node != NULL; node = node->next)
 214.161 +            {  if (node->bound >= bound - eps)
 214.162 +               {  xassert(node->up != NULL);
 214.163 +                  if (best == NULL ||
 214.164 +#if 1
 214.165 +                  best->up->ii_sum > node->up->ii_sum) best = node;
 214.166 +#else
 214.167 +                  best->lp_obj < node->lp_obj) best = node;
 214.168 +#endif
 214.169 +               }
 214.170 +            }
 214.171 +            break;
 214.172 +         default:
 214.173 +            xassert(T != T);
 214.174 +      }
 214.175 +      xassert(best != NULL);
 214.176 +      return best->p;
 214.177 +}
 214.178 +
 214.179 +/* eof */
   215.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   215.2 +++ b/src/glpipm.c	Mon Dec 06 13:09:21 2010 +0100
   215.3 @@ -0,0 +1,1143 @@
   215.4 +/* glpipm.c */
   215.5 +
   215.6 +/***********************************************************************
   215.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   215.8 +*
   215.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  215.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  215.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  215.12 +*  E-mail: <mao@gnu.org>.
  215.13 +*
  215.14 +*  GLPK is free software: you can redistribute it and/or modify it
  215.15 +*  under the terms of the GNU General Public License as published by
  215.16 +*  the Free Software Foundation, either version 3 of the License, or
  215.17 +*  (at your option) any later version.
  215.18 +*
  215.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  215.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  215.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  215.22 +*  License for more details.
  215.23 +*
  215.24 +*  You should have received a copy of the GNU General Public License
  215.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  215.26 +***********************************************************************/
  215.27 +
  215.28 +#include "glpipm.h"
  215.29 +#include "glpmat.h"
  215.30 +
  215.31 +#define ITER_MAX 100
  215.32 +/* maximal number of iterations */
  215.33 +
  215.34 +struct csa
  215.35 +{     /* common storage area */
  215.36 +      /*--------------------------------------------------------------*/
  215.37 +      /* LP data */
  215.38 +      int m;
  215.39 +      /* number of rows (equality constraints) */
  215.40 +      int n;
  215.41 +      /* number of columns (structural variables) */
  215.42 +      int *A_ptr; /* int A_ptr[1+m+1]; */
  215.43 +      int *A_ind; /* int A_ind[A_ptr[m+1]]; */
  215.44 +      double *A_val; /* double A_val[A_ptr[m+1]]; */
  215.45 +      /* mxn-matrix A in storage-by-rows format */
  215.46 +      double *b; /* double b[1+m]; */
  215.47 +      /* m-vector b of right-hand sides */
  215.48 +      double *c; /* double c[1+n]; */
  215.49 +      /* n-vector c of objective coefficients; c[0] is constant term of
  215.50 +         the objective function */
  215.51 +      /*--------------------------------------------------------------*/
  215.52 +      /* LP solution */
  215.53 +      double *x; /* double x[1+n]; */
  215.54 +      double *y; /* double y[1+m]; */
  215.55 +      double *z; /* double z[1+n]; */
  215.56 +      /* current point in primal-dual space; the best point on exit */
  215.57 +      /*--------------------------------------------------------------*/
  215.58 +      /* control parameters */
  215.59 +      const glp_iptcp *parm;
  215.60 +      /*--------------------------------------------------------------*/
  215.61 +      /* working arrays and variables */
  215.62 +      double *D; /* double D[1+n]; */
  215.63 +      /* diagonal nxn-matrix D = X*inv(Z), where X = diag(x[j]) and
  215.64 +         Z = diag(z[j]) */
  215.65 +      int *P; /* int P[1+m+m]; */
  215.66 +      /* permutation mxm-matrix P used to minimize fill-in in Cholesky
  215.67 +         factorization */
  215.68 +      int *S_ptr; /* int S_ptr[1+m+1]; */
  215.69 +      int *S_ind; /* int S_ind[S_ptr[m+1]]; */
  215.70 +      double *S_val; /* double S_val[S_ptr[m+1]]; */
  215.71 +      double *S_diag; /* double S_diag[1+m]; */
  215.72 +      /* symmetric mxm-matrix S = P*A*D*A'*P' whose upper triangular
  215.73 +         part without diagonal elements is stored in S_ptr, S_ind, and
  215.74 +         S_val in storage-by-rows format, diagonal elements are stored
  215.75 +         in S_diag */
  215.76 +      int *U_ptr; /* int U_ptr[1+m+1]; */
  215.77 +      int *U_ind; /* int U_ind[U_ptr[m+1]]; */
  215.78 +      double *U_val; /* double U_val[U_ptr[m+1]]; */
  215.79 +      double *U_diag; /* double U_diag[1+m]; */
  215.80 +      /* upper triangular mxm-matrix U defining Cholesky factorization
  215.81 +         S = U'*U; its non-diagonal elements are stored in U_ptr, U_ind,
  215.82 +         U_val in storage-by-rows format, diagonal elements are stored
  215.83 +         in U_diag */
  215.84 +      int iter;
  215.85 +      /* iteration number (0, 1, 2, ...); iter = 0 corresponds to the
  215.86 +         initial point */
  215.87 +      double obj;
  215.88 +      /* current value of the objective function */
  215.89 +      double rpi;
  215.90 +      /* relative primal infeasibility rpi = ||A*x-b||/(1+||b||) */
  215.91 +      double rdi;
  215.92 +      /* relative dual infeasibility rdi = ||A'*y+z-c||/(1+||c||) */
  215.93 +      double gap;
  215.94 +      /* primal-dual gap = |c'*x-b'*y|/(1+|c'*x|) which is a relative
  215.95 +         difference between primal and dual objective functions */
  215.96 +      double phi;
  215.97 +      /* merit function phi = ||A*x-b||/max(1,||b||) +
  215.98 +                            + ||A'*y+z-c||/max(1,||c||) +
  215.99 +                            + |c'*x-b'*y|/max(1,||b||,||c||) */
 215.100 +      double mu;
 215.101 +      /* duality measure mu = x'*z/n (used as barrier parameter) */
 215.102 +      double rmu;
 215.103 +      /* rmu = max(||A*x-b||,||A'*y+z-c||)/mu */
 215.104 +      double rmu0;
 215.105 +      /* the initial value of rmu on iteration 0 */
 215.106 +      double *phi_min; /* double phi_min[1+ITER_MAX]; */
 215.107 +      /* phi_min[k] = min(phi[k]), where phi[k] is the value of phi on
 215.108 +         k-th iteration, 0 <= k <= iter */
 215.109 +      int best_iter;
 215.110 +      /* iteration number, on which the value of phi reached its best
 215.111 +         (minimal) value */
 215.112 +      double *best_x; /* double best_x[1+n]; */
 215.113 +      double *best_y; /* double best_y[1+m]; */
 215.114 +      double *best_z; /* double best_z[1+n]; */
 215.115 +      /* best point (in the sense of the merit function phi) which has
 215.116 +         been reached on iteration iter_best */
 215.117 +      double best_obj;
 215.118 +      /* objective value at the best point */
 215.119 +      double *dx_aff; /* double dx_aff[1+n]; */
 215.120 +      double *dy_aff; /* double dy_aff[1+m]; */
 215.121 +      double *dz_aff; /* double dz_aff[1+n]; */
 215.122 +      /* affine scaling direction */
 215.123 +      double alfa_aff_p, alfa_aff_d;
 215.124 +      /* maximal primal and dual stepsizes in affine scaling direction,
 215.125 +         on which x and z are still non-negative */
 215.126 +      double mu_aff;
 215.127 +      /* duality measure mu_aff = x_aff'*z_aff/n in the boundary point
 215.128 +         x_aff' = x+alfa_aff_p*dx_aff, z_aff' = z+alfa_aff_d*dz_aff */
 215.129 +      double sigma;
 215.130 +      /* Mehrotra's heuristic parameter (0 <= sigma <= 1) */
 215.131 +      double *dx_cc; /* double dx_cc[1+n]; */
 215.132 +      double *dy_cc; /* double dy_cc[1+m]; */
 215.133 +      double *dz_cc; /* double dz_cc[1+n]; */
 215.134 +      /* centering corrector direction */
 215.135 +      double *dx; /* double dx[1+n]; */
 215.136 +      double *dy; /* double dy[1+m]; */
 215.137 +      double *dz; /* double dz[1+n]; */
 215.138 +      /* final combined direction dx = dx_aff+dx_cc, dy = dy_aff+dy_cc,
 215.139 +         dz = dz_aff+dz_cc */
 215.140 +      double alfa_max_p;
 215.141 +      double alfa_max_d;
 215.142 +      /* maximal primal and dual stepsizes in combined direction, on
 215.143 +         which x and z are still non-negative */
 215.144 +};
 215.145 +
 215.146 +/***********************************************************************
 215.147 +*  initialize - allocate and initialize common storage area
 215.148 +*
 215.149 +*  This routine allocates and initializes the common storage area (CSA)
 215.150 +*  used by interior-point method routines. */
 215.151 +
 215.152 +static void initialize(struct csa *csa)
 215.153 +{     int m = csa->m;
 215.154 +      int n = csa->n;
 215.155 +      int i;
 215.156 +      if (csa->parm->msg_lev >= GLP_MSG_ALL)
 215.157 +         xprintf("Matrix A has %d non-zeros\n", csa->A_ptr[m+1]-1);
 215.158 +      csa->D = xcalloc(1+n, sizeof(double));
 215.159 +      /* P := I */
 215.160 +      csa->P = xcalloc(1+m+m, sizeof(int));
 215.161 +      for (i = 1; i <= m; i++) csa->P[i] = csa->P[m+i] = i;
 215.162 +      /* S := A*A', symbolically */
 215.163 +      csa->S_ptr = xcalloc(1+m+1, sizeof(int));
 215.164 +      csa->S_ind = adat_symbolic(m, n, csa->P, csa->A_ptr, csa->A_ind,
 215.165 +         csa->S_ptr);
 215.166 +      if (csa->parm->msg_lev >= GLP_MSG_ALL)
 215.167 +         xprintf("Matrix S = A*A' has %d non-zeros (upper triangle)\n",
 215.168 +            csa->S_ptr[m+1]-1 + m);
 215.169 +      /* determine P using specified ordering algorithm */
 215.170 +      if (csa->parm->ord_alg == GLP_ORD_NONE)
 215.171 +      {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
 215.172 +            xprintf("Original ordering is being used\n");
 215.173 +         for (i = 1; i <= m; i++)
 215.174 +            csa->P[i] = csa->P[m+i] = i;
 215.175 +      }
 215.176 +      else if (csa->parm->ord_alg == GLP_ORD_QMD)
 215.177 +      {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
 215.178 +            xprintf("Minimum degree ordering (QMD)...\n");
 215.179 +         min_degree(m, csa->S_ptr, csa->S_ind, csa->P);
 215.180 +      }
 215.181 +      else if (csa->parm->ord_alg == GLP_ORD_AMD)
 215.182 +      {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
 215.183 +            xprintf("Approximate minimum degree ordering (AMD)...\n");
 215.184 +         amd_order1(m, csa->S_ptr, csa->S_ind, csa->P);
 215.185 +      }
 215.186 +      else if (csa->parm->ord_alg == GLP_ORD_SYMAMD)
 215.187 +      {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
 215.188 +            xprintf("Approximate minimum degree ordering (SYMAMD)...\n")
 215.189 +               ;
 215.190 +         symamd_ord(m, csa->S_ptr, csa->S_ind, csa->P);
 215.191 +      }
 215.192 +      else
 215.193 +         xassert(csa != csa);
 215.194 +      /* S := P*A*A'*P', symbolically */
 215.195 +      xfree(csa->S_ind);
 215.196 +      csa->S_ind = adat_symbolic(m, n, csa->P, csa->A_ptr, csa->A_ind,
 215.197 +         csa->S_ptr);
 215.198 +      csa->S_val = xcalloc(csa->S_ptr[m+1], sizeof(double));
 215.199 +      csa->S_diag = xcalloc(1+m, sizeof(double));
 215.200 +      /* compute Cholesky factorization S = U'*U, symbolically */
 215.201 +      if (csa->parm->msg_lev >= GLP_MSG_ALL)
 215.202 +         xprintf("Computing Cholesky factorization S = L*L'...\n");
 215.203 +      csa->U_ptr = xcalloc(1+m+1, sizeof(int));
 215.204 +      csa->U_ind = chol_symbolic(m, csa->S_ptr, csa->S_ind, csa->U_ptr);
 215.205 +      if (csa->parm->msg_lev >= GLP_MSG_ALL)
 215.206 +         xprintf("Matrix L has %d non-zeros\n", csa->U_ptr[m+1]-1 + m);
 215.207 +      csa->U_val = xcalloc(csa->U_ptr[m+1], sizeof(double));
 215.208 +      csa->U_diag = xcalloc(1+m, sizeof(double));
 215.209 +      csa->iter = 0;
 215.210 +      csa->obj = 0.0;
 215.211 +      csa->rpi = 0.0;
 215.212 +      csa->rdi = 0.0;
 215.213 +      csa->gap = 0.0;
 215.214 +      csa->phi = 0.0;
 215.215 +      csa->mu = 0.0;
 215.216 +      csa->rmu = 0.0;
 215.217 +      csa->rmu0 = 0.0;
 215.218 +      csa->phi_min = xcalloc(1+ITER_MAX, sizeof(double));
 215.219 +      csa->best_iter = 0;
 215.220 +      csa->best_x = xcalloc(1+n, sizeof(double));
 215.221 +      csa->best_y = xcalloc(1+m, sizeof(double));
 215.222 +      csa->best_z = xcalloc(1+n, sizeof(double));
 215.223 +      csa->best_obj = 0.0;
 215.224 +      csa->dx_aff = xcalloc(1+n, sizeof(double));
 215.225 +      csa->dy_aff = xcalloc(1+m, sizeof(double));
 215.226 +      csa->dz_aff = xcalloc(1+n, sizeof(double));
 215.227 +      csa->alfa_aff_p = 0.0;
 215.228 +      csa->alfa_aff_d = 0.0;
 215.229 +      csa->mu_aff = 0.0;
 215.230 +      csa->sigma = 0.0;
 215.231 +      csa->dx_cc = xcalloc(1+n, sizeof(double));
 215.232 +      csa->dy_cc = xcalloc(1+m, sizeof(double));
 215.233 +      csa->dz_cc = xcalloc(1+n, sizeof(double));
 215.234 +      csa->dx = csa->dx_aff;
 215.235 +      csa->dy = csa->dy_aff;
 215.236 +      csa->dz = csa->dz_aff;
 215.237 +      csa->alfa_max_p = 0.0;
 215.238 +      csa->alfa_max_d = 0.0;
 215.239 +      return;
 215.240 +}
 215.241 +
 215.242 +/***********************************************************************
 215.243 +*  A_by_vec - compute y = A*x
 215.244 +*
 215.245 +*  This routine computes matrix-vector product y = A*x, where A is the
 215.246 +*  constraint matrix. */
 215.247 +
 215.248 +static void A_by_vec(struct csa *csa, double x[], double y[])
 215.249 +{     /* compute y = A*x */
 215.250 +      int m = csa->m;
 215.251 +      int *A_ptr = csa->A_ptr;
 215.252 +      int *A_ind = csa->A_ind;
 215.253 +      double *A_val = csa->A_val;
 215.254 +      int i, t, beg, end;
 215.255 +      double temp;
 215.256 +      for (i = 1; i <= m; i++)
 215.257 +      {  temp = 0.0;
 215.258 +         beg = A_ptr[i], end = A_ptr[i+1];
 215.259 +         for (t = beg; t < end; t++) temp += A_val[t] * x[A_ind[t]];
 215.260 +         y[i] = temp;
 215.261 +      }
 215.262 +      return;
 215.263 +}
 215.264 +
 215.265 +/***********************************************************************
 215.266 +*  AT_by_vec - compute y = A'*x
 215.267 +*
 215.268 +*  This routine computes matrix-vector product y = A'*x, where A' is a
 215.269 +*  matrix transposed to the constraint matrix A. */
 215.270 +
 215.271 +static void AT_by_vec(struct csa *csa, double x[], double y[])
 215.272 +{     /* compute y = A'*x, where A' is transposed to A */
 215.273 +      int m = csa->m;
 215.274 +      int n = csa->n;
 215.275 +      int *A_ptr = csa->A_ptr;
 215.276 +      int *A_ind = csa->A_ind;
 215.277 +      double *A_val = csa->A_val;
 215.278 +      int i, j, t, beg, end;
 215.279 +      double temp;
 215.280 +      for (j = 1; j <= n; j++) y[j] = 0.0;
 215.281 +      for (i = 1; i <= m; i++)
 215.282 +      {  temp = x[i];
 215.283 +         if (temp == 0.0) continue;
 215.284 +         beg = A_ptr[i], end = A_ptr[i+1];
 215.285 +         for (t = beg; t < end; t++) y[A_ind[t]] += A_val[t] * temp;
 215.286 +      }
 215.287 +      return;
 215.288 +}
 215.289 +
 215.290 +/***********************************************************************
 215.291 +*  decomp_NE - numeric factorization of matrix S = P*A*D*A'*P'
 215.292 +*
 215.293 +*  This routine implements numeric phase of Cholesky factorization of
 215.294 +*  the matrix S = P*A*D*A'*P', which is a permuted matrix of the normal
 215.295 +*  equation system. Matrix D is assumed to be already computed. */
 215.296 +
 215.297 +static void decomp_NE(struct csa *csa)
 215.298 +{     adat_numeric(csa->m, csa->n, csa->P, csa->A_ptr, csa->A_ind,
 215.299 +         csa->A_val, csa->D, csa->S_ptr, csa->S_ind, csa->S_val,
 215.300 +         csa->S_diag);
 215.301 +      chol_numeric(csa->m, csa->S_ptr, csa->S_ind, csa->S_val,
 215.302 +         csa->S_diag, csa->U_ptr, csa->U_ind, csa->U_val, csa->U_diag);
 215.303 +      return;
 215.304 +}
 215.305 +
 215.306 +/***********************************************************************
 215.307 +*  solve_NE - solve normal equation system
 215.308 +*
 215.309 +*  This routine solves the normal equation system:
 215.310 +*
 215.311 +*     A*D*A'*y = h.
 215.312 +*
 215.313 +*  It is assumed that the matrix A*D*A' has been previously factorized
 215.314 +*  by the routine decomp_NE.
 215.315 +*
 215.316 +*  On entry the array y contains the vector of right-hand sides h. On
 215.317 +*  exit this array contains the computed vector of unknowns y.
 215.318 +*
 215.319 +*  Once the vector y has been computed the routine checks for numeric
 215.320 +*  stability. If the residual vector:
 215.321 +*
 215.322 +*     r = A*D*A'*y - h
 215.323 +*
 215.324 +*  is relatively small, the routine returns zero, otherwise non-zero is
 215.325 +*  returned. */
 215.326 +
 215.327 +static int solve_NE(struct csa *csa, double y[])
 215.328 +{     int m = csa->m;
 215.329 +      int n = csa->n;
 215.330 +      int *P = csa->P;
 215.331 +      int i, j, ret = 0;
 215.332 +      double *h, *r, *w;
 215.333 +      /* save vector of right-hand sides h */
 215.334 +      h = xcalloc(1+m, sizeof(double));
 215.335 +      for (i = 1; i <= m; i++) h[i] = y[i];
 215.336 +      /* solve normal equation system (A*D*A')*y = h */
 215.337 +      /* since S = P*A*D*A'*P' = U'*U, then A*D*A' = P'*U'*U*P, so we
 215.338 +         have inv(A*D*A') = P'*inv(U)*inv(U')*P */
 215.339 +      /* w := P*h */
 215.340 +      w = xcalloc(1+m, sizeof(double));
 215.341 +      for (i = 1; i <= m; i++) w[i] = y[P[i]];
 215.342 +      /* w := inv(U')*w */
 215.343 +      ut_solve(m, csa->U_ptr, csa->U_ind, csa->U_val, csa->U_diag, w);
 215.344 +      /* w := inv(U)*w */
 215.345 +      u_solve(m, csa->U_ptr, csa->U_ind, csa->U_val, csa->U_diag, w);
 215.346 +      /* y := P'*w */
 215.347 +      for (i = 1; i <= m; i++) y[i] = w[P[m+i]];
 215.348 +      xfree(w);
 215.349 +      /* compute residual vector r = A*D*A'*y - h */
 215.350 +      r = xcalloc(1+m, sizeof(double));
 215.351 +      /* w := A'*y */
 215.352 +      w = xcalloc(1+n, sizeof(double));
 215.353 +      AT_by_vec(csa, y, w);
 215.354 +      /* w := D*w */
 215.355 +      for (j = 1; j <= n; j++) w[j] *= csa->D[j];
 215.356 +      /* r := A*w */
 215.357 +      A_by_vec(csa, w, r);
 215.358 +      xfree(w);
 215.359 +      /* r := r - h */
 215.360 +      for (i = 1; i <= m; i++) r[i] -= h[i];
 215.361 +      /* check for numeric stability */
 215.362 +      for (i = 1; i <= m; i++)
 215.363 +      {  if (fabs(r[i]) / (1.0 + fabs(h[i])) > 1e-4)
 215.364 +         {  ret = 1;
 215.365 +            break;
 215.366 +         }
 215.367 +      }
 215.368 +      xfree(h);
 215.369 +      xfree(r);
 215.370 +      return ret;
 215.371 +}
 215.372 +
 215.373 +/***********************************************************************
 215.374 +*  solve_NS - solve Newtonian system
 215.375 +*
 215.376 +*  This routine solves the Newtonian system:
 215.377 +*
 215.378 +*     A*dx               = p
 215.379 +*
 215.380 +*           A'*dy +   dz = q
 215.381 +*
 215.382 +*     Z*dx        + X*dz = r
 215.383 +*
 215.384 +*  where X = diag(x[j]), Z = diag(z[j]), by reducing it to the normal
 215.385 +*  equation system:
 215.386 +*
 215.387 +*     (A*inv(Z)*X*A')*dy = A*inv(Z)*(X*q-r)+p
 215.388 +*
 215.389 +*  (it is assumed that the matrix A*inv(Z)*X*A' has been factorized by
 215.390 +*  the routine decomp_NE).
 215.391 +*
 215.392 +*  Once vector dy has been computed the routine computes vectors dx and
 215.393 +*  dz as follows:
 215.394 +*
 215.395 +*     dx = inv(Z)*(X*(A'*dy-q)+r)
 215.396 +*
 215.397 +*     dz = inv(X)*(r-Z*dx)
 215.398 +*
 215.399 +*  The routine solve_NS returns the same code which was reported by the
 215.400 +*  routine solve_NE (see above). */
 215.401 +
 215.402 +static int solve_NS(struct csa *csa, double p[], double q[], double r[],
 215.403 +      double dx[], double dy[], double dz[])
 215.404 +{     int m = csa->m;
 215.405 +      int n = csa->n;
 215.406 +      double *x = csa->x;
 215.407 +      double *z = csa->z;
 215.408 +      int i, j, ret;
 215.409 +      double *w = dx;
 215.410 +      /* compute the vector of right-hand sides A*inv(Z)*(X*q-r)+p for
 215.411 +         the normal equation system */
 215.412 +      for (j = 1; j <= n; j++)
 215.413 +         w[j] = (x[j] * q[j] - r[j]) / z[j];
 215.414 +      A_by_vec(csa, w, dy);
 215.415 +      for (i = 1; i <= m; i++) dy[i] += p[i];
 215.416 +      /* solve the normal equation system to compute vector dy */
 215.417 +      ret = solve_NE(csa, dy);
 215.418 +      /* compute vectors dx and dz */
 215.419 +      AT_by_vec(csa, dy, dx);
 215.420 +      for (j = 1; j <= n; j++)
 215.421 +      {  dx[j] = (x[j] * (dx[j] - q[j]) + r[j]) / z[j];
 215.422 +         dz[j] = (r[j] - z[j] * dx[j]) / x[j];
 215.423 +      }
 215.424 +      return ret;
 215.425 +}
 215.426 +
 215.427 +/***********************************************************************
 215.428 +*  initial_point - choose initial point using Mehrotra's heuristic
 215.429 +*
 215.430 +*  This routine chooses a starting point using a heuristic proposed in
 215.431 +*  the paper:
 215.432 +*
 215.433 +*  S. Mehrotra. On the implementation of a primal-dual interior point
 215.434 +*  method. SIAM J. on Optim., 2(4), pp. 575-601, 1992.
 215.435 +*
 215.436 +*  The starting point x in the primal space is chosen as a solution of
 215.437 +*  the following least squares problem:
 215.438 +*
 215.439 +*     minimize    ||x||
 215.440 +*
 215.441 +*     subject to  A*x = b
 215.442 +*
 215.443 +*  which can be computed explicitly as follows:
 215.444 +*
 215.445 +*     x = A'*inv(A*A')*b
 215.446 +*
 215.447 +*  Similarly, the starting point (y, z) in the dual space is chosen as
 215.448 +*  a solution of the following least squares problem:
 215.449 +*
 215.450 +*     minimize    ||z||
 215.451 +*
 215.452 +*     subject to  A'*y + z = c
 215.453 +*
 215.454 +*  which can be computed explicitly as follows:
 215.455 +*
 215.456 +*     y = inv(A*A')*A*c
 215.457 +*
 215.458 +*     z = c - A'*y
 215.459 +*
 215.460 +*  However, some components of the vectors x and z may be non-positive
 215.461 +*  or close to zero, so the routine uses a Mehrotra's heuristic to find
 215.462 +*  a more appropriate starting point. */
 215.463 +
 215.464 +static void initial_point(struct csa *csa)
 215.465 +{     int m = csa->m;
 215.466 +      int n = csa->n;
 215.467 +      double *b = csa->b;
 215.468 +      double *c = csa->c;
 215.469 +      double *x = csa->x;
 215.470 +      double *y = csa->y;
 215.471 +      double *z = csa->z;
 215.472 +      double *D = csa->D;
 215.473 +      int i, j;
 215.474 +      double dp, dd, ex, ez, xz;
 215.475 +      /* factorize A*A' */
 215.476 +      for (j = 1; j <= n; j++) D[j] = 1.0;
 215.477 +      decomp_NE(csa);
 215.478 +      /* x~ = A'*inv(A*A')*b */
 215.479 +      for (i = 1; i <= m; i++) y[i] = b[i];
 215.480 +      solve_NE(csa, y);
 215.481 +      AT_by_vec(csa, y, x);
 215.482 +      /* y~ = inv(A*A')*A*c */
 215.483 +      A_by_vec(csa, c, y);
 215.484 +      solve_NE(csa, y);
 215.485 +      /* z~ = c - A'*y~ */
 215.486 +      AT_by_vec(csa, y,z);
 215.487 +      for (j = 1; j <= n; j++) z[j] = c[j] - z[j];
 215.488 +      /* use Mehrotra's heuristic in order to choose more appropriate
 215.489 +         starting point with positive components of vectors x and z */
 215.490 +      dp = dd = 0.0;
 215.491 +      for (j = 1; j <= n; j++)
 215.492 +      {  if (dp < -1.5 * x[j]) dp = -1.5 * x[j];
 215.493 +         if (dd < -1.5 * z[j]) dd = -1.5 * z[j];
 215.494 +      }
 215.495 +      /* note that b = 0 involves x = 0, and c = 0 involves y = 0 and
 215.496 +         z = 0, so we need to be careful */
 215.497 +      if (dp == 0.0) dp = 1.5;
 215.498 +      if (dd == 0.0) dd = 1.5;
 215.499 +      ex = ez = xz = 0.0;
 215.500 +      for (j = 1; j <= n; j++)
 215.501 +      {  ex += (x[j] + dp);
 215.502 +         ez += (z[j] + dd);
 215.503 +         xz += (x[j] + dp) * (z[j] + dd);
 215.504 +      }
 215.505 +      dp += 0.5 * (xz / ez);
 215.506 +      dd += 0.5 * (xz / ex);
 215.507 +      for (j = 1; j <= n; j++)
 215.508 +      {  x[j] += dp;
 215.509 +         z[j] += dd;
 215.510 +         xassert(x[j] > 0.0 && z[j] > 0.0);
 215.511 +      }
 215.512 +      return;
 215.513 +}
 215.514 +
 215.515 +/***********************************************************************
 215.516 +*  basic_info - perform basic computations at the current point
 215.517 +*
 215.518 +*  This routine computes the following quantities at the current point:
 215.519 +*
 215.520 +*  1) value of the objective function:
 215.521 +*
 215.522 +*     F = c'*x + c[0]
 215.523 +*
 215.524 +*  2) relative primal infeasibility:
 215.525 +*
 215.526 +*     rpi = ||A*x-b|| / (1+||b||)
 215.527 +*
 215.528 +*  3) relative dual infeasibility:
 215.529 +*
 215.530 +*     rdi = ||A'*y+z-c|| / (1+||c||)
 215.531 +*
 215.532 +*  4) primal-dual gap (relative difference between the primal and the
 215.533 +*     dual objective function values):
 215.534 +*
 215.535 +*     gap = |c'*x-b'*y| / (1+|c'*x|)
 215.536 +*
 215.537 +*  5) merit function:
 215.538 +*
 215.539 +*     phi = ||A*x-b|| / max(1,||b||) + ||A'*y+z-c|| / max(1,||c||) +
 215.540 +*
 215.541 +*         + |c'*x-b'*y| / max(1,||b||,||c||)
 215.542 +*
 215.543 +*  6) duality measure:
 215.544 +*
 215.545 +*     mu = x'*z / n
 215.546 +*
 215.547 +*  7) the ratio of infeasibility to mu:
 215.548 +*
 215.549 +*     rmu = max(||A*x-b||,||A'*y+z-c||) / mu
 215.550 +*
 215.551 +*  where ||*|| denotes euclidian norm, *' denotes transposition. */
 215.552 +
 215.553 +static void basic_info(struct csa *csa)
 215.554 +{     int m = csa->m;
 215.555 +      int n = csa->n;
 215.556 +      double *b = csa->b;
 215.557 +      double *c = csa->c;
 215.558 +      double *x = csa->x;
 215.559 +      double *y = csa->y;
 215.560 +      double *z = csa->z;
 215.561 +      int i, j;
 215.562 +      double norm1, bnorm, norm2, cnorm, cx, by, *work, temp;
 215.563 +      /* compute value of the objective function */
 215.564 +      temp = c[0];
 215.565 +      for (j = 1; j <= n; j++) temp += c[j] * x[j];
 215.566 +      csa->obj = temp;
 215.567 +      /* norm1 = ||A*x-b|| */
 215.568 +      work = xcalloc(1+m, sizeof(double));
 215.569 +      A_by_vec(csa, x, work);
 215.570 +      norm1 = 0.0;
 215.571 +      for (i = 1; i <= m; i++)
 215.572 +         norm1 += (work[i] - b[i]) * (work[i] - b[i]);
 215.573 +      norm1 = sqrt(norm1);
 215.574 +      xfree(work);
 215.575 +      /* bnorm = ||b|| */
 215.576 +      bnorm = 0.0;
 215.577 +      for (i = 1; i <= m; i++) bnorm += b[i] * b[i];
 215.578 +      bnorm = sqrt(bnorm);
 215.579 +      /* compute relative primal infeasibility */
 215.580 +      csa->rpi = norm1 / (1.0 + bnorm);
 215.581 +      /* norm2 = ||A'*y+z-c|| */
 215.582 +      work = xcalloc(1+n, sizeof(double));
 215.583 +      AT_by_vec(csa, y, work);
 215.584 +      norm2 = 0.0;
 215.585 +      for (j = 1; j <= n; j++)
 215.586 +         norm2 += (work[j] + z[j] - c[j]) * (work[j] + z[j] - c[j]);
 215.587 +      norm2 = sqrt(norm2);
 215.588 +      xfree(work);
 215.589 +      /* cnorm = ||c|| */
 215.590 +      cnorm = 0.0;
 215.591 +      for (j = 1; j <= n; j++) cnorm += c[j] * c[j];
 215.592 +      cnorm = sqrt(cnorm);
 215.593 +      /* compute relative dual infeasibility */
 215.594 +      csa->rdi = norm2 / (1.0 + cnorm);
 215.595 +      /* by = b'*y */
 215.596 +      by = 0.0;
 215.597 +      for (i = 1; i <= m; i++) by += b[i] * y[i];
 215.598 +      /* cx = c'*x */
 215.599 +      cx = 0.0;
 215.600 +      for (j = 1; j <= n; j++) cx += c[j] * x[j];
 215.601 +      /* compute primal-dual gap */
 215.602 +      csa->gap = fabs(cx - by) / (1.0 + fabs(cx));
 215.603 +      /* compute merit function */
 215.604 +      csa->phi = 0.0;
 215.605 +      csa->phi += norm1 / (bnorm > 1.0 ? bnorm : 1.0);
 215.606 +      csa->phi += norm2 / (cnorm > 1.0 ? cnorm : 1.0);
 215.607 +      temp = 1.0;
 215.608 +      if (temp < bnorm) temp = bnorm;
 215.609 +      if (temp < cnorm) temp = cnorm;
 215.610 +      csa->phi += fabs(cx - by) / temp;
 215.611 +      /* compute duality measure */
 215.612 +      temp = 0.0;
 215.613 +      for (j = 1; j <= n; j++) temp += x[j] * z[j];
 215.614 +      csa->mu = temp / (double)n;
 215.615 +      /* compute the ratio of infeasibility to mu */
 215.616 +      csa->rmu = (norm1 > norm2 ? norm1 : norm2) / csa->mu;
 215.617 +      return;
 215.618 +}
 215.619 +
 215.620 +/***********************************************************************
 215.621 +*  make_step - compute next point using Mehrotra's technique
 215.622 +*
 215.623 +*  This routine computes the next point using the predictor-corrector
 215.624 +*  technique proposed in the paper:
 215.625 +*
 215.626 +*  S. Mehrotra. On the implementation of a primal-dual interior point
 215.627 +*  method. SIAM J. on Optim., 2(4), pp. 575-601, 1992.
 215.628 +*
 215.629 +*  At first, the routine computes so called affine scaling (predictor)
 215.630 +*  direction (dx_aff,dy_aff,dz_aff) which is a solution of the system:
 215.631 +*
 215.632 +*     A*dx_aff                       = b - A*x
 215.633 +*
 215.634 +*               A'*dy_aff +   dz_aff = c - A'*y - z
 215.635 +*
 215.636 +*     Z*dx_aff            + X*dz_aff = - X*Z*e
 215.637 +*
 215.638 +*  where (x,y,z) is the current point, X = diag(x[j]), Z = diag(z[j]),
 215.639 +*  e = (1,...,1)'.
 215.640 +*
 215.641 +*  Then, the routine computes the centering parameter sigma, using the
 215.642 +*  following Mehrotra's heuristic:
 215.643 +*
 215.644 +*     alfa_aff_p = inf{0 <= alfa <= 1 | x+alfa*dx_aff >= 0}
 215.645 +*
 215.646 +*     alfa_aff_d = inf{0 <= alfa <= 1 | z+alfa*dz_aff >= 0}
 215.647 +*
 215.648 +*     mu_aff = (x+alfa_aff_p*dx_aff)'*(z+alfa_aff_d*dz_aff)/n
 215.649 +*
 215.650 +*     sigma = (mu_aff/mu)^3
 215.651 +*
 215.652 +*  where alfa_aff_p is the maximal stepsize along the affine scaling
 215.653 +*  direction in the primal space, alfa_aff_d is the maximal stepsize
 215.654 +*  along the same direction in the dual space.
 215.655 +*
 215.656 +*  After determining sigma the routine computes so called centering
 215.657 +*  (corrector) direction (dx_cc,dy_cc,dz_cc) which is the solution of
 215.658 +*  the system:
 215.659 +*
 215.660 +*     A*dx_cc                     = 0
 215.661 +*
 215.662 +*              A'*dy_cc +   dz_cc = 0
 215.663 +*
 215.664 +*     Z*dx_cc           + X*dz_cc = sigma*mu*e - X*Z*e
 215.665 +*
 215.666 +*  Finally, the routine computes the combined direction
 215.667 +*
 215.668 +*     (dx,dy,dz) = (dx_aff,dy_aff,dz_aff) + (dx_cc,dy_cc,dz_cc)
 215.669 +*
 215.670 +*  and determines maximal primal and dual stepsizes along the combined
 215.671 +*  direction:
 215.672 +*
 215.673 +*     alfa_max_p = inf{0 <= alfa <= 1 | x+alfa*dx >= 0}
 215.674 +*
 215.675 +*     alfa_max_d = inf{0 <= alfa <= 1 | z+alfa*dz >= 0}
 215.676 +*
 215.677 +*  In order to prevent the next point to be too close to the boundary
 215.678 +*  of the positive ortant, the routine decreases maximal stepsizes:
 215.679 +*
 215.680 +*     alfa_p = gamma_p * alfa_max_p
 215.681 +*
 215.682 +*     alfa_d = gamma_d * alfa_max_d
 215.683 +*
 215.684 +*  where gamma_p and gamma_d are scaling factors, and computes the next
 215.685 +*  point:
 215.686 +*
 215.687 +*     x_new = x + alfa_p * dx
 215.688 +*
 215.689 +*     y_new = y + alfa_d * dy
 215.690 +*
 215.691 +*     z_new = z + alfa_d * dz
 215.692 +*
 215.693 +*  which becomes the current point on the next iteration. */
 215.694 +
 215.695 +static int make_step(struct csa *csa)
 215.696 +{     int m = csa->m;
 215.697 +      int n = csa->n;
 215.698 +      double *b = csa->b;
 215.699 +      double *c = csa->c;
 215.700 +      double *x = csa->x;
 215.701 +      double *y = csa->y;
 215.702 +      double *z = csa->z;
 215.703 +      double *dx_aff = csa->dx_aff;
 215.704 +      double *dy_aff = csa->dy_aff;
 215.705 +      double *dz_aff = csa->dz_aff;
 215.706 +      double *dx_cc = csa->dx_cc;
 215.707 +      double *dy_cc = csa->dy_cc;
 215.708 +      double *dz_cc = csa->dz_cc;
 215.709 +      double *dx = csa->dx;
 215.710 +      double *dy = csa->dy;
 215.711 +      double *dz = csa->dz;
 215.712 +      int i, j, ret = 0;
 215.713 +      double temp, gamma_p, gamma_d, *p, *q, *r;
 215.714 +      /* allocate working arrays */
 215.715 +      p = xcalloc(1+m, sizeof(double));
 215.716 +      q = xcalloc(1+n, sizeof(double));
 215.717 +      r = xcalloc(1+n, sizeof(double));
 215.718 +      /* p = b - A*x */
 215.719 +      A_by_vec(csa, x, p);
 215.720 +      for (i = 1; i <= m; i++) p[i] = b[i] - p[i];
 215.721 +      /* q = c - A'*y - z */
 215.722 +      AT_by_vec(csa, y,q);
 215.723 +      for (j = 1; j <= n; j++) q[j] = c[j] - q[j] - z[j];
 215.724 +      /* r = - X * Z * e */
 215.725 +      for (j = 1; j <= n; j++) r[j] = - x[j] * z[j];
 215.726 +      /* solve the first Newtonian system */
 215.727 +      if (solve_NS(csa, p, q, r, dx_aff, dy_aff, dz_aff))
 215.728 +      {  ret = 1;
 215.729 +         goto done;
 215.730 +      }
 215.731 +      /* alfa_aff_p = inf{0 <= alfa <= 1 | x + alfa*dx_aff >= 0} */
 215.732 +      /* alfa_aff_d = inf{0 <= alfa <= 1 | z + alfa*dz_aff >= 0} */
 215.733 +      csa->alfa_aff_p = csa->alfa_aff_d = 1.0;
 215.734 +      for (j = 1; j <= n; j++)
 215.735 +      {  if (dx_aff[j] < 0.0)
 215.736 +         {  temp = - x[j] / dx_aff[j];
 215.737 +            if (csa->alfa_aff_p > temp) csa->alfa_aff_p = temp;
 215.738 +         }
 215.739 +         if (dz_aff[j] < 0.0)
 215.740 +         {  temp = - z[j] / dz_aff[j];
 215.741 +            if (csa->alfa_aff_d > temp) csa->alfa_aff_d = temp;
 215.742 +         }
 215.743 +      }
 215.744 +      /* mu_aff = (x+alfa_aff_p*dx_aff)' * (z+alfa_aff_d*dz_aff) / n */
 215.745 +      temp = 0.0;
 215.746 +      for (j = 1; j <= n; j++)
 215.747 +         temp += (x[j] + csa->alfa_aff_p * dx_aff[j]) *
 215.748 +                 (z[j] + csa->alfa_aff_d * dz_aff[j]);
 215.749 +      csa->mu_aff = temp / (double)n;
 215.750 +      /* sigma = (mu_aff/mu)^3 */
 215.751 +      temp = csa->mu_aff / csa->mu;
 215.752 +      csa->sigma = temp * temp * temp;
 215.753 +      /* p = 0 */
 215.754 +      for (i = 1; i <= m; i++) p[i] = 0.0;
 215.755 +      /* q = 0 */
 215.756 +      for (j = 1; j <= n; j++) q[j] = 0.0;
 215.757 +      /* r = sigma * mu * e - X * Z * e */
 215.758 +      for (j = 1; j <= n; j++)
 215.759 +         r[j] = csa->sigma * csa->mu - dx_aff[j] * dz_aff[j];
 215.760 +      /* solve the second Newtonian system with the same coefficients
 215.761 +         but with altered right-hand sides */
 215.762 +      if (solve_NS(csa, p, q, r, dx_cc, dy_cc, dz_cc))
 215.763 +      {  ret = 1;
 215.764 +         goto done;
 215.765 +      }
 215.766 +      /* (dx,dy,dz) = (dx_aff,dy_aff,dz_aff) + (dx_cc,dy_cc,dz_cc) */
 215.767 +      for (j = 1; j <= n; j++) dx[j] = dx_aff[j] + dx_cc[j];
 215.768 +      for (i = 1; i <= m; i++) dy[i] = dy_aff[i] + dy_cc[i];
 215.769 +      for (j = 1; j <= n; j++) dz[j] = dz_aff[j] + dz_cc[j];
 215.770 +      /* alfa_max_p = inf{0 <= alfa <= 1 | x + alfa*dx >= 0} */
 215.771 +      /* alfa_max_d = inf{0 <= alfa <= 1 | z + alfa*dz >= 0} */
 215.772 +      csa->alfa_max_p = csa->alfa_max_d = 1.0;
 215.773 +      for (j = 1; j <= n; j++)
 215.774 +      {  if (dx[j] < 0.0)
 215.775 +         {  temp = - x[j] / dx[j];
 215.776 +            if (csa->alfa_max_p > temp) csa->alfa_max_p = temp;
 215.777 +         }
 215.778 +         if (dz[j] < 0.0)
 215.779 +         {  temp = - z[j] / dz[j];
 215.780 +            if (csa->alfa_max_d > temp) csa->alfa_max_d = temp;
 215.781 +         }
 215.782 +      }
 215.783 +      /* determine scale factors (not implemented yet) */
 215.784 +      gamma_p = 0.90;
 215.785 +      gamma_d = 0.90;
 215.786 +      /* compute the next point */
 215.787 +      for (j = 1; j <= n; j++)
 215.788 +      {  x[j] += gamma_p * csa->alfa_max_p * dx[j];
 215.789 +         xassert(x[j] > 0.0);
 215.790 +      }
 215.791 +      for (i = 1; i <= m; i++)
 215.792 +         y[i] += gamma_d * csa->alfa_max_d * dy[i];
 215.793 +      for (j = 1; j <= n; j++)
 215.794 +      {  z[j] += gamma_d * csa->alfa_max_d * dz[j];
 215.795 +         xassert(z[j] > 0.0);
 215.796 +      }
 215.797 +done: /* free working arrays */
 215.798 +      xfree(p);
 215.799 +      xfree(q);
 215.800 +      xfree(r);
 215.801 +      return ret;
 215.802 +}
 215.803 +
 215.804 +/***********************************************************************
 215.805 +*  terminate - deallocate common storage area
 215.806 +*
 215.807 +*  This routine frees all memory allocated to the common storage area
 215.808 +*  used by interior-point method routines. */
 215.809 +
 215.810 +static void terminate(struct csa *csa)
 215.811 +{     xfree(csa->D);
 215.812 +      xfree(csa->P);
 215.813 +      xfree(csa->S_ptr);
 215.814 +      xfree(csa->S_ind);
 215.815 +      xfree(csa->S_val);
 215.816 +      xfree(csa->S_diag);
 215.817 +      xfree(csa->U_ptr);
 215.818 +      xfree(csa->U_ind);
 215.819 +      xfree(csa->U_val);
 215.820 +      xfree(csa->U_diag);
 215.821 +      xfree(csa->phi_min);
 215.822 +      xfree(csa->best_x);
 215.823 +      xfree(csa->best_y);
 215.824 +      xfree(csa->best_z);
 215.825 +      xfree(csa->dx_aff);
 215.826 +      xfree(csa->dy_aff);
 215.827 +      xfree(csa->dz_aff);
 215.828 +      xfree(csa->dx_cc);
 215.829 +      xfree(csa->dy_cc);
 215.830 +      xfree(csa->dz_cc);
 215.831 +      return;
 215.832 +}
 215.833 +
 215.834 +/***********************************************************************
 215.835 +*  ipm_main - main interior-point method routine
 215.836 +*
 215.837 +*  This is a main routine of the primal-dual interior-point method.
 215.838 +*
 215.839 +*  The routine ipm_main returns one of the following codes:
 215.840 +*
 215.841 +*  0 - optimal solution found;
 215.842 +*  1 - problem has no feasible (primal or dual) solution;
 215.843 +*  2 - no convergence;
 215.844 +*  3 - iteration limit exceeded;
 215.845 +*  4 - numeric instability on solving Newtonian system.
 215.846 +*
 215.847 +*  In case of non-zero return code the routine returns the best point,
 215.848 +*  which has been reached during optimization. */
 215.849 +
 215.850 +static int ipm_main(struct csa *csa)
 215.851 +{     int m = csa->m;
 215.852 +      int n = csa->n;
 215.853 +      int i, j, status;
 215.854 +      double temp;
 215.855 +      /* choose initial point using Mehrotra's heuristic */
 215.856 +      if (csa->parm->msg_lev >= GLP_MSG_ALL)
 215.857 +         xprintf("Guessing initial point...\n");
 215.858 +      initial_point(csa);
 215.859 +      /* main loop starts here */
 215.860 +      if (csa->parm->msg_lev >= GLP_MSG_ALL)
 215.861 +         xprintf("Optimization begins...\n");
 215.862 +      for (;;)
 215.863 +      {  /* perform basic computations at the current point */
 215.864 +         basic_info(csa);
 215.865 +         /* save initial value of rmu */
 215.866 +         if (csa->iter == 0) csa->rmu0 = csa->rmu;
 215.867 +         /* accumulate values of min(phi[k]) and save the best point */
 215.868 +         xassert(csa->iter <= ITER_MAX);
 215.869 +         if (csa->iter == 0 || csa->phi_min[csa->iter-1] > csa->phi)
 215.870 +         {  csa->phi_min[csa->iter] = csa->phi;
 215.871 +            csa->best_iter = csa->iter;
 215.872 +            for (j = 1; j <= n; j++) csa->best_x[j] = csa->x[j];
 215.873 +            for (i = 1; i <= m; i++) csa->best_y[i] = csa->y[i];
 215.874 +            for (j = 1; j <= n; j++) csa->best_z[j] = csa->z[j];
 215.875 +            csa->best_obj = csa->obj;
 215.876 +         }
 215.877 +         else
 215.878 +            csa->phi_min[csa->iter] = csa->phi_min[csa->iter-1];
 215.879 +         /* display information at the current point */
 215.880 +         if (csa->parm->msg_lev >= GLP_MSG_ON)
 215.881 +            xprintf("%3d: obj = %17.9e; rpi = %8.1e; rdi = %8.1e; gap ="
 215.882 +               " %8.1e\n", csa->iter, csa->obj, csa->rpi, csa->rdi,
 215.883 +               csa->gap);
 215.884 +         /* check if the current point is optimal */
 215.885 +         if (csa->rpi < 1e-8 && csa->rdi < 1e-8 && csa->gap < 1e-8)
 215.886 +         {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
 215.887 +               xprintf("OPTIMAL SOLUTION FOUND\n");
 215.888 +            status = 0;
 215.889 +            break;
 215.890 +         }
 215.891 +         /* check if the problem has no feasible solution */
 215.892 +         temp = 1e5 * csa->phi_min[csa->iter];
 215.893 +         if (temp < 1e-8) temp = 1e-8;
 215.894 +         if (csa->phi >= temp)
 215.895 +         {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
 215.896 +               xprintf("PROBLEM HAS NO FEASIBLE PRIMAL/DUAL SOLUTION\n")
 215.897 +                  ;
 215.898 +            status = 1;
 215.899 +            break;
 215.900 +         }
 215.901 +         /* check for very slow convergence or divergence */
 215.902 +         if (((csa->rpi >= 1e-8 || csa->rdi >= 1e-8) && csa->rmu /
 215.903 +               csa->rmu0 >= 1e6) ||
 215.904 +               (csa->iter >= 30 && csa->phi_min[csa->iter] >= 0.5 *
 215.905 +               csa->phi_min[csa->iter - 30]))
 215.906 +         {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
 215.907 +               xprintf("NO CONVERGENCE; SEARCH TERMINATED\n");
 215.908 +            status = 2;
 215.909 +            break;
 215.910 +         }
 215.911 +         /* check for maximal number of iterations */
 215.912 +         if (csa->iter == ITER_MAX)
 215.913 +         {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
 215.914 +               xprintf("ITERATION LIMIT EXCEEDED; SEARCH TERMINATED\n");
 215.915 +            status = 3;
 215.916 +            break;
 215.917 +         }
 215.918 +         /* start the next iteration */
 215.919 +         csa->iter++;
 215.920 +         /* factorize normal equation system */
 215.921 +         for (j = 1; j <= n; j++) csa->D[j] = csa->x[j] / csa->z[j];
 215.922 +         decomp_NE(csa);
 215.923 +         /* compute the next point using Mehrotra's predictor-corrector
 215.924 +            technique */
 215.925 +         if (make_step(csa))
 215.926 +         {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
 215.927 +               xprintf("NUMERIC INSTABILITY; SEARCH TERMINATED\n");
 215.928 +            status = 4;
 215.929 +            break;
 215.930 +         }
 215.931 +      }
 215.932 +      /* restore the best point */
 215.933 +      if (status != 0)
 215.934 +      {  for (j = 1; j <= n; j++) csa->x[j] = csa->best_x[j];
 215.935 +         for (i = 1; i <= m; i++) csa->y[i] = csa->best_y[i];
 215.936 +         for (j = 1; j <= n; j++) csa->z[j] = csa->best_z[j];
 215.937 +         if (csa->parm->msg_lev >= GLP_MSG_ALL)
 215.938 +            xprintf("Best point %17.9e was reached on iteration %d\n",
 215.939 +               csa->best_obj, csa->best_iter);
 215.940 +      }
 215.941 +      /* return to the calling program */
 215.942 +      return status;
 215.943 +}
 215.944 +
 215.945 +/***********************************************************************
 215.946 +*  NAME
 215.947 +*
 215.948 +*  ipm_solve - core LP solver based on the interior-point method
 215.949 +*
 215.950 +*  SYNOPSIS
 215.951 +*
 215.952 +*  #include "glpipm.h"
 215.953 +*  int ipm_solve(glp_prob *P, const glp_iptcp *parm);
 215.954 +*
 215.955 +*  DESCRIPTION
 215.956 +*
 215.957 +*  The routine ipm_solve is a core LP solver based on the primal-dual
 215.958 +*  interior-point method.
 215.959 +*
 215.960 +*  The routine assumes the following standard formulation of LP problem
 215.961 +*  to be solved:
 215.962 +*
 215.963 +*     minimize
 215.964 +*
 215.965 +*        F = c[0] + c[1]*x[1] + c[2]*x[2] + ... + c[n]*x[n]
 215.966 +*
 215.967 +*     subject to linear constraints
 215.968 +*
 215.969 +*        a[1,1]*x[1] + a[1,2]*x[2] + ... + a[1,n]*x[n] = b[1]
 215.970 +*
 215.971 +*        a[2,1]*x[1] + a[2,2]*x[2] + ... + a[2,n]*x[n] = b[2]
 215.972 +*
 215.973 +*              . . . . . .
 215.974 +*
 215.975 +*        a[m,1]*x[1] + a[m,2]*x[2] + ... + a[m,n]*x[n] = b[m]
 215.976 +*
 215.977 +*     and non-negative variables
 215.978 +*
 215.979 +*        x[1] >= 0, x[2] >= 0, ..., x[n] >= 0
 215.980 +*
 215.981 +*  where:
 215.982 +*  F                    is the objective function;
 215.983 +*  x[1], ..., x[n]      are (structural) variables;
 215.984 +*  c[0]                 is a constant term of the objective function;
 215.985 +*  c[1], ..., c[n]      are objective coefficients;
 215.986 +*  a[1,1], ..., a[m,n]  are constraint coefficients;
 215.987 +*  b[1], ..., b[n]      are right-hand sides.
 215.988 +*
 215.989 +*  The solution is three vectors x, y, and z, which are stored by the
 215.990 +*  routine in the arrays x, y, and z, respectively. These vectors
 215.991 +*  correspond to the best primal-dual point found during optimization.
 215.992 +*  They are approximate solution of the following system (which is the
 215.993 +*  Karush-Kuhn-Tucker optimality conditions):
 215.994 +*
 215.995 +*     A*x      = b      (primal feasibility condition)
 215.996 +*
 215.997 +*     A'*y + z = c      (dual feasibility condition)
 215.998 +*
 215.999 +*     x'*z     = 0      (primal-dual complementarity condition)
215.1000 +*
215.1001 +*     x >= 0, z >= 0    (non-negativity condition)
215.1002 +*
215.1003 +*  where:
215.1004 +*  x[1], ..., x[n]      are primal (structural) variables;
215.1005 +*  y[1], ..., y[m]      are dual variables (Lagrange multipliers) for
215.1006 +*                       equality constraints;
215.1007 +*  z[1], ..., z[n]      are dual variables (Lagrange multipliers) for
215.1008 +*                       non-negativity constraints.
215.1009 +*
215.1010 +*  RETURNS
215.1011 +*
215.1012 +*  0  LP has been successfully solved.
215.1013 +*
215.1014 +*  GLP_ENOCVG
215.1015 +*     No convergence.
215.1016 +*
215.1017 +*  GLP_EITLIM
215.1018 +*     Iteration limit exceeded.
215.1019 +*
215.1020 +*  GLP_EINSTAB
215.1021 +*     Numeric instability on solving Newtonian system.
215.1022 +*
215.1023 +*  In case of non-zero return code the routine returns the best point,
215.1024 +*  which has been reached during optimization. */
215.1025 +
215.1026 +int ipm_solve(glp_prob *P, const glp_iptcp *parm)
215.1027 +{     struct csa _dsa, *csa = &_dsa;
215.1028 +      int m = P->m;
215.1029 +      int n = P->n;
215.1030 +      int nnz = P->nnz;
215.1031 +      GLPROW *row;
215.1032 +      GLPCOL *col;
215.1033 +      GLPAIJ *aij;
215.1034 +      int i, j, loc, ret, *A_ind, *A_ptr;
215.1035 +      double dir, *A_val, *b, *c, *x, *y, *z;
215.1036 +      xassert(m > 0);
215.1037 +      xassert(n > 0);
215.1038 +      /* allocate working arrays */
215.1039 +      A_ptr = xcalloc(1+m+1, sizeof(int));
215.1040 +      A_ind = xcalloc(1+nnz, sizeof(int));
215.1041 +      A_val = xcalloc(1+nnz, sizeof(double));
215.1042 +      b = xcalloc(1+m, sizeof(double));
215.1043 +      c = xcalloc(1+n, sizeof(double));
215.1044 +      x = xcalloc(1+n, sizeof(double));
215.1045 +      y = xcalloc(1+m, sizeof(double));
215.1046 +      z = xcalloc(1+n, sizeof(double));
215.1047 +      /* prepare rows and constraint coefficients */
215.1048 +      loc = 1;
215.1049 +      for (i = 1; i <= m; i++)
215.1050 +      {  row = P->row[i];
215.1051 +         xassert(row->type == GLP_FX);
215.1052 +         b[i] = row->lb * row->rii;
215.1053 +         A_ptr[i] = loc;
215.1054 +         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
215.1055 +         {  A_ind[loc] = aij->col->j;
215.1056 +            A_val[loc] = row->rii * aij->val * aij->col->sjj;
215.1057 +            loc++;
215.1058 +         }
215.1059 +      }
215.1060 +      A_ptr[m+1] = loc;
215.1061 +      xassert(loc-1 == nnz);
215.1062 +      /* prepare columns and objective coefficients */
215.1063 +      if (P->dir == GLP_MIN)
215.1064 +         dir = +1.0;
215.1065 +      else if (P->dir == GLP_MAX)
215.1066 +         dir = -1.0;
215.1067 +      else
215.1068 +         xassert(P != P);
215.1069 +      c[0] = dir * P->c0;
215.1070 +      for (j = 1; j <= n; j++)
215.1071 +      {  col = P->col[j];
215.1072 +         xassert(col->type == GLP_LO && col->lb == 0.0);
215.1073 +         c[j] = dir * col->coef * col->sjj;
215.1074 +      }
215.1075 +      /* allocate and initialize the common storage area */
215.1076 +      csa->m = m;
215.1077 +      csa->n = n;
215.1078 +      csa->A_ptr = A_ptr;
215.1079 +      csa->A_ind = A_ind;
215.1080 +      csa->A_val = A_val;
215.1081 +      csa->b = b;
215.1082 +      csa->c = c;
215.1083 +      csa->x = x;
215.1084 +      csa->y = y;
215.1085 +      csa->z = z;
215.1086 +      csa->parm = parm;
215.1087 +      initialize(csa);
215.1088 +      /* solve LP with the interior-point method */
215.1089 +      ret = ipm_main(csa);
215.1090 +      /* deallocate the common storage area */
215.1091 +      terminate(csa);
215.1092 +      /* determine solution status */
215.1093 +      if (ret == 0)
215.1094 +      {  /* optimal solution found */
215.1095 +         P->ipt_stat = GLP_OPT;
215.1096 +         ret = 0;
215.1097 +      }
215.1098 +      else if (ret == 1)
215.1099 +      {  /* problem has no feasible (primal or dual) solution */
215.1100 +         P->ipt_stat = GLP_NOFEAS;
215.1101 +         ret = 0;
215.1102 +      }
215.1103 +      else if (ret == 2)
215.1104 +      {  /* no convergence */
215.1105 +         P->ipt_stat = GLP_INFEAS;
215.1106 +         ret = GLP_ENOCVG;
215.1107 +      }
215.1108 +      else if (ret == 3)
215.1109 +      {  /* iteration limit exceeded */
215.1110 +         P->ipt_stat = GLP_INFEAS;
215.1111 +         ret = GLP_EITLIM;
215.1112 +      }
215.1113 +      else if (ret == 4)
215.1114 +      {  /* numeric instability on solving Newtonian system */
215.1115 +         P->ipt_stat = GLP_INFEAS;
215.1116 +         ret = GLP_EINSTAB;
215.1117 +      }
215.1118 +      else
215.1119 +         xassert(ret != ret);
215.1120 +      /* store row solution components */
215.1121 +      for (i = 1; i <= m; i++)
215.1122 +      {  row = P->row[i];
215.1123 +         row->pval = row->lb;
215.1124 +         row->dval = dir * y[i] * row->rii;
215.1125 +      }
215.1126 +      /* store column solution components */
215.1127 +      P->ipt_obj = P->c0;
215.1128 +      for (j = 1; j <= n; j++)
215.1129 +      {  col = P->col[j];
215.1130 +         col->pval = x[j] * col->sjj;
215.1131 +         col->dval = dir * z[j] / col->sjj;
215.1132 +         P->ipt_obj += col->coef * col->pval;
215.1133 +      }
215.1134 +      /* free working arrays */
215.1135 +      xfree(A_ptr);
215.1136 +      xfree(A_ind);
215.1137 +      xfree(A_val);
215.1138 +      xfree(b);
215.1139 +      xfree(c);
215.1140 +      xfree(x);
215.1141 +      xfree(y);
215.1142 +      xfree(z);
215.1143 +      return ret;
215.1144 +}
215.1145 +
215.1146 +/* eof */
   216.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   216.2 +++ b/src/glpipm.h	Mon Dec 06 13:09:21 2010 +0100
   216.3 @@ -0,0 +1,36 @@
   216.4 +/* glpipm.h (primal-dual interior-point method) */
   216.5 +
   216.6 +/***********************************************************************
   216.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   216.8 +*
   216.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  216.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  216.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  216.12 +*  E-mail: <mao@gnu.org>.
  216.13 +*
  216.14 +*  GLPK is free software: you can redistribute it and/or modify it
  216.15 +*  under the terms of the GNU General Public License as published by
  216.16 +*  the Free Software Foundation, either version 3 of the License, or
  216.17 +*  (at your option) any later version.
  216.18 +*
  216.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  216.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  216.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  216.22 +*  License for more details.
  216.23 +*
  216.24 +*  You should have received a copy of the GNU General Public License
  216.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  216.26 +***********************************************************************/
  216.27 +
  216.28 +#ifndef GLPIPM_H
  216.29 +#define GLPIPM_H
  216.30 +
  216.31 +#include "glpapi.h"
  216.32 +
  216.33 +#define ipm_solve _glp_ipm_solve
  216.34 +int ipm_solve(glp_prob *P, const glp_iptcp *parm);
  216.35 +/* core LP solver based on the interior-point method */
  216.36 +
  216.37 +#endif
  216.38 +
  216.39 +/* eof */
   217.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   217.2 +++ b/src/glplib.h	Mon Dec 06 13:09:21 2010 +0100
   217.3 @@ -0,0 +1,135 @@
   217.4 +/* glplib.h (miscellaneous library routines) */
   217.5 +
   217.6 +/***********************************************************************
   217.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   217.8 +*
   217.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  217.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  217.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  217.12 +*  E-mail: <mao@gnu.org>.
  217.13 +*
  217.14 +*  GLPK is free software: you can redistribute it and/or modify it
  217.15 +*  under the terms of the GNU General Public License as published by
  217.16 +*  the Free Software Foundation, either version 3 of the License, or
  217.17 +*  (at your option) any later version.
  217.18 +*
  217.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  217.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  217.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  217.22 +*  License for more details.
  217.23 +*
  217.24 +*  You should have received a copy of the GNU General Public License
  217.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  217.26 +***********************************************************************/
  217.27 +
  217.28 +#ifndef GLPLIB_H
  217.29 +#define GLPLIB_H
  217.30 +
  217.31 +#define bigmul _glp_lib_bigmul
  217.32 +void bigmul(int n, int m, unsigned short x[], unsigned short y[]);
  217.33 +/* multiply unsigned integer numbers of arbitrary precision */
  217.34 +
  217.35 +#define bigdiv _glp_lib_bigdiv
  217.36 +void bigdiv(int n, int m, unsigned short x[], unsigned short y[]);
  217.37 +/* divide unsigned integer numbers of arbitrary precision */
  217.38 +
  217.39 +#ifndef GLP_LONG_DEFINED
  217.40 +#define GLP_LONG_DEFINED
  217.41 +typedef struct { int lo, hi; } glp_long;
  217.42 +/* long integer data type */
  217.43 +#endif
  217.44 +
  217.45 +typedef struct { glp_long quot, rem; } glp_ldiv;
  217.46 +/* result of long integer division */
  217.47 +
  217.48 +#define xlset _glp_lib_xlset
  217.49 +glp_long xlset(int x);
  217.50 +/* expand integer to long integer */
  217.51 +
  217.52 +#define xlneg _glp_lib_xlneg
  217.53 +glp_long xlneg(glp_long x);
  217.54 +/* negate long integer */
  217.55 +
  217.56 +#define xladd _glp_lib_xladd
  217.57 +glp_long xladd(glp_long x, glp_long y);
  217.58 +/* add long integers */
  217.59 +
  217.60 +#define xlsub _glp_lib_xlsub
  217.61 +glp_long xlsub(glp_long x, glp_long y);
  217.62 +/* subtract long integers */
  217.63 +
  217.64 +#define xlcmp _glp_lib_xlcmp
  217.65 +int xlcmp(glp_long x, glp_long y);
  217.66 +/* compare long integers */
  217.67 +
  217.68 +#define xlmul _glp_lib_xlmul
  217.69 +glp_long xlmul(glp_long x, glp_long y);
  217.70 +/* multiply long integers */
  217.71 +
  217.72 +#define xldiv _glp_lib_xldiv
  217.73 +glp_ldiv xldiv(glp_long x, glp_long y);
  217.74 +/* divide long integers */
  217.75 +
  217.76 +#define xltod _glp_lib_xltod
  217.77 +double xltod(glp_long x);
  217.78 +/* convert long integer to double */
  217.79 +
  217.80 +#define xltoa _glp_lib_xltoa
  217.81 +char *xltoa(glp_long x, char *s);
  217.82 +/* convert long integer to character string */
  217.83 +
  217.84 +#define str2int _glp_lib_str2int
  217.85 +int str2int(const char *str, int *val);
  217.86 +/* convert character string to value of int type */
  217.87 +
  217.88 +#define str2num _glp_lib_str2num
  217.89 +int str2num(const char *str, double *val);
  217.90 +/* convert character string to value of double type */
  217.91 +
  217.92 +#define strspx _glp_lib_strspx
  217.93 +char *strspx(char *str);
  217.94 +/* remove all spaces from character string */
  217.95 +
  217.96 +#define strtrim _glp_lib_strtrim
  217.97 +char *strtrim(char *str);
  217.98 +/* remove trailing spaces from character string */
  217.99 +
 217.100 +#define strrev _glp_lib_strrev
 217.101 +char *strrev(char *s);
 217.102 +/* reverse character string */
 217.103 +
 217.104 +#define gcd _glp_lib_gcd
 217.105 +int gcd(int x, int y);
 217.106 +/* find greatest common divisor of two integers */
 217.107 +
 217.108 +#define gcdn _glp_lib_gcdn
 217.109 +int gcdn(int n, int x[]);
 217.110 +/* find greatest common divisor of n integers */
 217.111 +
 217.112 +#define lcm _glp_lib_lcm
 217.113 +int lcm(int x, int y);
 217.114 +/* find least common multiple of two integers */
 217.115 +
 217.116 +#define lcmn _glp_lib_lcmn
 217.117 +int lcmn(int n, int x[]);
 217.118 +/* find least common multiple of n integers */
 217.119 +
 217.120 +#define round2n _glp_lib_round2n
 217.121 +double round2n(double x);
 217.122 +/* round floating-point number to nearest power of two */
 217.123 +
 217.124 +#define fp2rat _glp_lib_fp2rat
 217.125 +int fp2rat(double x, double eps, double *p, double *q);
 217.126 +/* convert floating-point number to rational number */
 217.127 +
 217.128 +#define jday _glp_lib_jday
 217.129 +int jday(int d, int m, int y);
 217.130 +/* convert calendar date to Julian day number */
 217.131 +
 217.132 +#define jdate _glp_lib_jdate
 217.133 +int jdate(int j, int *d, int *m, int *y);
 217.134 +/* convert Julian day number to calendar date */
 217.135 +
 217.136 +#endif
 217.137 +
 217.138 +/* eof */
   218.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   218.2 +++ b/src/glplib01.c	Mon Dec 06 13:09:21 2010 +0100
   218.3 @@ -0,0 +1,287 @@
   218.4 +/* glplib01.c (bignum arithmetic) */
   218.5 +
   218.6 +/***********************************************************************
   218.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   218.8 +*
   218.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  218.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  218.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  218.12 +*  E-mail: <mao@gnu.org>.
  218.13 +*
  218.14 +*  GLPK is free software: you can redistribute it and/or modify it
  218.15 +*  under the terms of the GNU General Public License as published by
  218.16 +*  the Free Software Foundation, either version 3 of the License, or
  218.17 +*  (at your option) any later version.
  218.18 +*
  218.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  218.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  218.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  218.22 +*  License for more details.
  218.23 +*
  218.24 +*  You should have received a copy of the GNU General Public License
  218.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  218.26 +***********************************************************************/
  218.27 +
  218.28 +#include "glpenv.h"
  218.29 +#include "glplib.h"
  218.30 +
  218.31 +/***********************************************************************
  218.32 +*  Two routines below are intended to multiply and divide unsigned
  218.33 +*  integer numbers of arbitrary precision.
  218.34 +* 
  218.35 +*  The routines assume that an unsigned integer number is represented in
  218.36 +*  the positional numeral system with the base 2^16 = 65536, i.e. each
  218.37 +*  "digit" of the number is in the range [0, 65535] and represented as
  218.38 +*  a 16-bit value of the unsigned short type. In other words, a number x
  218.39 +*  has the following representation:
  218.40 +* 
  218.41 +*         n-1
  218.42 +*     x = sum d[j] * 65536^j,
  218.43 +*         j=0
  218.44 +* 
  218.45 +*  where n is the number of places (positions), and d[j] is j-th "digit"
  218.46 +*  of x, 0 <= d[j] <= 65535.
  218.47 +***********************************************************************/
  218.48 +
  218.49 +/***********************************************************************
  218.50 +*  NAME
  218.51 +*
  218.52 +*  bigmul - multiply unsigned integer numbers of arbitrary precision
  218.53 +* 
  218.54 +*  SYNOPSIS
  218.55 +* 
  218.56 +*  #include "glplib.h"
  218.57 +*  void bigmul(int n, int m, unsigned short x[], unsigned short y[]);
  218.58 +* 
  218.59 +*  DESCRIPTION
  218.60 +* 
  218.61 +*  The routine bigmul multiplies unsigned integer numbers of arbitrary
  218.62 +*  precision.
  218.63 +* 
  218.64 +*  n is the number of digits of multiplicand, n >= 1;
  218.65 +* 
  218.66 +*  m is the number of digits of multiplier, m >= 1;
  218.67 +* 
  218.68 +*  x is an array containing digits of the multiplicand in elements
  218.69 +*  x[m], x[m+1], ..., x[n+m-1]. Contents of x[0], x[1], ..., x[m-1] are
  218.70 +*  ignored on entry.
  218.71 +* 
  218.72 +*  y is an array containing digits of the multiplier in elements y[0],
  218.73 +*  y[1], ..., y[m-1].
  218.74 +* 
  218.75 +*  On exit digits of the product are stored in elements x[0], x[1], ...,
  218.76 +*  x[n+m-1]. The array y is not changed. */
  218.77 +
  218.78 +void bigmul(int n, int m, unsigned short x[], unsigned short y[])
  218.79 +{     int i, j;
  218.80 +      unsigned int t;
  218.81 +      xassert(n >= 1);
  218.82 +      xassert(m >= 1);
  218.83 +      for (j = 0; j < m; j++) x[j] = 0;
  218.84 +      for (i = 0; i < n; i++)
  218.85 +      {  if (x[i+m])
  218.86 +         {  t = 0;
  218.87 +            for (j = 0; j < m; j++)
  218.88 +            {  t += (unsigned int)x[i+m] * (unsigned int)y[j] +
  218.89 +                    (unsigned int)x[i+j];
  218.90 +               x[i+j] = (unsigned short)t;
  218.91 +               t >>= 16;
  218.92 +            }
  218.93 +            x[i+m] = (unsigned short)t;
  218.94 +         }
  218.95 +      }
  218.96 +      return;
  218.97 +}
  218.98 +
  218.99 +/***********************************************************************
 218.100 +*  NAME
 218.101 +*
 218.102 +*  bigdiv - divide unsigned integer numbers of arbitrary precision
 218.103 +* 
 218.104 +*  SYNOPSIS
 218.105 +* 
 218.106 +*  #include "glplib.h"
 218.107 +*  void bigdiv(int n, int m, unsigned short x[], unsigned short y[]);
 218.108 +* 
 218.109 +*  DESCRIPTION
 218.110 +* 
 218.111 +*  The routine bigdiv divides one unsigned integer number of arbitrary
 218.112 +*  precision by another with the algorithm described in [1].
 218.113 +* 
 218.114 +*  n is the difference between the number of digits of dividend and the
 218.115 +*  number of digits of divisor, n >= 0.
 218.116 +* 
 218.117 +*  m is the number of digits of divisor, m >= 1.
 218.118 +* 
 218.119 +*  x is an array containing digits of the dividend in elements x[0],
 218.120 +*  x[1], ..., x[n+m-1].
 218.121 +* 
 218.122 +*  y is an array containing digits of the divisor in elements y[0],
 218.123 +*  y[1], ..., y[m-1]. The highest digit y[m-1] must be non-zero.
 218.124 +* 
 218.125 +*  On exit n+1 digits of the quotient are stored in elements x[m],
 218.126 +*  x[m+1], ..., x[n+m], and m digits of the remainder are stored in
 218.127 +*  elements x[0], x[1], ..., x[m-1]. The array y is changed but then
 218.128 +*  restored.
 218.129 +*
 218.130 +*  REFERENCES
 218.131 +*
 218.132 +*  1. D. Knuth. The Art of Computer Programming. Vol. 2: Seminumerical
 218.133 +*  Algorithms. Stanford University, 1969. */
 218.134 +
 218.135 +void bigdiv(int n, int m, unsigned short x[], unsigned short y[])
 218.136 +{     int i, j;
 218.137 +      unsigned int t;
 218.138 +      unsigned short d, q, r;
 218.139 +      xassert(n >= 0);
 218.140 +      xassert(m >= 1);
 218.141 +      xassert(y[m-1] != 0);
 218.142 +      /* special case when divisor has the only digit */
 218.143 +      if (m == 1)
 218.144 +      {  d = 0;
 218.145 +         for (i = n; i >= 0; i--)
 218.146 +         {  t = ((unsigned int)d << 16) + (unsigned int)x[i];
 218.147 +            x[i+1] = (unsigned short)(t / y[0]);
 218.148 +            d = (unsigned short)(t % y[0]);
 218.149 +         }
 218.150 +         x[0] = d;
 218.151 +         goto done;
 218.152 +      }
 218.153 +      /* multiply dividend and divisor by a normalizing coefficient in
 218.154 +         order to provide the condition y[m-1] >= base / 2 */
 218.155 +      d = (unsigned short)(0x10000 / ((unsigned int)y[m-1] + 1));
 218.156 +      if (d == 1)
 218.157 +         x[n+m] = 0;
 218.158 +      else
 218.159 +      {  t = 0;
 218.160 +         for (i = 0; i < n+m; i++)
 218.161 +         {  t += (unsigned int)x[i] * (unsigned int)d;
 218.162 +            x[i] = (unsigned short)t;
 218.163 +            t >>= 16;
 218.164 +         }
 218.165 +         x[n+m] = (unsigned short)t;
 218.166 +         t = 0;
 218.167 +         for (j = 0; j < m; j++)
 218.168 +         {  t += (unsigned int)y[j] * (unsigned int)d;
 218.169 +            y[j] = (unsigned short)t;
 218.170 +            t >>= 16;
 218.171 +         }
 218.172 +      }
 218.173 +      /* main loop */
 218.174 +      for (i = n; i >= 0; i--)
 218.175 +      {  /* estimate and correct the current digit of quotient */
 218.176 +         if (x[i+m] < y[m-1])
 218.177 +         {  t = ((unsigned int)x[i+m] << 16) + (unsigned int)x[i+m-1];
 218.178 +            q = (unsigned short)(t / (unsigned int)y[m-1]);
 218.179 +            r = (unsigned short)(t % (unsigned int)y[m-1]);
 218.180 +            if (q == 0) goto putq; else goto test;
 218.181 +         }
 218.182 +         q = 0;
 218.183 +         r = x[i+m-1];
 218.184 +decr:    q--; /* if q = 0 then q-- = 0xFFFF */
 218.185 +         t = (unsigned int)r + (unsigned int)y[m-1];
 218.186 +         r = (unsigned short)t;
 218.187 +         if (t > 0xFFFF) goto msub;
 218.188 +test:    t = (unsigned int)y[m-2] * (unsigned int)q;
 218.189 +         if ((unsigned short)(t >> 16) > r) goto decr;
 218.190 +         if ((unsigned short)(t >> 16) < r) goto msub;
 218.191 +         if ((unsigned short)t > x[i+m-2]) goto decr;
 218.192 +msub:    /* now subtract divisor multiplied by the current digit of
 218.193 +            quotient from the current dividend */
 218.194 +         if (q == 0) goto putq;
 218.195 +         t = 0;
 218.196 +         for (j = 0; j < m; j++)
 218.197 +         {  t += (unsigned int)y[j] * (unsigned int)q;
 218.198 +            if (x[i+j] < (unsigned short)t) t += 0x10000;
 218.199 +            x[i+j] -= (unsigned short)t;
 218.200 +            t >>= 16;
 218.201 +         }
 218.202 +         if (x[i+m] >= (unsigned short)t) goto putq;
 218.203 +         /* perform correcting addition, because the current digit of
 218.204 +            quotient is greater by one than its correct value */
 218.205 +         q--;
 218.206 +         t = 0;
 218.207 +         for (j = 0; j < m; j++)
 218.208 +         {  t += (unsigned int)x[i+j] + (unsigned int)y[j];
 218.209 +            x[i+j] = (unsigned short)t;
 218.210 +            t >>= 16;
 218.211 +         }
 218.212 +putq:    /* store the current digit of quotient */
 218.213 +         x[i+m] = q;
 218.214 +      }
 218.215 +      /* divide divisor and remainder by the normalizing coefficient in
 218.216 +         order to restore their original values */
 218.217 +      if (d > 1)
 218.218 +      {  t = 0;
 218.219 +         for (i = m-1; i >= 0; i--)
 218.220 +         {  t = (t << 16) + (unsigned int)x[i];
 218.221 +            x[i] = (unsigned short)(t / (unsigned int)d);
 218.222 +            t %= (unsigned int)d;
 218.223 +         }
 218.224 +         t = 0;
 218.225 +         for (j = m-1; j >= 0; j--)
 218.226 +         {  t = (t << 16) + (unsigned int)y[j];
 218.227 +            y[j] = (unsigned short)(t / (unsigned int)d);
 218.228 +            t %= (unsigned int)d;
 218.229 +         }
 218.230 +      }
 218.231 +done: return;
 218.232 +}
 218.233 +
 218.234 +/**********************************************************************/
 218.235 +
 218.236 +#if 0
 218.237 +#include <assert.h>
 218.238 +#include <stdio.h>
 218.239 +#include <stdlib.h>
 218.240 +#include "glprng.h"
 218.241 +
 218.242 +#define N_MAX 7
 218.243 +/* maximal number of digits in multiplicand */
 218.244 +
 218.245 +#define M_MAX 5
 218.246 +/* maximal number of digits in multiplier */
 218.247 +
 218.248 +#define N_TEST 1000000
 218.249 +/* number of tests */
 218.250 +
 218.251 +int main(void)
 218.252 +{     RNG *rand;
 218.253 +      int d, j, n, m, test;
 218.254 +      unsigned short x[N_MAX], y[M_MAX], z[N_MAX+M_MAX];
 218.255 +      rand = rng_create_rand();
 218.256 +      for (test = 1; test <= N_TEST; test++)
 218.257 +      {  /* x[0,...,n-1] := multiplicand */
 218.258 +         n = 1 + rng_unif_rand(rand, N_MAX-1);
 218.259 +         assert(1 <= n && n <= N_MAX);
 218.260 +         for (j = 0; j < n; j++)
 218.261 +         {  d = rng_unif_rand(rand, 65536);
 218.262 +            assert(0 <= d && d <= 65535);
 218.263 +            x[j] = (unsigned short)d;
 218.264 +         }
 218.265 +         /* y[0,...,m-1] := multiplier */
 218.266 +         m = 1 + rng_unif_rand(rand, M_MAX-1);
 218.267 +         assert(1 <= m && m <= M_MAX);
 218.268 +         for (j = 0; j < m; j++)
 218.269 +         {  d = rng_unif_rand(rand, 65536);
 218.270 +            assert(0 <= d && d <= 65535);
 218.271 +            y[j] = (unsigned short)d;
 218.272 +         }
 218.273 +         if (y[m-1] == 0) y[m-1] = 1;
 218.274 +         /* z[0,...,n+m-1] := x * y */
 218.275 +         for (j = 0; j < n; j++) z[m+j] = x[j];
 218.276 +         bigmul(n, m, z, y);
 218.277 +         /* z[0,...,m-1] := z mod y, z[m,...,n+m-1] := z div y */
 218.278 +         bigdiv(n, m, z, y);
 218.279 +         /* z mod y must be 0 */
 218.280 +         for (j = 0; j < m; j++) assert(z[j] == 0);
 218.281 +         /* z div y must be x */
 218.282 +         for (j = 0; j < n; j++) assert(z[m+j] == x[j]);
 218.283 +      }
 218.284 +      fprintf(stderr, "%d tests successfully passed\n", N_TEST);
 218.285 +      rng_delete_rand(rand);
 218.286 +      return 0;
 218.287 +}
 218.288 +#endif
 218.289 +
 218.290 +/* eof */
   219.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   219.2 +++ b/src/glplib02.c	Mon Dec 06 13:09:21 2010 +0100
   219.3 @@ -0,0 +1,335 @@
   219.4 +/* glplib02.c (64-bit arithmetic) */
   219.5 +
   219.6 +/***********************************************************************
   219.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   219.8 +*
   219.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  219.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  219.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  219.12 +*  E-mail: <mao@gnu.org>.
  219.13 +*
  219.14 +*  GLPK is free software: you can redistribute it and/or modify it
  219.15 +*  under the terms of the GNU General Public License as published by
  219.16 +*  the Free Software Foundation, either version 3 of the License, or
  219.17 +*  (at your option) any later version.
  219.18 +*
  219.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  219.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  219.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  219.22 +*  License for more details.
  219.23 +*
  219.24 +*  You should have received a copy of the GNU General Public License
  219.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  219.26 +***********************************************************************/
  219.27 +
  219.28 +#include "glpenv.h"
  219.29 +#include "glplib.h"
  219.30 +
  219.31 +/***********************************************************************
  219.32 +*  NAME
  219.33 +*
  219.34 +*  xlset - expand integer to long integer
  219.35 +*
  219.36 +*  SYNOPSIS
  219.37 +*
  219.38 +*  #include "glplib.h"
  219.39 +*  glp_long xlset(int x);
  219.40 +*
  219.41 +*  RETURNS
  219.42 +*
  219.43 +*  The routine xlset returns x expanded to long integer. */
  219.44 +
  219.45 +glp_long xlset(int x)
  219.46 +{     glp_long t;
  219.47 +      t.lo = x, t.hi = (x >= 0 ? 0 : -1);
  219.48 +      return t;
  219.49 +}
  219.50 +
  219.51 +/***********************************************************************
  219.52 +*  NAME
  219.53 +*
  219.54 +*  xlneg - negate long integer
  219.55 +*
  219.56 +*  SYNOPSIS
  219.57 +*
  219.58 +*  #include "glplib.h"
  219.59 +*  glp_long xlneg(glp_long x);
  219.60 +*
  219.61 +*  RETURNS
  219.62 +*
  219.63 +*  The routine xlneg returns the difference  0 - x. */
  219.64 +
  219.65 +glp_long xlneg(glp_long x)
  219.66 +{     if (x.lo)
  219.67 +         x.lo = - x.lo, x.hi = ~x.hi;
  219.68 +      else
  219.69 +         x.hi = - x.hi;
  219.70 +      return x;
  219.71 +}
  219.72 +
  219.73 +/***********************************************************************
  219.74 +*  NAME
  219.75 +*
  219.76 +*  xladd - add long integers
  219.77 +*
  219.78 +*  SYNOPSIS
  219.79 +*
  219.80 +*  #include "glplib.h"
  219.81 +*  glp_long xladd(glp_long x, glp_long y);
  219.82 +*
  219.83 +*  RETURNS
  219.84 +*
  219.85 +*  The routine xladd returns the sum x + y. */
  219.86 +
  219.87 +glp_long xladd(glp_long x, glp_long y)
  219.88 +{     if ((unsigned int)x.lo <= 0xFFFFFFFF - (unsigned int)y.lo)
  219.89 +         x.lo += y.lo, x.hi += y.hi;
  219.90 +      else
  219.91 +         x.lo += y.lo, x.hi += y.hi + 1;
  219.92 +      return x;
  219.93 +}
  219.94 +
  219.95 +/***********************************************************************
  219.96 +*  NAME
  219.97 +*
  219.98 +*  xlsub - subtract long integers
  219.99 +*
 219.100 +*  SYNOPSIS
 219.101 +*
 219.102 +*  #include "glplib.h"
 219.103 +*  glp_long xlsub(glp_long x, glp_long y);
 219.104 +*
 219.105 +*  RETURNS
 219.106 +*
 219.107 +*  The routine xlsub returns the difference x - y. */
 219.108 +
 219.109 +glp_long xlsub(glp_long x, glp_long y)
 219.110 +{     return
 219.111 +         xladd(x, xlneg(y));
 219.112 +}
 219.113 +
 219.114 +/***********************************************************************
 219.115 +*  NAME
 219.116 +*
 219.117 +*  xlcmp - compare long integers
 219.118 +*
 219.119 +*  SYNOPSIS
 219.120 +*
 219.121 +*  #include "glplib.h"
 219.122 +*  int xlcmp(glp_long x, glp_long y);
 219.123 +*
 219.124 +*  RETURNS
 219.125 +*
 219.126 +*  The routine xlcmp returns the sign of the difference x - y. */
 219.127 +
 219.128 +int xlcmp(glp_long x, glp_long y)
 219.129 +{     if (x.hi >= 0 && y.hi <  0) return +1;
 219.130 +      if (x.hi <  0 && y.hi >= 0) return -1;
 219.131 +      if ((unsigned int)x.hi < (unsigned int)y.hi) return -1;
 219.132 +      if ((unsigned int)x.hi > (unsigned int)y.hi) return +1;
 219.133 +      if ((unsigned int)x.lo < (unsigned int)y.lo) return -1;
 219.134 +      if ((unsigned int)x.lo > (unsigned int)y.lo) return +1;
 219.135 +      return 0;
 219.136 +}
 219.137 +
 219.138 +/***********************************************************************
 219.139 +*  NAME
 219.140 +*
 219.141 +*  xlmul - multiply long integers
 219.142 +*
 219.143 +*  SYNOPSIS
 219.144 +*
 219.145 +*  #include "glplib.h"
 219.146 +*  glp_long xlmul(glp_long x, glp_long y);
 219.147 +*
 219.148 +*  RETURNS
 219.149 +*
 219.150 +*  The routine xlmul returns the product x * y. */
 219.151 +
 219.152 +glp_long xlmul(glp_long x, glp_long y)
 219.153 +{     unsigned short xx[8], yy[4];
 219.154 +      xx[4] = (unsigned short)x.lo;
 219.155 +      xx[5] = (unsigned short)(x.lo >> 16);
 219.156 +      xx[6] = (unsigned short)x.hi;
 219.157 +      xx[7] = (unsigned short)(x.hi >> 16);
 219.158 +      yy[0] = (unsigned short)y.lo;
 219.159 +      yy[1] = (unsigned short)(y.lo >> 16);
 219.160 +      yy[2] = (unsigned short)y.hi;
 219.161 +      yy[3] = (unsigned short)(y.hi >> 16);
 219.162 +      bigmul(4, 4, xx, yy);
 219.163 +      x.lo = (unsigned int)xx[0] | ((unsigned int)xx[1] << 16);
 219.164 +      x.hi = (unsigned int)xx[2] | ((unsigned int)xx[3] << 16);
 219.165 +      return x;
 219.166 +}
 219.167 +
 219.168 +/***********************************************************************
 219.169 +*  NAME
 219.170 +*
 219.171 +*  xldiv - divide long integers
 219.172 +*
 219.173 +*  SYNOPSIS
 219.174 +*
 219.175 +*  #include "glplib.h"
 219.176 +*  glp_ldiv xldiv(glp_long x, glp_long y);
 219.177 +*
 219.178 +*  RETURNS
 219.179 +*
 219.180 +*  The routine xldiv returns a structure of type glp_ldiv containing
 219.181 +*  members quot (the quotient) and rem (the remainder), both of type
 219.182 +*  glp_long. */
 219.183 +
 219.184 +glp_ldiv xldiv(glp_long x, glp_long y)
 219.185 +{     glp_ldiv t;
 219.186 +      int m, sx, sy;
 219.187 +      unsigned short xx[8], yy[4];
 219.188 +      /* sx := sign(x) */
 219.189 +      sx = (x.hi < 0);
 219.190 +      /* sy := sign(y) */
 219.191 +      sy = (y.hi < 0);
 219.192 +      /* x := |x| */
 219.193 +      if (sx) x = xlneg(x);
 219.194 +      /* y := |y| */
 219.195 +      if (sy) y = xlneg(y);
 219.196 +      /* compute x div y and x mod y */
 219.197 +      xx[0] = (unsigned short)x.lo;
 219.198 +      xx[1] = (unsigned short)(x.lo >> 16);
 219.199 +      xx[2] = (unsigned short)x.hi;
 219.200 +      xx[3] = (unsigned short)(x.hi >> 16);
 219.201 +      yy[0] = (unsigned short)y.lo;
 219.202 +      yy[1] = (unsigned short)(y.lo >> 16);
 219.203 +      yy[2] = (unsigned short)y.hi;
 219.204 +      yy[3] = (unsigned short)(y.hi >> 16);
 219.205 +      if (yy[3])
 219.206 +         m = 4;
 219.207 +      else if (yy[2])
 219.208 +         m = 3;
 219.209 +      else if (yy[1])
 219.210 +         m = 2;
 219.211 +      else if (yy[0])
 219.212 +         m = 1;
 219.213 +      else
 219.214 +         xerror("xldiv: divide by zero\n");
 219.215 +      bigdiv(4 - m, m, xx, yy);
 219.216 +      /* remainder in x[0], x[1], ..., x[m-1] */
 219.217 +      t.rem.lo = (unsigned int)xx[0], t.rem.hi = 0;
 219.218 +      if (m >= 2) t.rem.lo |= (unsigned int)xx[1] << 16;
 219.219 +      if (m >= 3) t.rem.hi = (unsigned int)xx[2];
 219.220 +      if (m >= 4) t.rem.hi |= (unsigned int)xx[3] << 16;
 219.221 +      if (sx) t.rem = xlneg(t.rem);
 219.222 +      /* quotient in x[m], x[m+1], ..., x[4] */
 219.223 +      t.quot.lo = (unsigned int)xx[m], t.quot.hi = 0;
 219.224 +      if (m <= 3) t.quot.lo |= (unsigned int)xx[m+1] << 16;
 219.225 +      if (m <= 2) t.quot.hi = (unsigned int)xx[m+2];
 219.226 +      if (m <= 1) t.quot.hi |= (unsigned int)xx[m+3] << 16;
 219.227 +      if (sx ^ sy) t.quot = xlneg(t.quot);
 219.228 +      return t;
 219.229 +}
 219.230 +
 219.231 +/***********************************************************************
 219.232 +*  NAME
 219.233 +*
 219.234 +*  xltod - convert long integer to double
 219.235 +*
 219.236 +*  SYNOPSIS
 219.237 +*
 219.238 +*  #include "glplib.h"
 219.239 +*  double xltod(glp_long x);
 219.240 +*
 219.241 +*  RETURNS
 219.242 +*
 219.243 +*  The routine xltod returns x converted to double. */
 219.244 +
 219.245 +double xltod(glp_long x)
 219.246 +{     double s, z;
 219.247 +      if (x.hi >= 0)
 219.248 +         s = +1.0;
 219.249 +      else
 219.250 +         s = -1.0, x = xlneg(x);
 219.251 +      if (x.hi >= 0)
 219.252 +         z = 4294967296.0 * (double)x.hi + (double)(unsigned int)x.lo;
 219.253 +      else
 219.254 +      {  xassert(x.hi == 0x80000000 && x.lo == 0x00000000);
 219.255 +         z = 9223372036854775808.0; /* 2^63 */
 219.256 +      }
 219.257 +      return s * z;
 219.258 +}
 219.259 +
 219.260 +char *xltoa(glp_long x, char *s)
 219.261 +{     /* convert long integer to character string */
 219.262 +      static const char *d = "0123456789";
 219.263 +      glp_ldiv t;
 219.264 +      int neg, len;
 219.265 +      if (x.hi >= 0)
 219.266 +         neg = 0;
 219.267 +      else
 219.268 +         neg = 1, x = xlneg(x);
 219.269 +      if (x.hi >= 0)
 219.270 +      {  len = 0;
 219.271 +         while (!(x.hi == 0 && x.lo == 0))
 219.272 +         {  t = xldiv(x, xlset(10));
 219.273 +            xassert(0 <= t.rem.lo && t.rem.lo <= 9);
 219.274 +            s[len++] = d[t.rem.lo];
 219.275 +            x = t.quot;
 219.276 +         }
 219.277 +         if (len == 0) s[len++] = d[0];
 219.278 +         if (neg) s[len++] = '-';
 219.279 +         s[len] = '\0';
 219.280 +         strrev(s);
 219.281 +      }
 219.282 +      else
 219.283 +         strcpy(s, "-9223372036854775808"); /* -2^63 */
 219.284 +      return s;
 219.285 +}
 219.286 +
 219.287 +/**********************************************************************/
 219.288 +
 219.289 +#if 0
 219.290 +#include "glprng.h"
 219.291 +
 219.292 +#define N_TEST 1000000
 219.293 +/* number of tests */
 219.294 +
 219.295 +static glp_long myrand(RNG *rand)
 219.296 +{     glp_long x;
 219.297 +      int k;
 219.298 +      k = rng_unif_rand(rand, 4);
 219.299 +      xassert(0 <= k && k <= 3);
 219.300 +      x.lo = rng_unif_rand(rand, 65536);
 219.301 +      if (k == 1 || k == 3)
 219.302 +      {  x.lo <<= 16;
 219.303 +         x.lo += rng_unif_rand(rand, 65536);
 219.304 +      }
 219.305 +      if (k <= 1)
 219.306 +         x.hi = 0;
 219.307 +      else
 219.308 +         x.hi = rng_unif_rand(rand, 65536);
 219.309 +      if (k == 3)
 219.310 +      {  x.hi <<= 16;
 219.311 +         x.hi += rng_unif_rand(rand, 65536);
 219.312 +      }
 219.313 +      if (rng_unif_rand(rand, 2)) x = xlneg(x);
 219.314 +      return x;
 219.315 +}
 219.316 +
 219.317 +int main(void)
 219.318 +{     RNG *rand;
 219.319 +      glp_long x, y;
 219.320 +      glp_ldiv z;
 219.321 +      int test;
 219.322 +      rand = rng_create_rand();
 219.323 +      for (test = 1; test <= N_TEST; test++)
 219.324 +      {  x = myrand(rand);
 219.325 +         y = myrand(rand);
 219.326 +         if (y.lo == 0 && y.hi == 0) y.lo = 1;
 219.327 +         /* z.quot := x div y, z.rem := x mod y */
 219.328 +         z = xldiv(x, y);
 219.329 +         /* x must be equal to y * z.quot + z.rem */
 219.330 +         xassert(xlcmp(x, xladd(xlmul(y, z.quot), z.rem)) == 0);
 219.331 +      }
 219.332 +      xprintf("%d tests successfully passed\n", N_TEST);
 219.333 +      rng_delete_rand(rand);
 219.334 +      return 0;
 219.335 +}
 219.336 +#endif
 219.337 +
 219.338 +/* eof */
   220.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   220.2 +++ b/src/glplib03.c	Mon Dec 06 13:09:21 2010 +0100
   220.3 @@ -0,0 +1,692 @@
   220.4 +/* glplib03.c (miscellaneous library routines) */
   220.5 +
   220.6 +/***********************************************************************
   220.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   220.8 +*
   220.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  220.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  220.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  220.12 +*  E-mail: <mao@gnu.org>.
  220.13 +*
  220.14 +*  GLPK is free software: you can redistribute it and/or modify it
  220.15 +*  under the terms of the GNU General Public License as published by
  220.16 +*  the Free Software Foundation, either version 3 of the License, or
  220.17 +*  (at your option) any later version.
  220.18 +*
  220.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  220.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  220.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  220.22 +*  License for more details.
  220.23 +*
  220.24 +*  You should have received a copy of the GNU General Public License
  220.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  220.26 +***********************************************************************/
  220.27 +
  220.28 +#include "glpenv.h"
  220.29 +#include "glplib.h"
  220.30 +
  220.31 +/***********************************************************************
  220.32 +*  NAME
  220.33 +*
  220.34 +*  str2int - convert character string to value of int type
  220.35 +*
  220.36 +*  SYNOPSIS
  220.37 +*
  220.38 +*  #include "glplib.h"
  220.39 +*  int str2int(const char *str, int *val);
  220.40 +*
  220.41 +*  DESCRIPTION
  220.42 +*
  220.43 +*  The routine str2int converts the character string str to a value of
  220.44 +*  integer type and stores the value into location, which the parameter
  220.45 +*  val points to (in the case of error content of this location is not
  220.46 +*  changed).
  220.47 +*
  220.48 +*  RETURNS
  220.49 +*
  220.50 +*  The routine returns one of the following error codes:
  220.51 +*
  220.52 +*  0 - no error;
  220.53 +*  1 - value out of range;
  220.54 +*  2 - character string is syntactically incorrect. */
  220.55 +
  220.56 +int str2int(const char *str, int *_val)
  220.57 +{     int d, k, s, val = 0;
  220.58 +      /* scan optional sign */
  220.59 +      if (str[0] == '+')
  220.60 +         s = +1, k = 1;
  220.61 +      else if (str[0] == '-')
  220.62 +         s = -1, k = 1;
  220.63 +      else
  220.64 +         s = +1, k = 0;
  220.65 +      /* check for the first digit */
  220.66 +      if (!isdigit((unsigned char)str[k])) return 2;
  220.67 +      /* scan digits */
  220.68 +      while (isdigit((unsigned char)str[k]))
  220.69 +      {  d = str[k++] - '0';
  220.70 +         if (s > 0)
  220.71 +         {  if (val > INT_MAX / 10) return 1;
  220.72 +            val *= 10;
  220.73 +            if (val > INT_MAX - d) return 1;
  220.74 +            val += d;
  220.75 +         }
  220.76 +         else
  220.77 +         {  if (val < INT_MIN / 10) return 1;
  220.78 +            val *= 10;
  220.79 +            if (val < INT_MIN + d) return 1;
  220.80 +            val -= d;
  220.81 +         }
  220.82 +      }
  220.83 +      /* check for terminator */
  220.84 +      if (str[k] != '\0') return 2;
  220.85 +      /* conversion has been done */
  220.86 +      *_val = val;
  220.87 +      return 0;
  220.88 +}
  220.89 +
  220.90 +/***********************************************************************
  220.91 +*  NAME
  220.92 +*
  220.93 +*  str2num - convert character string to value of double type
  220.94 +*
  220.95 +*  SYNOPSIS
  220.96 +*
  220.97 +*  #include "glplib.h"
  220.98 +*  int str2num(const char *str, double *val);
  220.99 +*
 220.100 +*  DESCRIPTION
 220.101 +*
 220.102 +*  The routine str2num converts the character string str to a value of
 220.103 +*  double type and stores the value into location, which the parameter
 220.104 +*  val points to (in the case of error content of this location is not
 220.105 +*  changed).
 220.106 +*
 220.107 +*  RETURNS
 220.108 +*
 220.109 +*  The routine returns one of the following error codes:
 220.110 +*
 220.111 +*  0 - no error;
 220.112 +*  1 - value out of range;
 220.113 +*  2 - character string is syntactically incorrect. */
 220.114 +
 220.115 +int str2num(const char *str, double *_val)
 220.116 +{     int k;
 220.117 +      double val;
 220.118 +      /* scan optional sign */
 220.119 +      k = (str[0] == '+' || str[0] == '-' ? 1 : 0);
 220.120 +      /* check for decimal point */
 220.121 +      if (str[k] == '.')
 220.122 +      {  k++;
 220.123 +         /* a digit should follow it */
 220.124 +         if (!isdigit((unsigned char)str[k])) return 2;
 220.125 +         k++;
 220.126 +         goto frac;
 220.127 +      }
 220.128 +      /* integer part should start with a digit */
 220.129 +      if (!isdigit((unsigned char)str[k])) return 2;
 220.130 +      /* scan integer part */
 220.131 +      while (isdigit((unsigned char)str[k])) k++;
 220.132 +      /* check for decimal point */
 220.133 +      if (str[k] == '.') k++;
 220.134 +frac: /* scan optional fraction part */
 220.135 +      while (isdigit((unsigned char)str[k])) k++;
 220.136 +      /* check for decimal exponent */
 220.137 +      if (str[k] == 'E' || str[k] == 'e')
 220.138 +      {  k++;
 220.139 +         /* scan optional sign */
 220.140 +         if (str[k] == '+' || str[k] == '-') k++;
 220.141 +         /* a digit should follow E, E+ or E- */
 220.142 +         if (!isdigit((unsigned char)str[k])) return 2;
 220.143 +      }
 220.144 +      /* scan optional exponent part */
 220.145 +      while (isdigit((unsigned char)str[k])) k++;
 220.146 +      /* check for terminator */
 220.147 +      if (str[k] != '\0') return 2;
 220.148 +      /* perform conversion */
 220.149 +      {  char *endptr;
 220.150 +         val = strtod(str, &endptr);
 220.151 +         if (*endptr != '\0') return 2;
 220.152 +      }
 220.153 +      /* check for overflow */
 220.154 +      if (!(-DBL_MAX <= val && val <= +DBL_MAX)) return 1;
 220.155 +      /* check for underflow */
 220.156 +      if (-DBL_MIN < val && val < +DBL_MIN) val = 0.0;
 220.157 +      /* conversion has been done */
 220.158 +      *_val = val;
 220.159 +      return 0;
 220.160 +}
 220.161 +
 220.162 +/***********************************************************************
 220.163 +*  NAME
 220.164 +*
 220.165 +*  strspx - remove all spaces from character string
 220.166 +*
 220.167 +*  SYNOPSIS
 220.168 +*
 220.169 +*  #include "glplib.h"
 220.170 +*  char *strspx(char *str);
 220.171 +*
 220.172 +*  DESCRIPTION
 220.173 +*
 220.174 +*  The routine strspx removes all spaces from the character string str.
 220.175 +*
 220.176 +*  RETURNS
 220.177 +*
 220.178 +*  The routine returns a pointer to the character string.
 220.179 +*
 220.180 +*  EXAMPLES
 220.181 +*
 220.182 +*  strspx("   Errare   humanum   est   ") => "Errarehumanumest"
 220.183 +*
 220.184 +*  strspx("      ")                       => "" */
 220.185 +
 220.186 +char *strspx(char *str)
 220.187 +{     char *s, *t;
 220.188 +      for (s = t = str; *s; s++) if (*s != ' ') *t++ = *s;
 220.189 +      *t = '\0';
 220.190 +      return str;
 220.191 +}
 220.192 +
 220.193 +/***********************************************************************
 220.194 +*  NAME
 220.195 +*
 220.196 +*  strtrim - remove trailing spaces from character string
 220.197 +*
 220.198 +*  SYNOPSIS
 220.199 +*
 220.200 +*  #include "glplib.h"
 220.201 +*  char *strtrim(char *str);
 220.202 +*
 220.203 +*  DESCRIPTION
 220.204 +*
 220.205 +*  The routine strtrim removes trailing spaces from the character
 220.206 +*  string str.
 220.207 +*
 220.208 +*  RETURNS
 220.209 +*
 220.210 +*  The routine returns a pointer to the character string.
 220.211 +*
 220.212 +*  EXAMPLES
 220.213 +*
 220.214 +*  strtrim("Errare humanum est   ") => "Errare humanum est"
 220.215 +*
 220.216 +*  strtrim("      ")                => "" */
 220.217 +
 220.218 +char *strtrim(char *str)
 220.219 +{     char *t;
 220.220 +      for (t = strrchr(str, '\0') - 1; t >= str; t--)
 220.221 +      {  if (*t != ' ') break;
 220.222 +         *t = '\0';
 220.223 +      }
 220.224 +      return str;
 220.225 +}
 220.226 +
 220.227 +/***********************************************************************
 220.228 +*  NAME
 220.229 +*
 220.230 +*  strrev - reverse character string
 220.231 +*
 220.232 +*  SYNOPSIS
 220.233 +*
 220.234 +*  #include "glplib.h"
 220.235 +*  char *strrev(char *s);
 220.236 +*
 220.237 +*  DESCRIPTION
 220.238 +*
 220.239 +*  The routine strrev changes characters in a character string s to the
 220.240 +*  reverse order, except the terminating null character.
 220.241 +*
 220.242 +*  RETURNS
 220.243 +*
 220.244 +*  The routine returns the pointer s.
 220.245 +*
 220.246 +*  EXAMPLES
 220.247 +*
 220.248 +*  strrev("")                => ""
 220.249 +*
 220.250 +*  strrev("Today is Monday") => "yadnoM si yadoT" */
 220.251 +
 220.252 +char *strrev(char *s)
 220.253 +{     int i, j;
 220.254 +      char t;
 220.255 +      for (i = 0, j = strlen(s)-1; i < j; i++, j--)
 220.256 +         t = s[i], s[i] = s[j], s[j] = t;
 220.257 +      return s;
 220.258 +}
 220.259 +
 220.260 +/***********************************************************************
 220.261 +*  NAME
 220.262 +*
 220.263 +*  gcd - find greatest common divisor of two integers
 220.264 +*
 220.265 +*  SYNOPSIS
 220.266 +*
 220.267 +*  #include "glplib.h"
 220.268 +*  int gcd(int x, int y);
 220.269 +*
 220.270 +*  RETURNS
 220.271 +*
 220.272 +*  The routine gcd returns gcd(x, y), the greatest common divisor of
 220.273 +*  the two positive integers given.
 220.274 +*
 220.275 +*  ALGORITHM
 220.276 +*
 220.277 +*  The routine gcd is based on Euclid's algorithm.
 220.278 +*
 220.279 +*  REFERENCES
 220.280 +*
 220.281 +*  Don Knuth, The Art of Computer Programming, Vol.2: Seminumerical
 220.282 +*  Algorithms, 3rd Edition, Addison-Wesley, 1997. Section 4.5.2: The
 220.283 +*  Greatest Common Divisor, pp. 333-56. */
 220.284 +
 220.285 +int gcd(int x, int y)
 220.286 +{     int r;
 220.287 +      xassert(x > 0 && y > 0);
 220.288 +      while (y > 0)
 220.289 +         r = x % y, x = y, y = r;
 220.290 +      return x;
 220.291 +}
 220.292 +
 220.293 +/***********************************************************************
 220.294 +*  NAME
 220.295 +*
 220.296 +*  gcdn - find greatest common divisor of n integers
 220.297 +*
 220.298 +*  SYNOPSIS
 220.299 +*
 220.300 +*  #include "glplib.h"
 220.301 +*  int gcdn(int n, int x[]);
 220.302 +*
 220.303 +*  RETURNS
 220.304 +*
 220.305 +*  The routine gcdn returns gcd(x[1], x[2], ..., x[n]), the greatest
 220.306 +*  common divisor of n positive integers given, n > 0.
 220.307 +*
 220.308 +*  BACKGROUND
 220.309 +*
 220.310 +*  The routine gcdn is based on the following identity:
 220.311 +*
 220.312 +*     gcd(x, y, z) = gcd(gcd(x, y), z).
 220.313 +*
 220.314 +*  REFERENCES
 220.315 +*
 220.316 +*  Don Knuth, The Art of Computer Programming, Vol.2: Seminumerical
 220.317 +*  Algorithms, 3rd Edition, Addison-Wesley, 1997. Section 4.5.2: The
 220.318 +*  Greatest Common Divisor, pp. 333-56. */
 220.319 +
 220.320 +int gcdn(int n, int x[])
 220.321 +{     int d, j;
 220.322 +      xassert(n > 0);
 220.323 +      for (j = 1; j <= n; j++)
 220.324 +      {  xassert(x[j] > 0);
 220.325 +         if (j == 1)
 220.326 +            d = x[1];
 220.327 +         else
 220.328 +            d = gcd(d, x[j]);
 220.329 +         if (d == 1) break;
 220.330 +      }
 220.331 +      return d;
 220.332 +}
 220.333 +
 220.334 +/***********************************************************************
 220.335 +*  NAME
 220.336 +*
 220.337 +*  lcm - find least common multiple of two integers
 220.338 +*
 220.339 +*  SYNOPSIS
 220.340 +*
 220.341 +*  #include "glplib.h"
 220.342 +*  int lcm(int x, int y);
 220.343 +*
 220.344 +*  RETURNS
 220.345 +*
 220.346 +*  The routine lcm returns lcm(x, y), the least common multiple of the
 220.347 +*  two positive integers given. In case of integer overflow the routine
 220.348 +*  returns zero.
 220.349 +*
 220.350 +*  BACKGROUND
 220.351 +*
 220.352 +*  The routine lcm is based on the following identity:
 220.353 +*
 220.354 +*     lcm(x, y) = (x * y) / gcd(x, y) = x * [y / gcd(x, y)],
 220.355 +*
 220.356 +*  where gcd(x, y) is the greatest common divisor of x and y. */
 220.357 +
 220.358 +int lcm(int x, int y)
 220.359 +{     xassert(x > 0);
 220.360 +      xassert(y > 0);
 220.361 +      y /= gcd(x, y);
 220.362 +      if (x > INT_MAX / y) return 0;
 220.363 +      return x * y;
 220.364 +}
 220.365 +
 220.366 +/***********************************************************************
 220.367 +*  NAME
 220.368 +*
 220.369 +*  lcmn - find least common multiple of n integers
 220.370 +*
 220.371 +*  SYNOPSIS
 220.372 +*
 220.373 +*  #include "glplib.h"
 220.374 +*  int lcmn(int n, int x[]);
 220.375 +*
 220.376 +*  RETURNS
 220.377 +*
 220.378 +*  The routine lcmn returns lcm(x[1], x[2], ..., x[n]), the least
 220.379 +*  common multiple of n positive integers given, n > 0. In case of
 220.380 +*  integer overflow the routine returns zero.
 220.381 +*
 220.382 +*  BACKGROUND
 220.383 +*
 220.384 +*  The routine lcmn is based on the following identity:
 220.385 +*
 220.386 +*     lcmn(x, y, z) = lcm(lcm(x, y), z),
 220.387 +*
 220.388 +*  where lcm(x, y) is the least common multiple of x and y. */
 220.389 +
 220.390 +int lcmn(int n, int x[])
 220.391 +{     int m, j;
 220.392 +      xassert(n > 0);
 220.393 +      for (j = 1; j <= n; j++)
 220.394 +      {  xassert(x[j] > 0);
 220.395 +         if (j == 1)
 220.396 +            m = x[1];
 220.397 +         else
 220.398 +            m = lcm(m, x[j]);
 220.399 +         if (m == 0) break;
 220.400 +      }
 220.401 +      return m;
 220.402 +}
 220.403 +
 220.404 +/***********************************************************************
 220.405 +*  NAME
 220.406 +*
 220.407 +*  round2n - round floating-point number to nearest power of two
 220.408 +*
 220.409 +*  SYNOPSIS
 220.410 +*
 220.411 +*  #include "glplib.h"
 220.412 +*  double round2n(double x);
 220.413 +*
 220.414 +*  RETURNS
 220.415 +*
 220.416 +*  Given a positive floating-point value x the routine round2n returns
 220.417 +*  2^n such that |x - 2^n| is minimal.
 220.418 +*
 220.419 +*  EXAMPLES
 220.420 +*
 220.421 +*  round2n(10.1) = 2^3 = 8
 220.422 +*  round2n(15.3) = 2^4 = 16
 220.423 +*  round2n(0.01) = 2^(-7) = 0.0078125
 220.424 +*
 220.425 +*  BACKGROUND
 220.426 +*
 220.427 +*  Let x = f * 2^e, where 0.5 <= f < 1 is a normalized fractional part,
 220.428 +*  e is an integer exponent. Then, obviously, 0.5 * 2^e <= x < 2^e, so
 220.429 +*  if x - 0.5 * 2^e <= 2^e - x, we choose 0.5 * 2^e = 2^(e-1), and 2^e
 220.430 +*  otherwise. The latter condition can be written as 2 * x <= 1.5 * 2^e
 220.431 +*  or 2 * f * 2^e <= 1.5 * 2^e or, finally, f <= 0.75. */
 220.432 +
 220.433 +double round2n(double x)
 220.434 +{     int e;
 220.435 +      double f;
 220.436 +      xassert(x > 0.0);
 220.437 +      f = frexp(x, &e);
 220.438 +      return ldexp(1.0, f <= 0.75 ? e-1 : e);
 220.439 +}
 220.440 +
 220.441 +/***********************************************************************
 220.442 +*  NAME
 220.443 +*
 220.444 +*  fp2rat - convert floating-point number to rational number
 220.445 +*
 220.446 +*  SYNOPSIS
 220.447 +*
 220.448 +*  #include "glplib.h"
 220.449 +*  int fp2rat(double x, double eps, double *p, double *q);
 220.450 +*
 220.451 +*  DESCRIPTION
 220.452 +*
 220.453 +*  Given a floating-point number 0 <= x < 1 the routine fp2rat finds
 220.454 +*  its "best" rational approximation p / q, where p >= 0 and q > 0 are
 220.455 +*  integer numbers, such that |x - p / q| <= eps.
 220.456 +*
 220.457 +*  RETURNS
 220.458 +*
 220.459 +*  The routine fp2rat returns the number of iterations used to achieve
 220.460 +*  the specified precision eps.
 220.461 +*
 220.462 +*  EXAMPLES
 220.463 +*
 220.464 +*  For x = sqrt(2) - 1 = 0.414213562373095 and eps = 1e-6 the routine
 220.465 +*  gives p = 408 and q = 985, where 408 / 985 = 0.414213197969543.
 220.466 +*
 220.467 +*  BACKGROUND
 220.468 +*
 220.469 +*  It is well known that every positive real number x can be expressed
 220.470 +*  as the following continued fraction:
 220.471 +*
 220.472 +*     x = b[0] + a[1]
 220.473 +*                ------------------------
 220.474 +*                b[1] + a[2]
 220.475 +*                       -----------------
 220.476 +*                       b[2] + a[3]
 220.477 +*                              ----------
 220.478 +*                              b[3] + ...
 220.479 +*
 220.480 +*  where:
 220.481 +*
 220.482 +*     a[k] = 1,                  k = 0, 1, 2, ...
 220.483 +*
 220.484 +*     b[k] = floor(x[k]),        k = 0, 1, 2, ...
 220.485 +*
 220.486 +*     x[0] = x,
 220.487 +*
 220.488 +*     x[k] = 1 / frac(x[k-1]),   k = 1, 2, 3, ...
 220.489 +*
 220.490 +*  To find the "best" rational approximation of x the routine computes
 220.491 +*  partial fractions f[k] by dropping after k terms as follows:
 220.492 +*
 220.493 +*     f[k] = A[k] / B[k],
 220.494 +*
 220.495 +*  where:
 220.496 +*
 220.497 +*     A[-1] = 1,   A[0] = b[0],   B[-1] = 0,   B[0] = 1,
 220.498 +*
 220.499 +*     A[k] = b[k] * A[k-1] + a[k] * A[k-2],
 220.500 +*
 220.501 +*     B[k] = b[k] * B[k-1] + a[k] * B[k-2].
 220.502 +*
 220.503 +*  Once the condition
 220.504 +*
 220.505 +*     |x - f[k]| <= eps
 220.506 +*
 220.507 +*  has been satisfied, the routine reports p = A[k] and q = B[k] as the
 220.508 +*  final answer.
 220.509 +*
 220.510 +*  In the table below here is some statistics obtained for one million
 220.511 +*  random numbers uniformly distributed in the range [0, 1).
 220.512 +*
 220.513 +*      eps      max p   mean p      max q    mean q  max k   mean k
 220.514 +*     -------------------------------------------------------------
 220.515 +*     1e-1          8      1.6          9       3.2    3      1.4
 220.516 +*     1e-2         98      6.2         99      12.4    5      2.4
 220.517 +*     1e-3        997     20.7        998      41.5    8      3.4
 220.518 +*     1e-4       9959     66.6       9960     133.5   10      4.4
 220.519 +*     1e-5      97403    211.7      97404     424.2   13      5.3
 220.520 +*     1e-6     479669    669.9     479670    1342.9   15      6.3
 220.521 +*     1e-7    1579030   2127.3    3962146    4257.8   16      7.3
 220.522 +*     1e-8   26188823   6749.4   26188824   13503.4   19      8.2
 220.523 +*
 220.524 +*  REFERENCES
 220.525 +*
 220.526 +*  W. B. Jones and W. J. Thron, "Continued Fractions: Analytic Theory
 220.527 +*  and Applications," Encyclopedia on Mathematics and Its Applications,
 220.528 +*  Addison-Wesley, 1980. */
 220.529 +
 220.530 +int fp2rat(double x, double eps, double *p, double *q)
 220.531 +{     int k;
 220.532 +      double xk, Akm1, Ak, Bkm1, Bk, ak, bk, fk, temp;
 220.533 +      if (!(0.0 <= x && x < 1.0))
 220.534 +         xerror("fp2rat: x = %g; number out of range\n", x);
 220.535 +      for (k = 0; ; k++)
 220.536 +      {  xassert(k <= 100);
 220.537 +         if (k == 0)
 220.538 +         {  /* x[0] = x */
 220.539 +            xk = x;
 220.540 +            /* A[-1] = 1 */
 220.541 +            Akm1 = 1.0;
 220.542 +            /* A[0] = b[0] = floor(x[0]) = 0 */
 220.543 +            Ak = 0.0;
 220.544 +            /* B[-1] = 0 */
 220.545 +            Bkm1 = 0.0;
 220.546 +            /* B[0] = 1 */
 220.547 +            Bk = 1.0;
 220.548 +         }
 220.549 +         else
 220.550 +         {  /* x[k] = 1 / frac(x[k-1]) */
 220.551 +            temp = xk - floor(xk);
 220.552 +            xassert(temp != 0.0);
 220.553 +            xk = 1.0 / temp;
 220.554 +            /* a[k] = 1 */
 220.555 +            ak = 1.0;
 220.556 +            /* b[k] = floor(x[k]) */
 220.557 +            bk = floor(xk);
 220.558 +            /* A[k] = b[k] * A[k-1] + a[k] * A[k-2] */
 220.559 +            temp = bk * Ak + ak * Akm1;
 220.560 +            Akm1 = Ak, Ak = temp;
 220.561 +            /* B[k] = b[k] * B[k-1] + a[k] * B[k-2] */
 220.562 +            temp = bk * Bk + ak * Bkm1;
 220.563 +            Bkm1 = Bk, Bk = temp;
 220.564 +         }
 220.565 +         /* f[k] = A[k] / B[k] */
 220.566 +         fk = Ak / Bk;
 220.567 +#if 0
 220.568 +         print("%.*g / %.*g = %.*g", DBL_DIG, Ak, DBL_DIG, Bk, DBL_DIG,
 220.569 +            fk);
 220.570 +#endif
 220.571 +         if (fabs(x - fk) <= eps) break;
 220.572 +      }
 220.573 +      *p = Ak;
 220.574 +      *q = Bk;
 220.575 +      return k;
 220.576 +}
 220.577 +
 220.578 +/***********************************************************************
 220.579 +*  NAME
 220.580 +*
 220.581 +*  jday - convert calendar date to Julian day number
 220.582 +*
 220.583 +*  SYNOPSIS
 220.584 +*
 220.585 +*  #include "glplib.h"
 220.586 +*  int jday(int d, int m, int y);
 220.587 +*
 220.588 +*  DESCRIPTION
 220.589 +*
 220.590 +*  The routine jday converts a calendar date, Gregorian calendar, to
 220.591 +*  corresponding Julian day number j.
 220.592 +*
 220.593 +*  From the given day d, month m, and year y, the Julian day number j
 220.594 +*  is computed without using tables.
 220.595 +*
 220.596 +*  The routine is valid for 1 <= y <= 4000.
 220.597 +*
 220.598 +*  RETURNS
 220.599 +*
 220.600 +*  The routine jday returns the Julian day number, or negative value if
 220.601 +*  the specified date is incorrect.
 220.602 +*
 220.603 +*  REFERENCES
 220.604 +*
 220.605 +*  R. G. Tantzen, Algorithm 199: conversions between calendar date and
 220.606 +*  Julian day number, Communications of the ACM, vol. 6, no. 8, p. 444,
 220.607 +*  Aug. 1963. */
 220.608 +
 220.609 +int jday(int d, int m, int y)
 220.610 +{     int c, ya, j, dd;
 220.611 +      if (!(1 <= d && d <= 31 && 1 <= m && m <= 12 && 1 <= y &&
 220.612 +            y <= 4000))
 220.613 +      {  j = -1;
 220.614 +         goto done;
 220.615 +      }
 220.616 +      if (m >= 3) m -= 3; else m += 9, y--;
 220.617 +      c = y / 100;
 220.618 +      ya = y - 100 * c;
 220.619 +      j = (146097 * c) / 4 + (1461 * ya) / 4 + (153 * m + 2) / 5 + d +
 220.620 +         1721119;
 220.621 +      jdate(j, &dd, NULL, NULL);
 220.622 +      if (d != dd) j = -1;
 220.623 +done: return j;
 220.624 +}
 220.625 +
 220.626 +/***********************************************************************
 220.627 +*  NAME
 220.628 +*
 220.629 +*  jdate - convert Julian day number to calendar date
 220.630 +*
 220.631 +*  SYNOPSIS
 220.632 +*
 220.633 +*  #include "glplib.h"
 220.634 +*  void jdate(int j, int *d, int *m, int *y);
 220.635 +*
 220.636 +*  DESCRIPTION
 220.637 +*
 220.638 +*  The routine jdate converts a Julian day number j to corresponding
 220.639 +*  calendar date, Gregorian calendar.
 220.640 +*
 220.641 +*  The day d, month m, and year y are computed without using tables and
 220.642 +*  stored in corresponding locations.
 220.643 +*
 220.644 +*  The routine is valid for 1721426 <= j <= 3182395.
 220.645 +*
 220.646 +*  RETURNS
 220.647 +*
 220.648 +*  If the conversion is successful, the routine returns zero, otherwise
 220.649 +*  non-zero.
 220.650 +*
 220.651 +*  REFERENCES
 220.652 +*
 220.653 +*  R. G. Tantzen, Algorithm 199: conversions between calendar date and
 220.654 +*  Julian day number, Communications of the ACM, vol. 6, no. 8, p. 444,
 220.655 +*  Aug. 1963. */
 220.656 +
 220.657 +int jdate(int j, int *_d, int *_m, int *_y)
 220.658 +{     int d, m, y, ret = 0;
 220.659 +      if (!(1721426 <= j && j <= 3182395))
 220.660 +      {  ret = 1;
 220.661 +         goto done;
 220.662 +      }
 220.663 +      j -= 1721119;
 220.664 +      y = (4 * j - 1) / 146097;
 220.665 +      j = (4 * j - 1) % 146097;
 220.666 +      d = j / 4;
 220.667 +      j = (4 * d + 3) / 1461;
 220.668 +      d = (4 * d + 3) % 1461;
 220.669 +      d = (d + 4) / 4;
 220.670 +      m = (5 * d - 3) / 153;
 220.671 +      d = (5 * d - 3) % 153;
 220.672 +      d = (d + 5) / 5;
 220.673 +      y = 100 * y + j;
 220.674 +      if (m <= 9) m += 3; else m -= 9, y++;
 220.675 +      if (_d != NULL) *_d = d;
 220.676 +      if (_m != NULL) *_m = m;
 220.677 +      if (_y != NULL) *_y = y;
 220.678 +done: return ret;
 220.679 +}
 220.680 +
 220.681 +#if 0
 220.682 +int main(void)
 220.683 +{     int jbeg, jend, j, d, m, y;
 220.684 +      jbeg = jday(1, 1, 1);
 220.685 +      jend = jday(31, 12, 4000);
 220.686 +      for (j = jbeg; j <= jend; j++)
 220.687 +      {  xassert(jdate(j, &d, &m, &y) == 0);
 220.688 +         xassert(jday(d, m, y) == j);
 220.689 +      }
 220.690 +      xprintf("Routines jday and jdate work correctly.\n");
 220.691 +      return 0;
 220.692 +}
 220.693 +#endif
 220.694 +
 220.695 +/* eof */
   221.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   221.2 +++ b/src/glplpf.c	Mon Dec 06 13:09:21 2010 +0100
   221.3 @@ -0,0 +1,978 @@
   221.4 +/* glplpf.c (LP basis factorization, Schur complement version) */
   221.5 +
   221.6 +/***********************************************************************
   221.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   221.8 +*
   221.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  221.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  221.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  221.12 +*  E-mail: <mao@gnu.org>.
  221.13 +*
  221.14 +*  GLPK is free software: you can redistribute it and/or modify it
  221.15 +*  under the terms of the GNU General Public License as published by
  221.16 +*  the Free Software Foundation, either version 3 of the License, or
  221.17 +*  (at your option) any later version.
  221.18 +*
  221.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  221.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  221.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  221.22 +*  License for more details.
  221.23 +*
  221.24 +*  You should have received a copy of the GNU General Public License
  221.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  221.26 +***********************************************************************/
  221.27 +
  221.28 +#include "glplpf.h"
  221.29 +#include "glpenv.h"
  221.30 +#define xfault xerror
  221.31 +
  221.32 +#define _GLPLPF_DEBUG 0
  221.33 +
  221.34 +/* CAUTION: DO NOT CHANGE THE LIMIT BELOW */
  221.35 +
  221.36 +#define M_MAX 100000000 /* = 100*10^6 */
  221.37 +/* maximal order of the basis matrix */
  221.38 +
  221.39 +/***********************************************************************
  221.40 +*  NAME
  221.41 +*
  221.42 +*  lpf_create_it - create LP basis factorization
  221.43 +*
  221.44 +*  SYNOPSIS
  221.45 +*
  221.46 +*  #include "glplpf.h"
  221.47 +*  LPF *lpf_create_it(void);
  221.48 +*
  221.49 +*  DESCRIPTION
  221.50 +*
  221.51 +*  The routine lpf_create_it creates a program object, which represents
  221.52 +*  a factorization of LP basis.
  221.53 +*
  221.54 +*  RETURNS
  221.55 +*
  221.56 +*  The routine lpf_create_it returns a pointer to the object created. */
  221.57 +
  221.58 +LPF *lpf_create_it(void)
  221.59 +{     LPF *lpf;
  221.60 +#if _GLPLPF_DEBUG
  221.61 +      xprintf("lpf_create_it: warning: debug mode enabled\n");
  221.62 +#endif
  221.63 +      lpf = xmalloc(sizeof(LPF));
  221.64 +      lpf->valid = 0;
  221.65 +      lpf->m0_max = lpf->m0 = 0;
  221.66 +      lpf->luf = luf_create_it();
  221.67 +      lpf->m = 0;
  221.68 +      lpf->B = NULL;
  221.69 +      lpf->n_max = 50;
  221.70 +      lpf->n = 0;
  221.71 +      lpf->R_ptr = lpf->R_len = NULL;
  221.72 +      lpf->S_ptr = lpf->S_len = NULL;
  221.73 +      lpf->scf = NULL;
  221.74 +      lpf->P_row = lpf->P_col = NULL;
  221.75 +      lpf->Q_row = lpf->Q_col = NULL;
  221.76 +      lpf->v_size = 1000;
  221.77 +      lpf->v_ptr = 0;
  221.78 +      lpf->v_ind = NULL;
  221.79 +      lpf->v_val = NULL;
  221.80 +      lpf->work1 = lpf->work2 = NULL;
  221.81 +      return lpf;
  221.82 +}
  221.83 +
  221.84 +/***********************************************************************
  221.85 +*  NAME
  221.86 +*
  221.87 +*  lpf_factorize - compute LP basis factorization
  221.88 +*
  221.89 +*  SYNOPSIS
  221.90 +*
  221.91 +*  #include "glplpf.h"
  221.92 +*  int lpf_factorize(LPF *lpf, int m, const int bh[], int (*col)
  221.93 +*     (void *info, int j, int ind[], double val[]), void *info);
  221.94 +*
  221.95 +*  DESCRIPTION
  221.96 +*
  221.97 +*  The routine lpf_factorize computes the factorization of the basis
  221.98 +*  matrix B specified by the routine col.
  221.99 +*
 221.100 +*  The parameter lpf specified the basis factorization data structure
 221.101 +*  created with the routine lpf_create_it.
 221.102 +*
 221.103 +*  The parameter m specifies the order of B, m > 0.
 221.104 +*
 221.105 +*  The array bh specifies the basis header: bh[j], 1 <= j <= m, is the
 221.106 +*  number of j-th column of B in some original matrix. The array bh is
 221.107 +*  optional and can be specified as NULL.
 221.108 +*
 221.109 +*  The formal routine col specifies the matrix B to be factorized. To
 221.110 +*  obtain j-th column of A the routine lpf_factorize calls the routine
 221.111 +*  col with the parameter j (1 <= j <= n). In response the routine col
 221.112 +*  should store row indices and numerical values of non-zero elements
 221.113 +*  of j-th column of B to locations ind[1,...,len] and val[1,...,len],
 221.114 +*  respectively, where len is the number of non-zeros in j-th column
 221.115 +*  returned on exit. Neither zero nor duplicate elements are allowed.
 221.116 +*
 221.117 +*  The parameter info is a transit pointer passed to the routine col.
 221.118 +*
 221.119 +*  RETURNS
 221.120 +*
 221.121 +*  0  The factorization has been successfully computed.
 221.122 +*
 221.123 +*  LPF_ESING
 221.124 +*     The specified matrix is singular within the working precision.
 221.125 +*
 221.126 +*  LPF_ECOND
 221.127 +*     The specified matrix is ill-conditioned.
 221.128 +*
 221.129 +*  For more details see comments to the routine luf_factorize. */
 221.130 +
 221.131 +int lpf_factorize(LPF *lpf, int m, const int bh[], int (*col)
 221.132 +      (void *info, int j, int ind[], double val[]), void *info)
 221.133 +{     int k, ret;
 221.134 +#if _GLPLPF_DEBUG
 221.135 +      int i, j, len, *ind;
 221.136 +      double *B, *val;
 221.137 +#endif
 221.138 +      xassert(bh == bh);
 221.139 +      if (m < 1)
 221.140 +         xfault("lpf_factorize: m = %d; invalid parameter\n", m);
 221.141 +      if (m > M_MAX)
 221.142 +         xfault("lpf_factorize: m = %d; matrix too big\n", m);
 221.143 +      lpf->m0 = lpf->m = m;
 221.144 +      /* invalidate the factorization */
 221.145 +      lpf->valid = 0;
 221.146 +      /* allocate/reallocate arrays, if necessary */
 221.147 +      if (lpf->R_ptr == NULL)
 221.148 +         lpf->R_ptr = xcalloc(1+lpf->n_max, sizeof(int));
 221.149 +      if (lpf->R_len == NULL)
 221.150 +         lpf->R_len = xcalloc(1+lpf->n_max, sizeof(int));
 221.151 +      if (lpf->S_ptr == NULL)
 221.152 +         lpf->S_ptr = xcalloc(1+lpf->n_max, sizeof(int));
 221.153 +      if (lpf->S_len == NULL)
 221.154 +         lpf->S_len = xcalloc(1+lpf->n_max, sizeof(int));
 221.155 +      if (lpf->scf == NULL)
 221.156 +         lpf->scf = scf_create_it(lpf->n_max);
 221.157 +      if (lpf->v_ind == NULL)
 221.158 +         lpf->v_ind = xcalloc(1+lpf->v_size, sizeof(int));
 221.159 +      if (lpf->v_val == NULL)
 221.160 +         lpf->v_val = xcalloc(1+lpf->v_size, sizeof(double));
 221.161 +      if (lpf->m0_max < m)
 221.162 +      {  if (lpf->P_row != NULL) xfree(lpf->P_row);
 221.163 +         if (lpf->P_col != NULL) xfree(lpf->P_col);
 221.164 +         if (lpf->Q_row != NULL) xfree(lpf->Q_row);
 221.165 +         if (lpf->Q_col != NULL) xfree(lpf->Q_col);
 221.166 +         if (lpf->work1 != NULL) xfree(lpf->work1);
 221.167 +         if (lpf->work2 != NULL) xfree(lpf->work2);
 221.168 +         lpf->m0_max = m + 100;
 221.169 +         lpf->P_row = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int));
 221.170 +         lpf->P_col = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int));
 221.171 +         lpf->Q_row = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int));
 221.172 +         lpf->Q_col = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int));
 221.173 +         lpf->work1 = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(double));
 221.174 +         lpf->work2 = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(double));
 221.175 +      }
 221.176 +      /* try to factorize the basis matrix */
 221.177 +      switch (luf_factorize(lpf->luf, m, col, info))
 221.178 +      {  case 0:
 221.179 +            break;
 221.180 +         case LUF_ESING:
 221.181 +            ret = LPF_ESING;
 221.182 +            goto done;
 221.183 +         case LUF_ECOND:
 221.184 +            ret = LPF_ECOND;
 221.185 +            goto done;
 221.186 +         default:
 221.187 +            xassert(lpf != lpf);
 221.188 +      }
 221.189 +      /* the basis matrix has been successfully factorized */
 221.190 +      lpf->valid = 1;
 221.191 +#if _GLPLPF_DEBUG
 221.192 +      /* store the basis matrix for debugging */
 221.193 +      if (lpf->B != NULL) xfree(lpf->B);
 221.194 +      xassert(m <= 32767);
 221.195 +      lpf->B = B = xcalloc(1+m*m, sizeof(double));
 221.196 +      ind = xcalloc(1+m, sizeof(int));
 221.197 +      val = xcalloc(1+m, sizeof(double));
 221.198 +      for (k = 1; k <= m * m; k++)
 221.199 +         B[k] = 0.0;
 221.200 +      for (j = 1; j <= m; j++)
 221.201 +      {  len = col(info, j, ind, val);
 221.202 +         xassert(0 <= len && len <= m);
 221.203 +         for (k = 1; k <= len; k++)
 221.204 +         {  i = ind[k];
 221.205 +            xassert(1 <= i && i <= m);
 221.206 +            xassert(B[(i - 1) * m + j] == 0.0);
 221.207 +            xassert(val[k] != 0.0);
 221.208 +            B[(i - 1) * m + j] = val[k];
 221.209 +         }
 221.210 +      }
 221.211 +      xfree(ind);
 221.212 +      xfree(val);
 221.213 +#endif
 221.214 +      /* B = B0, so there are no additional rows/columns */
 221.215 +      lpf->n = 0;
 221.216 +      /* reset the Schur complement factorization */
 221.217 +      scf_reset_it(lpf->scf);
 221.218 +      /* P := Q := I */
 221.219 +      for (k = 1; k <= m; k++)
 221.220 +      {  lpf->P_row[k] = lpf->P_col[k] = k;
 221.221 +         lpf->Q_row[k] = lpf->Q_col[k] = k;
 221.222 +      }
 221.223 +      /* make all SVA locations free */
 221.224 +      lpf->v_ptr = 1;
 221.225 +      ret = 0;
 221.226 +done: /* return to the calling program */
 221.227 +      return ret;
 221.228 +}
 221.229 +
 221.230 +/***********************************************************************
 221.231 +*  The routine r_prod computes the product y := y + alpha * R * x,
 221.232 +*  where x is a n-vector, alpha is a scalar, y is a m0-vector.
 221.233 +*
 221.234 +*  Since matrix R is available by columns, the product is computed as
 221.235 +*  a linear combination:
 221.236 +*
 221.237 +*     y := y + alpha * (R[1] * x[1] + ... + R[n] * x[n]),
 221.238 +*
 221.239 +*  where R[j] is j-th column of R. */
 221.240 +
 221.241 +static void r_prod(LPF *lpf, double y[], double a, const double x[])
 221.242 +{     int n = lpf->n;
 221.243 +      int *R_ptr = lpf->R_ptr;
 221.244 +      int *R_len = lpf->R_len;
 221.245 +      int *v_ind = lpf->v_ind;
 221.246 +      double *v_val = lpf->v_val;
 221.247 +      int j, beg, end, ptr;
 221.248 +      double t;
 221.249 +      for (j = 1; j <= n; j++)
 221.250 +      {  if (x[j] == 0.0) continue;
 221.251 +         /* y := y + alpha * R[j] * x[j] */
 221.252 +         t = a * x[j];
 221.253 +         beg = R_ptr[j];
 221.254 +         end = beg + R_len[j];
 221.255 +         for (ptr = beg; ptr < end; ptr++)
 221.256 +            y[v_ind[ptr]] += t * v_val[ptr];
 221.257 +      }
 221.258 +      return;
 221.259 +}
 221.260 +
 221.261 +/***********************************************************************
 221.262 +*  The routine rt_prod computes the product y := y + alpha * R' * x,
 221.263 +*  where R' is a matrix transposed to R, x is a m0-vector, alpha is a
 221.264 +*  scalar, y is a n-vector.
 221.265 +*
 221.266 +*  Since matrix R is available by columns, the product components are
 221.267 +*  computed as inner products:
 221.268 +*
 221.269 +*     y[j] := y[j] + alpha * (j-th column of R) * x
 221.270 +*
 221.271 +*  for j = 1, 2, ..., n. */
 221.272 +
 221.273 +static void rt_prod(LPF *lpf, double y[], double a, const double x[])
 221.274 +{     int n = lpf->n;
 221.275 +      int *R_ptr = lpf->R_ptr;
 221.276 +      int *R_len = lpf->R_len;
 221.277 +      int *v_ind = lpf->v_ind;
 221.278 +      double *v_val = lpf->v_val;
 221.279 +      int j, beg, end, ptr;
 221.280 +      double t;
 221.281 +      for (j = 1; j <= n; j++)
 221.282 +      {  /* t := (j-th column of R) * x */
 221.283 +         t = 0.0;
 221.284 +         beg = R_ptr[j];
 221.285 +         end = beg + R_len[j];
 221.286 +         for (ptr = beg; ptr < end; ptr++)
 221.287 +            t += v_val[ptr] * x[v_ind[ptr]];
 221.288 +         /* y[j] := y[j] + alpha * t */
 221.289 +         y[j] += a * t;
 221.290 +      }
 221.291 +      return;
 221.292 +}
 221.293 +
 221.294 +/***********************************************************************
 221.295 +*  The routine s_prod computes the product y := y + alpha * S * x,
 221.296 +*  where x is a m0-vector, alpha is a scalar, y is a n-vector.
 221.297 +*
 221.298 +*  Since matrix S is available by rows, the product components are
 221.299 +*  computed as inner products:
 221.300 +*
 221.301 +*     y[i] = y[i] + alpha * (i-th row of S) * x
 221.302 +*
 221.303 +*  for i = 1, 2, ..., n. */
 221.304 +
 221.305 +static void s_prod(LPF *lpf, double y[], double a, const double x[])
 221.306 +{     int n = lpf->n;
 221.307 +      int *S_ptr = lpf->S_ptr;
 221.308 +      int *S_len = lpf->S_len;
 221.309 +      int *v_ind = lpf->v_ind;
 221.310 +      double *v_val = lpf->v_val;
 221.311 +      int i, beg, end, ptr;
 221.312 +      double t;
 221.313 +      for (i = 1; i <= n; i++)
 221.314 +      {  /* t := (i-th row of S) * x */
 221.315 +         t = 0.0;
 221.316 +         beg = S_ptr[i];
 221.317 +         end = beg + S_len[i];
 221.318 +         for (ptr = beg; ptr < end; ptr++)
 221.319 +            t += v_val[ptr] * x[v_ind[ptr]];
 221.320 +         /* y[i] := y[i] + alpha * t */
 221.321 +         y[i] += a * t;
 221.322 +      }
 221.323 +      return;
 221.324 +}
 221.325 +
 221.326 +/***********************************************************************
 221.327 +*  The routine st_prod computes the product y := y + alpha * S' * x,
 221.328 +*  where S' is a matrix transposed to S, x is a n-vector, alpha is a
 221.329 +*  scalar, y is m0-vector.
 221.330 +*
 221.331 +*  Since matrix R is available by rows, the product is computed as a
 221.332 +*  linear combination:
 221.333 +*
 221.334 +*     y := y + alpha * (S'[1] * x[1] + ... + S'[n] * x[n]),
 221.335 +*
 221.336 +*  where S'[i] is i-th row of S. */
 221.337 +
 221.338 +static void st_prod(LPF *lpf, double y[], double a, const double x[])
 221.339 +{     int n = lpf->n;
 221.340 +      int *S_ptr = lpf->S_ptr;
 221.341 +      int *S_len = lpf->S_len;
 221.342 +      int *v_ind = lpf->v_ind;
 221.343 +      double *v_val = lpf->v_val;
 221.344 +      int i, beg, end, ptr;
 221.345 +      double t;
 221.346 +      for (i = 1; i <= n; i++)
 221.347 +      {  if (x[i] == 0.0) continue;
 221.348 +         /* y := y + alpha * S'[i] * x[i] */
 221.349 +         t = a * x[i];
 221.350 +         beg = S_ptr[i];
 221.351 +         end = beg + S_len[i];
 221.352 +         for (ptr = beg; ptr < end; ptr++)
 221.353 +            y[v_ind[ptr]] += t * v_val[ptr];
 221.354 +      }
 221.355 +      return;
 221.356 +}
 221.357 +
 221.358 +#if _GLPLPF_DEBUG
 221.359 +/***********************************************************************
 221.360 +*  The routine check_error computes the maximal relative error between
 221.361 +*  left- and right-hand sides for the system B * x = b (if tr is zero)
 221.362 +*  or B' * x = b (if tr is non-zero), where B' is a matrix transposed
 221.363 +*  to B. (This routine is intended for debugging only.) */
 221.364 +
 221.365 +static void check_error(LPF *lpf, int tr, const double x[],
 221.366 +      const double b[])
 221.367 +{     int m = lpf->m;
 221.368 +      double *B = lpf->B;
 221.369 +      int i, j;
 221.370 +      double  d, dmax = 0.0, s, t, tmax;
 221.371 +      for (i = 1; i <= m; i++)
 221.372 +      {  s = 0.0;
 221.373 +         tmax = 1.0;
 221.374 +         for (j = 1; j <= m; j++)
 221.375 +         {  if (!tr)
 221.376 +               t = B[m * (i - 1) + j] * x[j];
 221.377 +            else
 221.378 +               t = B[m * (j - 1) + i] * x[j];
 221.379 +            if (tmax < fabs(t)) tmax = fabs(t);
 221.380 +            s += t;
 221.381 +         }
 221.382 +         d = fabs(s - b[i]) / tmax;
 221.383 +         if (dmax < d) dmax = d;
 221.384 +      }
 221.385 +      if (dmax > 1e-8)
 221.386 +         xprintf("%s: dmax = %g; relative error too large\n",
 221.387 +            !tr ? "lpf_ftran" : "lpf_btran", dmax);
 221.388 +      return;
 221.389 +}
 221.390 +#endif
 221.391 +
 221.392 +/***********************************************************************
 221.393 +*  NAME
 221.394 +*
 221.395 +*  lpf_ftran - perform forward transformation (solve system B*x = b)
 221.396 +*
 221.397 +*  SYNOPSIS
 221.398 +*
 221.399 +*  #include "glplpf.h"
 221.400 +*  void lpf_ftran(LPF *lpf, double x[]);
 221.401 +*
 221.402 +*  DESCRIPTION
 221.403 +*
 221.404 +*  The routine lpf_ftran performs forward transformation, i.e. solves
 221.405 +*  the system B*x = b, where B is the basis matrix, x is the vector of
 221.406 +*  unknowns to be computed, b is the vector of right-hand sides.
 221.407 +*
 221.408 +*  On entry elements of the vector b should be stored in dense format
 221.409 +*  in locations x[1], ..., x[m], where m is the number of rows. On exit
 221.410 +*  the routine stores elements of the vector x in the same locations.
 221.411 +*
 221.412 +*  BACKGROUND
 221.413 +*
 221.414 +*  Solution of the system B * x = b can be obtained by solving the
 221.415 +*  following augmented system:
 221.416 +*
 221.417 +*     ( B  F^) ( x )   ( b )
 221.418 +*     (      ) (   ) = (   )
 221.419 +*     ( G^ H^) ( y )   ( 0 )
 221.420 +*
 221.421 +*  which, using the main equality, can be written as follows:
 221.422 +*
 221.423 +*       ( L0 0 ) ( U0 R )   ( x )   ( b )
 221.424 +*     P (      ) (      ) Q (   ) = (   )
 221.425 +*       ( S  I ) ( 0  C )   ( y )   ( 0 )
 221.426 +*
 221.427 +*  therefore,
 221.428 +*
 221.429 +*     ( x )      ( U0 R )-1 ( L0 0 )-1    ( b )
 221.430 +*     (   ) = Q' (      )   (      )   P' (   )
 221.431 +*     ( y )      ( 0  C )   ( S  I )      ( 0 )
 221.432 +*
 221.433 +*  Thus, computing the solution includes the following steps:
 221.434 +*
 221.435 +*  1. Compute
 221.436 +*
 221.437 +*     ( f )      ( b )
 221.438 +*     (   ) = P' (   )
 221.439 +*     ( g )      ( 0 )
 221.440 +*
 221.441 +*  2. Solve the system
 221.442 +*
 221.443 +*     ( f1 )   ( L0 0 )-1 ( f )      ( L0 0 ) ( f1 )   ( f )
 221.444 +*     (    ) = (      )   (   )  =>  (      ) (    ) = (   )
 221.445 +*     ( g1 )   ( S  I )   ( g )      ( S  I ) ( g1 )   ( g )
 221.446 +*
 221.447 +*     from which it follows that:
 221.448 +*
 221.449 +*     { L0 * f1      = f      f1 = inv(L0) * f
 221.450 +*     {                   =>
 221.451 +*     {  S * f1 + g1 = g      g1 = g - S * f1
 221.452 +*
 221.453 +*  3. Solve the system
 221.454 +*
 221.455 +*     ( f2 )   ( U0 R )-1 ( f1 )      ( U0 R ) ( f2 )   ( f1 )
 221.456 +*     (    ) = (      )   (    )  =>  (      ) (    ) = (    )
 221.457 +*     ( g2 )   ( 0  C )   ( g1 )      ( 0  C ) ( g2 )   ( g1 )
 221.458 +*
 221.459 +*     from which it follows that:
 221.460 +*
 221.461 +*     { U0 * f2 + R * g2 = f1      f2 = inv(U0) * (f1 - R * g2)
 221.462 +*     {                        =>
 221.463 +*     {           C * g2 = g1      g2 = inv(C) * g1
 221.464 +*
 221.465 +*  4. Compute
 221.466 +*
 221.467 +*     ( x )      ( f2 )
 221.468 +*     (   ) = Q' (    )
 221.469 +*     ( y )      ( g2 )                                               */
 221.470 +
 221.471 +void lpf_ftran(LPF *lpf, double x[])
 221.472 +{     int m0 = lpf->m0;
 221.473 +      int m = lpf->m;
 221.474 +      int n  = lpf->n;
 221.475 +      int *P_col = lpf->P_col;
 221.476 +      int *Q_col = lpf->Q_col;
 221.477 +      double *fg = lpf->work1;
 221.478 +      double *f = fg;
 221.479 +      double *g = fg + m0;
 221.480 +      int i, ii;
 221.481 +#if _GLPLPF_DEBUG
 221.482 +      double *b;
 221.483 +#endif
 221.484 +      if (!lpf->valid)
 221.485 +         xfault("lpf_ftran: the factorization is not valid\n");
 221.486 +      xassert(0 <= m && m <= m0 + n);
 221.487 +#if _GLPLPF_DEBUG
 221.488 +      /* save the right-hand side vector */
 221.489 +      b = xcalloc(1+m, sizeof(double));
 221.490 +      for (i = 1; i <= m; i++) b[i] = x[i];
 221.491 +#endif
 221.492 +      /* (f g) := inv(P) * (b 0) */
 221.493 +      for (i = 1; i <= m0 + n; i++)
 221.494 +         fg[i] = ((ii = P_col[i]) <= m ? x[ii] : 0.0);
 221.495 +      /* f1 := inv(L0) * f */
 221.496 +      luf_f_solve(lpf->luf, 0, f);
 221.497 +      /* g1 := g - S * f1 */
 221.498 +      s_prod(lpf, g, -1.0, f);
 221.499 +      /* g2 := inv(C) * g1 */
 221.500 +      scf_solve_it(lpf->scf, 0, g);
 221.501 +      /* f2 := inv(U0) * (f1 - R * g2) */
 221.502 +      r_prod(lpf, f, -1.0, g);
 221.503 +      luf_v_solve(lpf->luf, 0, f);
 221.504 +      /* (x y) := inv(Q) * (f2 g2) */
 221.505 +      for (i = 1; i <= m; i++)
 221.506 +         x[i] = fg[Q_col[i]];
 221.507 +#if _GLPLPF_DEBUG
 221.508 +      /* check relative error in solution */
 221.509 +      check_error(lpf, 0, x, b);
 221.510 +      xfree(b);
 221.511 +#endif
 221.512 +      return;
 221.513 +}
 221.514 +
 221.515 +/***********************************************************************
 221.516 +*  NAME
 221.517 +*
 221.518 +*  lpf_btran - perform backward transformation (solve system B'*x = b)
 221.519 +*
 221.520 +*  SYNOPSIS
 221.521 +*
 221.522 +*  #include "glplpf.h"
 221.523 +*  void lpf_btran(LPF *lpf, double x[]);
 221.524 +*
 221.525 +*  DESCRIPTION
 221.526 +*
 221.527 +*  The routine lpf_btran performs backward transformation, i.e. solves
 221.528 +*  the system B'*x = b, where B' is a matrix transposed to the basis
 221.529 +*  matrix B, x is the vector of unknowns to be computed, b is the vector
 221.530 +*  of right-hand sides.
 221.531 +*
 221.532 +*  On entry elements of the vector b should be stored in dense format
 221.533 +*  in locations x[1], ..., x[m], where m is the number of rows. On exit
 221.534 +*  the routine stores elements of the vector x in the same locations.
 221.535 +*
 221.536 +*  BACKGROUND
 221.537 +*
 221.538 +*  Solution of the system B' * x = b, where B' is a matrix transposed
 221.539 +*  to B, can be obtained by solving the following augmented system:
 221.540 +*
 221.541 +*     ( B  F^)T ( x )   ( b )
 221.542 +*     (      )  (   ) = (   )
 221.543 +*     ( G^ H^)  ( y )   ( 0 )
 221.544 +*
 221.545 +*  which, using the main equality, can be written as follows:
 221.546 +*
 221.547 +*      T ( U0 R )T ( L0 0 )T  T ( x )   ( b )
 221.548 +*     Q  (      )  (      )  P  (   ) = (   )
 221.549 +*        ( 0  C )  ( S  I )     ( y )   ( 0 )
 221.550 +*
 221.551 +*  or, equivalently, as follows:
 221.552 +*
 221.553 +*        ( U'0 0 ) ( L'0 S')    ( x )   ( b )
 221.554 +*     Q' (       ) (       ) P' (   ) = (   )
 221.555 +*        ( R'  C') ( 0   I )    ( y )   ( 0 )
 221.556 +*
 221.557 +*  therefore,
 221.558 +*
 221.559 +*     ( x )     ( L'0 S')-1 ( U'0 0 )-1   ( b )
 221.560 +*     (   ) = P (       )   (       )   Q (   )
 221.561 +*     ( y )     ( 0   I )   ( R'  C')     ( 0 )
 221.562 +*
 221.563 +*  Thus, computing the solution includes the following steps:
 221.564 +*
 221.565 +*  1. Compute
 221.566 +*
 221.567 +*     ( f )     ( b )
 221.568 +*     (   ) = Q (   )
 221.569 +*     ( g )     ( 0 )
 221.570 +*
 221.571 +*  2. Solve the system
 221.572 +*
 221.573 +*     ( f1 )   ( U'0 0 )-1 ( f )      ( U'0 0 ) ( f1 )   ( f )
 221.574 +*     (    ) = (       )   (   )  =>  (       ) (    ) = (   )
 221.575 +*     ( g1 )   ( R'  C')   ( g )      ( R'  C') ( g1 )   ( g )
 221.576 +*
 221.577 +*     from which it follows that:
 221.578 +*
 221.579 +*     { U'0 * f1           = f      f1 = inv(U'0) * f
 221.580 +*     {                         =>
 221.581 +*     { R'  * f1 + C' * g1 = g      g1 = inv(C') * (g - R' * f1)
 221.582 +*
 221.583 +*  3. Solve the system
 221.584 +*
 221.585 +*     ( f2 )   ( L'0 S')-1 ( f1 )      ( L'0 S') ( f2 )   ( f1 )
 221.586 +*     (    ) = (       )   (    )  =>  (       ) (    ) = (    )
 221.587 +*     ( g2 )   ( 0   I )   ( g1 )      ( 0   I ) ( g2 )   ( g1 )
 221.588 +*
 221.589 +*     from which it follows that:
 221.590 +*
 221.591 +*     { L'0 * f2 + S' * g2 = f1
 221.592 +*     {                          =>  f2 = inv(L'0) * ( f1 - S' * g2)
 221.593 +*     {                 g2 = g1
 221.594 +*
 221.595 +*  4. Compute
 221.596 +*
 221.597 +*     ( x )     ( f2 )
 221.598 +*     (   ) = P (    )
 221.599 +*     ( y )     ( g2 )                                                */
 221.600 +
 221.601 +void lpf_btran(LPF *lpf, double x[])
 221.602 +{     int m0 = lpf->m0;
 221.603 +      int m = lpf->m;
 221.604 +      int n = lpf->n;
 221.605 +      int *P_row = lpf->P_row;
 221.606 +      int *Q_row = lpf->Q_row;
 221.607 +      double *fg = lpf->work1;
 221.608 +      double *f = fg;
 221.609 +      double *g = fg + m0;
 221.610 +      int i, ii;
 221.611 +#if _GLPLPF_DEBUG
 221.612 +      double *b;
 221.613 +#endif
 221.614 +      if (!lpf->valid)
 221.615 +         xfault("lpf_btran: the factorization is not valid\n");
 221.616 +      xassert(0 <= m && m <= m0 + n);
 221.617 +#if _GLPLPF_DEBUG
 221.618 +      /* save the right-hand side vector */
 221.619 +      b = xcalloc(1+m, sizeof(double));
 221.620 +      for (i = 1; i <= m; i++) b[i] = x[i];
 221.621 +#endif
 221.622 +      /* (f g) := Q * (b 0) */
 221.623 +      for (i = 1; i <= m0 + n; i++)
 221.624 +         fg[i] = ((ii = Q_row[i]) <= m ? x[ii] : 0.0);
 221.625 +      /* f1 := inv(U'0) * f */
 221.626 +      luf_v_solve(lpf->luf, 1, f);
 221.627 +      /* g1 := inv(C') * (g - R' * f1) */
 221.628 +      rt_prod(lpf, g, -1.0, f);
 221.629 +      scf_solve_it(lpf->scf, 1, g);
 221.630 +      /* g2 := g1 */
 221.631 +      g = g;
 221.632 +      /* f2 := inv(L'0) * (f1 - S' * g2) */
 221.633 +      st_prod(lpf, f, -1.0, g);
 221.634 +      luf_f_solve(lpf->luf, 1, f);
 221.635 +      /* (x y) := P * (f2 g2) */
 221.636 +      for (i = 1; i <= m; i++)
 221.637 +         x[i] = fg[P_row[i]];
 221.638 +#if _GLPLPF_DEBUG
 221.639 +      /* check relative error in solution */
 221.640 +      check_error(lpf, 1, x, b);
 221.641 +      xfree(b);
 221.642 +#endif
 221.643 +      return;
 221.644 +}
 221.645 +
 221.646 +/***********************************************************************
 221.647 +*  The routine enlarge_sva enlarges the Sparse Vector Area to new_size
 221.648 +*  locations by reallocating the arrays v_ind and v_val. */
 221.649 +
 221.650 +static void enlarge_sva(LPF *lpf, int new_size)
 221.651 +{     int v_size = lpf->v_size;
 221.652 +      int used = lpf->v_ptr - 1;
 221.653 +      int *v_ind = lpf->v_ind;
 221.654 +      double *v_val = lpf->v_val;
 221.655 +      xassert(v_size < new_size);
 221.656 +      while (v_size < new_size) v_size += v_size;
 221.657 +      lpf->v_size = v_size;
 221.658 +      lpf->v_ind = xcalloc(1+v_size, sizeof(int));
 221.659 +      lpf->v_val = xcalloc(1+v_size, sizeof(double));
 221.660 +      xassert(used >= 0);
 221.661 +      memcpy(&lpf->v_ind[1], &v_ind[1], used * sizeof(int));
 221.662 +      memcpy(&lpf->v_val[1], &v_val[1], used * sizeof(double));
 221.663 +      xfree(v_ind);
 221.664 +      xfree(v_val);
 221.665 +      return;
 221.666 +}
 221.667 +
 221.668 +/***********************************************************************
 221.669 +*  NAME
 221.670 +*
 221.671 +*  lpf_update_it - update LP basis factorization
 221.672 +*
 221.673 +*  SYNOPSIS
 221.674 +*
 221.675 +*  #include "glplpf.h"
 221.676 +*  int lpf_update_it(LPF *lpf, int j, int bh, int len, const int ind[],
 221.677 +*     const double val[]);
 221.678 +*
 221.679 +*  DESCRIPTION
 221.680 +*
 221.681 +*  The routine lpf_update_it updates the factorization of the basis
 221.682 +*  matrix B after replacing its j-th column by a new vector.
 221.683 +*
 221.684 +*  The parameter j specifies the number of column of B, which has been
 221.685 +*  replaced, 1 <= j <= m, where m is the order of B.
 221.686 +*
 221.687 +*  The parameter bh specifies the basis header entry for the new column
 221.688 +*  of B, which is the number of the new column in some original matrix.
 221.689 +*  This parameter is optional and can be specified as 0.
 221.690 +*
 221.691 +*  Row indices and numerical values of non-zero elements of the new
 221.692 +*  column of B should be placed in locations ind[1], ..., ind[len] and
 221.693 +*  val[1], ..., val[len], resp., where len is the number of non-zeros
 221.694 +*  in the column. Neither zero nor duplicate elements are allowed.
 221.695 +*
 221.696 +*  RETURNS
 221.697 +*
 221.698 +*  0  The factorization has been successfully updated.
 221.699 +*
 221.700 +*  LPF_ESING
 221.701 +*     New basis B is singular within the working precision.
 221.702 +*
 221.703 +*  LPF_ELIMIT
 221.704 +*     Maximal number of additional rows and columns has been reached.
 221.705 +*
 221.706 +*  BACKGROUND
 221.707 +*
 221.708 +*  Let j-th column of the current basis matrix B have to be replaced by
 221.709 +*  a new column a. This replacement is equivalent to removing the old
 221.710 +*  j-th column by fixing it at zero and introducing the new column as
 221.711 +*  follows:
 221.712 +*
 221.713 +*                   ( B   F^| a )
 221.714 +*     ( B  F^)      (       |   )
 221.715 +*     (      ) ---> ( G^  H^| 0 )
 221.716 +*     ( G^ H^)      (-------+---)
 221.717 +*                   ( e'j 0 | 0 )
 221.718 +*
 221.719 +*  where ej is a unit vector with 1 in j-th position which used to fix
 221.720 +*  the old j-th column of B (at zero). Then using the main equality we
 221.721 +*  have:
 221.722 +*
 221.723 +*     ( B   F^| a )            ( B0  F | f )
 221.724 +*     (       |   )   ( P  0 ) (       |   ) ( Q  0 )
 221.725 +*     ( G^  H^| 0 ) = (      ) ( G   H | g ) (      ) =
 221.726 +*     (-------+---)   ( 0  1 ) (-------+---) ( 0  1 )
 221.727 +*     ( e'j 0 | 0 )            ( v'  w'| 0 )
 221.728 +*
 221.729 +*       [   ( B0  F )|   ( f ) ]            [   ( B0 F )  |   ( f ) ]
 221.730 +*       [ P (       )| P (   ) ] ( Q  0 )   [ P (      ) Q| P (   ) ]
 221.731 +*     = [   ( G   H )|   ( g ) ] (      ) = [   ( G  H )  |   ( g ) ]
 221.732 +*       [------------+-------- ] ( 0  1 )   [-------------+---------]
 221.733 +*       [   ( v'  w')|     0   ]            [   ( v' w') Q|    0    ]
 221.734 +*
 221.735 +*  where:
 221.736 +*
 221.737 +*     ( a )     ( f )      ( f )        ( a )
 221.738 +*     (   ) = P (   )  =>  (   ) = P' * (   )
 221.739 +*     ( 0 )     ( g )      ( g )        ( 0 )
 221.740 +*
 221.741 +*                                 ( ej )      ( v )    ( v )     ( ej )
 221.742 +*     ( e'j  0 ) = ( v' w' ) Q => (    ) = Q' (   ) => (   ) = Q (    )
 221.743 +*                                 ( 0  )      ( w )    ( w )     ( 0  )
 221.744 +*
 221.745 +*  On the other hand:
 221.746 +*
 221.747 +*              ( B0| F  f )
 221.748 +*     ( P  0 ) (---+------) ( Q  0 )         ( B0    new F )
 221.749 +*     (      ) ( G | H  g ) (      ) = new P (             ) new Q
 221.750 +*     ( 0  1 ) (   |      ) ( 0  1 )         ( new G new H )
 221.751 +*              ( v'| w' 0 )
 221.752 +*
 221.753 +*  where:
 221.754 +*                               ( G )           ( H  g )
 221.755 +*     new F = ( F  f ), new G = (   ),  new H = (      ),
 221.756 +*                               ( v')           ( w' 0 )
 221.757 +*
 221.758 +*             ( P  0 )           ( Q  0 )
 221.759 +*     new P = (      ) , new Q = (      ) .
 221.760 +*             ( 0  1 )           ( 0  1 )
 221.761 +*
 221.762 +*  The factorization structure for the new augmented matrix remains the
 221.763 +*  same, therefore:
 221.764 +*
 221.765 +*           ( B0    new F )         ( L0     0 ) ( U0 new R )
 221.766 +*     new P (             ) new Q = (          ) (          )
 221.767 +*           ( new G new H )         ( new S  I ) ( 0  new C )
 221.768 +*
 221.769 +*  where:
 221.770 +*
 221.771 +*     new F = L0 * new R  =>
 221.772 +*
 221.773 +*     new R = inv(L0) * new F = inv(L0) * (F  f) = ( R  inv(L0)*f )
 221.774 +*
 221.775 +*     new G = new S * U0  =>
 221.776 +*
 221.777 +*                               ( G )             (     S      )
 221.778 +*     new S = new G * inv(U0) = (   ) * inv(U0) = (            )
 221.779 +*                               ( v')             ( v'*inv(U0) )
 221.780 +*
 221.781 +*     new H = new S * new R + new C  =>
 221.782 +*
 221.783 +*     new C = new H - new S * new R =
 221.784 +*
 221.785 +*             ( H  g )   (     S      )
 221.786 +*           = (      ) - (            ) * ( R  inv(L0)*f ) =
 221.787 +*             ( w' 0 )   ( v'*inv(U0) )
 221.788 +*
 221.789 +*             ( H - S*R           g - S*inv(L0)*f      )   ( C  x )
 221.790 +*           = (                                        ) = (      )
 221.791 +*             ( w'- v'*inv(U0)*R  -v'*inv(U0)*inv(L0)*f)   ( y' z )
 221.792 +*
 221.793 +*  Note that new C is resulted by expanding old C with new column x,
 221.794 +*  row y', and diagonal element z, where:
 221.795 +*
 221.796 +*     x = g - S * inv(L0) * f = g - S * (new column of R)
 221.797 +*
 221.798 +*     y = w - R'* inv(U'0)* v = w - R'* (new row of S)
 221.799 +*
 221.800 +*     z = - (new row of S) * (new column of R)
 221.801 +*
 221.802 +*  Finally, to replace old B by new B we have to permute j-th and last
 221.803 +*  (just added) columns of the matrix
 221.804 +*
 221.805 +*     ( B   F^| a )
 221.806 +*     (       |   )
 221.807 +*     ( G^  H^| 0 )
 221.808 +*     (-------+---)
 221.809 +*     ( e'j 0 | 0 )
 221.810 +*
 221.811 +*  and to keep the main equality do the same for matrix Q. */
 221.812 +
 221.813 +int lpf_update_it(LPF *lpf, int j, int bh, int len, const int ind[],
 221.814 +      const double val[])
 221.815 +{     int m0 = lpf->m0;
 221.816 +      int m = lpf->m;
 221.817 +#if _GLPLPF_DEBUG
 221.818 +      double *B = lpf->B;
 221.819 +#endif
 221.820 +      int n = lpf->n;
 221.821 +      int *R_ptr = lpf->R_ptr;
 221.822 +      int *R_len = lpf->R_len;
 221.823 +      int *S_ptr = lpf->S_ptr;
 221.824 +      int *S_len = lpf->S_len;
 221.825 +      int *P_row = lpf->P_row;
 221.826 +      int *P_col = lpf->P_col;
 221.827 +      int *Q_row = lpf->Q_row;
 221.828 +      int *Q_col = lpf->Q_col;
 221.829 +      int v_ptr = lpf->v_ptr;
 221.830 +      int *v_ind = lpf->v_ind;
 221.831 +      double *v_val = lpf->v_val;
 221.832 +      double *a = lpf->work2; /* new column */
 221.833 +      double *fg = lpf->work1, *f = fg, *g = fg + m0;
 221.834 +      double *vw = lpf->work2, *v = vw, *w = vw + m0;
 221.835 +      double *x = g, *y = w, z;
 221.836 +      int i, ii, k, ret;
 221.837 +      xassert(bh == bh);
 221.838 +      if (!lpf->valid)
 221.839 +         xfault("lpf_update_it: the factorization is not valid\n");
 221.840 +      if (!(1 <= j && j <= m))
 221.841 +         xfault("lpf_update_it: j = %d; column number out of range\n",
 221.842 +            j);
 221.843 +      xassert(0 <= m && m <= m0 + n);
 221.844 +      /* check if the basis factorization can be expanded */
 221.845 +      if (n == lpf->n_max)
 221.846 +      {  lpf->valid = 0;
 221.847 +         ret = LPF_ELIMIT;
 221.848 +         goto done;
 221.849 +      }
 221.850 +      /* convert new j-th column of B to dense format */
 221.851 +      for (i = 1; i <= m; i++)
 221.852 +         a[i] = 0.0;
 221.853 +      for (k = 1; k <= len; k++)
 221.854 +      {  i = ind[k];
 221.855 +         if (!(1 <= i && i <= m))
 221.856 +            xfault("lpf_update_it: ind[%d] = %d; row number out of rang"
 221.857 +               "e\n", k, i);
 221.858 +         if (a[i] != 0.0)
 221.859 +            xfault("lpf_update_it: ind[%d] = %d; duplicate row index no"
 221.860 +               "t allowed\n", k, i);
 221.861 +         if (val[k] == 0.0)
 221.862 +            xfault("lpf_update_it: val[%d] = %g; zero element not allow"
 221.863 +               "ed\n", k, val[k]);
 221.864 +         a[i] = val[k];
 221.865 +      }
 221.866 +#if _GLPLPF_DEBUG
 221.867 +      /* change column in the basis matrix for debugging */
 221.868 +      for (i = 1; i <= m; i++)
 221.869 +         B[(i - 1) * m + j] = a[i];
 221.870 +#endif
 221.871 +      /* (f g) := inv(P) * (a 0) */
 221.872 +      for (i = 1; i <= m0+n; i++)
 221.873 +         fg[i] = ((ii = P_col[i]) <= m ? a[ii] : 0.0);
 221.874 +      /* (v w) := Q * (ej 0) */
 221.875 +      for (i = 1; i <= m0+n; i++) vw[i] = 0.0;
 221.876 +      vw[Q_col[j]] = 1.0;
 221.877 +      /* f1 := inv(L0) * f (new column of R) */
 221.878 +      luf_f_solve(lpf->luf, 0, f);
 221.879 +      /* v1 := inv(U'0) * v (new row of S) */
 221.880 +      luf_v_solve(lpf->luf, 1, v);
 221.881 +      /* we need at most 2 * m0 available locations in the SVA to store
 221.882 +         new column of matrix R and new row of matrix S */
 221.883 +      if (lpf->v_size < v_ptr + m0 + m0)
 221.884 +      {  enlarge_sva(lpf, v_ptr + m0 + m0);
 221.885 +         v_ind = lpf->v_ind;
 221.886 +         v_val = lpf->v_val;
 221.887 +      }
 221.888 +      /* store new column of R */
 221.889 +      R_ptr[n+1] = v_ptr;
 221.890 +      for (i = 1; i <= m0; i++)
 221.891 +      {  if (f[i] != 0.0)
 221.892 +            v_ind[v_ptr] = i, v_val[v_ptr] = f[i], v_ptr++;
 221.893 +      }
 221.894 +      R_len[n+1] = v_ptr - lpf->v_ptr;
 221.895 +      lpf->v_ptr = v_ptr;
 221.896 +      /* store new row of S */
 221.897 +      S_ptr[n+1] = v_ptr;
 221.898 +      for (i = 1; i <= m0; i++)
 221.899 +      {  if (v[i] != 0.0)
 221.900 +            v_ind[v_ptr] = i, v_val[v_ptr] = v[i], v_ptr++;
 221.901 +      }
 221.902 +      S_len[n+1] = v_ptr - lpf->v_ptr;
 221.903 +      lpf->v_ptr = v_ptr;
 221.904 +      /* x := g - S * f1 (new column of C) */
 221.905 +      s_prod(lpf, x, -1.0, f);
 221.906 +      /* y := w - R' * v1 (new row of C) */
 221.907 +      rt_prod(lpf, y, -1.0, v);
 221.908 +      /* z := - v1 * f1 (new diagonal element of C) */
 221.909 +      z = 0.0;
 221.910 +      for (i = 1; i <= m0; i++) z -= v[i] * f[i];
 221.911 +      /* update factorization of new matrix C */
 221.912 +      switch (scf_update_exp(lpf->scf, x, y, z))
 221.913 +      {  case 0:
 221.914 +            break;
 221.915 +         case SCF_ESING:
 221.916 +            lpf->valid = 0;
 221.917 +            ret = LPF_ESING;
 221.918 +            goto done;
 221.919 +         case SCF_ELIMIT:
 221.920 +            xassert(lpf != lpf);
 221.921 +         default:
 221.922 +            xassert(lpf != lpf);
 221.923 +      }
 221.924 +      /* expand matrix P */
 221.925 +      P_row[m0+n+1] = P_col[m0+n+1] = m0+n+1;
 221.926 +      /* expand matrix Q */
 221.927 +      Q_row[m0+n+1] = Q_col[m0+n+1] = m0+n+1;
 221.928 +      /* permute j-th and last (just added) column of matrix Q */
 221.929 +      i = Q_col[j], ii = Q_col[m0+n+1];
 221.930 +      Q_row[i] = m0+n+1, Q_col[m0+n+1] = i;
 221.931 +      Q_row[ii] = j, Q_col[j] = ii;
 221.932 +      /* increase the number of additional rows and columns */
 221.933 +      lpf->n++;
 221.934 +      xassert(lpf->n <= lpf->n_max);
 221.935 +      /* the factorization has been successfully updated */
 221.936 +      ret = 0;
 221.937 +done: /* return to the calling program */
 221.938 +      return ret;
 221.939 +}
 221.940 +
 221.941 +/***********************************************************************
 221.942 +*  NAME
 221.943 +*
 221.944 +*  lpf_delete_it - delete LP basis factorization
 221.945 +*
 221.946 +*  SYNOPSIS
 221.947 +*
 221.948 +*  #include "glplpf.h"
 221.949 +*  void lpf_delete_it(LPF *lpf)
 221.950 +*
 221.951 +*  DESCRIPTION
 221.952 +*
 221.953 +*  The routine lpf_delete_it deletes LP basis factorization specified
 221.954 +*  by the parameter lpf and frees all memory allocated to this program
 221.955 +*  object. */
 221.956 +
 221.957 +void lpf_delete_it(LPF *lpf)
 221.958 +{     luf_delete_it(lpf->luf);
 221.959 +#if _GLPLPF_DEBUG
 221.960 +      if (lpf->B != NULL) xfree(lpf->B);
 221.961 +#else
 221.962 +      xassert(lpf->B == NULL);
 221.963 +#endif
 221.964 +      if (lpf->R_ptr != NULL) xfree(lpf->R_ptr);
 221.965 +      if (lpf->R_len != NULL) xfree(lpf->R_len);
 221.966 +      if (lpf->S_ptr != NULL) xfree(lpf->S_ptr);
 221.967 +      if (lpf->S_len != NULL) xfree(lpf->S_len);
 221.968 +      if (lpf->scf != NULL) scf_delete_it(lpf->scf);
 221.969 +      if (lpf->P_row != NULL) xfree(lpf->P_row);
 221.970 +      if (lpf->P_col != NULL) xfree(lpf->P_col);
 221.971 +      if (lpf->Q_row != NULL) xfree(lpf->Q_row);
 221.972 +      if (lpf->Q_col != NULL) xfree(lpf->Q_col);
 221.973 +      if (lpf->v_ind != NULL) xfree(lpf->v_ind);
 221.974 +      if (lpf->v_val != NULL) xfree(lpf->v_val);
 221.975 +      if (lpf->work1 != NULL) xfree(lpf->work1);
 221.976 +      if (lpf->work2 != NULL) xfree(lpf->work2);
 221.977 +      xfree(lpf);
 221.978 +      return;
 221.979 +}
 221.980 +
 221.981 +/* eof */
   222.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   222.2 +++ b/src/glplpf.h	Mon Dec 06 13:09:21 2010 +0100
   222.3 @@ -0,0 +1,194 @@
   222.4 +/* glplpf.h (LP basis factorization, Schur complement version) */
   222.5 +
   222.6 +/***********************************************************************
   222.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   222.8 +*
   222.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  222.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  222.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  222.12 +*  E-mail: <mao@gnu.org>.
  222.13 +*
  222.14 +*  GLPK is free software: you can redistribute it and/or modify it
  222.15 +*  under the terms of the GNU General Public License as published by
  222.16 +*  the Free Software Foundation, either version 3 of the License, or
  222.17 +*  (at your option) any later version.
  222.18 +*
  222.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  222.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  222.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  222.22 +*  License for more details.
  222.23 +*
  222.24 +*  You should have received a copy of the GNU General Public License
  222.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  222.26 +***********************************************************************/
  222.27 +
  222.28 +#ifndef GLPLPF_H
  222.29 +#define GLPLPF_H
  222.30 +
  222.31 +#include "glpscf.h"
  222.32 +#include "glpluf.h"
  222.33 +
  222.34 +/***********************************************************************
  222.35 +*  The structure LPF defines the factorization of the basis mxm matrix
  222.36 +*  B, where m is the number of rows in corresponding problem instance.
  222.37 +*
  222.38 +*  This factorization is the following septet:
  222.39 +*
  222.40 +*     [B] = (L0, U0, R, S, C, P, Q),                                 (1)
  222.41 +*
  222.42 +*  and is based on the following main equality:
  222.43 +*
  222.44 +*     ( B  F^)     ( B0 F )       ( L0 0 ) ( U0 R )
  222.45 +*     (      ) = P (      ) Q = P (      ) (      ) Q,               (2)
  222.46 +*     ( G^ H^)     ( G  H )       ( S  I ) ( 0  C )
  222.47 +*
  222.48 +*  where:
  222.49 +*
  222.50 +*  B is the current basis matrix (not stored);
  222.51 +*
  222.52 +*  F^, G^, H^ are some additional matrices (not stored);
  222.53 +*
  222.54 +*  B0 is some initial basis matrix (not stored);
  222.55 +*
  222.56 +*  F, G, H are some additional matrices (not stored);
  222.57 +*
  222.58 +*  P, Q are permutation matrices (stored in both row- and column-like
  222.59 +*  formats);
  222.60 +*
  222.61 +*  L0, U0 are some matrices that defines a factorization of the initial
  222.62 +*  basis matrix B0 = L0 * U0 (stored in an invertable form);
  222.63 +*
  222.64 +*  R is a matrix defined from L0 * R = F, so R = inv(L0) * F (stored in
  222.65 +*  a column-wise sparse format);
  222.66 +*
  222.67 +*  S is a matrix defined from S * U0 = G, so S = G * inv(U0) (stored in
  222.68 +*  a row-wise sparse format);
  222.69 +*
  222.70 +*  C is the Schur complement for matrix (B0 F G H). It is defined from
  222.71 +*  S * R + C = H, so C = H - S * R = H - G * inv(U0) * inv(L0) * F =
  222.72 +*  = H - G * inv(B0) * F. Matrix C is stored in an invertable form.
  222.73 +*
  222.74 +*  REFERENCES
  222.75 +*
  222.76 +*  1. M.A.Saunders, "LUSOL: A basis package for constrained optimiza-
  222.77 +*     tion," SCCM, Stanford University, 2006.
  222.78 +*
  222.79 +*  2. M.A.Saunders, "Notes 5: Basis Updates," CME 318, Stanford Univer-
  222.80 +*     sity, Spring 2006.
  222.81 +*
  222.82 +*  3. M.A.Saunders, "Notes 6: LUSOL---a Basis Factorization Package,"
  222.83 +*     ibid. */
  222.84 +
  222.85 +typedef struct LPF LPF;
  222.86 +
  222.87 +struct LPF
  222.88 +{     /* LP basis factorization */
  222.89 +      int valid;
  222.90 +      /* the factorization is valid only if this flag is set */
  222.91 +      /*--------------------------------------------------------------*/
  222.92 +      /* initial basis matrix B0 */
  222.93 +      int m0_max;
  222.94 +      /* maximal value of m0 (increased automatically, if necessary) */
  222.95 +      int m0;
  222.96 +      /* the order of B0 */
  222.97 +      LUF *luf;
  222.98 +      /* LU-factorization of B0 */
  222.99 +      /*--------------------------------------------------------------*/
 222.100 +      /* current basis matrix B */
 222.101 +      int m;
 222.102 +      /* the order of B */
 222.103 +      double *B; /* double B[1+m*m]; */
 222.104 +      /* B in dense format stored by rows and used only for debugging;
 222.105 +         normally this array is not allocated */
 222.106 +      /*--------------------------------------------------------------*/
 222.107 +      /* augmented matrix (B0 F G H) of the order m0+n */
 222.108 +      int n_max;
 222.109 +      /* maximal number of additional rows and columns */
 222.110 +      int n;
 222.111 +      /* current number of additional rows and columns */
 222.112 +      /*--------------------------------------------------------------*/
 222.113 +      /* m0xn matrix R in column-wise format */
 222.114 +      int *R_ptr; /* int R_ptr[1+n_max]; */
 222.115 +      /* R_ptr[j], 1 <= j <= n, is a pointer to j-th column */
 222.116 +      int *R_len; /* int R_len[1+n_max]; */
 222.117 +      /* R_len[j], 1 <= j <= n, is the length of j-th column */
 222.118 +      /*--------------------------------------------------------------*/
 222.119 +      /* nxm0 matrix S in row-wise format */
 222.120 +      int *S_ptr; /* int S_ptr[1+n_max]; */
 222.121 +      /* S_ptr[i], 1 <= i <= n, is a pointer to i-th row */
 222.122 +      int *S_len; /* int S_len[1+n_max]; */
 222.123 +      /* S_len[i], 1 <= i <= n, is the length of i-th row */
 222.124 +      /*--------------------------------------------------------------*/
 222.125 +      /* Schur complement C of the order n */
 222.126 +      SCF *scf; /* SCF scf[1:n_max]; */
 222.127 +      /* factorization of the Schur complement */
 222.128 +      /*--------------------------------------------------------------*/
 222.129 +      /* matrix P of the order m0+n */
 222.130 +      int *P_row; /* int P_row[1+m0_max+n_max]; */
 222.131 +      /* P_row[i] = j means that P[i,j] = 1 */
 222.132 +      int *P_col; /* int P_col[1+m0_max+n_max]; */
 222.133 +      /* P_col[j] = i means that P[i,j] = 1 */
 222.134 +      /*--------------------------------------------------------------*/
 222.135 +      /* matrix Q of the order m0+n */
 222.136 +      int *Q_row; /* int Q_row[1+m0_max+n_max]; */
 222.137 +      /* Q_row[i] = j means that Q[i,j] = 1 */
 222.138 +      int *Q_col; /* int Q_col[1+m0_max+n_max]; */
 222.139 +      /* Q_col[j] = i means that Q[i,j] = 1 */
 222.140 +      /*--------------------------------------------------------------*/
 222.141 +      /* Sparse Vector Area (SVA) is a set of locations intended to
 222.142 +         store sparse vectors which represent columns of matrix R and
 222.143 +         rows of matrix S; each location is a doublet (ind, val), where
 222.144 +         ind is an index, val is a numerical value of a sparse vector
 222.145 +         element; in the whole each sparse vector is a set of adjacent
 222.146 +         locations defined by a pointer to its first element and its
 222.147 +         length, i.e. the number of its elements */
 222.148 +      int v_size;
 222.149 +      /* the SVA size, in locations; locations are numbered by integers
 222.150 +         1, 2, ..., v_size, and location 0 is not used */
 222.151 +      int v_ptr;
 222.152 +      /* pointer to the first available location */
 222.153 +      int *v_ind; /* int v_ind[1+v_size]; */
 222.154 +      /* v_ind[k], 1 <= k <= v_size, is the index field of location k */
 222.155 +      double *v_val; /* double v_val[1+v_size]; */
 222.156 +      /* v_val[k], 1 <= k <= v_size, is the value field of location k */
 222.157 +      /*--------------------------------------------------------------*/
 222.158 +      double *work1; /* double work1[1+m0+n_max]; */
 222.159 +      /* working array */
 222.160 +      double *work2; /* double work2[1+m0+n_max]; */
 222.161 +      /* working array */
 222.162 +};
 222.163 +
 222.164 +/* return codes: */
 222.165 +#define LPF_ESING    1  /* singular matrix */
 222.166 +#define LPF_ECOND    2  /* ill-conditioned matrix */
 222.167 +#define LPF_ELIMIT   3  /* update limit reached */
 222.168 +
 222.169 +#define lpf_create_it _glp_lpf_create_it
 222.170 +LPF *lpf_create_it(void);
 222.171 +/* create LP basis factorization */
 222.172 +
 222.173 +#define lpf_factorize _glp_lpf_factorize
 222.174 +int lpf_factorize(LPF *lpf, int m, const int bh[], int (*col)
 222.175 +      (void *info, int j, int ind[], double val[]), void *info);
 222.176 +/* compute LP basis factorization */
 222.177 +
 222.178 +#define lpf_ftran _glp_lpf_ftran
 222.179 +void lpf_ftran(LPF *lpf, double x[]);
 222.180 +/* perform forward transformation (solve system B*x = b) */
 222.181 +
 222.182 +#define lpf_btran _glp_lpf_btran
 222.183 +void lpf_btran(LPF *lpf, double x[]);
 222.184 +/* perform backward transformation (solve system B'*x = b) */
 222.185 +
 222.186 +#define lpf_update_it _glp_lpf_update_it
 222.187 +int lpf_update_it(LPF *lpf, int j, int bh, int len, const int ind[],
 222.188 +      const double val[]);
 222.189 +/* update LP basis factorization */
 222.190 +
 222.191 +#define lpf_delete_it _glp_lpf_delete_it
 222.192 +void lpf_delete_it(LPF *lpf);
 222.193 +/* delete LP basis factorization */
 222.194 +
 222.195 +#endif
 222.196 +
 222.197 +/* eof */
   223.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   223.2 +++ b/src/glplpx01.c	Mon Dec 06 13:09:21 2010 +0100
   223.3 @@ -0,0 +1,1542 @@
   223.4 +/* glplpx01.c (obsolete API routines) */
   223.5 +
   223.6 +/***********************************************************************
   223.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   223.8 +*
   223.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  223.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  223.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  223.12 +*  E-mail: <mao@gnu.org>.
  223.13 +*
  223.14 +*  GLPK is free software: you can redistribute it and/or modify it
  223.15 +*  under the terms of the GNU General Public License as published by
  223.16 +*  the Free Software Foundation, either version 3 of the License, or
  223.17 +*  (at your option) any later version.
  223.18 +*
  223.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  223.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  223.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  223.22 +*  License for more details.
  223.23 +*
  223.24 +*  You should have received a copy of the GNU General Public License
  223.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  223.26 +***********************************************************************/
  223.27 +
  223.28 +#include "glpapi.h"
  223.29 +
  223.30 +struct LPXCPS
  223.31 +{     /* control parameters and statistics */
  223.32 +      int msg_lev;
  223.33 +      /* level of messages output by the solver:
  223.34 +         0 - no output
  223.35 +         1 - error messages only
  223.36 +         2 - normal output
  223.37 +         3 - full output (includes informational messages) */
  223.38 +      int scale;
  223.39 +      /* scaling option:
  223.40 +         0 - no scaling
  223.41 +         1 - equilibration scaling
  223.42 +         2 - geometric mean scaling
  223.43 +         3 - geometric mean scaling, then equilibration scaling */
  223.44 +      int dual;
  223.45 +      /* dual simplex option:
  223.46 +         0 - use primal simplex
  223.47 +         1 - use dual simplex */
  223.48 +      int price;
  223.49 +      /* pricing option (for both primal and dual simplex):
  223.50 +         0 - textbook pricing
  223.51 +         1 - steepest edge pricing */
  223.52 +      double relax;
  223.53 +      /* relaxation parameter used in the ratio test; if it is zero,
  223.54 +         the textbook ratio test is used; if it is non-zero (should be
  223.55 +         positive), Harris' two-pass ratio test is used; in the latter
  223.56 +         case on the first pass basic variables (in the case of primal
  223.57 +         simplex) or reduced costs of non-basic variables (in the case
  223.58 +         of dual simplex) are allowed to slightly violate their bounds,
  223.59 +         but not more than (relax * tol_bnd) or (relax * tol_dj) (thus,
  223.60 +         relax is a percentage of tol_bnd or tol_dj) */
  223.61 +      double tol_bnd;
  223.62 +      /* relative tolerance used to check if the current basic solution
  223.63 +         is primal feasible */
  223.64 +      double tol_dj;
  223.65 +      /* absolute tolerance used to check if the current basic solution
  223.66 +         is dual feasible */
  223.67 +      double tol_piv;
  223.68 +      /* relative tolerance used to choose eligible pivotal elements of
  223.69 +         the simplex table in the ratio test */
  223.70 +      int round;
  223.71 +      /* solution rounding option:
  223.72 +         0 - report all computed values and reduced costs "as is"
  223.73 +         1 - if possible (allowed by the tolerances), replace computed
  223.74 +             values and reduced costs which are close to zero by exact
  223.75 +             zeros */
  223.76 +      double obj_ll;
  223.77 +      /* lower limit of the objective function; if on the phase II the
  223.78 +         objective function reaches this limit and continues decreasing,
  223.79 +         the solver stops the search */
  223.80 +      double obj_ul;
  223.81 +      /* upper limit of the objective function; if on the phase II the
  223.82 +         objective function reaches this limit and continues increasing,
  223.83 +         the solver stops the search */
  223.84 +      int it_lim;
  223.85 +      /* simplex iterations limit; if this value is positive, it is
  223.86 +         decreased by one each time when one simplex iteration has been
  223.87 +         performed, and reaching zero value signals the solver to stop
  223.88 +         the search; negative value means no iterations limit */
  223.89 +      double tm_lim;
  223.90 +      /* searching time limit, in seconds; if this value is positive,
  223.91 +         it is decreased each time when one simplex iteration has been
  223.92 +         performed by the amount of time spent for the iteration, and
  223.93 +         reaching zero value signals the solver to stop the search;
  223.94 +         negative value means no time limit */
  223.95 +      int out_frq;
  223.96 +      /* output frequency, in iterations; this parameter specifies how
  223.97 +         frequently the solver sends information about the solution to
  223.98 +         the standard output */
  223.99 +      double out_dly;
 223.100 +      /* output delay, in seconds; this parameter specifies how long
 223.101 +         the solver should delay sending information about the solution
 223.102 +         to the standard output; zero value means no delay */
 223.103 +      int branch; /* MIP */
 223.104 +      /* branching heuristic:
 223.105 +         0 - branch on first variable
 223.106 +         1 - branch on last variable
 223.107 +         2 - branch using heuristic by Driebeck and Tomlin
 223.108 +         3 - branch on most fractional variable */
 223.109 +      int btrack; /* MIP */
 223.110 +      /* backtracking heuristic:
 223.111 +         0 - select most recent node (depth first search)
 223.112 +         1 - select earliest node (breadth first search)
 223.113 +         2 - select node using the best projection heuristic
 223.114 +         3 - select node with best local bound */
 223.115 +      double tol_int; /* MIP */
 223.116 +      /* absolute tolerance used to check if the current basic solution
 223.117 +         is integer feasible */
 223.118 +      double tol_obj; /* MIP */
 223.119 +      /* relative tolerance used to check if the value of the objective
 223.120 +         function is not better than in the best known integer feasible
 223.121 +         solution */
 223.122 +      int mps_info; /* lpx_write_mps */
 223.123 +      /* if this flag is set, the routine lpx_write_mps outputs several
 223.124 +         comment cards that contains some information about the problem;
 223.125 +         otherwise the routine outputs no comment cards */
 223.126 +      int mps_obj; /* lpx_write_mps */
 223.127 +      /* this parameter tells the routine lpx_write_mps how to output
 223.128 +         the objective function row:
 223.129 +         0 - never output objective function row
 223.130 +         1 - always output objective function row
 223.131 +         2 - output objective function row if and only if the problem
 223.132 +             has no free rows */
 223.133 +      int mps_orig; /* lpx_write_mps */
 223.134 +      /* if this flag is set, the routine lpx_write_mps uses original
 223.135 +         row and column symbolic names; otherwise the routine generates
 223.136 +         plain names using ordinal numbers of rows and columns */
 223.137 +      int mps_wide; /* lpx_write_mps */
 223.138 +      /* if this flag is set, the routine lpx_write_mps uses all data
 223.139 +         fields; otherwise the routine keeps fields 5 and 6 empty */
 223.140 +      int mps_free; /* lpx_write_mps */
 223.141 +      /* if this flag is set, the routine lpx_write_mps omits column
 223.142 +         and vector names everytime if possible (free style); otherwise
 223.143 +         the routine never omits these names (pedantic style) */
 223.144 +      int mps_skip; /* lpx_write_mps */
 223.145 +      /* if this flag is set, the routine lpx_write_mps skips empty
 223.146 +         columns (i.e. which has no constraint coefficients); otherwise
 223.147 +         the routine outputs all columns */
 223.148 +      int lpt_orig; /* lpx_write_lpt */
 223.149 +      /* if this flag is set, the routine lpx_write_lpt uses original
 223.150 +         row and column symbolic names; otherwise the routine generates
 223.151 +         plain names using ordinal numbers of rows and columns */
 223.152 +      int presol; /* lpx_simplex */
 223.153 +      /* LP presolver option:
 223.154 +         0 - do not use LP presolver
 223.155 +         1 - use LP presolver */
 223.156 +      int binarize; /* lpx_intopt */
 223.157 +      /* if this flag is set, the routine lpx_intopt replaces integer
 223.158 +         columns by binary ones */
 223.159 +      int use_cuts; /* lpx_intopt */
 223.160 +      /* if this flag is set, the routine lpx_intopt tries generating
 223.161 +         cutting planes:
 223.162 +         LPX_C_COVER  - mixed cover cuts
 223.163 +         LPX_C_CLIQUE - clique cuts
 223.164 +         LPX_C_GOMORY - Gomory's mixed integer cuts
 223.165 +         LPX_C_ALL    - all cuts */
 223.166 +      double mip_gap; /* MIP */
 223.167 +      /* relative MIP gap tolerance */
 223.168 +};
 223.169 +
 223.170 +LPX *lpx_create_prob(void)
 223.171 +{     /* create problem object */
 223.172 +      return glp_create_prob();
 223.173 +}
 223.174 +
 223.175 +void lpx_set_prob_name(LPX *lp, const char *name)
 223.176 +{     /* assign (change) problem name */
 223.177 +      glp_set_prob_name(lp, name);
 223.178 +      return;
 223.179 +}
 223.180 +
 223.181 +void lpx_set_obj_name(LPX *lp, const char *name)
 223.182 +{     /* assign (change) objective function name */
 223.183 +      glp_set_obj_name(lp, name);
 223.184 +      return;
 223.185 +}
 223.186 +
 223.187 +void lpx_set_obj_dir(LPX *lp, int dir)
 223.188 +{     /* set (change) optimization direction flag */
 223.189 +      glp_set_obj_dir(lp, dir - LPX_MIN + GLP_MIN);
 223.190 +      return;
 223.191 +}
 223.192 +
 223.193 +int lpx_add_rows(LPX *lp, int nrs)
 223.194 +{     /* add new rows to problem object */
 223.195 +      return glp_add_rows(lp, nrs);
 223.196 +}
 223.197 +
 223.198 +int lpx_add_cols(LPX *lp, int ncs)
 223.199 +{     /* add new columns to problem object */
 223.200 +      return glp_add_cols(lp, ncs);
 223.201 +}
 223.202 +
 223.203 +void lpx_set_row_name(LPX *lp, int i, const char *name)
 223.204 +{     /* assign (change) row name */
 223.205 +      glp_set_row_name(lp, i, name);
 223.206 +      return;
 223.207 +}
 223.208 +
 223.209 +void lpx_set_col_name(LPX *lp, int j, const char *name)
 223.210 +{     /* assign (change) column name */
 223.211 +      glp_set_col_name(lp, j, name);
 223.212 +      return;
 223.213 +}
 223.214 +
 223.215 +void lpx_set_row_bnds(LPX *lp, int i, int type, double lb, double ub)
 223.216 +{     /* set (change) row bounds */
 223.217 +      glp_set_row_bnds(lp, i, type - LPX_FR + GLP_FR, lb, ub);
 223.218 +      return;
 223.219 +}
 223.220 +
 223.221 +void lpx_set_col_bnds(LPX *lp, int j, int type, double lb, double ub)
 223.222 +{     /* set (change) column bounds */
 223.223 +      glp_set_col_bnds(lp, j, type - LPX_FR + GLP_FR, lb, ub);
 223.224 +      return;
 223.225 +}
 223.226 +
 223.227 +void lpx_set_obj_coef(glp_prob *lp, int j, double coef)
 223.228 +{     /* set (change) obj. coefficient or constant term */
 223.229 +      glp_set_obj_coef(lp, j, coef);
 223.230 +      return;
 223.231 +}
 223.232 +
 223.233 +void lpx_set_mat_row(LPX *lp, int i, int len, const int ind[],
 223.234 +      const double val[])
 223.235 +{     /* set (replace) row of the constraint matrix */
 223.236 +      glp_set_mat_row(lp, i, len, ind, val);
 223.237 +      return;
 223.238 +}
 223.239 +
 223.240 +void lpx_set_mat_col(LPX *lp, int j, int len, const int ind[],
 223.241 +      const double val[])
 223.242 +{     /* set (replace) column of the constraint matrix */
 223.243 +      glp_set_mat_col(lp, j, len, ind, val);
 223.244 +      return;
 223.245 +}
 223.246 +
 223.247 +void lpx_load_matrix(LPX *lp, int ne, const int ia[], const int ja[],
 223.248 +      const double ar[])
 223.249 +{     /* load (replace) the whole constraint matrix */
 223.250 +      glp_load_matrix(lp, ne, ia, ja, ar);
 223.251 +      return;
 223.252 +}
 223.253 +
 223.254 +void lpx_del_rows(LPX *lp, int nrs, const int num[])
 223.255 +{     /* delete specified rows from problem object */
 223.256 +      glp_del_rows(lp, nrs, num);
 223.257 +      return;
 223.258 +}
 223.259 +
 223.260 +void lpx_del_cols(LPX *lp, int ncs, const int num[])
 223.261 +{     /* delete specified columns from problem object */
 223.262 +      glp_del_cols(lp, ncs, num);
 223.263 +      return;
 223.264 +}
 223.265 +
 223.266 +void lpx_delete_prob(LPX *lp)
 223.267 +{     /* delete problem object */
 223.268 +      glp_delete_prob(lp);
 223.269 +      return;
 223.270 +}
 223.271 +
 223.272 +const char *lpx_get_prob_name(LPX *lp)
 223.273 +{     /* retrieve problem name */
 223.274 +      return glp_get_prob_name(lp);
 223.275 +}
 223.276 +
 223.277 +const char *lpx_get_obj_name(LPX *lp)
 223.278 +{     /* retrieve objective function name */
 223.279 +      return glp_get_obj_name(lp);
 223.280 +}
 223.281 +
 223.282 +int lpx_get_obj_dir(LPX *lp)
 223.283 +{     /* retrieve optimization direction flag */
 223.284 +      return glp_get_obj_dir(lp) - GLP_MIN + LPX_MIN;
 223.285 +}
 223.286 +
 223.287 +int lpx_get_num_rows(LPX *lp)
 223.288 +{     /* retrieve number of rows */
 223.289 +      return glp_get_num_rows(lp);
 223.290 +}
 223.291 +
 223.292 +int lpx_get_num_cols(LPX *lp)
 223.293 +{     /* retrieve number of columns */
 223.294 +      return glp_get_num_cols(lp);
 223.295 +}
 223.296 +
 223.297 +const char *lpx_get_row_name(LPX *lp, int i)
 223.298 +{     /* retrieve row name */
 223.299 +      return glp_get_row_name(lp, i);
 223.300 +}
 223.301 +
 223.302 +const char *lpx_get_col_name(LPX *lp, int j)
 223.303 +{     /* retrieve column name */
 223.304 +      return glp_get_col_name(lp, j);
 223.305 +}
 223.306 +
 223.307 +int lpx_get_row_type(LPX *lp, int i)
 223.308 +{     /* retrieve row type */
 223.309 +      return glp_get_row_type(lp, i) - GLP_FR + LPX_FR;
 223.310 +}
 223.311 +
 223.312 +double lpx_get_row_lb(glp_prob *lp, int i)
 223.313 +{     /* retrieve row lower bound */
 223.314 +      double lb;
 223.315 +      lb = glp_get_row_lb(lp, i);
 223.316 +      if (lb == -DBL_MAX) lb = 0.0;
 223.317 +      return lb;
 223.318 +}
 223.319 +
 223.320 +double lpx_get_row_ub(glp_prob *lp, int i)
 223.321 +{     /* retrieve row upper bound */
 223.322 +      double ub;
 223.323 +      ub = glp_get_row_ub(lp, i);
 223.324 +      if (ub == +DBL_MAX) ub = 0.0;
 223.325 +      return ub;
 223.326 +}
 223.327 +
 223.328 +void lpx_get_row_bnds(glp_prob *lp, int i, int *typx, double *lb,
 223.329 +      double *ub)
 223.330 +{     /* retrieve row bounds */
 223.331 +      if (typx != NULL) *typx = lpx_get_row_type(lp, i);
 223.332 +      if (lb != NULL) *lb = lpx_get_row_lb(lp, i);
 223.333 +      if (ub != NULL) *ub = lpx_get_row_ub(lp, i);
 223.334 +      return;
 223.335 +}
 223.336 +
 223.337 +int lpx_get_col_type(LPX *lp, int j)
 223.338 +{     /* retrieve column type */
 223.339 +      return glp_get_col_type(lp, j) - GLP_FR + LPX_FR;
 223.340 +}
 223.341 +
 223.342 +double lpx_get_col_lb(glp_prob *lp, int j)
 223.343 +{     /* retrieve column lower bound */
 223.344 +      double lb;
 223.345 +      lb = glp_get_col_lb(lp, j);
 223.346 +      if (lb == -DBL_MAX) lb = 0.0;
 223.347 +      return lb;
 223.348 +}
 223.349 +
 223.350 +double lpx_get_col_ub(glp_prob *lp, int j)
 223.351 +{     /* retrieve column upper bound */
 223.352 +      double ub;
 223.353 +      ub = glp_get_col_ub(lp, j);
 223.354 +      if (ub == +DBL_MAX) ub = 0.0;
 223.355 +      return ub;
 223.356 +}
 223.357 +
 223.358 +void lpx_get_col_bnds(glp_prob *lp, int j, int *typx, double *lb,
 223.359 +      double *ub)
 223.360 +{     /* retrieve column bounds */
 223.361 +      if (typx != NULL) *typx = lpx_get_col_type(lp, j);
 223.362 +      if (lb != NULL) *lb = lpx_get_col_lb(lp, j);
 223.363 +      if (ub != NULL) *ub = lpx_get_col_ub(lp, j);
 223.364 +      return;
 223.365 +}
 223.366 +
 223.367 +double lpx_get_obj_coef(LPX *lp, int j)
 223.368 +{     /* retrieve obj. coefficient or constant term */
 223.369 +      return glp_get_obj_coef(lp, j);
 223.370 +}
 223.371 +
 223.372 +int lpx_get_num_nz(LPX *lp)
 223.373 +{     /* retrieve number of constraint coefficients */
 223.374 +      return glp_get_num_nz(lp);
 223.375 +}
 223.376 +
 223.377 +int lpx_get_mat_row(LPX *lp, int i, int ind[], double val[])
 223.378 +{     /* retrieve row of the constraint matrix */
 223.379 +      return glp_get_mat_row(lp, i, ind, val);
 223.380 +}
 223.381 +
 223.382 +int lpx_get_mat_col(LPX *lp, int j, int ind[], double val[])
 223.383 +{     /* retrieve column of the constraint matrix */
 223.384 +      return glp_get_mat_col(lp, j, ind, val);
 223.385 +}
 223.386 +
 223.387 +void lpx_create_index(LPX *lp)
 223.388 +{     /* create the name index */
 223.389 +      glp_create_index(lp);
 223.390 +      return;
 223.391 +}
 223.392 +
 223.393 +int lpx_find_row(LPX *lp, const char *name)
 223.394 +{     /* find row by its name */
 223.395 +      return glp_find_row(lp, name);
 223.396 +}
 223.397 +
 223.398 +int lpx_find_col(LPX *lp, const char *name)
 223.399 +{     /* find column by its name */
 223.400 +      return glp_find_col(lp, name);
 223.401 +}
 223.402 +
 223.403 +void lpx_delete_index(LPX *lp)
 223.404 +{     /* delete the name index */
 223.405 +      glp_delete_index(lp);
 223.406 +      return;
 223.407 +}
 223.408 +
 223.409 +void lpx_scale_prob(LPX *lp)
 223.410 +{     /* scale problem data */
 223.411 +      switch (lpx_get_int_parm(lp, LPX_K_SCALE))
 223.412 +      {  case 0:
 223.413 +            /* no scaling */
 223.414 +            glp_unscale_prob(lp);
 223.415 +            break;
 223.416 +         case 1:
 223.417 +            /* equilibration scaling */
 223.418 +            glp_scale_prob(lp, GLP_SF_EQ);
 223.419 +            break;
 223.420 +         case 2:
 223.421 +            /* geometric mean scaling */
 223.422 +            glp_scale_prob(lp, GLP_SF_GM);
 223.423 +            break;
 223.424 +         case 3:
 223.425 +            /* geometric mean scaling, then equilibration scaling */
 223.426 +            glp_scale_prob(lp, GLP_SF_GM | GLP_SF_EQ);
 223.427 +            break;
 223.428 +         default:
 223.429 +            xassert(lp != lp);
 223.430 +      }
 223.431 +      return;
 223.432 +}
 223.433 +
 223.434 +void lpx_unscale_prob(LPX *lp)
 223.435 +{     /* unscale problem data */
 223.436 +      glp_unscale_prob(lp);
 223.437 +      return;
 223.438 +}
 223.439 +
 223.440 +void lpx_set_row_stat(LPX *lp, int i, int stat)
 223.441 +{     /* set (change) row status */
 223.442 +      glp_set_row_stat(lp, i, stat - LPX_BS + GLP_BS);
 223.443 +      return;
 223.444 +}
 223.445 +
 223.446 +void lpx_set_col_stat(LPX *lp, int j, int stat)
 223.447 +{     /* set (change) column status */
 223.448 +      glp_set_col_stat(lp, j, stat - LPX_BS + GLP_BS);
 223.449 +      return;
 223.450 +}
 223.451 +
 223.452 +void lpx_std_basis(LPX *lp)
 223.453 +{     /* construct standard initial LP basis */
 223.454 +      glp_std_basis(lp);
 223.455 +      return;
 223.456 +}
 223.457 +
 223.458 +void lpx_adv_basis(LPX *lp)
 223.459 +{     /* construct advanced initial LP basis */
 223.460 +      glp_adv_basis(lp, 0);
 223.461 +      return;
 223.462 +}
 223.463 +
 223.464 +void lpx_cpx_basis(LPX *lp)
 223.465 +{     /* construct Bixby's initial LP basis */
 223.466 +      glp_cpx_basis(lp);
 223.467 +      return;
 223.468 +}
 223.469 +
 223.470 +static void fill_smcp(LPX *lp, glp_smcp *parm)
 223.471 +{     glp_init_smcp(parm);
 223.472 +      switch (lpx_get_int_parm(lp, LPX_K_MSGLEV))
 223.473 +      {  case 0:  parm->msg_lev = GLP_MSG_OFF;   break;
 223.474 +         case 1:  parm->msg_lev = GLP_MSG_ERR;   break;
 223.475 +         case 2:  parm->msg_lev = GLP_MSG_ON;    break;
 223.476 +         case 3:  parm->msg_lev = GLP_MSG_ALL;   break;
 223.477 +         default: xassert(lp != lp);
 223.478 +      }
 223.479 +      switch (lpx_get_int_parm(lp, LPX_K_DUAL))
 223.480 +      {  case 0:  parm->meth = GLP_PRIMAL;       break;
 223.481 +         case 1:  parm->meth = GLP_DUAL;         break;
 223.482 +         default: xassert(lp != lp);
 223.483 +      }
 223.484 +      switch (lpx_get_int_parm(lp, LPX_K_PRICE))
 223.485 +      {  case 0:  parm->pricing = GLP_PT_STD;    break;
 223.486 +         case 1:  parm->pricing = GLP_PT_PSE;    break;
 223.487 +         default: xassert(lp != lp);
 223.488 +      }
 223.489 +      if (lpx_get_real_parm(lp, LPX_K_RELAX) == 0.0)
 223.490 +         parm->r_test = GLP_RT_STD;
 223.491 +      else
 223.492 +         parm->r_test = GLP_RT_HAR;
 223.493 +      parm->tol_bnd = lpx_get_real_parm(lp, LPX_K_TOLBND);
 223.494 +      parm->tol_dj  = lpx_get_real_parm(lp, LPX_K_TOLDJ);
 223.495 +      parm->tol_piv = lpx_get_real_parm(lp, LPX_K_TOLPIV);
 223.496 +      parm->obj_ll  = lpx_get_real_parm(lp, LPX_K_OBJLL);
 223.497 +      parm->obj_ul  = lpx_get_real_parm(lp, LPX_K_OBJUL);
 223.498 +      if (lpx_get_int_parm(lp, LPX_K_ITLIM) < 0)
 223.499 +         parm->it_lim = INT_MAX;
 223.500 +      else
 223.501 +         parm->it_lim = lpx_get_int_parm(lp, LPX_K_ITLIM);
 223.502 +      if (lpx_get_real_parm(lp, LPX_K_TMLIM) < 0.0)
 223.503 +         parm->tm_lim = INT_MAX;
 223.504 +      else
 223.505 +         parm->tm_lim =
 223.506 +            (int)(1000.0 * lpx_get_real_parm(lp, LPX_K_TMLIM));
 223.507 +      parm->out_frq = lpx_get_int_parm(lp, LPX_K_OUTFRQ);
 223.508 +      parm->out_dly =
 223.509 +            (int)(1000.0 * lpx_get_real_parm(lp, LPX_K_OUTDLY));
 223.510 +      switch (lpx_get_int_parm(lp, LPX_K_PRESOL))
 223.511 +      {  case 0:  parm->presolve = GLP_OFF;      break;
 223.512 +         case 1:  parm->presolve = GLP_ON;       break;
 223.513 +         default: xassert(lp != lp);
 223.514 +      }
 223.515 +      return;
 223.516 +}
 223.517 +
 223.518 +int lpx_simplex(LPX *lp)
 223.519 +{     /* easy-to-use driver to the simplex method */
 223.520 +      glp_smcp parm;
 223.521 +      int ret;
 223.522 +      fill_smcp(lp, &parm);
 223.523 +      ret = glp_simplex(lp, &parm);
 223.524 +      switch (ret)
 223.525 +      {  case 0:           ret = LPX_E_OK;      break;
 223.526 +         case GLP_EBADB:
 223.527 +         case GLP_ESING:
 223.528 +         case GLP_ECOND:
 223.529 +         case GLP_EBOUND:  ret = LPX_E_FAULT;   break;
 223.530 +         case GLP_EFAIL:   ret = LPX_E_SING;    break;
 223.531 +         case GLP_EOBJLL:  ret = LPX_E_OBJLL;   break;
 223.532 +         case GLP_EOBJUL:  ret = LPX_E_OBJUL;   break;
 223.533 +         case GLP_EITLIM:  ret = LPX_E_ITLIM;   break;
 223.534 +         case GLP_ETMLIM:  ret = LPX_E_TMLIM;   break;
 223.535 +         case GLP_ENOPFS:  ret = LPX_E_NOPFS;   break;
 223.536 +         case GLP_ENODFS:  ret = LPX_E_NODFS;   break;
 223.537 +         default:          xassert(ret != ret);
 223.538 +      }
 223.539 +      return ret;
 223.540 +}
 223.541 +
 223.542 +int lpx_exact(LPX *lp)
 223.543 +{     /* easy-to-use driver to the exact simplex method */
 223.544 +      glp_smcp parm;
 223.545 +      int ret;
 223.546 +      fill_smcp(lp, &parm);
 223.547 +      ret = glp_exact(lp, &parm);
 223.548 +      switch (ret)
 223.549 +      {  case 0:           ret = LPX_E_OK;      break;
 223.550 +         case GLP_EBADB:
 223.551 +         case GLP_ESING:
 223.552 +         case GLP_EBOUND:
 223.553 +         case GLP_EFAIL:   ret = LPX_E_FAULT;   break;
 223.554 +         case GLP_EITLIM:  ret = LPX_E_ITLIM;   break;
 223.555 +         case GLP_ETMLIM:  ret = LPX_E_TMLIM;   break;
 223.556 +         default:          xassert(ret != ret);
 223.557 +      }
 223.558 +      return ret;
 223.559 +}
 223.560 +
 223.561 +int lpx_get_status(glp_prob *lp)
 223.562 +{     /* retrieve generic status of basic solution */
 223.563 +      int status;
 223.564 +      switch (glp_get_status(lp))
 223.565 +      {  case GLP_OPT:    status = LPX_OPT;    break;
 223.566 +         case GLP_FEAS:   status = LPX_FEAS;   break;
 223.567 +         case GLP_INFEAS: status = LPX_INFEAS; break;
 223.568 +         case GLP_NOFEAS: status = LPX_NOFEAS; break;
 223.569 +         case GLP_UNBND:  status = LPX_UNBND;  break;
 223.570 +         case GLP_UNDEF:  status = LPX_UNDEF;  break;
 223.571 +         default:         xassert(lp != lp);
 223.572 +      }
 223.573 +      return status;
 223.574 +}
 223.575 +
 223.576 +int lpx_get_prim_stat(glp_prob *lp)
 223.577 +{     /* retrieve status of primal basic solution */
 223.578 +      return glp_get_prim_stat(lp) - GLP_UNDEF + LPX_P_UNDEF;
 223.579 +}
 223.580 +
 223.581 +int lpx_get_dual_stat(glp_prob *lp)
 223.582 +{     /* retrieve status of dual basic solution */
 223.583 +      return glp_get_dual_stat(lp) - GLP_UNDEF + LPX_D_UNDEF;
 223.584 +}
 223.585 +
 223.586 +double lpx_get_obj_val(LPX *lp)
 223.587 +{     /* retrieve objective value (basic solution) */
 223.588 +      return glp_get_obj_val(lp);
 223.589 +}
 223.590 +
 223.591 +int lpx_get_row_stat(LPX *lp, int i)
 223.592 +{     /* retrieve row status (basic solution) */
 223.593 +      return glp_get_row_stat(lp, i) - GLP_BS + LPX_BS;
 223.594 +}
 223.595 +
 223.596 +double lpx_get_row_prim(LPX *lp, int i)
 223.597 +{     /* retrieve row primal value (basic solution) */
 223.598 +      return glp_get_row_prim(lp, i);
 223.599 +}
 223.600 +
 223.601 +double lpx_get_row_dual(LPX *lp, int i)
 223.602 +{     /* retrieve row dual value (basic solution) */
 223.603 +      return glp_get_row_dual(lp, i);
 223.604 +}
 223.605 +
 223.606 +void lpx_get_row_info(glp_prob *lp, int i, int *tagx, double *vx,
 223.607 +      double *dx)
 223.608 +{     /* obtain row solution information */
 223.609 +      if (tagx != NULL) *tagx = lpx_get_row_stat(lp, i);
 223.610 +      if (vx != NULL) *vx = lpx_get_row_prim(lp, i);
 223.611 +      if (dx != NULL) *dx = lpx_get_row_dual(lp, i);
 223.612 +      return;
 223.613 +}
 223.614 +
 223.615 +int lpx_get_col_stat(LPX *lp, int j)
 223.616 +{     /* retrieve column status (basic solution) */
 223.617 +      return glp_get_col_stat(lp, j) - GLP_BS + LPX_BS;
 223.618 +}
 223.619 +
 223.620 +double lpx_get_col_prim(LPX *lp, int j)
 223.621 +{     /* retrieve column primal value (basic solution) */
 223.622 +      return glp_get_col_prim(lp, j);
 223.623 +}
 223.624 +
 223.625 +double lpx_get_col_dual(glp_prob *lp, int j)
 223.626 +{     /* retrieve column dual value (basic solution) */
 223.627 +      return glp_get_col_dual(lp, j);
 223.628 +}
 223.629 +
 223.630 +void lpx_get_col_info(glp_prob *lp, int j, int *tagx, double *vx,
 223.631 +      double *dx)
 223.632 +{     /* obtain column solution information */
 223.633 +      if (tagx != NULL) *tagx = lpx_get_col_stat(lp, j);
 223.634 +      if (vx != NULL) *vx = lpx_get_col_prim(lp, j);
 223.635 +      if (dx != NULL) *dx = lpx_get_col_dual(lp, j);
 223.636 +      return;
 223.637 +}
 223.638 +
 223.639 +int lpx_get_ray_info(LPX *lp)
 223.640 +{     /* determine what causes primal unboundness */
 223.641 +      return glp_get_unbnd_ray(lp);
 223.642 +}
 223.643 +
 223.644 +void lpx_check_kkt(LPX *lp, int scaled, LPXKKT *kkt)
 223.645 +{     /* check Karush-Kuhn-Tucker conditions */
 223.646 +      int ae_ind, re_ind;
 223.647 +      double ae_max, re_max;
 223.648 +      xassert(scaled == scaled);
 223.649 +      _glp_check_kkt(lp, GLP_SOL, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
 223.650 +         &re_ind);
 223.651 +      kkt->pe_ae_max = ae_max;
 223.652 +      kkt->pe_ae_row = ae_ind;
 223.653 +      kkt->pe_re_max = re_max;
 223.654 +      kkt->pe_re_row = re_ind;
 223.655 +      if (re_max <= 1e-9)
 223.656 +         kkt->pe_quality = 'H';
 223.657 +      else if (re_max <= 1e-6)
 223.658 +         kkt->pe_quality = 'M';
 223.659 +      else if (re_max <= 1e-3)
 223.660 +         kkt->pe_quality = 'L';
 223.661 +      else
 223.662 +         kkt->pe_quality = '?';
 223.663 +      _glp_check_kkt(lp, GLP_SOL, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
 223.664 +         &re_ind);
 223.665 +      kkt->pb_ae_max = ae_max;
 223.666 +      kkt->pb_ae_ind = ae_ind;
 223.667 +      kkt->pb_re_max = re_max;
 223.668 +      kkt->pb_re_ind = re_ind;
 223.669 +      if (re_max <= 1e-9)
 223.670 +         kkt->pb_quality = 'H';
 223.671 +      else if (re_max <= 1e-6)
 223.672 +         kkt->pb_quality = 'M';
 223.673 +      else if (re_max <= 1e-3)
 223.674 +         kkt->pb_quality = 'L';
 223.675 +      else
 223.676 +         kkt->pb_quality = '?';
 223.677 +      _glp_check_kkt(lp, GLP_SOL, GLP_KKT_DE, &ae_max, &ae_ind, &re_max,
 223.678 +         &re_ind);
 223.679 +      kkt->de_ae_max = ae_max;
 223.680 +      if (ae_ind == 0)
 223.681 +         kkt->de_ae_col = 0;
 223.682 +      else
 223.683 +         kkt->de_ae_col = ae_ind - lp->m;
 223.684 +      kkt->de_re_max = re_max;
 223.685 +      if (re_ind == 0)
 223.686 +         kkt->de_re_col = 0;
 223.687 +      else
 223.688 +         kkt->de_re_col = ae_ind - lp->m;
 223.689 +      if (re_max <= 1e-9)
 223.690 +         kkt->de_quality = 'H';
 223.691 +      else if (re_max <= 1e-6)
 223.692 +         kkt->de_quality = 'M';
 223.693 +      else if (re_max <= 1e-3)
 223.694 +         kkt->de_quality = 'L';
 223.695 +      else
 223.696 +         kkt->de_quality = '?';
 223.697 +      _glp_check_kkt(lp, GLP_SOL, GLP_KKT_DB, &ae_max, &ae_ind, &re_max,
 223.698 +         &re_ind);
 223.699 +      kkt->db_ae_max = ae_max;
 223.700 +      kkt->db_ae_ind = ae_ind;
 223.701 +      kkt->db_re_max = re_max;
 223.702 +      kkt->db_re_ind = re_ind;
 223.703 +      if (re_max <= 1e-9)
 223.704 +         kkt->db_quality = 'H';
 223.705 +      else if (re_max <= 1e-6)
 223.706 +         kkt->db_quality = 'M';
 223.707 +      else if (re_max <= 1e-3)
 223.708 +         kkt->db_quality = 'L';
 223.709 +      else
 223.710 +         kkt->db_quality = '?';
 223.711 +      kkt->cs_ae_max = 0.0, kkt->cs_ae_ind = 0;
 223.712 +      kkt->cs_re_max = 0.0, kkt->cs_re_ind = 0;
 223.713 +      kkt->cs_quality = 'H';
 223.714 +      return;
 223.715 +}
 223.716 +
 223.717 +int lpx_warm_up(LPX *lp)
 223.718 +{     /* "warm up" LP basis */
 223.719 +      int ret;
 223.720 +      ret = glp_warm_up(lp);
 223.721 +      if (ret == 0)
 223.722 +         ret = LPX_E_OK;
 223.723 +      else if (ret == GLP_EBADB)
 223.724 +         ret = LPX_E_BADB;
 223.725 +      else if (ret == GLP_ESING)
 223.726 +         ret = LPX_E_SING;
 223.727 +      else if (ret == GLP_ECOND)
 223.728 +         ret = LPX_E_SING;
 223.729 +      else
 223.730 +         xassert(ret != ret);
 223.731 +      return ret;
 223.732 +}
 223.733 +
 223.734 +int lpx_eval_tab_row(LPX *lp, int k, int ind[], double val[])
 223.735 +{     /* compute row of the simplex tableau */
 223.736 +      return glp_eval_tab_row(lp, k, ind, val);
 223.737 +}
 223.738 +
 223.739 +int lpx_eval_tab_col(LPX *lp, int k, int ind[], double val[])
 223.740 +{     /* compute column of the simplex tableau */
 223.741 +      return glp_eval_tab_col(lp, k, ind, val);
 223.742 +}
 223.743 +
 223.744 +int lpx_transform_row(LPX *lp, int len, int ind[], double val[])
 223.745 +{     /* transform explicitly specified row */
 223.746 +      return glp_transform_row(lp, len, ind, val);
 223.747 +}
 223.748 +
 223.749 +int lpx_transform_col(LPX *lp, int len, int ind[], double val[])
 223.750 +{     /* transform explicitly specified column */
 223.751 +      return glp_transform_col(lp, len, ind, val);
 223.752 +}
 223.753 +
 223.754 +int lpx_prim_ratio_test(LPX *lp, int len, const int ind[],
 223.755 +      const double val[], int how, double tol)
 223.756 +{     /* perform primal ratio test */
 223.757 +      int piv;
 223.758 +      piv = glp_prim_rtest(lp, len, ind, val, how, tol);
 223.759 +      xassert(0 <= piv && piv <= len);
 223.760 +      return piv == 0 ? 0 : ind[piv];
 223.761 +}
 223.762 +
 223.763 +int lpx_dual_ratio_test(LPX *lp, int len, const int ind[],
 223.764 +      const double val[], int how, double tol)
 223.765 +{     /* perform dual ratio test */
 223.766 +      int piv;
 223.767 +      piv = glp_dual_rtest(lp, len, ind, val, how, tol);
 223.768 +      xassert(0 <= piv && piv <= len);
 223.769 +      return piv == 0 ? 0 : ind[piv];
 223.770 +}
 223.771 +
 223.772 +int lpx_interior(LPX *lp)
 223.773 +{     /* easy-to-use driver to the interior-point method */
 223.774 +      int ret;
 223.775 +      ret = glp_interior(lp, NULL);
 223.776 +      switch (ret)
 223.777 +      {  case 0:           ret = LPX_E_OK;      break;
 223.778 +         case GLP_EFAIL:   ret = LPX_E_FAULT;   break;
 223.779 +         case GLP_ENOFEAS: ret = LPX_E_NOFEAS;  break;
 223.780 +         case GLP_ENOCVG:  ret = LPX_E_NOCONV;  break;
 223.781 +         case GLP_EITLIM:  ret = LPX_E_ITLIM;   break;
 223.782 +         case GLP_EINSTAB: ret = LPX_E_INSTAB;  break;
 223.783 +         default:          xassert(ret != ret);
 223.784 +      }
 223.785 +      return ret;
 223.786 +}
 223.787 +
 223.788 +int lpx_ipt_status(glp_prob *lp)
 223.789 +{     /* retrieve status of interior-point solution */
 223.790 +      int status;
 223.791 +      switch (glp_ipt_status(lp))
 223.792 +      {  case GLP_UNDEF:  status = LPX_T_UNDEF;  break;
 223.793 +         case GLP_OPT:    status = LPX_T_OPT;    break;
 223.794 +         default:         xassert(lp != lp);
 223.795 +      }
 223.796 +      return status;
 223.797 +}
 223.798 +
 223.799 +double lpx_ipt_obj_val(LPX *lp)
 223.800 +{     /* retrieve objective value (interior point) */
 223.801 +      return glp_ipt_obj_val(lp);
 223.802 +}
 223.803 +
 223.804 +double lpx_ipt_row_prim(LPX *lp, int i)
 223.805 +{     /* retrieve row primal value (interior point) */
 223.806 +      return glp_ipt_row_prim(lp, i);
 223.807 +}
 223.808 +
 223.809 +double lpx_ipt_row_dual(LPX *lp, int i)
 223.810 +{     /* retrieve row dual value (interior point) */
 223.811 +      return glp_ipt_row_dual(lp, i);
 223.812 +}
 223.813 +
 223.814 +double lpx_ipt_col_prim(LPX *lp, int j)
 223.815 +{     /* retrieve column primal value (interior point) */
 223.816 +      return glp_ipt_col_prim(lp, j);
 223.817 +}
 223.818 +
 223.819 +double lpx_ipt_col_dual(LPX *lp, int j)
 223.820 +{     /* retrieve column dual value (interior point) */
 223.821 +      return glp_ipt_col_dual(lp, j);
 223.822 +}
 223.823 +
 223.824 +void lpx_set_class(LPX *lp, int klass)
 223.825 +{     /* set problem class */
 223.826 +      xassert(lp == lp);
 223.827 +      if (!(klass == LPX_LP || klass == LPX_MIP))
 223.828 +         xerror("lpx_set_class: invalid problem class\n");
 223.829 +      return;
 223.830 +}
 223.831 +
 223.832 +int lpx_get_class(LPX *lp)
 223.833 +{     /* determine problem klass */
 223.834 +      return glp_get_num_int(lp) == 0 ? LPX_LP : LPX_MIP;
 223.835 +}
 223.836 +
 223.837 +void lpx_set_col_kind(LPX *lp, int j, int kind)
 223.838 +{     /* set (change) column kind */
 223.839 +      glp_set_col_kind(lp, j, kind - LPX_CV + GLP_CV);
 223.840 +      return;
 223.841 +}
 223.842 +
 223.843 +int lpx_get_col_kind(LPX *lp, int j)
 223.844 +{     /* retrieve column kind */
 223.845 +      return glp_get_col_kind(lp, j) == GLP_CV ? LPX_CV : LPX_IV;
 223.846 +}
 223.847 +
 223.848 +int lpx_get_num_int(LPX *lp)
 223.849 +{     /* retrieve number of integer columns */
 223.850 +      return glp_get_num_int(lp);
 223.851 +}
 223.852 +
 223.853 +int lpx_get_num_bin(LPX *lp)
 223.854 +{     /* retrieve number of binary columns */
 223.855 +      return glp_get_num_bin(lp);
 223.856 +}
 223.857 +
 223.858 +static int solve_mip(LPX *lp, int presolve)
 223.859 +{     glp_iocp parm;
 223.860 +      int ret;
 223.861 +      glp_init_iocp(&parm);
 223.862 +      switch (lpx_get_int_parm(lp, LPX_K_MSGLEV))
 223.863 +      {  case 0:  parm.msg_lev = GLP_MSG_OFF;   break;
 223.864 +         case 1:  parm.msg_lev = GLP_MSG_ERR;   break;
 223.865 +         case 2:  parm.msg_lev = GLP_MSG_ON;    break;
 223.866 +         case 3:  parm.msg_lev = GLP_MSG_ALL;   break;
 223.867 +         default: xassert(lp != lp);
 223.868 +      }
 223.869 +      switch (lpx_get_int_parm(lp, LPX_K_BRANCH))
 223.870 +      {  case 0:  parm.br_tech = GLP_BR_FFV;    break;
 223.871 +         case 1:  parm.br_tech = GLP_BR_LFV;    break;
 223.872 +         case 2:  parm.br_tech = GLP_BR_DTH;    break;
 223.873 +         case 3:  parm.br_tech = GLP_BR_MFV;    break;
 223.874 +         default: xassert(lp != lp);
 223.875 +      }
 223.876 +      switch (lpx_get_int_parm(lp, LPX_K_BTRACK))
 223.877 +      {  case 0:  parm.bt_tech = GLP_BT_DFS;    break;
 223.878 +         case 1:  parm.bt_tech = GLP_BT_BFS;    break;
 223.879 +         case 2:  parm.bt_tech = GLP_BT_BPH;    break;
 223.880 +         case 3:  parm.bt_tech = GLP_BT_BLB;    break;
 223.881 +         default: xassert(lp != lp);
 223.882 +      }
 223.883 +      parm.tol_int = lpx_get_real_parm(lp, LPX_K_TOLINT);
 223.884 +      parm.tol_obj = lpx_get_real_parm(lp, LPX_K_TOLOBJ);
 223.885 +      if (lpx_get_real_parm(lp, LPX_K_TMLIM) < 0.0 ||
 223.886 +          lpx_get_real_parm(lp, LPX_K_TMLIM) > 1e6)
 223.887 +         parm.tm_lim = INT_MAX;
 223.888 +      else
 223.889 +         parm.tm_lim =
 223.890 +            (int)(1000.0 * lpx_get_real_parm(lp, LPX_K_TMLIM));
 223.891 +      parm.mip_gap = lpx_get_real_parm(lp, LPX_K_MIPGAP);
 223.892 +      if (lpx_get_int_parm(lp, LPX_K_USECUTS) & LPX_C_GOMORY)
 223.893 +         parm.gmi_cuts = GLP_ON;
 223.894 +      else
 223.895 +         parm.gmi_cuts = GLP_OFF;
 223.896 +      if (lpx_get_int_parm(lp, LPX_K_USECUTS) & LPX_C_MIR)
 223.897 +         parm.mir_cuts = GLP_ON;
 223.898 +      else
 223.899 +         parm.mir_cuts = GLP_OFF;
 223.900 +      if (lpx_get_int_parm(lp, LPX_K_USECUTS) & LPX_C_COVER)
 223.901 +         parm.cov_cuts = GLP_ON;
 223.902 +      else
 223.903 +         parm.cov_cuts = GLP_OFF;
 223.904 +      if (lpx_get_int_parm(lp, LPX_K_USECUTS) & LPX_C_CLIQUE)
 223.905 +         parm.clq_cuts = GLP_ON;
 223.906 +      else
 223.907 +         parm.clq_cuts = GLP_OFF;
 223.908 +      parm.presolve = presolve;
 223.909 +      if (lpx_get_int_parm(lp, LPX_K_BINARIZE))
 223.910 +         parm.binarize = GLP_ON;
 223.911 +      ret = glp_intopt(lp, &parm);
 223.912 +      switch (ret)
 223.913 +      {  case 0:           ret = LPX_E_OK;      break;
 223.914 +         case GLP_ENOPFS:  ret = LPX_E_NOPFS;   break;
 223.915 +         case GLP_ENODFS:  ret = LPX_E_NODFS;   break;
 223.916 +         case GLP_EBOUND:
 223.917 +         case GLP_EROOT:   ret = LPX_E_FAULT;   break;
 223.918 +         case GLP_EFAIL:   ret = LPX_E_SING;    break;
 223.919 +         case GLP_EMIPGAP: ret = LPX_E_MIPGAP;  break;
 223.920 +         case GLP_ETMLIM:  ret = LPX_E_TMLIM;   break;
 223.921 +         default:          xassert(ret != ret);
 223.922 +      }
 223.923 +      return ret;
 223.924 +}
 223.925 +
 223.926 +int lpx_integer(LPX *lp)
 223.927 +{     /* easy-to-use driver to the branch-and-bound method */
 223.928 +      return solve_mip(lp, GLP_OFF);
 223.929 +}
 223.930 +
 223.931 +int lpx_intopt(LPX *lp)
 223.932 +{     /* easy-to-use driver to the branch-and-bound method */
 223.933 +      return solve_mip(lp, GLP_ON);
 223.934 +}
 223.935 +
 223.936 +int lpx_mip_status(glp_prob *lp)
 223.937 +{     /* retrieve status of MIP solution */
 223.938 +      int status;
 223.939 +      switch (glp_mip_status(lp))
 223.940 +      {  case GLP_UNDEF:  status = LPX_I_UNDEF;  break;
 223.941 +         case GLP_OPT:    status = LPX_I_OPT;    break;
 223.942 +         case GLP_FEAS:   status = LPX_I_FEAS;   break;
 223.943 +         case GLP_NOFEAS: status = LPX_I_NOFEAS; break;
 223.944 +         default:         xassert(lp != lp);
 223.945 +      }
 223.946 +      return status;
 223.947 +}
 223.948 +
 223.949 +double lpx_mip_obj_val(LPX *lp)
 223.950 +{     /* retrieve objective value (MIP solution) */
 223.951 +      return glp_mip_obj_val(lp);
 223.952 +}
 223.953 +
 223.954 +double lpx_mip_row_val(LPX *lp, int i)
 223.955 +{     /* retrieve row value (MIP solution) */
 223.956 +      return glp_mip_row_val(lp, i);
 223.957 +}
 223.958 +
 223.959 +double lpx_mip_col_val(LPX *lp, int j)
 223.960 +{     /* retrieve column value (MIP solution) */
 223.961 +      return glp_mip_col_val(lp, j);
 223.962 +}
 223.963 +
 223.964 +void lpx_check_int(LPX *lp, LPXKKT *kkt)
 223.965 +{     /* check integer feasibility conditions */
 223.966 +      int ae_ind, re_ind;
 223.967 +      double ae_max, re_max;
 223.968 +      _glp_check_kkt(lp, GLP_MIP, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
 223.969 +         &re_ind);
 223.970 +      kkt->pe_ae_max = ae_max;
 223.971 +      kkt->pe_ae_row = ae_ind;
 223.972 +      kkt->pe_re_max = re_max;
 223.973 +      kkt->pe_re_row = re_ind;
 223.974 +      if (re_max <= 1e-9)
 223.975 +         kkt->pe_quality = 'H';
 223.976 +      else if (re_max <= 1e-6)
 223.977 +         kkt->pe_quality = 'M';
 223.978 +      else if (re_max <= 1e-3)
 223.979 +         kkt->pe_quality = 'L';
 223.980 +      else
 223.981 +         kkt->pe_quality = '?';
 223.982 +      _glp_check_kkt(lp, GLP_MIP, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
 223.983 +         &re_ind);
 223.984 +      kkt->pb_ae_max = ae_max;
 223.985 +      kkt->pb_ae_ind = ae_ind;
 223.986 +      kkt->pb_re_max = re_max;
 223.987 +      kkt->pb_re_ind = re_ind;
 223.988 +      if (re_max <= 1e-9)
 223.989 +         kkt->pb_quality = 'H';
 223.990 +      else if (re_max <= 1e-6)
 223.991 +         kkt->pb_quality = 'M';
 223.992 +      else if (re_max <= 1e-3)
 223.993 +         kkt->pb_quality = 'L';
 223.994 +      else
 223.995 +         kkt->pb_quality = '?';
 223.996 +      return;
 223.997 +}
 223.998 +
 223.999 +#if 1 /* 17/XI-2009 */
223.1000 +static void reset_parms(LPX *lp)
223.1001 +{     /* reset control parameters to default values */
223.1002 +      struct LPXCPS *cps = lp->parms;
223.1003 +      xassert(cps != NULL);
223.1004 +      cps->msg_lev  = 3;
223.1005 +      cps->scale    = 1;
223.1006 +      cps->dual     = 0;
223.1007 +      cps->price    = 1;
223.1008 +      cps->relax    = 0.07;
223.1009 +      cps->tol_bnd  = 1e-7;
223.1010 +      cps->tol_dj   = 1e-7;
223.1011 +      cps->tol_piv  = 1e-9;
223.1012 +      cps->round    = 0;
223.1013 +      cps->obj_ll   = -DBL_MAX;
223.1014 +      cps->obj_ul   = +DBL_MAX;
223.1015 +      cps->it_lim   = -1;
223.1016 +#if 0 /* 02/XII-2010 */
223.1017 +      lp->it_cnt   = 0;
223.1018 +#endif
223.1019 +      cps->tm_lim   = -1.0;
223.1020 +      cps->out_frq  = 200;
223.1021 +      cps->out_dly  = 0.0;
223.1022 +      cps->branch   = 2;
223.1023 +      cps->btrack   = 3;
223.1024 +      cps->tol_int  = 1e-5;
223.1025 +      cps->tol_obj  = 1e-7;
223.1026 +      cps->mps_info = 1;
223.1027 +      cps->mps_obj  = 2;
223.1028 +      cps->mps_orig = 0;
223.1029 +      cps->mps_wide = 1;
223.1030 +      cps->mps_free = 0;
223.1031 +      cps->mps_skip = 0;
223.1032 +      cps->lpt_orig = 0;
223.1033 +      cps->presol = 0;
223.1034 +      cps->binarize = 0;
223.1035 +      cps->use_cuts = 0;
223.1036 +      cps->mip_gap = 0.0;
223.1037 +      return;
223.1038 +}
223.1039 +#endif
223.1040 +
223.1041 +#if 1 /* 17/XI-2009 */
223.1042 +static struct LPXCPS *access_parms(LPX *lp)
223.1043 +{     /* allocate and initialize control parameters, if necessary */
223.1044 +      if (lp->parms == NULL)
223.1045 +      {  lp->parms = xmalloc(sizeof(struct LPXCPS));
223.1046 +         reset_parms(lp);
223.1047 +      }
223.1048 +      return lp->parms;
223.1049 +}
223.1050 +#endif
223.1051 +
223.1052 +#if 1 /* 17/XI-2009 */
223.1053 +void lpx_reset_parms(LPX *lp)
223.1054 +{     /* reset control parameters to default values */
223.1055 +      access_parms(lp);
223.1056 +      reset_parms(lp);
223.1057 +      return;
223.1058 +}
223.1059 +#endif
223.1060 +
223.1061 +void lpx_set_int_parm(LPX *lp, int parm, int val)
223.1062 +{     /* set (change) integer control parameter */
223.1063 +#if 0 /* 17/XI-2009 */
223.1064 +      struct LPXCPS *cps = lp->cps;
223.1065 +#else
223.1066 +      struct LPXCPS *cps = access_parms(lp);
223.1067 +#endif
223.1068 +      switch (parm)
223.1069 +      {  case LPX_K_MSGLEV:
223.1070 +            if (!(0 <= val && val <= 3))
223.1071 +               xerror("lpx_set_int_parm: MSGLEV = %d; invalid value\n",
223.1072 +                  val);
223.1073 +            cps->msg_lev = val;
223.1074 +            break;
223.1075 +         case LPX_K_SCALE:
223.1076 +            if (!(0 <= val && val <= 3))
223.1077 +               xerror("lpx_set_int_parm: SCALE = %d; invalid value\n",
223.1078 +                  val);
223.1079 +            cps->scale = val;
223.1080 +            break;
223.1081 +         case LPX_K_DUAL:
223.1082 +            if (!(val == 0 || val == 1))
223.1083 +               xerror("lpx_set_int_parm: DUAL = %d; invalid value\n",
223.1084 +                  val);
223.1085 +            cps->dual = val;
223.1086 +            break;
223.1087 +         case LPX_K_PRICE:
223.1088 +            if (!(val == 0 || val == 1))
223.1089 +               xerror("lpx_set_int_parm: PRICE = %d; invalid value\n",
223.1090 +                  val);
223.1091 +            cps->price = val;
223.1092 +            break;
223.1093 +         case LPX_K_ROUND:
223.1094 +            if (!(val == 0 || val == 1))
223.1095 +               xerror("lpx_set_int_parm: ROUND = %d; invalid value\n",
223.1096 +                  val);
223.1097 +            cps->round = val;
223.1098 +            break;
223.1099 +         case LPX_K_ITLIM:
223.1100 +            cps->it_lim = val;
223.1101 +            break;
223.1102 +         case LPX_K_ITCNT:
223.1103 +            lp->it_cnt = val;
223.1104 +            break;
223.1105 +         case LPX_K_OUTFRQ:
223.1106 +            if (!(val > 0))
223.1107 +               xerror("lpx_set_int_parm: OUTFRQ = %d; invalid value\n",
223.1108 +                  val);
223.1109 +            cps->out_frq = val;
223.1110 +            break;
223.1111 +         case LPX_K_BRANCH:
223.1112 +            if (!(val == 0 || val == 1 || val == 2 || val == 3))
223.1113 +               xerror("lpx_set_int_parm: BRANCH = %d; invalid value\n",
223.1114 +                  val);
223.1115 +            cps->branch = val;
223.1116 +            break;
223.1117 +         case LPX_K_BTRACK:
223.1118 +            if (!(val == 0 || val == 1 || val == 2 || val == 3))
223.1119 +               xerror("lpx_set_int_parm: BTRACK = %d; invalid value\n",
223.1120 +                  val);
223.1121 +            cps->btrack = val;
223.1122 +            break;
223.1123 +         case LPX_K_MPSINFO:
223.1124 +            if (!(val == 0 || val == 1))
223.1125 +               xerror("lpx_set_int_parm: MPSINFO = %d; invalid value\n",
223.1126 +                  val);
223.1127 +            cps->mps_info = val;
223.1128 +            break;
223.1129 +         case LPX_K_MPSOBJ:
223.1130 +            if (!(val == 0 || val == 1 || val == 2))
223.1131 +               xerror("lpx_set_int_parm: MPSOBJ = %d; invalid value\n",
223.1132 +                  val);
223.1133 +            cps->mps_obj = val;
223.1134 +            break;
223.1135 +         case LPX_K_MPSORIG:
223.1136 +            if (!(val == 0 || val == 1))
223.1137 +               xerror("lpx_set_int_parm: MPSORIG = %d; invalid value\n",
223.1138 +                  val);
223.1139 +            cps->mps_orig = val;
223.1140 +            break;
223.1141 +         case LPX_K_MPSWIDE:
223.1142 +            if (!(val == 0 || val == 1))
223.1143 +               xerror("lpx_set_int_parm: MPSWIDE = %d; invalid value\n",
223.1144 +                  val);
223.1145 +            cps->mps_wide = val;
223.1146 +            break;
223.1147 +         case LPX_K_MPSFREE:
223.1148 +            if (!(val == 0 || val == 1))
223.1149 +               xerror("lpx_set_int_parm: MPSFREE = %d; invalid value\n",
223.1150 +                  val);
223.1151 +            cps->mps_free = val;
223.1152 +            break;
223.1153 +         case LPX_K_MPSSKIP:
223.1154 +            if (!(val == 0 || val == 1))
223.1155 +               xerror("lpx_set_int_parm: MPSSKIP = %d; invalid value\n",
223.1156 +                  val);
223.1157 +            cps->mps_skip = val;
223.1158 +            break;
223.1159 +         case LPX_K_LPTORIG:
223.1160 +            if (!(val == 0 || val == 1))
223.1161 +               xerror("lpx_set_int_parm: LPTORIG = %d; invalid value\n",
223.1162 +                  val);
223.1163 +            cps->lpt_orig = val;
223.1164 +            break;
223.1165 +         case LPX_K_PRESOL:
223.1166 +            if (!(val == 0 || val == 1))
223.1167 +               xerror("lpx_set_int_parm: PRESOL = %d; invalid value\n",
223.1168 +                  val);
223.1169 +            cps->presol = val;
223.1170 +            break;
223.1171 +         case LPX_K_BINARIZE:
223.1172 +            if (!(val == 0 || val == 1))
223.1173 +               xerror("lpx_set_int_parm: BINARIZE = %d; invalid value\n"
223.1174 +                  , val);
223.1175 +            cps->binarize = val;
223.1176 +            break;
223.1177 +         case LPX_K_USECUTS:
223.1178 +            if (val & ~LPX_C_ALL)
223.1179 +            xerror("lpx_set_int_parm: USECUTS = 0x%X; invalid value\n",
223.1180 +                  val);
223.1181 +            cps->use_cuts = val;
223.1182 +            break;
223.1183 +         case LPX_K_BFTYPE:
223.1184 +#if 0
223.1185 +            if (!(1 <= val && val <= 3))
223.1186 +               xerror("lpx_set_int_parm: BFTYPE = %d; invalid value\n",
223.1187 +                  val);
223.1188 +            cps->bf_type = val;
223.1189 +#else
223.1190 +            {  glp_bfcp parm;
223.1191 +               glp_get_bfcp(lp, &parm);
223.1192 +               switch (val)
223.1193 +               {  case 1:
223.1194 +                     parm.type = GLP_BF_FT; break;
223.1195 +                  case 2:
223.1196 +                     parm.type = GLP_BF_BG; break;
223.1197 +                  case 3:
223.1198 +                     parm.type = GLP_BF_GR; break;
223.1199 +                  default:
223.1200 +                     xerror("lpx_set_int_parm: BFTYPE = %d; invalid val"
223.1201 +                        "ue\n", val);
223.1202 +               }
223.1203 +               glp_set_bfcp(lp, &parm);
223.1204 +            }
223.1205 +#endif
223.1206 +            break;
223.1207 +         default:
223.1208 +            xerror("lpx_set_int_parm: parm = %d; invalid parameter\n",
223.1209 +               parm);
223.1210 +      }
223.1211 +      return;
223.1212 +}
223.1213 +
223.1214 +int lpx_get_int_parm(LPX *lp, int parm)
223.1215 +{     /* query integer control parameter */
223.1216 +#if 0 /* 17/XI-2009 */
223.1217 +      struct LPXCPS *cps = lp->cps;
223.1218 +#else
223.1219 +      struct LPXCPS *cps = access_parms(lp);
223.1220 +#endif
223.1221 +      int val = 0;
223.1222 +      switch (parm)
223.1223 +      {  case LPX_K_MSGLEV:
223.1224 +            val = cps->msg_lev; break;
223.1225 +         case LPX_K_SCALE:
223.1226 +            val = cps->scale; break;
223.1227 +         case LPX_K_DUAL:
223.1228 +            val = cps->dual; break;
223.1229 +         case LPX_K_PRICE:
223.1230 +            val = cps->price; break;
223.1231 +         case LPX_K_ROUND:
223.1232 +            val = cps->round; break;
223.1233 +         case LPX_K_ITLIM:
223.1234 +            val = cps->it_lim; break;
223.1235 +         case LPX_K_ITCNT:
223.1236 +            val = lp->it_cnt; break;
223.1237 +         case LPX_K_OUTFRQ:
223.1238 +            val = cps->out_frq; break;
223.1239 +         case LPX_K_BRANCH:
223.1240 +            val = cps->branch; break;
223.1241 +         case LPX_K_BTRACK:
223.1242 +            val = cps->btrack; break;
223.1243 +         case LPX_K_MPSINFO:
223.1244 +            val = cps->mps_info; break;
223.1245 +         case LPX_K_MPSOBJ:
223.1246 +            val = cps->mps_obj; break;
223.1247 +         case LPX_K_MPSORIG:
223.1248 +            val = cps->mps_orig; break;
223.1249 +         case LPX_K_MPSWIDE:
223.1250 +            val = cps->mps_wide; break;
223.1251 +         case LPX_K_MPSFREE:
223.1252 +            val = cps->mps_free; break;
223.1253 +         case LPX_K_MPSSKIP:
223.1254 +            val = cps->mps_skip; break;
223.1255 +         case LPX_K_LPTORIG:
223.1256 +            val = cps->lpt_orig; break;
223.1257 +         case LPX_K_PRESOL:
223.1258 +            val = cps->presol; break;
223.1259 +         case LPX_K_BINARIZE:
223.1260 +            val = cps->binarize; break;
223.1261 +         case LPX_K_USECUTS:
223.1262 +            val = cps->use_cuts; break;
223.1263 +         case LPX_K_BFTYPE:
223.1264 +#if 0
223.1265 +            val = cps->bf_type; break;
223.1266 +#else
223.1267 +            {  glp_bfcp parm;
223.1268 +               glp_get_bfcp(lp, &parm);
223.1269 +               switch (parm.type)
223.1270 +               {  case GLP_BF_FT:
223.1271 +                     val = 1; break;
223.1272 +                  case GLP_BF_BG:
223.1273 +                     val = 2; break;
223.1274 +                  case GLP_BF_GR:
223.1275 +                     val = 3; break;
223.1276 +                  default:
223.1277 +                     xassert(lp != lp);
223.1278 +               }
223.1279 +            }
223.1280 +            break;
223.1281 +#endif
223.1282 +         default:
223.1283 +            xerror("lpx_get_int_parm: parm = %d; invalid parameter\n",
223.1284 +               parm);
223.1285 +      }
223.1286 +      return val;
223.1287 +}
223.1288 +
223.1289 +void lpx_set_real_parm(LPX *lp, int parm, double val)
223.1290 +{     /* set (change) real control parameter */
223.1291 +#if 0 /* 17/XI-2009 */
223.1292 +      struct LPXCPS *cps = lp->cps;
223.1293 +#else
223.1294 +      struct LPXCPS *cps = access_parms(lp);
223.1295 +#endif
223.1296 +      switch (parm)
223.1297 +      {  case LPX_K_RELAX:
223.1298 +            if (!(0.0 <= val && val <= 1.0))
223.1299 +               xerror("lpx_set_real_parm: RELAX = %g; invalid value\n",
223.1300 +                  val);
223.1301 +            cps->relax = val;
223.1302 +            break;
223.1303 +         case LPX_K_TOLBND:
223.1304 +            if (!(DBL_EPSILON <= val && val <= 0.001))
223.1305 +               xerror("lpx_set_real_parm: TOLBND = %g; invalid value\n",
223.1306 +                  val);
223.1307 +#if 0
223.1308 +            if (cps->tol_bnd > val)
223.1309 +            {  /* invalidate the basic solution */
223.1310 +               lp->p_stat = LPX_P_UNDEF;
223.1311 +               lp->d_stat = LPX_D_UNDEF;
223.1312 +            }
223.1313 +#endif
223.1314 +            cps->tol_bnd = val;
223.1315 +            break;
223.1316 +         case LPX_K_TOLDJ:
223.1317 +            if (!(DBL_EPSILON <= val && val <= 0.001))
223.1318 +               xerror("lpx_set_real_parm: TOLDJ = %g; invalid value\n",
223.1319 +                  val);
223.1320 +#if 0
223.1321 +            if (cps->tol_dj > val)
223.1322 +            {  /* invalidate the basic solution */
223.1323 +               lp->p_stat = LPX_P_UNDEF;
223.1324 +               lp->d_stat = LPX_D_UNDEF;
223.1325 +            }
223.1326 +#endif
223.1327 +            cps->tol_dj = val;
223.1328 +            break;
223.1329 +         case LPX_K_TOLPIV:
223.1330 +            if (!(DBL_EPSILON <= val && val <= 0.001))
223.1331 +               xerror("lpx_set_real_parm: TOLPIV = %g; invalid value\n",
223.1332 +                  val);
223.1333 +            cps->tol_piv = val;
223.1334 +            break;
223.1335 +         case LPX_K_OBJLL:
223.1336 +            cps->obj_ll = val;
223.1337 +            break;
223.1338 +         case LPX_K_OBJUL:
223.1339 +            cps->obj_ul = val;
223.1340 +            break;
223.1341 +         case LPX_K_TMLIM:
223.1342 +            cps->tm_lim = val;
223.1343 +            break;
223.1344 +         case LPX_K_OUTDLY:
223.1345 +            cps->out_dly = val;
223.1346 +            break;
223.1347 +         case LPX_K_TOLINT:
223.1348 +            if (!(DBL_EPSILON <= val && val <= 0.001))
223.1349 +               xerror("lpx_set_real_parm: TOLINT = %g; invalid value\n",
223.1350 +                  val);
223.1351 +            cps->tol_int = val;
223.1352 +            break;
223.1353 +         case LPX_K_TOLOBJ:
223.1354 +            if (!(DBL_EPSILON <= val && val <= 0.001))
223.1355 +               xerror("lpx_set_real_parm: TOLOBJ = %g; invalid value\n",
223.1356 +                  val);
223.1357 +            cps->tol_obj = val;
223.1358 +            break;
223.1359 +         case LPX_K_MIPGAP:
223.1360 +            if (val < 0.0)
223.1361 +               xerror("lpx_set_real_parm: MIPGAP = %g; invalid value\n",
223.1362 +                  val);
223.1363 +            cps->mip_gap = val;
223.1364 +            break;
223.1365 +         default:
223.1366 +            xerror("lpx_set_real_parm: parm = %d; invalid parameter\n",
223.1367 +               parm);
223.1368 +      }
223.1369 +      return;
223.1370 +}
223.1371 +
223.1372 +double lpx_get_real_parm(LPX *lp, int parm)
223.1373 +{     /* query real control parameter */
223.1374 +#if 0 /* 17/XI-2009 */
223.1375 +      struct LPXCPS *cps = lp->cps;
223.1376 +#else
223.1377 +      struct LPXCPS *cps = access_parms(lp);
223.1378 +#endif
223.1379 +      double val = 0.0;
223.1380 +      switch (parm)
223.1381 +      {  case LPX_K_RELAX:
223.1382 +            val = cps->relax;
223.1383 +            break;
223.1384 +         case LPX_K_TOLBND:
223.1385 +            val = cps->tol_bnd;
223.1386 +            break;
223.1387 +         case LPX_K_TOLDJ:
223.1388 +            val = cps->tol_dj;
223.1389 +            break;
223.1390 +         case LPX_K_TOLPIV:
223.1391 +            val = cps->tol_piv;
223.1392 +            break;
223.1393 +         case LPX_K_OBJLL:
223.1394 +            val = cps->obj_ll;
223.1395 +            break;
223.1396 +         case LPX_K_OBJUL:
223.1397 +            val = cps->obj_ul;
223.1398 +            break;
223.1399 +         case LPX_K_TMLIM:
223.1400 +            val = cps->tm_lim;
223.1401 +            break;
223.1402 +         case LPX_K_OUTDLY:
223.1403 +            val = cps->out_dly;
223.1404 +            break;
223.1405 +         case LPX_K_TOLINT:
223.1406 +            val = cps->tol_int;
223.1407 +            break;
223.1408 +         case LPX_K_TOLOBJ:
223.1409 +            val = cps->tol_obj;
223.1410 +            break;
223.1411 +         case LPX_K_MIPGAP:
223.1412 +            val = cps->mip_gap;
223.1413 +            break;
223.1414 +         default:
223.1415 +            xerror("lpx_get_real_parm: parm = %d; invalid parameter\n",
223.1416 +               parm);
223.1417 +      }
223.1418 +      return val;
223.1419 +}
223.1420 +
223.1421 +LPX *lpx_read_mps(const char *fname)
223.1422 +{     /* read problem data in fixed MPS format */
223.1423 +      LPX *lp = lpx_create_prob();
223.1424 +      if (glp_read_mps(lp, GLP_MPS_DECK, NULL, fname))
223.1425 +         lpx_delete_prob(lp), lp = NULL;
223.1426 +      return lp;
223.1427 +}
223.1428 +
223.1429 +int lpx_write_mps(LPX *lp, const char *fname)
223.1430 +{     /* write problem data in fixed MPS format */
223.1431 +      return glp_write_mps(lp, GLP_MPS_DECK, NULL, fname);
223.1432 +}
223.1433 +
223.1434 +int lpx_read_bas(LPX *lp, const char *fname)
223.1435 +{     /* read LP basis in fixed MPS format */
223.1436 +#if 0 /* 13/IV-2009 */
223.1437 +      return read_bas(lp, fname);
223.1438 +#else
223.1439 +      xassert(lp == lp);
223.1440 +      xassert(fname == fname);
223.1441 +      xerror("lpx_read_bas: operation not supported\n");
223.1442 +      return 0;
223.1443 +#endif
223.1444 +}
223.1445 +
223.1446 +int lpx_write_bas(LPX *lp, const char *fname)
223.1447 +{     /* write LP basis in fixed MPS format */
223.1448 +#if 0 /* 13/IV-2009 */
223.1449 +      return write_bas(lp, fname);
223.1450 +#else
223.1451 +      xassert(lp == lp);
223.1452 +      xassert(fname == fname);
223.1453 +      xerror("lpx_write_bas: operation not supported\n");
223.1454 +      return 0;
223.1455 +#endif
223.1456 +}
223.1457 +
223.1458 +LPX *lpx_read_freemps(const char *fname)
223.1459 +{     /* read problem data in free MPS format */
223.1460 +      LPX *lp = lpx_create_prob();
223.1461 +      if (glp_read_mps(lp, GLP_MPS_FILE, NULL, fname))
223.1462 +         lpx_delete_prob(lp), lp = NULL;
223.1463 +      return lp;
223.1464 +}
223.1465 +
223.1466 +int lpx_write_freemps(LPX *lp, const char *fname)
223.1467 +{     /* write problem data in free MPS format */
223.1468 +      return glp_write_mps(lp, GLP_MPS_FILE, NULL, fname);
223.1469 +}
223.1470 +
223.1471 +LPX *lpx_read_cpxlp(const char *fname)
223.1472 +{     /* read problem data in CPLEX LP format */
223.1473 +      LPX *lp;
223.1474 +      lp = lpx_create_prob();
223.1475 +      if (glp_read_lp(lp, NULL, fname))
223.1476 +         lpx_delete_prob(lp), lp = NULL;
223.1477 +      return lp;
223.1478 +}
223.1479 +
223.1480 +int lpx_write_cpxlp(LPX *lp, const char *fname)
223.1481 +{     /* write problem data in CPLEX LP format */
223.1482 +      return glp_write_lp(lp, NULL, fname);
223.1483 +}
223.1484 +
223.1485 +LPX *lpx_read_model(const char *model, const char *data, const char
223.1486 +      *output)
223.1487 +{     /* read LP/MIP model written in GNU MathProg language */
223.1488 +      LPX *lp = NULL;
223.1489 +      glp_tran *tran;
223.1490 +      /* allocate the translator workspace */
223.1491 +      tran = glp_mpl_alloc_wksp();
223.1492 +      /* read model section and optional data section */
223.1493 +      if (glp_mpl_read_model(tran, model, data != NULL)) goto done;
223.1494 +      /* read separate data section, if required */
223.1495 +      if (data != NULL)
223.1496 +         if (glp_mpl_read_data(tran, data)) goto done;
223.1497 +      /* generate the model */
223.1498 +      if (glp_mpl_generate(tran, output)) goto done;
223.1499 +      /* build the problem instance from the model */
223.1500 +      lp = glp_create_prob();
223.1501 +      glp_mpl_build_prob(tran, lp);
223.1502 +done: /* free the translator workspace */
223.1503 +      glp_mpl_free_wksp(tran);
223.1504 +      /* bring the problem object to the calling program */
223.1505 +      return lp;
223.1506 +}
223.1507 +
223.1508 +int lpx_print_prob(LPX *lp, const char *fname)
223.1509 +{     /* write problem data in plain text format */
223.1510 +      return glp_write_lp(lp, NULL, fname);
223.1511 +}
223.1512 +
223.1513 +int lpx_print_sol(LPX *lp, const char *fname)
223.1514 +{     /* write LP problem solution in printable format */
223.1515 +      return glp_print_sol(lp, fname);
223.1516 +}
223.1517 +
223.1518 +int lpx_print_sens_bnds(LPX *lp, const char *fname)
223.1519 +{     /* write bounds sensitivity information */
223.1520 +      if (glp_get_status(lp) == GLP_OPT && !glp_bf_exists(lp))
223.1521 +         glp_factorize(lp);
223.1522 +      return glp_print_ranges(lp, 0, NULL, 0, fname);
223.1523 +}
223.1524 +
223.1525 +int lpx_print_ips(LPX *lp, const char *fname)
223.1526 +{     /* write interior point solution in printable format */
223.1527 +      return glp_print_ipt(lp, fname);
223.1528 +}
223.1529 +
223.1530 +int lpx_print_mip(LPX *lp, const char *fname)
223.1531 +{     /* write MIP problem solution in printable format */
223.1532 +      return glp_print_mip(lp, fname);
223.1533 +}
223.1534 +
223.1535 +int lpx_is_b_avail(glp_prob *lp)
223.1536 +{     /* check if LP basis is available */
223.1537 +      return glp_bf_exists(lp);
223.1538 +}
223.1539 +
223.1540 +int lpx_main(int argc, const char *argv[])
223.1541 +{     /* stand-alone LP/MIP solver */
223.1542 +      return glp_main(argc, argv);
223.1543 +}
223.1544 +
223.1545 +/* eof */
   224.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   224.2 +++ b/src/glplpx02.c	Mon Dec 06 13:09:21 2010 +0100
   224.3 @@ -0,0 +1,264 @@
   224.4 +/* glplpx02.c */
   224.5 +
   224.6 +/***********************************************************************
   224.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   224.8 +*
   224.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  224.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  224.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  224.12 +*  E-mail: <mao@gnu.org>.
  224.13 +*
  224.14 +*  GLPK is free software: you can redistribute it and/or modify it
  224.15 +*  under the terms of the GNU General Public License as published by
  224.16 +*  the Free Software Foundation, either version 3 of the License, or
  224.17 +*  (at your option) any later version.
  224.18 +*
  224.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  224.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  224.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  224.22 +*  License for more details.
  224.23 +*
  224.24 +*  You should have received a copy of the GNU General Public License
  224.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  224.26 +***********************************************************************/
  224.27 +
  224.28 +#include "glpapi.h"
  224.29 +
  224.30 +/***********************************************************************
  224.31 +*  NAME
  224.32 +*
  224.33 +*  lpx_put_solution - store basic solution components
  224.34 +*
  224.35 +*  SYNOPSIS
  224.36 +*
  224.37 +*  void lpx_put_solution(glp_prob *lp, int inval, const int *p_stat,
  224.38 +*     const int *d_stat, const double *obj_val, const int r_stat[],
  224.39 +*     const double r_prim[], const double r_dual[], const int c_stat[],
  224.40 +*     const double c_prim[], const double c_dual[])
  224.41 +*
  224.42 +*  DESCRIPTION
  224.43 +*
  224.44 +*  The routine lpx_put_solution stores basic solution components to the
  224.45 +*  specified problem object.
  224.46 +*
  224.47 +*  The parameter inval is the basis factorization invalidity flag.
  224.48 +*  If this flag is clear, the current status of the basis factorization
  224.49 +*  remains unchanged. If this flag is set, the routine invalidates the
  224.50 +*  basis factorization.
  224.51 +*
  224.52 +*  The parameter p_stat is a pointer to the status of primal basic
  224.53 +*  solution, which should be specified as follows:
  224.54 +*
  224.55 +*  GLP_UNDEF  - primal solution is undefined;
  224.56 +*  GLP_FEAS   - primal solution is feasible;
  224.57 +*  GLP_INFEAS - primal solution is infeasible;
  224.58 +*  GLP_NOFEAS - no primal feasible solution exists.
  224.59 +*
  224.60 +*  If the parameter p_stat is NULL, the current status of primal basic
  224.61 +*  solution remains unchanged.
  224.62 +*
  224.63 +*  The parameter d_stat is a pointer to the status of dual basic
  224.64 +*  solution, which should be specified as follows:
  224.65 +*
  224.66 +*  GLP_UNDEF  - dual solution is undefined;
  224.67 +*  GLP_FEAS   - dual solution is feasible;
  224.68 +*  GLP_INFEAS - dual solution is infeasible;
  224.69 +*  GLP_NOFEAS - no dual feasible solution exists.
  224.70 +*
  224.71 +*  If the parameter d_stat is NULL, the current status of dual basic
  224.72 +*  solution remains unchanged.
  224.73 +*
  224.74 +*  The parameter obj_val is a pointer to the objective function value.
  224.75 +*  If it is NULL, the current value of the objective function remains
  224.76 +*  unchanged.
  224.77 +*
  224.78 +*  The array element r_stat[i], 1 <= i <= m (where m is the number of
  224.79 +*  rows in the problem object), specifies the status of i-th auxiliary
  224.80 +*  variable, which should be specified as follows:
  224.81 +*
  224.82 +*  GLP_BS - basic variable;
  224.83 +*  GLP_NL - non-basic variable on lower bound;
  224.84 +*  GLP_NU - non-basic variable on upper bound;
  224.85 +*  GLP_NF - non-basic free variable;
  224.86 +*  GLP_NS - non-basic fixed variable.
  224.87 +*
  224.88 +*  If the parameter r_stat is NULL, the current statuses of auxiliary
  224.89 +*  variables remain unchanged.
  224.90 +*
  224.91 +*  The array element r_prim[i], 1 <= i <= m (where m is the number of
  224.92 +*  rows in the problem object), specifies a primal value of i-th
  224.93 +*  auxiliary variable. If the parameter r_prim is NULL, the current
  224.94 +*  primal values of auxiliary variables remain unchanged.
  224.95 +*
  224.96 +*  The array element r_dual[i], 1 <= i <= m (where m is the number of
  224.97 +*  rows in the problem object), specifies a dual value (reduced cost)
  224.98 +*  of i-th auxiliary variable. If the parameter r_dual is NULL, the
  224.99 +*  current dual values of auxiliary variables remain unchanged.
 224.100 +*
 224.101 +*  The array element c_stat[j], 1 <= j <= n (where n is the number of
 224.102 +*  columns in the problem object), specifies the status of j-th
 224.103 +*  structural variable, which should be specified as follows:
 224.104 +*
 224.105 +*  GLP_BS - basic variable;
 224.106 +*  GLP_NL - non-basic variable on lower bound;
 224.107 +*  GLP_NU - non-basic variable on upper bound;
 224.108 +*  GLP_NF - non-basic free variable;
 224.109 +*  GLP_NS - non-basic fixed variable.
 224.110 +*
 224.111 +*  If the parameter c_stat is NULL, the current statuses of structural
 224.112 +*  variables remain unchanged.
 224.113 +*
 224.114 +*  The array element c_prim[j], 1 <= j <= n (where n is the number of
 224.115 +*  columns in the problem object), specifies a primal value of j-th
 224.116 +*  structural variable. If the parameter c_prim is NULL, the current
 224.117 +*  primal values of structural variables remain unchanged.
 224.118 +*
 224.119 +*  The array element c_dual[j], 1 <= j <= n (where n is the number of
 224.120 +*  columns in the problem object), specifies a dual value (reduced cost)
 224.121 +*  of j-th structural variable. If the parameter c_dual is NULL, the
 224.122 +*  current dual values of structural variables remain unchanged. */
 224.123 +
 224.124 +void lpx_put_solution(glp_prob *lp, int inval, const int *p_stat,
 224.125 +      const int *d_stat, const double *obj_val, const int r_stat[],
 224.126 +      const double r_prim[], const double r_dual[], const int c_stat[],
 224.127 +      const double c_prim[], const double c_dual[])
 224.128 +{     GLPROW *row;
 224.129 +      GLPCOL *col;
 224.130 +      int i, j;
 224.131 +      /* invalidate the basis factorization, if required */
 224.132 +      if (inval) lp->valid = 0;
 224.133 +      /* store primal status */
 224.134 +      if (p_stat != NULL)
 224.135 +      {  if (!(*p_stat == GLP_UNDEF  || *p_stat == GLP_FEAS ||
 224.136 +               *p_stat == GLP_INFEAS || *p_stat == GLP_NOFEAS))
 224.137 +            xerror("lpx_put_solution: p_stat = %d; invalid primal statu"
 224.138 +               "s\n", *p_stat);
 224.139 +         lp->pbs_stat = *p_stat;
 224.140 +      }
 224.141 +      /* store dual status */
 224.142 +      if (d_stat != NULL)
 224.143 +      {  if (!(*d_stat == GLP_UNDEF  || *d_stat == GLP_FEAS ||
 224.144 +               *d_stat == GLP_INFEAS || *d_stat == GLP_NOFEAS))
 224.145 +            xerror("lpx_put_solution: d_stat = %d; invalid dual status "
 224.146 +               "\n", *d_stat);
 224.147 +         lp->dbs_stat = *d_stat;
 224.148 +      }
 224.149 +      /* store objective function value */
 224.150 +      if (obj_val != NULL) lp->obj_val = *obj_val;
 224.151 +      /* store row solution components */
 224.152 +      for (i = 1; i <= lp->m; i++)
 224.153 +      {  row = lp->row[i];
 224.154 +         if (r_stat != NULL)
 224.155 +         {  if (!(r_stat[i] == GLP_BS ||
 224.156 +                  row->type == GLP_FR && r_stat[i] == GLP_NF ||
 224.157 +                  row->type == GLP_LO && r_stat[i] == GLP_NL ||
 224.158 +                  row->type == GLP_UP && r_stat[i] == GLP_NU ||
 224.159 +                  row->type == GLP_DB && r_stat[i] == GLP_NL ||
 224.160 +                  row->type == GLP_DB && r_stat[i] == GLP_NU ||
 224.161 +                  row->type == GLP_FX && r_stat[i] == GLP_NS))
 224.162 +               xerror("lpx_put_solution: r_stat[%d] = %d; invalid row s"
 224.163 +                  "tatus\n", i, r_stat[i]);
 224.164 +            row->stat = r_stat[i];
 224.165 +         }
 224.166 +         if (r_prim != NULL) row->prim = r_prim[i];
 224.167 +         if (r_dual != NULL) row->dual = r_dual[i];
 224.168 +      }
 224.169 +      /* store column solution components */
 224.170 +      for (j = 1; j <= lp->n; j++)
 224.171 +      {  col = lp->col[j];
 224.172 +         if (c_stat != NULL)
 224.173 +         {  if (!(c_stat[j] == GLP_BS ||
 224.174 +                  col->type == GLP_FR && c_stat[j] == GLP_NF ||
 224.175 +                  col->type == GLP_LO && c_stat[j] == GLP_NL ||
 224.176 +                  col->type == GLP_UP && c_stat[j] == GLP_NU ||
 224.177 +                  col->type == GLP_DB && c_stat[j] == GLP_NL ||
 224.178 +                  col->type == GLP_DB && c_stat[j] == GLP_NU ||
 224.179 +                  col->type == GLP_FX && c_stat[j] == GLP_NS))
 224.180 +               xerror("lpx_put_solution: c_stat[%d] = %d; invalid colum"
 224.181 +                  "n status\n", j, c_stat[j]);
 224.182 +            col->stat = c_stat[j];
 224.183 +         }
 224.184 +         if (c_prim != NULL) col->prim = c_prim[j];
 224.185 +         if (c_dual != NULL) col->dual = c_dual[j];
 224.186 +      }
 224.187 +      return;
 224.188 +}
 224.189 +
 224.190 +/*----------------------------------------------------------------------
 224.191 +-- lpx_put_mip_soln - store mixed integer solution components.
 224.192 +--
 224.193 +-- *Synopsis*
 224.194 +--
 224.195 +-- #include "glplpx.h"
 224.196 +-- void lpx_put_mip_soln(glp_prob *lp, int i_stat, double row_mipx[],
 224.197 +--    double col_mipx[]);
 224.198 +--
 224.199 +-- *Description*
 224.200 +--
 224.201 +-- The routine lpx_put_mip_soln stores solution components obtained by
 224.202 +-- branch-and-bound solver into the specified problem object.
 224.203 +--
 224.204 +-- NOTE: This routine is intended for internal use only. */
 224.205 +
 224.206 +void lpx_put_mip_soln(glp_prob *lp, int i_stat, double row_mipx[],
 224.207 +      double col_mipx[])
 224.208 +{     GLPROW *row;
 224.209 +      GLPCOL *col;
 224.210 +      int i, j;
 224.211 +      double sum;
 224.212 +      /* store mixed integer status */
 224.213 +#if 0
 224.214 +      if (!(i_stat == LPX_I_UNDEF || i_stat == LPX_I_OPT ||
 224.215 +            i_stat == LPX_I_FEAS  || i_stat == LPX_I_NOFEAS))
 224.216 +         fault("lpx_put_mip_soln: i_stat = %d; invalid mixed integer st"
 224.217 +            "atus", i_stat);
 224.218 +      lp->i_stat = i_stat;
 224.219 +#else
 224.220 +      switch (i_stat)
 224.221 +      {  case LPX_I_UNDEF:
 224.222 +            lp->mip_stat = GLP_UNDEF; break;
 224.223 +         case LPX_I_OPT:
 224.224 +            lp->mip_stat = GLP_OPT;  break;
 224.225 +         case LPX_I_FEAS:
 224.226 +            lp->mip_stat = GLP_FEAS; break;
 224.227 +         case LPX_I_NOFEAS:
 224.228 +            lp->mip_stat = GLP_NOFEAS; break;
 224.229 +         default:
 224.230 +            xerror("lpx_put_mip_soln: i_stat = %d; invalid mixed intege"
 224.231 +               "r status\n", i_stat);
 224.232 +      }
 224.233 +#endif
 224.234 +      /* store row solution components */
 224.235 +      if (row_mipx != NULL)
 224.236 +      {  for (i = 1; i <= lp->m; i++)
 224.237 +         {  row = lp->row[i];
 224.238 +            row->mipx = row_mipx[i];
 224.239 +         }
 224.240 +      }
 224.241 +      /* store column solution components */
 224.242 +      if (col_mipx != NULL)
 224.243 +      {  for (j = 1; j <= lp->n; j++)
 224.244 +         {  col = lp->col[j];
 224.245 +            col->mipx = col_mipx[j];
 224.246 +         }
 224.247 +      }
 224.248 +      /* if the solution is claimed to be integer feasible, check it */
 224.249 +      if (lp->mip_stat == GLP_OPT || lp->mip_stat == GLP_FEAS)
 224.250 +      {  for (j = 1; j <= lp->n; j++)
 224.251 +         {  col = lp->col[j];
 224.252 +            if (col->kind == GLP_IV && col->mipx != floor(col->mipx))
 224.253 +               xerror("lpx_put_mip_soln: col_mipx[%d] = %.*g; must be i"
 224.254 +                  "ntegral\n", j, DBL_DIG, col->mipx);
 224.255 +         }
 224.256 +      }
 224.257 +      /* compute the objective function value */
 224.258 +      sum = lp->c0;
 224.259 +      for (j = 1; j <= lp->n; j++)
 224.260 +      {  col = lp->col[j];
 224.261 +         sum += col->coef * col->mipx;
 224.262 +      }
 224.263 +      lp->mip_obj = sum;
 224.264 +      return;
 224.265 +}
 224.266 +
 224.267 +/* eof */
   225.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   225.2 +++ b/src/glplpx03.c	Mon Dec 06 13:09:21 2010 +0100
   225.3 @@ -0,0 +1,302 @@
   225.4 +/* glplpx03.c (OPB format) */
   225.5 +
   225.6 +/***********************************************************************
   225.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   225.8 +*
   225.9 +*  Author: Oscar Gustafsson <oscarg@isy.liu.se>.
  225.10 +*
  225.11 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  225.12 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  225.13 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  225.14 +*  E-mail: <mao@gnu.org>.
  225.15 +*
  225.16 +*  GLPK is free software: you can redistribute it and/or modify it
  225.17 +*  under the terms of the GNU General Public License as published by
  225.18 +*  the Free Software Foundation, either version 3 of the License, or
  225.19 +*  (at your option) any later version.
  225.20 +*
  225.21 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  225.22 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  225.23 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  225.24 +*  License for more details.
  225.25 +*
  225.26 +*  You should have received a copy of the GNU General Public License
  225.27 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  225.28 +***********************************************************************/
  225.29 +
  225.30 +#define _GLPSTD_ERRNO
  225.31 +#define _GLPSTD_STDIO
  225.32 +#include "glpapi.h"
  225.33 +#if 0 /* 24/XII-2009; by mao */
  225.34 +#include "glpipp.h"
  225.35 +#endif
  225.36 +
  225.37 +/*----------------------------------------------------------------------
  225.38 +-- lpx_write_pb - write problem data in (normalized) OPB format.
  225.39 +--
  225.40 +-- *Synopsis*
  225.41 +--
  225.42 +-- #include "glplpx.h"
  225.43 +-- int lpx_write_pb(LPX *lp, const char *fname, int normalized,
  225.44 +--    int binarize);
  225.45 +--
  225.46 +-- *Description*
  225.47 +--
  225.48 +-- The routine lpx_write_pb writes problem data in OPB format
  225.49 +-- to an output text file whose name is the character string fname.
  225.50 +-- If normalized is non-zero the output will be generated in a
  225.51 +-- normalized form with sequentially numbered variables, x1, x2 etc.
  225.52 +-- If binarize, any integer variable will be repalzec by binary ones,
  225.53 +-- see ipp_binarize
  225.54 +--
  225.55 +-- *Returns*
  225.56 +--
  225.57 +-- If the operation was successful, the routine returns zero. Otherwise
  225.58 +-- the routine prints an error message and returns non-zero. */
  225.59 +
  225.60 +#if 1 /* 24/XII-2009; by mao (disabled, because IPP was removed) */
  225.61 +int lpx_write_pb(LPX *lp, const char *fname, int normalized,
  225.62 +      int binarize)
  225.63 +{     xassert(lp == lp);
  225.64 +      xassert(fname == fname);
  225.65 +      xassert(normalized == normalized);
  225.66 +      xassert(binarize == binarize);
  225.67 +      xprintf("lpx_write_pb: sorry, currently this operation is not ava"
  225.68 +         "ilable\n");
  225.69 +      return 1;
  225.70 +}
  225.71 +#else
  225.72 +int lpx_write_pb(LPX *lp, const char *fname, int normalized,
  225.73 +      int binarize)
  225.74 +{
  225.75 +  FILE* fp;
  225.76 +  int m,n,i,j,k,o,nonfree=0, obj_dir, dbl, *ndx, row_type, emptylhs=0;
  225.77 +  double coeff, *val, bound, constant/*=0.0*/;
  225.78 +  char* objconstname = "dummy_one";
  225.79 +  char* emptylhsname = "dummy_zero";
  225.80 +
  225.81 +  /* Variables needed for possible binarization */
  225.82 +  /*LPX* tlp;*/
  225.83 +  IPP *ipp = NULL;
  225.84 +  /*tlp=lp;*/
  225.85 +
  225.86 +  if(binarize) /* Transform integer variables to binary ones */
  225.87 +    {
  225.88 +      ipp = ipp_create_wksp();
  225.89 +      ipp_load_orig(ipp, lp);
  225.90 +      ipp_binarize(ipp);
  225.91 +      lp = ipp_build_prob(ipp);
  225.92 +    }
  225.93 +  fp = fopen(fname, "w");
  225.94 +
  225.95 +  if(fp!= NULL)
  225.96 +    {
  225.97 +      xprintf(
  225.98 +          "lpx_write_pb: writing problem in %sOPB format to `%s'...\n",
  225.99 +              (normalized?"normalized ":""), fname);
 225.100 +
 225.101 +      m = glp_get_num_rows(lp);
 225.102 +      n = glp_get_num_cols(lp);
 225.103 +      for(i=1;i<=m;i++)
 225.104 +        {
 225.105 +          switch(glp_get_row_type(lp,i))
 225.106 +            {
 225.107 +            case GLP_LO:
 225.108 +            case GLP_UP:
 225.109 +            case GLP_FX:
 225.110 +              {
 225.111 +                nonfree += 1;
 225.112 +                break;
 225.113 +              }
 225.114 +            case GLP_DB:
 225.115 +              {
 225.116 +                nonfree += 2;
 225.117 +                break;
 225.118 +              }
 225.119 +            }
 225.120 +        }
 225.121 +      constant=glp_get_obj_coef(lp,0);
 225.122 +      fprintf(fp,"* #variables = %d #constraints = %d\n",
 225.123 +         n + (constant == 0?1:0), nonfree + (constant == 0?1:0));
 225.124 +      /* Objective function */
 225.125 +      obj_dir = glp_get_obj_dir(lp);
 225.126 +      fprintf(fp,"min: ");
 225.127 +      for(i=1;i<=n;i++)
 225.128 +        {
 225.129 +          coeff = glp_get_obj_coef(lp,i);
 225.130 +          if(coeff != 0.0)
 225.131 +            {
 225.132 +              if(obj_dir == GLP_MAX)
 225.133 +                coeff=-coeff;
 225.134 +              if(normalized)
 225.135 +                fprintf(fp, " %d x%d", (int)coeff, i);
 225.136 +              else
 225.137 +                fprintf(fp, " %d*%s", (int)coeff,
 225.138 +                  glp_get_col_name(lp,i));
 225.139 +
 225.140 +            }
 225.141 +        }
 225.142 +      if(constant)
 225.143 +        {
 225.144 +          if(normalized)
 225.145 +            fprintf(fp, " %d x%d", (int)constant, n+1);
 225.146 +          else
 225.147 +            fprintf(fp, " %d*%s", (int)constant, objconstname);
 225.148 +        }
 225.149 +      fprintf(fp,";\n");
 225.150 +
 225.151 +      if(normalized && !binarize)  /* Name substitution */
 225.152 +        {
 225.153 +          fprintf(fp,"* Variable name substitution:\n");
 225.154 +          for(j=1;j<=n;j++)
 225.155 +            {
 225.156 +              fprintf(fp, "* x%d = %s\n", j, glp_get_col_name(lp,j));
 225.157 +            }
 225.158 +          if(constant)
 225.159 +            fprintf(fp, "* x%d = %s\n", n+1, objconstname);
 225.160 +        }
 225.161 +
 225.162 +      ndx = xcalloc(1+n, sizeof(int));
 225.163 +      val = xcalloc(1+n, sizeof(double));
 225.164 +
 225.165 +      /* Constraints */
 225.166 +      for(j=1;j<=m;j++)
 225.167 +        {
 225.168 +          row_type=glp_get_row_type(lp,j);
 225.169 +          if(row_type!=GLP_FR)
 225.170 +            {
 225.171 +              if(row_type == GLP_DB)
 225.172 +                {
 225.173 +                  dbl=2;
 225.174 +                  row_type = GLP_UP;
 225.175 +                }
 225.176 +              else
 225.177 +                {
 225.178 +                  dbl=1;
 225.179 +                }
 225.180 +              k=glp_get_mat_row(lp, j, ndx, val);
 225.181 +              for(o=1;o<=dbl;o++)
 225.182 +                {
 225.183 +                  if(o==2)
 225.184 +                    {
 225.185 +                      row_type = GLP_LO;
 225.186 +                    }
 225.187 +                  if(k==0) /* Empty LHS */
 225.188 +                    {
 225.189 +                      emptylhs = 1;
 225.190 +                      if(normalized)
 225.191 +                        {
 225.192 +                          fprintf(fp, "0 x%d ", n+2);
 225.193 +                        }
 225.194 +                      else
 225.195 +                        {
 225.196 +                          fprintf(fp, "0*%s ", emptylhsname);
 225.197 +                        }
 225.198 +                    }
 225.199 +
 225.200 +                  for(i=1;i<=k;i++)
 225.201 +                    {
 225.202 +                      if(val[i] != 0.0)
 225.203 +                        {
 225.204 +
 225.205 +                          if(normalized)
 225.206 +                            {
 225.207 +                              fprintf(fp, "%d x%d ",
 225.208 +              (row_type==GLP_UP)?(-(int)val[i]):((int)val[i]), ndx[i]);
 225.209 +                            }
 225.210 +                          else
 225.211 +                            {
 225.212 +                              fprintf(fp, "%d*%s ", (int)val[i],
 225.213 +                                      glp_get_col_name(lp,ndx[i]));
 225.214 +                            }
 225.215 +                        }
 225.216 +                    }
 225.217 +                  switch(row_type)
 225.218 +                    {
 225.219 +                    case GLP_LO:
 225.220 +                      {
 225.221 +                        fprintf(fp, ">=");
 225.222 +                        bound = glp_get_row_lb(lp,j);
 225.223 +                        break;
 225.224 +                      }
 225.225 +                    case GLP_UP:
 225.226 +                      {
 225.227 +                        if(normalized)
 225.228 +                          {
 225.229 +                            fprintf(fp, ">=");
 225.230 +                            bound = -glp_get_row_ub(lp,j);
 225.231 +                          }
 225.232 +                        else
 225.233 +                          {
 225.234 +                            fprintf(fp, "<=");
 225.235 +                            bound = glp_get_row_ub(lp,j);
 225.236 +                          }
 225.237 +
 225.238 +                        break;
 225.239 +                      }
 225.240 +                    case GLP_FX:
 225.241 +                      {
 225.242 +                        fprintf(fp, "=");
 225.243 +                        bound = glp_get_row_lb(lp,j);
 225.244 +                        break;
 225.245 +                      }
 225.246 +                    }
 225.247 +                  fprintf(fp," %d;\n",(int)bound);
 225.248 +                }
 225.249 +            }
 225.250 +        }
 225.251 +      xfree(ndx);
 225.252 +      xfree(val);
 225.253 +
 225.254 +      if(constant)
 225.255 +        {
 225.256 +          xprintf(
 225.257 +        "lpx_write_pb: adding constant objective function variable\n");
 225.258 +
 225.259 +          if(normalized)
 225.260 +            fprintf(fp, "1 x%d = 1;\n", n+1);
 225.261 +          else
 225.262 +            fprintf(fp, "1*%s = 1;\n", objconstname);
 225.263 +        }
 225.264 +      if(emptylhs)
 225.265 +        {
 225.266 +          xprintf(
 225.267 +            "lpx_write_pb: adding dummy variable for empty left-hand si"
 225.268 +            "de constraint\n");
 225.269 +
 225.270 +          if(normalized)
 225.271 +            fprintf(fp, "1 x%d = 0;\n", n+2);
 225.272 +          else
 225.273 +            fprintf(fp, "1*%s = 0;\n", emptylhsname);
 225.274 +        }
 225.275 +
 225.276 +    }
 225.277 +  else
 225.278 +    {
 225.279 +      xprintf("Problems opening file for writing: %s\n", fname);
 225.280 +      return(1);
 225.281 +    }
 225.282 +  fflush(fp);
 225.283 +  if (ferror(fp))
 225.284 +    {  xprintf("lpx_write_pb: can't write to `%s' - %s\n", fname,
 225.285 +               strerror(errno));
 225.286 +    goto fail;
 225.287 +    }
 225.288 +  fclose(fp);
 225.289 +
 225.290 +
 225.291 +  if(binarize)
 225.292 +    {
 225.293 +      /* delete the resultant problem object */
 225.294 +      if (lp != NULL) lpx_delete_prob(lp);
 225.295 +      /* delete MIP presolver workspace */
 225.296 +      if (ipp != NULL) ipp_delete_wksp(ipp);
 225.297 +      /*lp=tlp;*/
 225.298 +    }
 225.299 +  return 0;
 225.300 + fail: if (fp != NULL) fclose(fp);
 225.301 +  return 1;
 225.302 +}
 225.303 +#endif
 225.304 +
 225.305 +/* eof */
   226.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   226.2 +++ b/src/glpluf.c	Mon Dec 06 13:09:21 2010 +0100
   226.3 @@ -0,0 +1,1846 @@
   226.4 +/* glpluf.c (LU-factorization) */
   226.5 +
   226.6 +/***********************************************************************
   226.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   226.8 +*
   226.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  226.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  226.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  226.12 +*  E-mail: <mao@gnu.org>.
  226.13 +*
  226.14 +*  GLPK is free software: you can redistribute it and/or modify it
  226.15 +*  under the terms of the GNU General Public License as published by
  226.16 +*  the Free Software Foundation, either version 3 of the License, or
  226.17 +*  (at your option) any later version.
  226.18 +*
  226.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  226.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  226.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  226.22 +*  License for more details.
  226.23 +*
  226.24 +*  You should have received a copy of the GNU General Public License
  226.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  226.26 +***********************************************************************/
  226.27 +
  226.28 +#include "glpenv.h"
  226.29 +#include "glpluf.h"
  226.30 +#define xfault xerror
  226.31 +
  226.32 +/* CAUTION: DO NOT CHANGE THE LIMIT BELOW */
  226.33 +
  226.34 +#define N_MAX 100000000 /* = 100*10^6 */
  226.35 +/* maximal order of the original matrix */
  226.36 +
  226.37 +/***********************************************************************
  226.38 +*  NAME
  226.39 +*
  226.40 +*  luf_create_it - create LU-factorization
  226.41 +*
  226.42 +*  SYNOPSIS
  226.43 +*
  226.44 +*  #include "glpluf.h"
  226.45 +*  LUF *luf_create_it(void);
  226.46 +*
  226.47 +*  DESCRIPTION
  226.48 +*
  226.49 +*  The routine luf_create_it creates a program object, which represents
  226.50 +*  LU-factorization of a square matrix.
  226.51 +*
  226.52 +*  RETURNS
  226.53 +*
  226.54 +*  The routine luf_create_it returns a pointer to the object created. */
  226.55 +
  226.56 +LUF *luf_create_it(void)
  226.57 +{     LUF *luf;
  226.58 +      luf = xmalloc(sizeof(LUF));
  226.59 +      luf->n_max = luf->n = 0;
  226.60 +      luf->valid = 0;
  226.61 +      luf->fr_ptr = luf->fr_len = NULL;
  226.62 +      luf->fc_ptr = luf->fc_len = NULL;
  226.63 +      luf->vr_ptr = luf->vr_len = luf->vr_cap = NULL;
  226.64 +      luf->vr_piv = NULL;
  226.65 +      luf->vc_ptr = luf->vc_len = luf->vc_cap = NULL;
  226.66 +      luf->pp_row = luf->pp_col = NULL;
  226.67 +      luf->qq_row = luf->qq_col = NULL;
  226.68 +      luf->sv_size = 0;
  226.69 +      luf->sv_beg = luf->sv_end = 0;
  226.70 +      luf->sv_ind = NULL;
  226.71 +      luf->sv_val = NULL;
  226.72 +      luf->sv_head = luf->sv_tail = 0;
  226.73 +      luf->sv_prev = luf->sv_next = NULL;
  226.74 +      luf->vr_max = NULL;
  226.75 +      luf->rs_head = luf->rs_prev = luf->rs_next = NULL;
  226.76 +      luf->cs_head = luf->cs_prev = luf->cs_next = NULL;
  226.77 +      luf->flag = NULL;
  226.78 +      luf->work = NULL;
  226.79 +      luf->new_sva = 0;
  226.80 +      luf->piv_tol = 0.10;
  226.81 +      luf->piv_lim = 4;
  226.82 +      luf->suhl = 1;
  226.83 +      luf->eps_tol = 1e-15;
  226.84 +      luf->max_gro = 1e+10;
  226.85 +      luf->nnz_a = luf->nnz_f = luf->nnz_v = 0;
  226.86 +      luf->max_a = luf->big_v = 0.0;
  226.87 +      luf->rank = 0;
  226.88 +      return luf;
  226.89 +}
  226.90 +
  226.91 +/***********************************************************************
  226.92 +*  NAME
  226.93 +*
  226.94 +*  luf_defrag_sva - defragment the sparse vector area
  226.95 +*
  226.96 +*  SYNOPSIS
  226.97 +*
  226.98 +*  #include "glpluf.h"
  226.99 +*  void luf_defrag_sva(LUF *luf);
 226.100 +*
 226.101 +*  DESCRIPTION
 226.102 +*
 226.103 +*  The routine luf_defrag_sva defragments the sparse vector area (SVA)
 226.104 +*  gathering all unused locations in one continuous extent. In order to
 226.105 +*  do that the routine moves all unused locations from the left part of
 226.106 +*  SVA (which contains rows and columns of the matrix V) to the middle
 226.107 +*  part (which contains free locations). This is attained by relocating
 226.108 +*  elements of rows and columns of the matrix V toward the beginning of
 226.109 +*  the left part.
 226.110 +*
 226.111 +*  NOTE that this "garbage collection" involves changing row and column
 226.112 +*  pointers of the matrix V. */
 226.113 +
 226.114 +void luf_defrag_sva(LUF *luf)
 226.115 +{     int n = luf->n;
 226.116 +      int *vr_ptr = luf->vr_ptr;
 226.117 +      int *vr_len = luf->vr_len;
 226.118 +      int *vr_cap = luf->vr_cap;
 226.119 +      int *vc_ptr = luf->vc_ptr;
 226.120 +      int *vc_len = luf->vc_len;
 226.121 +      int *vc_cap = luf->vc_cap;
 226.122 +      int *sv_ind = luf->sv_ind;
 226.123 +      double *sv_val = luf->sv_val;
 226.124 +      int *sv_next = luf->sv_next;
 226.125 +      int sv_beg = 1;
 226.126 +      int i, j, k;
 226.127 +      /* skip rows and columns, which do not need to be relocated */
 226.128 +      for (k = luf->sv_head; k != 0; k = sv_next[k])
 226.129 +      {  if (k <= n)
 226.130 +         {  /* i-th row of the matrix V */
 226.131 +            i = k;
 226.132 +            if (vr_ptr[i] != sv_beg) break;
 226.133 +            vr_cap[i] = vr_len[i];
 226.134 +            sv_beg += vr_cap[i];
 226.135 +         }
 226.136 +         else
 226.137 +         {  /* j-th column of the matrix V */
 226.138 +            j = k - n;
 226.139 +            if (vc_ptr[j] != sv_beg) break;
 226.140 +            vc_cap[j] = vc_len[j];
 226.141 +            sv_beg += vc_cap[j];
 226.142 +         }
 226.143 +      }
 226.144 +      /* relocate other rows and columns in order to gather all unused
 226.145 +         locations in one continuous extent */
 226.146 +      for (k = k; k != 0; k = sv_next[k])
 226.147 +      {  if (k <= n)
 226.148 +         {  /* i-th row of the matrix V */
 226.149 +            i = k;
 226.150 +            memmove(&sv_ind[sv_beg], &sv_ind[vr_ptr[i]],
 226.151 +               vr_len[i] * sizeof(int));
 226.152 +            memmove(&sv_val[sv_beg], &sv_val[vr_ptr[i]],
 226.153 +               vr_len[i] * sizeof(double));
 226.154 +            vr_ptr[i] = sv_beg;
 226.155 +            vr_cap[i] = vr_len[i];
 226.156 +            sv_beg += vr_cap[i];
 226.157 +         }
 226.158 +         else
 226.159 +         {  /* j-th column of the matrix V */
 226.160 +            j = k - n;
 226.161 +            memmove(&sv_ind[sv_beg], &sv_ind[vc_ptr[j]],
 226.162 +               vc_len[j] * sizeof(int));
 226.163 +            memmove(&sv_val[sv_beg], &sv_val[vc_ptr[j]],
 226.164 +               vc_len[j] * sizeof(double));
 226.165 +            vc_ptr[j] = sv_beg;
 226.166 +            vc_cap[j] = vc_len[j];
 226.167 +            sv_beg += vc_cap[j];
 226.168 +         }
 226.169 +      }
 226.170 +      /* set new pointer to the beginning of the free part */
 226.171 +      luf->sv_beg = sv_beg;
 226.172 +      return;
 226.173 +}
 226.174 +
 226.175 +/***********************************************************************
 226.176 +*  NAME
 226.177 +*
 226.178 +*  luf_enlarge_row - enlarge row capacity
 226.179 +*
 226.180 +*  SYNOPSIS
 226.181 +*
 226.182 +*  #include "glpluf.h"
 226.183 +*  int luf_enlarge_row(LUF *luf, int i, int cap);
 226.184 +*
 226.185 +*  DESCRIPTION
 226.186 +*
 226.187 +*  The routine luf_enlarge_row enlarges capacity of the i-th row of the
 226.188 +*  matrix V to cap locations (assuming that its current capacity is less
 226.189 +*  than cap). In order to do that the routine relocates elements of the
 226.190 +*  i-th row to the end of the left part of SVA (which contains rows and
 226.191 +*  columns of the matrix V) and then expands the left part by allocating
 226.192 +*  cap free locations from the free part. If there are less than cap
 226.193 +*  free locations, the routine defragments the sparse vector area.
 226.194 +*
 226.195 +*  Due to "garbage collection" this operation may change row and column
 226.196 +*  pointers of the matrix V.
 226.197 +*
 226.198 +*  RETURNS
 226.199 +*
 226.200 +*  If no error occured, the routine returns zero. Otherwise, in case of
 226.201 +*  overflow of the sparse vector area, the routine returns non-zero. */
 226.202 +
 226.203 +int luf_enlarge_row(LUF *luf, int i, int cap)
 226.204 +{     int n = luf->n;
 226.205 +      int *vr_ptr = luf->vr_ptr;
 226.206 +      int *vr_len = luf->vr_len;
 226.207 +      int *vr_cap = luf->vr_cap;
 226.208 +      int *vc_cap = luf->vc_cap;
 226.209 +      int *sv_ind = luf->sv_ind;
 226.210 +      double *sv_val = luf->sv_val;
 226.211 +      int *sv_prev = luf->sv_prev;
 226.212 +      int *sv_next = luf->sv_next;
 226.213 +      int ret = 0;
 226.214 +      int cur, k, kk;
 226.215 +      xassert(1 <= i && i <= n);
 226.216 +      xassert(vr_cap[i] < cap);
 226.217 +      /* if there are less than cap free locations, defragment SVA */
 226.218 +      if (luf->sv_end - luf->sv_beg < cap)
 226.219 +      {  luf_defrag_sva(luf);
 226.220 +         if (luf->sv_end - luf->sv_beg < cap)
 226.221 +         {  ret = 1;
 226.222 +            goto done;
 226.223 +         }
 226.224 +      }
 226.225 +      /* save current capacity of the i-th row */
 226.226 +      cur = vr_cap[i];
 226.227 +      /* copy existing elements to the beginning of the free part */
 226.228 +      memmove(&sv_ind[luf->sv_beg], &sv_ind[vr_ptr[i]],
 226.229 +         vr_len[i] * sizeof(int));
 226.230 +      memmove(&sv_val[luf->sv_beg], &sv_val[vr_ptr[i]],
 226.231 +         vr_len[i] * sizeof(double));
 226.232 +      /* set new pointer and new capacity of the i-th row */
 226.233 +      vr_ptr[i] = luf->sv_beg;
 226.234 +      vr_cap[i] = cap;
 226.235 +      /* set new pointer to the beginning of the free part */
 226.236 +      luf->sv_beg += cap;
 226.237 +      /* now the i-th row starts in the rightmost location among other
 226.238 +         rows and columns of the matrix V, so its node should be moved
 226.239 +         to the end of the row/column linked list */
 226.240 +      k = i;
 226.241 +      /* remove the i-th row node from the linked list */
 226.242 +      if (sv_prev[k] == 0)
 226.243 +         luf->sv_head = sv_next[k];
 226.244 +      else
 226.245 +      {  /* capacity of the previous row/column can be increased at the
 226.246 +            expense of old locations of the i-th row */
 226.247 +         kk = sv_prev[k];
 226.248 +         if (kk <= n) vr_cap[kk] += cur; else vc_cap[kk-n] += cur;
 226.249 +         sv_next[sv_prev[k]] = sv_next[k];
 226.250 +      }
 226.251 +      if (sv_next[k] == 0)
 226.252 +         luf->sv_tail = sv_prev[k];
 226.253 +      else
 226.254 +         sv_prev[sv_next[k]] = sv_prev[k];
 226.255 +      /* insert the i-th row node to the end of the linked list */
 226.256 +      sv_prev[k] = luf->sv_tail;
 226.257 +      sv_next[k] = 0;
 226.258 +      if (sv_prev[k] == 0)
 226.259 +         luf->sv_head = k;
 226.260 +      else
 226.261 +         sv_next[sv_prev[k]] = k;
 226.262 +      luf->sv_tail = k;
 226.263 +done: return ret;
 226.264 +}
 226.265 +
 226.266 +/***********************************************************************
 226.267 +*  NAME
 226.268 +*
 226.269 +*  luf_enlarge_col - enlarge column capacity
 226.270 +*
 226.271 +*  SYNOPSIS
 226.272 +*
 226.273 +*  #include "glpluf.h"
 226.274 +*  int luf_enlarge_col(LUF *luf, int j, int cap);
 226.275 +*
 226.276 +*  DESCRIPTION
 226.277 +*
 226.278 +*  The routine luf_enlarge_col enlarges capacity of the j-th column of
 226.279 +*  the matrix V to cap locations (assuming that its current capacity is
 226.280 +*  less than cap). In order to do that the routine relocates elements
 226.281 +*  of the j-th column to the end of the left part of SVA (which contains
 226.282 +*  rows and columns of the matrix V) and then expands the left part by
 226.283 +*  allocating cap free locations from the free part. If there are less
 226.284 +*  than cap free locations, the routine defragments the sparse vector
 226.285 +*  area.
 226.286 +*
 226.287 +*  Due to "garbage collection" this operation may change row and column
 226.288 +*  pointers of the matrix V.
 226.289 +*
 226.290 +*  RETURNS
 226.291 +*
 226.292 +*  If no error occured, the routine returns zero. Otherwise, in case of
 226.293 +*  overflow of the sparse vector area, the routine returns non-zero. */
 226.294 +
 226.295 +int luf_enlarge_col(LUF *luf, int j, int cap)
 226.296 +{     int n = luf->n;
 226.297 +      int *vr_cap = luf->vr_cap;
 226.298 +      int *vc_ptr = luf->vc_ptr;
 226.299 +      int *vc_len = luf->vc_len;
 226.300 +      int *vc_cap = luf->vc_cap;
 226.301 +      int *sv_ind = luf->sv_ind;
 226.302 +      double *sv_val = luf->sv_val;
 226.303 +      int *sv_prev = luf->sv_prev;
 226.304 +      int *sv_next = luf->sv_next;
 226.305 +      int ret = 0;
 226.306 +      int cur, k, kk;
 226.307 +      xassert(1 <= j && j <= n);
 226.308 +      xassert(vc_cap[j] < cap);
 226.309 +      /* if there are less than cap free locations, defragment SVA */
 226.310 +      if (luf->sv_end - luf->sv_beg < cap)
 226.311 +      {  luf_defrag_sva(luf);
 226.312 +         if (luf->sv_end - luf->sv_beg < cap)
 226.313 +         {  ret = 1;
 226.314 +            goto done;
 226.315 +         }
 226.316 +      }
 226.317 +      /* save current capacity of the j-th column */
 226.318 +      cur = vc_cap[j];
 226.319 +      /* copy existing elements to the beginning of the free part */
 226.320 +      memmove(&sv_ind[luf->sv_beg], &sv_ind[vc_ptr[j]],
 226.321 +         vc_len[j] * sizeof(int));
 226.322 +      memmove(&sv_val[luf->sv_beg], &sv_val[vc_ptr[j]],
 226.323 +         vc_len[j] * sizeof(double));
 226.324 +      /* set new pointer and new capacity of the j-th column */
 226.325 +      vc_ptr[j] = luf->sv_beg;
 226.326 +      vc_cap[j] = cap;
 226.327 +      /* set new pointer to the beginning of the free part */
 226.328 +      luf->sv_beg += cap;
 226.329 +      /* now the j-th column starts in the rightmost location among
 226.330 +         other rows and columns of the matrix V, so its node should be
 226.331 +         moved to the end of the row/column linked list */
 226.332 +      k = n + j;
 226.333 +      /* remove the j-th column node from the linked list */
 226.334 +      if (sv_prev[k] == 0)
 226.335 +         luf->sv_head = sv_next[k];
 226.336 +      else
 226.337 +      {  /* capacity of the previous row/column can be increased at the
 226.338 +            expense of old locations of the j-th column */
 226.339 +         kk = sv_prev[k];
 226.340 +         if (kk <= n) vr_cap[kk] += cur; else vc_cap[kk-n] += cur;
 226.341 +         sv_next[sv_prev[k]] = sv_next[k];
 226.342 +      }
 226.343 +      if (sv_next[k] == 0)
 226.344 +         luf->sv_tail = sv_prev[k];
 226.345 +      else
 226.346 +         sv_prev[sv_next[k]] = sv_prev[k];
 226.347 +      /* insert the j-th column node to the end of the linked list */
 226.348 +      sv_prev[k] = luf->sv_tail;
 226.349 +      sv_next[k] = 0;
 226.350 +      if (sv_prev[k] == 0)
 226.351 +         luf->sv_head = k;
 226.352 +      else
 226.353 +         sv_next[sv_prev[k]] = k;
 226.354 +      luf->sv_tail = k;
 226.355 +done: return ret;
 226.356 +}
 226.357 +
 226.358 +/***********************************************************************
 226.359 +*  reallocate - reallocate LU-factorization arrays
 226.360 +*
 226.361 +*  This routine reallocates arrays, whose size depends of n, the order
 226.362 +*  of the matrix A to be factorized. */
 226.363 +
 226.364 +static void reallocate(LUF *luf, int n)
 226.365 +{     int n_max = luf->n_max;
 226.366 +      luf->n = n;
 226.367 +      if (n <= n_max) goto done;
 226.368 +      if (luf->fr_ptr != NULL) xfree(luf->fr_ptr);
 226.369 +      if (luf->fr_len != NULL) xfree(luf->fr_len);
 226.370 +      if (luf->fc_ptr != NULL) xfree(luf->fc_ptr);
 226.371 +      if (luf->fc_len != NULL) xfree(luf->fc_len);
 226.372 +      if (luf->vr_ptr != NULL) xfree(luf->vr_ptr);
 226.373 +      if (luf->vr_len != NULL) xfree(luf->vr_len);
 226.374 +      if (luf->vr_cap != NULL) xfree(luf->vr_cap);
 226.375 +      if (luf->vr_piv != NULL) xfree(luf->vr_piv);
 226.376 +      if (luf->vc_ptr != NULL) xfree(luf->vc_ptr);
 226.377 +      if (luf->vc_len != NULL) xfree(luf->vc_len);
 226.378 +      if (luf->vc_cap != NULL) xfree(luf->vc_cap);
 226.379 +      if (luf->pp_row != NULL) xfree(luf->pp_row);
 226.380 +      if (luf->pp_col != NULL) xfree(luf->pp_col);
 226.381 +      if (luf->qq_row != NULL) xfree(luf->qq_row);
 226.382 +      if (luf->qq_col != NULL) xfree(luf->qq_col);
 226.383 +      if (luf->sv_prev != NULL) xfree(luf->sv_prev);
 226.384 +      if (luf->sv_next != NULL) xfree(luf->sv_next);
 226.385 +      if (luf->vr_max != NULL) xfree(luf->vr_max);
 226.386 +      if (luf->rs_head != NULL) xfree(luf->rs_head);
 226.387 +      if (luf->rs_prev != NULL) xfree(luf->rs_prev);
 226.388 +      if (luf->rs_next != NULL) xfree(luf->rs_next);
 226.389 +      if (luf->cs_head != NULL) xfree(luf->cs_head);
 226.390 +      if (luf->cs_prev != NULL) xfree(luf->cs_prev);
 226.391 +      if (luf->cs_next != NULL) xfree(luf->cs_next);
 226.392 +      if (luf->flag != NULL) xfree(luf->flag);
 226.393 +      if (luf->work != NULL) xfree(luf->work);
 226.394 +      luf->n_max = n_max = n + 100;
 226.395 +      luf->fr_ptr = xcalloc(1+n_max, sizeof(int));
 226.396 +      luf->fr_len = xcalloc(1+n_max, sizeof(int));
 226.397 +      luf->fc_ptr = xcalloc(1+n_max, sizeof(int));
 226.398 +      luf->fc_len = xcalloc(1+n_max, sizeof(int));
 226.399 +      luf->vr_ptr = xcalloc(1+n_max, sizeof(int));
 226.400 +      luf->vr_len = xcalloc(1+n_max, sizeof(int));
 226.401 +      luf->vr_cap = xcalloc(1+n_max, sizeof(int));
 226.402 +      luf->vr_piv = xcalloc(1+n_max, sizeof(double));
 226.403 +      luf->vc_ptr = xcalloc(1+n_max, sizeof(int));
 226.404 +      luf->vc_len = xcalloc(1+n_max, sizeof(int));
 226.405 +      luf->vc_cap = xcalloc(1+n_max, sizeof(int));
 226.406 +      luf->pp_row = xcalloc(1+n_max, sizeof(int));
 226.407 +      luf->pp_col = xcalloc(1+n_max, sizeof(int));
 226.408 +      luf->qq_row = xcalloc(1+n_max, sizeof(int));
 226.409 +      luf->qq_col = xcalloc(1+n_max, sizeof(int));
 226.410 +      luf->sv_prev = xcalloc(1+n_max+n_max, sizeof(int));
 226.411 +      luf->sv_next = xcalloc(1+n_max+n_max, sizeof(int));
 226.412 +      luf->vr_max = xcalloc(1+n_max, sizeof(double));
 226.413 +      luf->rs_head = xcalloc(1+n_max, sizeof(int));
 226.414 +      luf->rs_prev = xcalloc(1+n_max, sizeof(int));
 226.415 +      luf->rs_next = xcalloc(1+n_max, sizeof(int));
 226.416 +      luf->cs_head = xcalloc(1+n_max, sizeof(int));
 226.417 +      luf->cs_prev = xcalloc(1+n_max, sizeof(int));
 226.418 +      luf->cs_next = xcalloc(1+n_max, sizeof(int));
 226.419 +      luf->flag = xcalloc(1+n_max, sizeof(int));
 226.420 +      luf->work = xcalloc(1+n_max, sizeof(double));
 226.421 +done: return;
 226.422 +}
 226.423 +
 226.424 +/***********************************************************************
 226.425 +*  initialize - initialize LU-factorization data structures
 226.426 +*
 226.427 +*  This routine initializes data structures for subsequent computing
 226.428 +*  the LU-factorization of a given matrix A, which is specified by the
 226.429 +*  formal routine col. On exit V = A and F = P = Q = I, where I is the
 226.430 +*  unity matrix. (Row-wise representation of the matrix F is not used
 226.431 +*  at the factorization stage and therefore is not initialized.)
 226.432 +*
 226.433 +*  If no error occured, the routine returns zero. Otherwise, in case of
 226.434 +*  overflow of the sparse vector area, the routine returns non-zero. */
 226.435 +
 226.436 +static int initialize(LUF *luf, int (*col)(void *info, int j, int rn[],
 226.437 +      double aj[]), void *info)
 226.438 +{     int n = luf->n;
 226.439 +      int *fc_ptr = luf->fc_ptr;
 226.440 +      int *fc_len = luf->fc_len;
 226.441 +      int *vr_ptr = luf->vr_ptr;
 226.442 +      int *vr_len = luf->vr_len;
 226.443 +      int *vr_cap = luf->vr_cap;
 226.444 +      int *vc_ptr = luf->vc_ptr;
 226.445 +      int *vc_len = luf->vc_len;
 226.446 +      int *vc_cap = luf->vc_cap;
 226.447 +      int *pp_row = luf->pp_row;
 226.448 +      int *pp_col = luf->pp_col;
 226.449 +      int *qq_row = luf->qq_row;
 226.450 +      int *qq_col = luf->qq_col;
 226.451 +      int *sv_ind = luf->sv_ind;
 226.452 +      double *sv_val = luf->sv_val;
 226.453 +      int *sv_prev = luf->sv_prev;
 226.454 +      int *sv_next = luf->sv_next;
 226.455 +      double *vr_max = luf->vr_max;
 226.456 +      int *rs_head = luf->rs_head;
 226.457 +      int *rs_prev = luf->rs_prev;
 226.458 +      int *rs_next = luf->rs_next;
 226.459 +      int *cs_head = luf->cs_head;
 226.460 +      int *cs_prev = luf->cs_prev;
 226.461 +      int *cs_next = luf->cs_next;
 226.462 +      int *flag = luf->flag;
 226.463 +      double *work = luf->work;
 226.464 +      int ret = 0;
 226.465 +      int i, i_ptr, j, j_beg, j_end, k, len, nnz, sv_beg, sv_end, ptr;
 226.466 +      double big, val;
 226.467 +      /* free all locations of the sparse vector area */
 226.468 +      sv_beg = 1;
 226.469 +      sv_end = luf->sv_size + 1;
 226.470 +      /* (row-wise representation of the matrix F is not initialized,
 226.471 +         because it is not used at the factorization stage) */
 226.472 +      /* build the matrix F in column-wise format (initially F = I) */
 226.473 +      for (j = 1; j <= n; j++)
 226.474 +      {  fc_ptr[j] = sv_end;
 226.475 +         fc_len[j] = 0;
 226.476 +      }
 226.477 +      /* clear rows of the matrix V; clear the flag array */
 226.478 +      for (i = 1; i <= n; i++)
 226.479 +         vr_len[i] = vr_cap[i] = 0, flag[i] = 0;
 226.480 +      /* build the matrix V in column-wise format (initially V = A);
 226.481 +         count non-zeros in rows of this matrix; count total number of
 226.482 +         non-zeros; compute largest of absolute values of elements */
 226.483 +      nnz = 0;
 226.484 +      big = 0.0;
 226.485 +      for (j = 1; j <= n; j++)
 226.486 +      {  int *rn = pp_row;
 226.487 +         double *aj = work;
 226.488 +         /* obtain j-th column of the matrix A */
 226.489 +         len = col(info, j, rn, aj);
 226.490 +         if (!(0 <= len && len <= n))
 226.491 +            xfault("luf_factorize: j = %d; len = %d; invalid column len"
 226.492 +               "gth\n", j, len);
 226.493 +         /* check for free locations */
 226.494 +         if (sv_end - sv_beg < len)
 226.495 +         {  /* overflow of the sparse vector area */
 226.496 +            ret = 1;
 226.497 +            goto done;
 226.498 +         }
 226.499 +         /* set pointer to the j-th column */
 226.500 +         vc_ptr[j] = sv_beg;
 226.501 +         /* set length of the j-th column */
 226.502 +         vc_len[j] = vc_cap[j] = len;
 226.503 +         /* count total number of non-zeros */
 226.504 +         nnz += len;
 226.505 +         /* walk through elements of the j-th column */
 226.506 +         for (ptr = 1; ptr <= len; ptr++)
 226.507 +         {  /* get row index and numerical value of a[i,j] */
 226.508 +            i = rn[ptr];
 226.509 +            val = aj[ptr];
 226.510 +            if (!(1 <= i && i <= n))
 226.511 +               xfault("luf_factorize: i = %d; j = %d; invalid row index"
 226.512 +                  "\n", i, j);
 226.513 +            if (flag[i])
 226.514 +               xfault("luf_factorize: i = %d; j = %d; duplicate element"
 226.515 +                  " not allowed\n", i, j);
 226.516 +            if (val == 0.0)
 226.517 +               xfault("luf_factorize: i = %d; j = %d; zero element not "
 226.518 +                  "allowed\n", i, j);
 226.519 +            /* add new element v[i,j] = a[i,j] to j-th column */
 226.520 +            sv_ind[sv_beg] = i;
 226.521 +            sv_val[sv_beg] = val;
 226.522 +            sv_beg++;
 226.523 +            /* big := max(big, |a[i,j]|) */
 226.524 +            if (val < 0.0) val = - val;
 226.525 +            if (big < val) big = val;
 226.526 +            /* mark non-zero in the i-th position of the j-th column */
 226.527 +            flag[i] = 1;
 226.528 +            /* increase length of the i-th row */
 226.529 +            vr_cap[i]++;
 226.530 +         }
 226.531 +         /* reset all non-zero marks */
 226.532 +         for (ptr = 1; ptr <= len; ptr++) flag[rn[ptr]] = 0;
 226.533 +      }
 226.534 +      /* allocate rows of the matrix V */
 226.535 +      for (i = 1; i <= n; i++)
 226.536 +      {  /* get length of the i-th row */
 226.537 +         len = vr_cap[i];
 226.538 +         /* check for free locations */
 226.539 +         if (sv_end - sv_beg < len)
 226.540 +         {  /* overflow of the sparse vector area */
 226.541 +            ret = 1;
 226.542 +            goto done;
 226.543 +         }
 226.544 +         /* set pointer to the i-th row */
 226.545 +         vr_ptr[i] = sv_beg;
 226.546 +         /* reserve locations for the i-th row */
 226.547 +         sv_beg += len;
 226.548 +      }
 226.549 +      /* build the matrix V in row-wise format using representation of
 226.550 +         this matrix in column-wise format */
 226.551 +      for (j = 1; j <= n; j++)
 226.552 +      {  /* walk through elements of the j-th column */
 226.553 +         j_beg = vc_ptr[j];
 226.554 +         j_end = j_beg + vc_len[j] - 1;
 226.555 +         for (k = j_beg; k <= j_end; k++)
 226.556 +         {  /* get row index and numerical value of v[i,j] */
 226.557 +            i = sv_ind[k];
 226.558 +            val = sv_val[k];
 226.559 +            /* store element in the i-th row */
 226.560 +            i_ptr = vr_ptr[i] + vr_len[i];
 226.561 +            sv_ind[i_ptr] = j;
 226.562 +            sv_val[i_ptr] = val;
 226.563 +            /* increase count of the i-th row */
 226.564 +            vr_len[i]++;
 226.565 +         }
 226.566 +      }
 226.567 +      /* initialize the matrices P and Q (initially P = Q = I) */
 226.568 +      for (k = 1; k <= n; k++)
 226.569 +         pp_row[k] = pp_col[k] = qq_row[k] = qq_col[k] = k;
 226.570 +      /* set sva partitioning pointers */
 226.571 +      luf->sv_beg = sv_beg;
 226.572 +      luf->sv_end = sv_end;
 226.573 +      /* the initial physical order of rows and columns of the matrix V
 226.574 +         is n+1, ..., n+n, 1, ..., n (firstly columns, then rows) */
 226.575 +      luf->sv_head = n+1;
 226.576 +      luf->sv_tail = n;
 226.577 +      for (i = 1; i <= n; i++)
 226.578 +      {  sv_prev[i] = i-1;
 226.579 +         sv_next[i] = i+1;
 226.580 +      }
 226.581 +      sv_prev[1] = n+n;
 226.582 +      sv_next[n] = 0;
 226.583 +      for (j = 1; j <= n; j++)
 226.584 +      {  sv_prev[n+j] = n+j-1;
 226.585 +         sv_next[n+j] = n+j+1;
 226.586 +      }
 226.587 +      sv_prev[n+1] = 0;
 226.588 +      sv_next[n+n] = 1;
 226.589 +      /* clear working arrays */
 226.590 +      for (k = 1; k <= n; k++)
 226.591 +      {  flag[k] = 0;
 226.592 +         work[k] = 0.0;
 226.593 +      }
 226.594 +      /* initialize some statistics */
 226.595 +      luf->nnz_a = nnz;
 226.596 +      luf->nnz_f = 0;
 226.597 +      luf->nnz_v = nnz;
 226.598 +      luf->max_a = big;
 226.599 +      luf->big_v = big;
 226.600 +      luf->rank = -1;
 226.601 +      /* initially the active submatrix is the entire matrix V */
 226.602 +      /* largest of absolute values of elements in each active row is
 226.603 +         unknown yet */
 226.604 +      for (i = 1; i <= n; i++) vr_max[i] = -1.0;
 226.605 +      /* build linked lists of active rows */
 226.606 +      for (len = 0; len <= n; len++) rs_head[len] = 0;
 226.607 +      for (i = 1; i <= n; i++)
 226.608 +      {  len = vr_len[i];
 226.609 +         rs_prev[i] = 0;
 226.610 +         rs_next[i] = rs_head[len];
 226.611 +         if (rs_next[i] != 0) rs_prev[rs_next[i]] = i;
 226.612 +         rs_head[len] = i;
 226.613 +      }
 226.614 +      /* build linked lists of active columns */
 226.615 +      for (len = 0; len <= n; len++) cs_head[len] = 0;
 226.616 +      for (j = 1; j <= n; j++)
 226.617 +      {  len = vc_len[j];
 226.618 +         cs_prev[j] = 0;
 226.619 +         cs_next[j] = cs_head[len];
 226.620 +         if (cs_next[j] != 0) cs_prev[cs_next[j]] = j;
 226.621 +         cs_head[len] = j;
 226.622 +      }
 226.623 +done: /* return to the factorizing routine */
 226.624 +      return ret;
 226.625 +}
 226.626 +
 226.627 +/***********************************************************************
 226.628 +*  find_pivot - choose a pivot element
 226.629 +*
 226.630 +*  This routine chooses a pivot element in the active submatrix of the
 226.631 +*  matrix U = P*V*Q.
 226.632 +*
 226.633 +*  It is assumed that on entry the matrix U has the following partially
 226.634 +*  triangularized form:
 226.635 +* 
 226.636 +*        1       k         n
 226.637 +*     1  x x x x x x x x x x
 226.638 +*        . x x x x x x x x x
 226.639 +*        . . x x x x x x x x
 226.640 +*        . . . x x x x x x x
 226.641 +*     k  . . . . * * * * * *
 226.642 +*        . . . . * * * * * *
 226.643 +*        . . . . * * * * * *
 226.644 +*        . . . . * * * * * *
 226.645 +*        . . . . * * * * * *
 226.646 +*     n  . . . . * * * * * *
 226.647 +* 
 226.648 +*  where rows and columns k, k+1, ..., n belong to the active submatrix
 226.649 +*  (elements of the active submatrix are marked by '*').
 226.650 +*
 226.651 +*  Since the matrix U = P*V*Q is not stored, the routine works with the
 226.652 +*  matrix V. It is assumed that the row-wise representation corresponds
 226.653 +*  to the matrix V, but the column-wise representation corresponds to
 226.654 +*  the active submatrix of the matrix V, i.e. elements of the matrix V,
 226.655 +*  which doesn't belong to the active submatrix, are missing from the
 226.656 +*  column linked lists. It is also assumed that each active row of the
 226.657 +*  matrix V is in the set R[len], where len is number of non-zeros in
 226.658 +*  the row, and each active column of the matrix V is in the set C[len],
 226.659 +*  where len is number of non-zeros in the column (in the latter case
 226.660 +*  only elements of the active submatrix are counted; such elements are
 226.661 +*  marked by '*' on the figure above).
 226.662 +* 
 226.663 +*  For the reason of numerical stability the routine applies so called
 226.664 +*  threshold pivoting proposed by J.Reid. It is assumed that an element
 226.665 +*  v[i,j] can be selected as a pivot candidate if it is not very small
 226.666 +*  (in absolute value) among other elements in the same row, i.e. if it
 226.667 +*  satisfies to the stability condition |v[i,j]| >= tol * max|v[i,*]|,
 226.668 +*  where 0 < tol < 1 is a given tolerance.
 226.669 +* 
 226.670 +*  In order to keep sparsity of the matrix V the routine uses Markowitz
 226.671 +*  strategy, trying to choose such element v[p,q], which satisfies to
 226.672 +*  the stability condition (see above) and has smallest Markowitz cost
 226.673 +*  (nr[p]-1) * (nc[q]-1), where nr[p] and nc[q] are numbers of non-zero
 226.674 +*  elements, respectively, in the p-th row and in the q-th column of the
 226.675 +*  active submatrix.
 226.676 +* 
 226.677 +*  In order to reduce the search, i.e. not to walk through all elements
 226.678 +*  of the active submatrix, the routine exploits a technique proposed by
 226.679 +*  I.Duff. This technique is based on using the sets R[len] and C[len]
 226.680 +*  of active rows and columns.
 226.681 +* 
 226.682 +*  If the pivot element v[p,q] has been chosen, the routine stores its
 226.683 +*  indices to the locations *p and *q and returns zero. Otherwise, if
 226.684 +*  the active submatrix is empty and therefore the pivot element can't
 226.685 +*  be chosen, the routine returns non-zero. */
 226.686 +
 226.687 +static int find_pivot(LUF *luf, int *_p, int *_q)
 226.688 +{     int n = luf->n;
 226.689 +      int *vr_ptr = luf->vr_ptr;
 226.690 +      int *vr_len = luf->vr_len;
 226.691 +      int *vc_ptr = luf->vc_ptr;
 226.692 +      int *vc_len = luf->vc_len;
 226.693 +      int *sv_ind = luf->sv_ind;
 226.694 +      double *sv_val = luf->sv_val;
 226.695 +      double *vr_max = luf->vr_max;
 226.696 +      int *rs_head = luf->rs_head;
 226.697 +      int *rs_next = luf->rs_next;
 226.698 +      int *cs_head = luf->cs_head;
 226.699 +      int *cs_prev = luf->cs_prev;
 226.700 +      int *cs_next = luf->cs_next;
 226.701 +      double piv_tol = luf->piv_tol;
 226.702 +      int piv_lim = luf->piv_lim;
 226.703 +      int suhl = luf->suhl;
 226.704 +      int p, q, len, i, i_beg, i_end, i_ptr, j, j_beg, j_end, j_ptr,
 226.705 +         ncand, next_j, min_p, min_q, min_len;
 226.706 +      double best, cost, big, temp;
 226.707 +      /* initially no pivot candidates have been found so far */
 226.708 +      p = q = 0, best = DBL_MAX, ncand = 0;
 226.709 +      /* if in the active submatrix there is a column that has the only
 226.710 +         non-zero (column singleton), choose it as pivot */
 226.711 +      j = cs_head[1];
 226.712 +      if (j != 0)
 226.713 +      {  xassert(vc_len[j] == 1);
 226.714 +         p = sv_ind[vc_ptr[j]], q = j;
 226.715 +         goto done;
 226.716 +      }
 226.717 +      /* if in the active submatrix there is a row that has the only
 226.718 +         non-zero (row singleton), choose it as pivot */
 226.719 +      i = rs_head[1];
 226.720 +      if (i != 0)
 226.721 +      {  xassert(vr_len[i] == 1);
 226.722 +         p = i, q = sv_ind[vr_ptr[i]];
 226.723 +         goto done;
 226.724 +      }
 226.725 +      /* there are no singletons in the active submatrix; walk through
 226.726 +         other non-empty rows and columns */
 226.727 +      for (len = 2; len <= n; len++)
 226.728 +      {  /* consider active columns that have len non-zeros */
 226.729 +         for (j = cs_head[len]; j != 0; j = next_j)
 226.730 +         {  /* the j-th column has len non-zeros */
 226.731 +            j_beg = vc_ptr[j];
 226.732 +            j_end = j_beg + vc_len[j] - 1;
 226.733 +            /* save pointer to the next column with the same length */
 226.734 +            next_j = cs_next[j];
 226.735 +            /* find an element in the j-th column, which is placed in a
 226.736 +               row with minimal number of non-zeros and satisfies to the
 226.737 +               stability condition (such element may not exist) */
 226.738 +            min_p = min_q = 0, min_len = INT_MAX;
 226.739 +            for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
 226.740 +            {  /* get row index of v[i,j] */
 226.741 +               i = sv_ind[j_ptr];
 226.742 +               i_beg = vr_ptr[i];
 226.743 +               i_end = i_beg + vr_len[i] - 1;
 226.744 +               /* if the i-th row is not shorter than that one, where
 226.745 +                  minimal element is currently placed, skip v[i,j] */
 226.746 +               if (vr_len[i] >= min_len) continue;
 226.747 +               /* determine the largest of absolute values of elements
 226.748 +                  in the i-th row */
 226.749 +               big = vr_max[i];
 226.750 +               if (big < 0.0)
 226.751 +               {  /* the largest value is unknown yet; compute it */
 226.752 +                  for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
 226.753 +                  {  temp = sv_val[i_ptr];
 226.754 +                     if (temp < 0.0) temp = - temp;
 226.755 +                     if (big < temp) big = temp;
 226.756 +                  }
 226.757 +                  vr_max[i] = big;
 226.758 +               }
 226.759 +               /* find v[i,j] in the i-th row */
 226.760 +               for (i_ptr = vr_ptr[i]; sv_ind[i_ptr] != j; i_ptr++);
 226.761 +               xassert(i_ptr <= i_end);
 226.762 +               /* if v[i,j] doesn't satisfy to the stability condition,
 226.763 +                  skip it */
 226.764 +               temp = sv_val[i_ptr];
 226.765 +               if (temp < 0.0) temp = - temp;
 226.766 +               if (temp < piv_tol * big) continue;
 226.767 +               /* v[i,j] is better than the current minimal element */
 226.768 +               min_p = i, min_q = j, min_len = vr_len[i];
 226.769 +               /* if Markowitz cost of the current minimal element is
 226.770 +                  not greater than (len-1)**2, it can be chosen right
 226.771 +                  now; this heuristic reduces the search and works well
 226.772 +                  in many cases */
 226.773 +               if (min_len <= len)
 226.774 +               {  p = min_p, q = min_q;
 226.775 +                  goto done;
 226.776 +               }
 226.777 +            }
 226.778 +            /* the j-th column has been scanned */
 226.779 +            if (min_p != 0)
 226.780 +            {  /* the minimal element is a next pivot candidate */
 226.781 +               ncand++;
 226.782 +               /* compute its Markowitz cost */
 226.783 +               cost = (double)(min_len - 1) * (double)(len - 1);
 226.784 +               /* choose between the minimal element and the current
 226.785 +                  candidate */
 226.786 +               if (cost < best) p = min_p, q = min_q, best = cost;
 226.787 +               /* if piv_lim candidates have been considered, there are
 226.788 +                  doubts that a much better candidate exists; therefore
 226.789 +                  it's time to terminate the search */
 226.790 +               if (ncand == piv_lim) goto done;
 226.791 +            }
 226.792 +            else
 226.793 +            {  /* the j-th column has no elements, which satisfy to the
 226.794 +                  stability condition; Uwe Suhl suggests to exclude such
 226.795 +                  column from the further consideration until it becomes
 226.796 +                  a column singleton; in hard cases this significantly
 226.797 +                  reduces a time needed for pivot searching */
 226.798 +               if (suhl)
 226.799 +               {  /* remove the j-th column from the active set */
 226.800 +                  if (cs_prev[j] == 0)
 226.801 +                     cs_head[len] = cs_next[j];
 226.802 +                  else
 226.803 +                     cs_next[cs_prev[j]] = cs_next[j];
 226.804 +                  if (cs_next[j] == 0)
 226.805 +                     /* nop */;
 226.806 +                  else
 226.807 +                     cs_prev[cs_next[j]] = cs_prev[j];
 226.808 +                  /* the following assignment is used to avoid an error
 226.809 +                     when the routine eliminate (see below) will try to
 226.810 +                     remove the j-th column from the active set */
 226.811 +                  cs_prev[j] = cs_next[j] = j;
 226.812 +               }
 226.813 +            }
 226.814 +         }
 226.815 +         /* consider active rows that have len non-zeros */
 226.816 +         for (i = rs_head[len]; i != 0; i = rs_next[i])
 226.817 +         {  /* the i-th row has len non-zeros */
 226.818 +            i_beg = vr_ptr[i];
 226.819 +            i_end = i_beg + vr_len[i] - 1;
 226.820 +            /* determine the largest of absolute values of elements in
 226.821 +               the i-th row */
 226.822 +            big = vr_max[i];
 226.823 +            if (big < 0.0)
 226.824 +            {  /* the largest value is unknown yet; compute it */
 226.825 +               for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
 226.826 +               {  temp = sv_val[i_ptr];
 226.827 +                  if (temp < 0.0) temp = - temp;
 226.828 +                  if (big < temp) big = temp;
 226.829 +               }
 226.830 +               vr_max[i] = big;
 226.831 +            }
 226.832 +            /* find an element in the i-th row, which is placed in a
 226.833 +               column with minimal number of non-zeros and satisfies to
 226.834 +               the stability condition (such element always exists) */
 226.835 +            min_p = min_q = 0, min_len = INT_MAX;
 226.836 +            for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
 226.837 +            {  /* get column index of v[i,j] */
 226.838 +               j = sv_ind[i_ptr];
 226.839 +               /* if the j-th column is not shorter than that one, where
 226.840 +                  minimal element is currently placed, skip v[i,j] */
 226.841 +               if (vc_len[j] >= min_len) continue;
 226.842 +               /* if v[i,j] doesn't satisfy to the stability condition,
 226.843 +                  skip it */
 226.844 +               temp = sv_val[i_ptr];
 226.845 +               if (temp < 0.0) temp = - temp;
 226.846 +               if (temp < piv_tol * big) continue;
 226.847 +               /* v[i,j] is better than the current minimal element */
 226.848 +               min_p = i, min_q = j, min_len = vc_len[j];
 226.849 +               /* if Markowitz cost of the current minimal element is
 226.850 +                  not greater than (len-1)**2, it can be chosen right
 226.851 +                  now; this heuristic reduces the search and works well
 226.852 +                  in many cases */
 226.853 +               if (min_len <= len)
 226.854 +               {  p = min_p, q = min_q;
 226.855 +                  goto done;
 226.856 +               }
 226.857 +            }
 226.858 +            /* the i-th row has been scanned */
 226.859 +            if (min_p != 0)
 226.860 +            {  /* the minimal element is a next pivot candidate */
 226.861 +               ncand++;
 226.862 +               /* compute its Markowitz cost */
 226.863 +               cost = (double)(len - 1) * (double)(min_len - 1);
 226.864 +               /* choose between the minimal element and the current
 226.865 +                  candidate */
 226.866 +               if (cost < best) p = min_p, q = min_q, best = cost;
 226.867 +               /* if piv_lim candidates have been considered, there are
 226.868 +                  doubts that a much better candidate exists; therefore
 226.869 +                  it's time to terminate the search */
 226.870 +               if (ncand == piv_lim) goto done;
 226.871 +            }
 226.872 +            else
 226.873 +            {  /* this can't be because this can never be */
 226.874 +               xassert(min_p != min_p);
 226.875 +            }
 226.876 +         }
 226.877 +      }
 226.878 +done: /* bring the pivot to the factorizing routine */
 226.879 +      *_p = p, *_q = q;
 226.880 +      return (p == 0);
 226.881 +}
 226.882 +
 226.883 +/***********************************************************************
 226.884 +*  eliminate - perform gaussian elimination.
 226.885 +* 
 226.886 +*  This routine performs elementary gaussian transformations in order
 226.887 +*  to eliminate subdiagonal elements in the k-th column of the matrix
 226.888 +*  U = P*V*Q using the pivot element u[k,k], where k is the number of
 226.889 +*  the current elimination step.
 226.890 +* 
 226.891 +*  The parameters p and q are, respectively, row and column indices of
 226.892 +*  the element v[p,q], which corresponds to the element u[k,k].
 226.893 +* 
 226.894 +*  Each time when the routine applies the elementary transformation to
 226.895 +*  a non-pivot row of the matrix V, it stores the corresponding element
 226.896 +*  to the matrix F in order to keep the main equality A = F*V.
 226.897 +* 
 226.898 +*  The routine assumes that on entry the matrices L = P*F*inv(P) and
 226.899 +*  U = P*V*Q are the following:
 226.900 +* 
 226.901 +*        1       k                  1       k         n
 226.902 +*     1  1 . . . . . . . . .     1  x x x x x x x x x x
 226.903 +*        x 1 . . . . . . . .        . x x x x x x x x x
 226.904 +*        x x 1 . . . . . . .        . . x x x x x x x x
 226.905 +*        x x x 1 . . . . . .        . . . x x x x x x x
 226.906 +*     k  x x x x 1 . . . . .     k  . . . . * * * * * *
 226.907 +*        x x x x _ 1 . . . .        . . . . # * * * * *
 226.908 +*        x x x x _ . 1 . . .        . . . . # * * * * *
 226.909 +*        x x x x _ . . 1 . .        . . . . # * * * * *
 226.910 +*        x x x x _ . . . 1 .        . . . . # * * * * *
 226.911 +*     n  x x x x _ . . . . 1     n  . . . . # * * * * *
 226.912 +* 
 226.913 +*             matrix L                   matrix U
 226.914 +* 
 226.915 +*  where rows and columns of the matrix U with numbers k, k+1, ..., n
 226.916 +*  form the active submatrix (eliminated elements are marked by '#' and
 226.917 +*  other elements of the active submatrix are marked by '*'). Note that
 226.918 +*  each eliminated non-zero element u[i,k] of the matrix U gives the
 226.919 +*  corresponding element l[i,k] of the matrix L (marked by '_').
 226.920 +* 
 226.921 +*  Actually all operations are performed on the matrix V. Should note
 226.922 +*  that the row-wise representation corresponds to the matrix V, but the
 226.923 +*  column-wise representation corresponds to the active submatrix of the
 226.924 +*  matrix V, i.e. elements of the matrix V, which doesn't belong to the
 226.925 +*  active submatrix, are missing from the column linked lists.
 226.926 +* 
 226.927 +*  Let u[k,k] = v[p,q] be the pivot. In order to eliminate subdiagonal
 226.928 +*  elements u[i',k] = v[i,q], i' = k+1, k+2, ..., n, the routine applies
 226.929 +*  the following elementary gaussian transformations:
 226.930 +* 
 226.931 +*     (i-th row of V) := (i-th row of V) - f[i,p] * (p-th row of V),
 226.932 +* 
 226.933 +*  where f[i,p] = v[i,q] / v[p,q] is a gaussian multiplier.
 226.934 +*
 226.935 +*  Additionally, in order to keep the main equality A = F*V, each time
 226.936 +*  when the routine applies the transformation to i-th row of the matrix
 226.937 +*  V, it also adds f[i,p] as a new element to the matrix F.
 226.938 +*
 226.939 +*  IMPORTANT: On entry the working arrays flag and work should contain
 226.940 +*  zeros. This status is provided by the routine on exit.
 226.941 +*
 226.942 +*  If no error occured, the routine returns zero. Otherwise, in case of
 226.943 +*  overflow of the sparse vector area, the routine returns non-zero. */
 226.944 +
 226.945 +static int eliminate(LUF *luf, int p, int q)
 226.946 +{     int n = luf->n;
 226.947 +      int *fc_ptr = luf->fc_ptr;
 226.948 +      int *fc_len = luf->fc_len;
 226.949 +      int *vr_ptr = luf->vr_ptr;
 226.950 +      int *vr_len = luf->vr_len;
 226.951 +      int *vr_cap = luf->vr_cap;
 226.952 +      double *vr_piv = luf->vr_piv;
 226.953 +      int *vc_ptr = luf->vc_ptr;
 226.954 +      int *vc_len = luf->vc_len;
 226.955 +      int *vc_cap = luf->vc_cap;
 226.956 +      int *sv_ind = luf->sv_ind;
 226.957 +      double *sv_val = luf->sv_val;
 226.958 +      int *sv_prev = luf->sv_prev;
 226.959 +      int *sv_next = luf->sv_next;
 226.960 +      double *vr_max = luf->vr_max;
 226.961 +      int *rs_head = luf->rs_head;
 226.962 +      int *rs_prev = luf->rs_prev;
 226.963 +      int *rs_next = luf->rs_next;
 226.964 +      int *cs_head = luf->cs_head;
 226.965 +      int *cs_prev = luf->cs_prev;
 226.966 +      int *cs_next = luf->cs_next;
 226.967 +      int *flag = luf->flag;
 226.968 +      double *work = luf->work;
 226.969 +      double eps_tol = luf->eps_tol;
 226.970 +      /* at this stage the row-wise representation of the matrix F is
 226.971 +         not used, so fr_len can be used as a working array */
 226.972 +      int *ndx = luf->fr_len;
 226.973 +      int ret = 0;
 226.974 +      int len, fill, i, i_beg, i_end, i_ptr, j, j_beg, j_end, j_ptr, k,
 226.975 +         p_beg, p_end, p_ptr, q_beg, q_end, q_ptr;
 226.976 +      double fip, val, vpq, temp;
 226.977 +      xassert(1 <= p && p <= n);
 226.978 +      xassert(1 <= q && q <= n);
 226.979 +      /* remove the p-th (pivot) row from the active set; this row will
 226.980 +         never return there */
 226.981 +      if (rs_prev[p] == 0)
 226.982 +         rs_head[vr_len[p]] = rs_next[p];
 226.983 +      else
 226.984 +         rs_next[rs_prev[p]] = rs_next[p];
 226.985 +      if (rs_next[p] == 0)
 226.986 +         ;
 226.987 +      else
 226.988 +         rs_prev[rs_next[p]] = rs_prev[p];
 226.989 +      /* remove the q-th (pivot) column from the active set; this column
 226.990 +         will never return there */
 226.991 +      if (cs_prev[q] == 0)
 226.992 +         cs_head[vc_len[q]] = cs_next[q];
 226.993 +      else
 226.994 +         cs_next[cs_prev[q]] = cs_next[q];
 226.995 +      if (cs_next[q] == 0)
 226.996 +         ;
 226.997 +      else
 226.998 +         cs_prev[cs_next[q]] = cs_prev[q];
 226.999 +      /* find the pivot v[p,q] = u[k,k] in the p-th row */
226.1000 +      p_beg = vr_ptr[p];
226.1001 +      p_end = p_beg + vr_len[p] - 1;
226.1002 +      for (p_ptr = p_beg; sv_ind[p_ptr] != q; p_ptr++) /* nop */;
226.1003 +      xassert(p_ptr <= p_end);
226.1004 +      /* store value of the pivot */
226.1005 +      vpq = (vr_piv[p] = sv_val[p_ptr]);
226.1006 +      /* remove the pivot from the p-th row */
226.1007 +      sv_ind[p_ptr] = sv_ind[p_end];
226.1008 +      sv_val[p_ptr] = sv_val[p_end];
226.1009 +      vr_len[p]--;
226.1010 +      p_end--;
226.1011 +      /* find the pivot v[p,q] = u[k,k] in the q-th column */
226.1012 +      q_beg = vc_ptr[q];
226.1013 +      q_end = q_beg + vc_len[q] - 1;
226.1014 +      for (q_ptr = q_beg; sv_ind[q_ptr] != p; q_ptr++) /* nop */;
226.1015 +      xassert(q_ptr <= q_end);
226.1016 +      /* remove the pivot from the q-th column */
226.1017 +      sv_ind[q_ptr] = sv_ind[q_end];
226.1018 +      vc_len[q]--;
226.1019 +      q_end--;
226.1020 +      /* walk through the p-th (pivot) row, which doesn't contain the
226.1021 +         pivot v[p,q] already, and do the following... */
226.1022 +      for (p_ptr = p_beg; p_ptr <= p_end; p_ptr++)
226.1023 +      {  /* get column index of v[p,j] */
226.1024 +         j = sv_ind[p_ptr];
226.1025 +         /* store v[p,j] to the working array */
226.1026 +         flag[j] = 1;
226.1027 +         work[j] = sv_val[p_ptr];
226.1028 +         /* remove the j-th column from the active set; this column will
226.1029 +            return there later with new length */
226.1030 +         if (cs_prev[j] == 0)
226.1031 +            cs_head[vc_len[j]] = cs_next[j];
226.1032 +         else
226.1033 +            cs_next[cs_prev[j]] = cs_next[j];
226.1034 +         if (cs_next[j] == 0)
226.1035 +            ;
226.1036 +         else
226.1037 +            cs_prev[cs_next[j]] = cs_prev[j];
226.1038 +         /* find v[p,j] in the j-th column */
226.1039 +         j_beg = vc_ptr[j];
226.1040 +         j_end = j_beg + vc_len[j] - 1;
226.1041 +         for (j_ptr = j_beg; sv_ind[j_ptr] != p; j_ptr++) /* nop */;
226.1042 +         xassert(j_ptr <= j_end);
226.1043 +         /* since v[p,j] leaves the active submatrix, remove it from the
226.1044 +            j-th column; however, v[p,j] is kept in the p-th row */
226.1045 +         sv_ind[j_ptr] = sv_ind[j_end];
226.1046 +         vc_len[j]--;
226.1047 +      }
226.1048 +      /* walk through the q-th (pivot) column, which doesn't contain the
226.1049 +         pivot v[p,q] already, and perform gaussian elimination */
226.1050 +      while (q_beg <= q_end)
226.1051 +      {  /* element v[i,q] should be eliminated */
226.1052 +         /* get row index of v[i,q] */
226.1053 +         i = sv_ind[q_beg];
226.1054 +         /* remove the i-th row from the active set; later this row will
226.1055 +            return there with new length */
226.1056 +         if (rs_prev[i] == 0)
226.1057 +            rs_head[vr_len[i]] = rs_next[i];
226.1058 +         else
226.1059 +            rs_next[rs_prev[i]] = rs_next[i];
226.1060 +         if (rs_next[i] == 0)
226.1061 +            ;
226.1062 +         else
226.1063 +            rs_prev[rs_next[i]] = rs_prev[i];
226.1064 +         /* find v[i,q] in the i-th row */
226.1065 +         i_beg = vr_ptr[i];
226.1066 +         i_end = i_beg + vr_len[i] - 1;
226.1067 +         for (i_ptr = i_beg; sv_ind[i_ptr] != q; i_ptr++) /* nop */;
226.1068 +         xassert(i_ptr <= i_end);
226.1069 +         /* compute gaussian multiplier f[i,p] = v[i,q] / v[p,q] */
226.1070 +         fip = sv_val[i_ptr] / vpq;
226.1071 +         /* since v[i,q] should be eliminated, remove it from the i-th
226.1072 +            row */
226.1073 +         sv_ind[i_ptr] = sv_ind[i_end];
226.1074 +         sv_val[i_ptr] = sv_val[i_end];
226.1075 +         vr_len[i]--;
226.1076 +         i_end--;
226.1077 +         /* and from the q-th column */
226.1078 +         sv_ind[q_beg] = sv_ind[q_end];
226.1079 +         vc_len[q]--;
226.1080 +         q_end--;
226.1081 +         /* perform gaussian transformation:
226.1082 +            (i-th row) := (i-th row) - f[i,p] * (p-th row)
226.1083 +            note that now the p-th row, which is in the working array,
226.1084 +            doesn't contain the pivot v[p,q], and the i-th row doesn't
226.1085 +            contain the eliminated element v[i,q] */
226.1086 +         /* walk through the i-th row and transform existing non-zero
226.1087 +            elements */
226.1088 +         fill = vr_len[p];
226.1089 +         for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
226.1090 +         {  /* get column index of v[i,j] */
226.1091 +            j = sv_ind[i_ptr];
226.1092 +            /* v[i,j] := v[i,j] - f[i,p] * v[p,j] */
226.1093 +            if (flag[j])
226.1094 +            {  /* v[p,j] != 0 */
226.1095 +               temp = (sv_val[i_ptr] -= fip * work[j]);
226.1096 +               if (temp < 0.0) temp = - temp;
226.1097 +               flag[j] = 0;
226.1098 +               fill--; /* since both v[i,j] and v[p,j] exist */
226.1099 +               if (temp == 0.0 || temp < eps_tol)
226.1100 +               {  /* new v[i,j] is closer to zero; replace it by exact
226.1101 +                     zero, i.e. remove it from the active submatrix */
226.1102 +                  /* remove v[i,j] from the i-th row */
226.1103 +                  sv_ind[i_ptr] = sv_ind[i_end];
226.1104 +                  sv_val[i_ptr] = sv_val[i_end];
226.1105 +                  vr_len[i]--;
226.1106 +                  i_ptr--;
226.1107 +                  i_end--;
226.1108 +                  /* find v[i,j] in the j-th column */
226.1109 +                  j_beg = vc_ptr[j];
226.1110 +                  j_end = j_beg + vc_len[j] - 1;
226.1111 +                  for (j_ptr = j_beg; sv_ind[j_ptr] != i; j_ptr++);
226.1112 +                  xassert(j_ptr <= j_end);
226.1113 +                  /* remove v[i,j] from the j-th column */
226.1114 +                  sv_ind[j_ptr] = sv_ind[j_end];
226.1115 +                  vc_len[j]--;
226.1116 +               }
226.1117 +               else
226.1118 +               {  /* v_big := max(v_big, |v[i,j]|) */
226.1119 +                  if (luf->big_v < temp) luf->big_v = temp;
226.1120 +               }
226.1121 +            }
226.1122 +         }
226.1123 +         /* now flag is the pattern of the set v[p,*] \ v[i,*], and fill
226.1124 +            is number of non-zeros in this set; therefore up to fill new
226.1125 +            non-zeros may appear in the i-th row */
226.1126 +         if (vr_len[i] + fill > vr_cap[i])
226.1127 +         {  /* enlarge the i-th row */
226.1128 +            if (luf_enlarge_row(luf, i, vr_len[i] + fill))
226.1129 +            {  /* overflow of the sparse vector area */
226.1130 +               ret = 1;
226.1131 +               goto done;
226.1132 +            }
226.1133 +            /* defragmentation may change row and column pointers of the
226.1134 +               matrix V */
226.1135 +            p_beg = vr_ptr[p];
226.1136 +            p_end = p_beg + vr_len[p] - 1;
226.1137 +            q_beg = vc_ptr[q];
226.1138 +            q_end = q_beg + vc_len[q] - 1;
226.1139 +         }
226.1140 +         /* walk through the p-th (pivot) row and create new elements
226.1141 +            of the i-th row that appear due to fill-in; column indices
226.1142 +            of these new elements are accumulated in the array ndx */
226.1143 +         len = 0;
226.1144 +         for (p_ptr = p_beg; p_ptr <= p_end; p_ptr++)
226.1145 +         {  /* get column index of v[p,j], which may cause fill-in */
226.1146 +            j = sv_ind[p_ptr];
226.1147 +            if (flag[j])
226.1148 +            {  /* compute new non-zero v[i,j] = 0 - f[i,p] * v[p,j] */
226.1149 +               temp = (val = - fip * work[j]);
226.1150 +               if (temp < 0.0) temp = - temp;
226.1151 +               if (temp == 0.0 || temp < eps_tol)
226.1152 +                  /* if v[i,j] is closer to zero; just ignore it */;
226.1153 +               else
226.1154 +               {  /* add v[i,j] to the i-th row */
226.1155 +                  i_ptr = vr_ptr[i] + vr_len[i];
226.1156 +                  sv_ind[i_ptr] = j;
226.1157 +                  sv_val[i_ptr] = val;
226.1158 +                  vr_len[i]++;
226.1159 +                  /* remember column index of v[i,j] */
226.1160 +                  ndx[++len] = j;
226.1161 +                  /* big_v := max(big_v, |v[i,j]|) */
226.1162 +                  if (luf->big_v < temp) luf->big_v = temp;
226.1163 +               }
226.1164 +            }
226.1165 +            else
226.1166 +            {  /* there is no fill-in, because v[i,j] already exists in
226.1167 +                  the i-th row; restore the flag of the element v[p,j],
226.1168 +                  which was reset before */
226.1169 +               flag[j] = 1;
226.1170 +            }
226.1171 +         }
226.1172 +         /* add new non-zeros v[i,j] to the corresponding columns */
226.1173 +         for (k = 1; k <= len; k++)
226.1174 +         {  /* get column index of new non-zero v[i,j] */
226.1175 +            j = ndx[k];
226.1176 +            /* one free location is needed in the j-th column */
226.1177 +            if (vc_len[j] + 1 > vc_cap[j])
226.1178 +            {  /* enlarge the j-th column */
226.1179 +               if (luf_enlarge_col(luf, j, vc_len[j] + 10))
226.1180 +               {  /* overflow of the sparse vector area */
226.1181 +                  ret = 1;
226.1182 +                  goto done;
226.1183 +               }
226.1184 +               /* defragmentation may change row and column pointers of
226.1185 +                  the matrix V */
226.1186 +               p_beg = vr_ptr[p];
226.1187 +               p_end = p_beg + vr_len[p] - 1;
226.1188 +               q_beg = vc_ptr[q];
226.1189 +               q_end = q_beg + vc_len[q] - 1;
226.1190 +            }
226.1191 +            /* add new non-zero v[i,j] to the j-th column */
226.1192 +            j_ptr = vc_ptr[j] + vc_len[j];
226.1193 +            sv_ind[j_ptr] = i;
226.1194 +            vc_len[j]++;
226.1195 +         }
226.1196 +         /* now the i-th row has been completely transformed, therefore
226.1197 +            it can return to the active set with new length */
226.1198 +         rs_prev[i] = 0;
226.1199 +         rs_next[i] = rs_head[vr_len[i]];
226.1200 +         if (rs_next[i] != 0) rs_prev[rs_next[i]] = i;
226.1201 +         rs_head[vr_len[i]] = i;
226.1202 +         /* the largest of absolute values of elements in the i-th row
226.1203 +            is currently unknown */
226.1204 +         vr_max[i] = -1.0;
226.1205 +         /* at least one free location is needed to store the gaussian
226.1206 +            multiplier */
226.1207 +         if (luf->sv_end - luf->sv_beg < 1)
226.1208 +         {  /* there are no free locations at all; defragment SVA */
226.1209 +            luf_defrag_sva(luf);
226.1210 +            if (luf->sv_end - luf->sv_beg < 1)
226.1211 +            {  /* overflow of the sparse vector area */
226.1212 +               ret = 1;
226.1213 +               goto done;
226.1214 +            }
226.1215 +            /* defragmentation may change row and column pointers of the
226.1216 +               matrix V */
226.1217 +            p_beg = vr_ptr[p];
226.1218 +            p_end = p_beg + vr_len[p] - 1;
226.1219 +            q_beg = vc_ptr[q];
226.1220 +            q_end = q_beg + vc_len[q] - 1;
226.1221 +         }
226.1222 +         /* add the element f[i,p], which is the gaussian multiplier,
226.1223 +            to the matrix F */
226.1224 +         luf->sv_end--;
226.1225 +         sv_ind[luf->sv_end] = i;
226.1226 +         sv_val[luf->sv_end] = fip;
226.1227 +         fc_len[p]++;
226.1228 +         /* end of elimination loop */
226.1229 +      }
226.1230 +      /* at this point the q-th (pivot) column should be empty */
226.1231 +      xassert(vc_len[q] == 0);
226.1232 +      /* reset capacity of the q-th column */
226.1233 +      vc_cap[q] = 0;
226.1234 +      /* remove node of the q-th column from the addressing list */
226.1235 +      k = n + q;
226.1236 +      if (sv_prev[k] == 0)
226.1237 +         luf->sv_head = sv_next[k];
226.1238 +      else
226.1239 +         sv_next[sv_prev[k]] = sv_next[k];
226.1240 +      if (sv_next[k] == 0)
226.1241 +         luf->sv_tail = sv_prev[k];
226.1242 +      else
226.1243 +         sv_prev[sv_next[k]] = sv_prev[k];
226.1244 +      /* the p-th column of the matrix F has been completely built; set
226.1245 +         its pointer */
226.1246 +      fc_ptr[p] = luf->sv_end;
226.1247 +      /* walk through the p-th (pivot) row and do the following... */
226.1248 +      for (p_ptr = p_beg; p_ptr <= p_end; p_ptr++)
226.1249 +      {  /* get column index of v[p,j] */
226.1250 +         j = sv_ind[p_ptr];
226.1251 +         /* erase v[p,j] from the working array */
226.1252 +         flag[j] = 0;
226.1253 +         work[j] = 0.0;
226.1254 +         /* the j-th column has been completely transformed, therefore
226.1255 +            it can return to the active set with new length; however
226.1256 +            the special case c_prev[j] = c_next[j] = j means that the
226.1257 +            routine find_pivot excluded the j-th column from the active
226.1258 +            set due to Uwe Suhl's rule, and therefore in this case the
226.1259 +            column can return to the active set only if it is a column
226.1260 +            singleton */
226.1261 +         if (!(vc_len[j] != 1 && cs_prev[j] == j && cs_next[j] == j))
226.1262 +         {  cs_prev[j] = 0;
226.1263 +            cs_next[j] = cs_head[vc_len[j]];
226.1264 +            if (cs_next[j] != 0) cs_prev[cs_next[j]] = j;
226.1265 +            cs_head[vc_len[j]] = j;
226.1266 +         }
226.1267 +      }
226.1268 +done: /* return to the factorizing routine */
226.1269 +      return ret;
226.1270 +}
226.1271 +
226.1272 +/***********************************************************************
226.1273 +*  build_v_cols - build the matrix V in column-wise format
226.1274 +*
226.1275 +*  This routine builds the column-wise representation of the matrix V
226.1276 +*  using its row-wise representation.
226.1277 +*
226.1278 +*  If no error occured, the routine returns zero. Otherwise, in case of
226.1279 +*  overflow of the sparse vector area, the routine returns non-zero. */
226.1280 +
226.1281 +static int build_v_cols(LUF *luf)
226.1282 +{     int n = luf->n;
226.1283 +      int *vr_ptr = luf->vr_ptr;
226.1284 +      int *vr_len = luf->vr_len;
226.1285 +      int *vc_ptr = luf->vc_ptr;
226.1286 +      int *vc_len = luf->vc_len;
226.1287 +      int *vc_cap = luf->vc_cap;
226.1288 +      int *sv_ind = luf->sv_ind;
226.1289 +      double *sv_val = luf->sv_val;
226.1290 +      int *sv_prev = luf->sv_prev;
226.1291 +      int *sv_next = luf->sv_next;
226.1292 +      int ret = 0;
226.1293 +      int i, i_beg, i_end, i_ptr, j, j_ptr, k, nnz;
226.1294 +      /* it is assumed that on entry all columns of the matrix V are
226.1295 +         empty, i.e. vc_len[j] = vc_cap[j] = 0 for all j = 1, ..., n,
226.1296 +         and have been removed from the addressing list */
226.1297 +      /* count non-zeros in columns of the matrix V; count total number
226.1298 +         of non-zeros in this matrix */
226.1299 +      nnz = 0;
226.1300 +      for (i = 1; i <= n; i++)
226.1301 +      {  /* walk through elements of the i-th row and count non-zeros
226.1302 +            in the corresponding columns */
226.1303 +         i_beg = vr_ptr[i];
226.1304 +         i_end = i_beg + vr_len[i] - 1;
226.1305 +         for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
226.1306 +            vc_cap[sv_ind[i_ptr]]++;
226.1307 +         /* count total number of non-zeros */
226.1308 +         nnz += vr_len[i];
226.1309 +      }
226.1310 +      /* store total number of non-zeros */
226.1311 +      luf->nnz_v = nnz;
226.1312 +      /* check for free locations */
226.1313 +      if (luf->sv_end - luf->sv_beg < nnz)
226.1314 +      {  /* overflow of the sparse vector area */
226.1315 +         ret = 1;
226.1316 +         goto done;
226.1317 +      }
226.1318 +      /* allocate columns of the matrix V */
226.1319 +      for (j = 1; j <= n; j++)
226.1320 +      {  /* set pointer to the j-th column */
226.1321 +         vc_ptr[j] = luf->sv_beg;
226.1322 +         /* reserve locations for the j-th column */
226.1323 +         luf->sv_beg += vc_cap[j];
226.1324 +      }
226.1325 +      /* build the matrix V in column-wise format using this matrix in
226.1326 +         row-wise format */
226.1327 +      for (i = 1; i <= n; i++)
226.1328 +      {  /* walk through elements of the i-th row */
226.1329 +         i_beg = vr_ptr[i];
226.1330 +         i_end = i_beg + vr_len[i] - 1;
226.1331 +         for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
226.1332 +         {  /* get column index */
226.1333 +            j = sv_ind[i_ptr];
226.1334 +            /* store element in the j-th column */
226.1335 +            j_ptr = vc_ptr[j] + vc_len[j];
226.1336 +            sv_ind[j_ptr] = i;
226.1337 +            sv_val[j_ptr] = sv_val[i_ptr];
226.1338 +            /* increase length of the j-th column */
226.1339 +            vc_len[j]++;
226.1340 +         }
226.1341 +      }
226.1342 +      /* now columns are placed in the sparse vector area behind rows
226.1343 +         in the order n+1, n+2, ..., n+n; so insert column nodes in the
226.1344 +         addressing list using this order */
226.1345 +      for (k = n+1; k <= n+n; k++)
226.1346 +      {  sv_prev[k] = k-1;
226.1347 +         sv_next[k] = k+1;
226.1348 +      }
226.1349 +      sv_prev[n+1] = luf->sv_tail;
226.1350 +      sv_next[luf->sv_tail] = n+1;
226.1351 +      sv_next[n+n] = 0;
226.1352 +      luf->sv_tail = n+n;
226.1353 +done: /* return to the factorizing routine */
226.1354 +      return ret;
226.1355 +}
226.1356 +
226.1357 +/***********************************************************************
226.1358 +*  build_f_rows - build the matrix F in row-wise format
226.1359 +*
226.1360 +*  This routine builds the row-wise representation of the matrix F using
226.1361 +*  its column-wise representation.
226.1362 +*
226.1363 +*  If no error occured, the routine returns zero. Otherwise, in case of
226.1364 +*  overflow of the sparse vector area, the routine returns non-zero. */
226.1365 +
226.1366 +static int build_f_rows(LUF *luf)
226.1367 +{     int n = luf->n;
226.1368 +      int *fr_ptr = luf->fr_ptr;
226.1369 +      int *fr_len = luf->fr_len;
226.1370 +      int *fc_ptr = luf->fc_ptr;
226.1371 +      int *fc_len = luf->fc_len;
226.1372 +      int *sv_ind = luf->sv_ind;
226.1373 +      double *sv_val = luf->sv_val;
226.1374 +      int ret = 0;
226.1375 +      int i, j, j_beg, j_end, j_ptr, ptr, nnz;
226.1376 +      /* clear rows of the matrix F */
226.1377 +      for (i = 1; i <= n; i++) fr_len[i] = 0;
226.1378 +      /* count non-zeros in rows of the matrix F; count total number of
226.1379 +         non-zeros in this matrix */
226.1380 +      nnz = 0;
226.1381 +      for (j = 1; j <= n; j++)
226.1382 +      {  /* walk through elements of the j-th column and count non-zeros
226.1383 +            in the corresponding rows */
226.1384 +         j_beg = fc_ptr[j];
226.1385 +         j_end = j_beg + fc_len[j] - 1;
226.1386 +         for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
226.1387 +            fr_len[sv_ind[j_ptr]]++;
226.1388 +         /* increase total number of non-zeros */
226.1389 +         nnz += fc_len[j];
226.1390 +      }
226.1391 +      /* store total number of non-zeros */
226.1392 +      luf->nnz_f = nnz;
226.1393 +      /* check for free locations */
226.1394 +      if (luf->sv_end - luf->sv_beg < nnz)
226.1395 +      {  /* overflow of the sparse vector area */
226.1396 +         ret = 1;
226.1397 +         goto done;
226.1398 +      }
226.1399 +      /* allocate rows of the matrix F */
226.1400 +      for (i = 1; i <= n; i++)
226.1401 +      {  /* set pointer to the end of the i-th row; later this pointer
226.1402 +            will be set to the beginning of the i-th row */
226.1403 +         fr_ptr[i] = luf->sv_end;
226.1404 +         /* reserve locations for the i-th row */
226.1405 +         luf->sv_end -= fr_len[i];
226.1406 +      }
226.1407 +      /* build the matrix F in row-wise format using this matrix in
226.1408 +         column-wise format */
226.1409 +      for (j = 1; j <= n; j++)
226.1410 +      {  /* walk through elements of the j-th column */
226.1411 +         j_beg = fc_ptr[j];
226.1412 +         j_end = j_beg + fc_len[j] - 1;
226.1413 +         for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
226.1414 +         {  /* get row index */
226.1415 +            i = sv_ind[j_ptr];
226.1416 +            /* store element in the i-th row */
226.1417 +            ptr = --fr_ptr[i];
226.1418 +            sv_ind[ptr] = j;
226.1419 +            sv_val[ptr] = sv_val[j_ptr];
226.1420 +         }
226.1421 +      }
226.1422 +done: /* return to the factorizing routine */
226.1423 +      return ret;
226.1424 +}
226.1425 +
226.1426 +/***********************************************************************
226.1427 +*  NAME
226.1428 +*
226.1429 +*  luf_factorize - compute LU-factorization
226.1430 +*
226.1431 +*  SYNOPSIS
226.1432 +*
226.1433 +*  #include "glpluf.h"
226.1434 +*  int luf_factorize(LUF *luf, int n, int (*col)(void *info, int j,
226.1435 +*     int ind[], double val[]), void *info);
226.1436 +*
226.1437 +*  DESCRIPTION
226.1438 +*
226.1439 +*  The routine luf_factorize computes LU-factorization of a specified
226.1440 +*  square matrix A.
226.1441 +*
226.1442 +*  The parameter luf specifies LU-factorization program object created
226.1443 +*  by the routine luf_create_it.
226.1444 +*
226.1445 +*  The parameter n specifies the order of A, n > 0.
226.1446 +*
226.1447 +*  The formal routine col specifies the matrix A to be factorized. To
226.1448 +*  obtain j-th column of A the routine luf_factorize calls the routine
226.1449 +*  col with the parameter j (1 <= j <= n). In response the routine col
226.1450 +*  should store row indices and numerical values of non-zero elements
226.1451 +*  of j-th column of A to locations ind[1,...,len] and val[1,...,len],
226.1452 +*  respectively, where len is the number of non-zeros in j-th column
226.1453 +*  returned on exit. Neither zero nor duplicate elements are allowed.
226.1454 +*
226.1455 +*  The parameter info is a transit pointer passed to the routine col.
226.1456 +*
226.1457 +*  RETURNS
226.1458 +*
226.1459 +*  0  LU-factorization has been successfully computed.
226.1460 +*
226.1461 +*  LUF_ESING
226.1462 +*     The specified matrix is singular within the working precision.
226.1463 +*     (On some elimination step the active submatrix is exactly zero,
226.1464 +*     so no pivot can be chosen.)
226.1465 +*
226.1466 +*  LUF_ECOND
226.1467 +*     The specified matrix is ill-conditioned.
226.1468 +*     (On some elimination step too intensive growth of elements of the
226.1469 +*     active submatix has been detected.)
226.1470 +*
226.1471 +*  If matrix A is well scaled, the return code LUF_ECOND may also mean
226.1472 +*  that the threshold pivoting tolerance piv_tol should be increased.
226.1473 +*
226.1474 +*  In case of non-zero return code the factorization becomes invalid.
226.1475 +*  It should not be used in other operations until the cause of failure
226.1476 +*  has been eliminated and the factorization has been recomputed again
226.1477 +*  with the routine luf_factorize.
226.1478 +*
226.1479 +*  REPAIRING SINGULAR MATRIX
226.1480 +*
226.1481 +*  If the routine luf_factorize returns non-zero code, it provides all
226.1482 +*  necessary information that can be used for "repairing" the matrix A,
226.1483 +*  where "repairing" means replacing linearly dependent columns of the
226.1484 +*  matrix A by appropriate columns of the unity matrix. This feature is
226.1485 +*  needed when this routine is used for factorizing the basis matrix
226.1486 +*  within the simplex method procedure.
226.1487 +*
226.1488 +*  On exit linearly dependent columns of the (partially transformed)
226.1489 +*  matrix U have numbers rank+1, rank+2, ..., n, where rank is estimated
226.1490 +*  rank of the matrix A stored by the routine to the member luf->rank.
226.1491 +*  The correspondence between columns of A and U is the same as between
226.1492 +*  columns of V and U. Thus, linearly dependent columns of the matrix A
226.1493 +*  have numbers qq_col[rank+1], qq_col[rank+2], ..., qq_col[n], where
226.1494 +*  qq_col is the column-like representation of the permutation matrix Q.
226.1495 +*  It is understood that each j-th linearly dependent column of the
226.1496 +*  matrix U should be replaced by the unity vector, where all elements
226.1497 +*  are zero except the unity diagonal element u[j,j]. On the other hand
226.1498 +*  j-th row of the matrix U corresponds to the row of the matrix V (and
226.1499 +*  therefore of the matrix A) with the number pp_row[j], where pp_row is
226.1500 +*  the row-like representation of the permutation matrix P. Thus, each
226.1501 +*  j-th linearly dependent column of the matrix U should be replaced by
226.1502 +*  column of the unity matrix with the number pp_row[j].
226.1503 +*
226.1504 +*  The code that repairs the matrix A may look like follows:
226.1505 +*
226.1506 +*     for (j = rank+1; j <= n; j++)
226.1507 +*     {  replace the column qq_col[j] of the matrix A by the column
226.1508 +*        pp_row[j] of the unity matrix;
226.1509 +*     }
226.1510 +*
226.1511 +*  where rank, pp_row, and qq_col are members of the structure LUF. */
226.1512 +
226.1513 +int luf_factorize(LUF *luf, int n, int (*col)(void *info, int j,
226.1514 +      int ind[], double val[]), void *info)
226.1515 +{     int *pp_row, *pp_col, *qq_row, *qq_col;
226.1516 +      double max_gro = luf->max_gro;
226.1517 +      int i, j, k, p, q, t, ret;
226.1518 +      if (n < 1)
226.1519 +         xfault("luf_factorize: n = %d; invalid parameter\n", n);
226.1520 +      if (n > N_MAX)
226.1521 +         xfault("luf_factorize: n = %d; matrix too big\n", n);
226.1522 +      /* invalidate the factorization */
226.1523 +      luf->valid = 0;
226.1524 +      /* reallocate arrays, if necessary */
226.1525 +      reallocate(luf, n);
226.1526 +      pp_row = luf->pp_row;
226.1527 +      pp_col = luf->pp_col;
226.1528 +      qq_row = luf->qq_row;
226.1529 +      qq_col = luf->qq_col;
226.1530 +      /* estimate initial size of the SVA, if not specified */
226.1531 +      if (luf->sv_size == 0 && luf->new_sva == 0)
226.1532 +         luf->new_sva = 5 * (n + 10);
226.1533 +more: /* reallocate the sparse vector area, if required */
226.1534 +      if (luf->new_sva > 0)
226.1535 +      {  if (luf->sv_ind != NULL) xfree(luf->sv_ind);
226.1536 +         if (luf->sv_val != NULL) xfree(luf->sv_val);
226.1537 +         luf->sv_size = luf->new_sva;
226.1538 +         luf->sv_ind = xcalloc(1+luf->sv_size, sizeof(int));
226.1539 +         luf->sv_val = xcalloc(1+luf->sv_size, sizeof(double));
226.1540 +         luf->new_sva = 0;
226.1541 +      }
226.1542 +      /* initialize LU-factorization data structures */
226.1543 +      if (initialize(luf, col, info))
226.1544 +      {  /* overflow of the sparse vector area */
226.1545 +         luf->new_sva = luf->sv_size + luf->sv_size;
226.1546 +         xassert(luf->new_sva > luf->sv_size);
226.1547 +         goto more;
226.1548 +      }
226.1549 +      /* main elimination loop */
226.1550 +      for (k = 1; k <= n; k++)
226.1551 +      {  /* choose a pivot element v[p,q] */
226.1552 +         if (find_pivot(luf, &p, &q))
226.1553 +         {  /* no pivot can be chosen, because the active submatrix is
226.1554 +               exactly zero */
226.1555 +            luf->rank = k - 1;
226.1556 +            ret = LUF_ESING;
226.1557 +            goto done;
226.1558 +         }
226.1559 +         /* let v[p,q] correspond to u[i',j']; permute k-th and i'-th
226.1560 +            rows and k-th and j'-th columns of the matrix U = P*V*Q to
226.1561 +            move the element u[i',j'] to the position u[k,k] */
226.1562 +         i = pp_col[p], j = qq_row[q];
226.1563 +         xassert(k <= i && i <= n && k <= j && j <= n);
226.1564 +         /* permute k-th and i-th rows of the matrix U */
226.1565 +         t = pp_row[k];
226.1566 +         pp_row[i] = t, pp_col[t] = i;
226.1567 +         pp_row[k] = p, pp_col[p] = k;
226.1568 +         /* permute k-th and j-th columns of the matrix U */
226.1569 +         t = qq_col[k];
226.1570 +         qq_col[j] = t, qq_row[t] = j;
226.1571 +         qq_col[k] = q, qq_row[q] = k;
226.1572 +         /* eliminate subdiagonal elements of k-th column of the matrix
226.1573 +            U = P*V*Q using the pivot element u[k,k] = v[p,q] */
226.1574 +         if (eliminate(luf, p, q))
226.1575 +         {  /* overflow of the sparse vector area */
226.1576 +            luf->new_sva = luf->sv_size + luf->sv_size;
226.1577 +            xassert(luf->new_sva > luf->sv_size);
226.1578 +            goto more;
226.1579 +         }
226.1580 +         /* check relative growth of elements of the matrix V */
226.1581 +         if (luf->big_v > max_gro * luf->max_a)
226.1582 +         {  /* the growth is too intensive, therefore most probably the
226.1583 +               matrix A is ill-conditioned */
226.1584 +            luf->rank = k - 1;
226.1585 +            ret = LUF_ECOND;
226.1586 +            goto done;
226.1587 +         }
226.1588 +      }
226.1589 +      /* now the matrix U = P*V*Q is upper triangular, the matrix V has
226.1590 +         been built in row-wise format, and the matrix F has been built
226.1591 +         in column-wise format */
226.1592 +      /* defragment the sparse vector area in order to merge all free
226.1593 +         locations in one continuous extent */
226.1594 +      luf_defrag_sva(luf);
226.1595 +      /* build the matrix V in column-wise format */
226.1596 +      if (build_v_cols(luf))
226.1597 +      {  /* overflow of the sparse vector area */
226.1598 +         luf->new_sva = luf->sv_size + luf->sv_size;
226.1599 +         xassert(luf->new_sva > luf->sv_size);
226.1600 +         goto more;
226.1601 +      }
226.1602 +      /* build the matrix F in row-wise format */
226.1603 +      if (build_f_rows(luf))
226.1604 +      {  /* overflow of the sparse vector area */
226.1605 +         luf->new_sva = luf->sv_size + luf->sv_size;
226.1606 +         xassert(luf->new_sva > luf->sv_size);
226.1607 +         goto more;
226.1608 +      }
226.1609 +      /* the LU-factorization has been successfully computed */
226.1610 +      luf->valid = 1;
226.1611 +      luf->rank = n;
226.1612 +      ret = 0;
226.1613 +      /* if there are few free locations in the sparse vector area, try
226.1614 +         increasing its size in the future */
226.1615 +      t = 3 * (n + luf->nnz_v) + 2 * luf->nnz_f;
226.1616 +      if (luf->sv_size < t)
226.1617 +      {  luf->new_sva = luf->sv_size;
226.1618 +         while (luf->new_sva < t)
226.1619 +         {  k = luf->new_sva;
226.1620 +            luf->new_sva = k + k;
226.1621 +            xassert(luf->new_sva > k);
226.1622 +         }
226.1623 +      }
226.1624 +done: /* return to the calling program */
226.1625 +      return ret;
226.1626 +}
226.1627 +
226.1628 +/***********************************************************************
226.1629 +*  NAME
226.1630 +*
226.1631 +*  luf_f_solve - solve system F*x = b or F'*x = b
226.1632 +*
226.1633 +*  SYNOPSIS
226.1634 +*
226.1635 +*  #include "glpluf.h"
226.1636 +*  void luf_f_solve(LUF *luf, int tr, double x[]);
226.1637 +*
226.1638 +*  DESCRIPTION
226.1639 +*
226.1640 +*  The routine luf_f_solve solves either the system F*x = b (if the
226.1641 +*  flag tr is zero) or the system F'*x = b (if the flag tr is non-zero),
226.1642 +*  where the matrix F is a component of LU-factorization specified by
226.1643 +*  the parameter luf, F' is a matrix transposed to F.
226.1644 +*
226.1645 +*  On entry the array x should contain elements of the right-hand side
226.1646 +*  vector b in locations x[1], ..., x[n], where n is the order of the
226.1647 +*  matrix F. On exit this array will contain elements of the solution
226.1648 +*  vector x in the same locations. */
226.1649 +
226.1650 +void luf_f_solve(LUF *luf, int tr, double x[])
226.1651 +{     int n = luf->n;
226.1652 +      int *fr_ptr = luf->fr_ptr;
226.1653 +      int *fr_len = luf->fr_len;
226.1654 +      int *fc_ptr = luf->fc_ptr;
226.1655 +      int *fc_len = luf->fc_len;
226.1656 +      int *pp_row = luf->pp_row;
226.1657 +      int *sv_ind = luf->sv_ind;
226.1658 +      double *sv_val = luf->sv_val;
226.1659 +      int i, j, k, beg, end, ptr;
226.1660 +      double xk;
226.1661 +      if (!luf->valid)
226.1662 +         xfault("luf_f_solve: LU-factorization is not valid\n");
226.1663 +      if (!tr)
226.1664 +      {  /* solve the system F*x = b */
226.1665 +         for (j = 1; j <= n; j++)
226.1666 +         {  k = pp_row[j];
226.1667 +            xk = x[k];
226.1668 +            if (xk != 0.0)
226.1669 +            {  beg = fc_ptr[k];
226.1670 +               end = beg + fc_len[k] - 1;
226.1671 +               for (ptr = beg; ptr <= end; ptr++)
226.1672 +                  x[sv_ind[ptr]] -= sv_val[ptr] * xk;
226.1673 +            }
226.1674 +         }
226.1675 +      }
226.1676 +      else
226.1677 +      {  /* solve the system F'*x = b */
226.1678 +         for (i = n; i >= 1; i--)
226.1679 +         {  k = pp_row[i];
226.1680 +            xk = x[k];
226.1681 +            if (xk != 0.0)
226.1682 +            {  beg = fr_ptr[k];
226.1683 +               end = beg + fr_len[k] - 1;
226.1684 +               for (ptr = beg; ptr <= end; ptr++)
226.1685 +                  x[sv_ind[ptr]] -= sv_val[ptr] * xk;
226.1686 +            }
226.1687 +         }
226.1688 +      }
226.1689 +      return;
226.1690 +}
226.1691 +
226.1692 +/***********************************************************************
226.1693 +*  NAME
226.1694 +*
226.1695 +*  luf_v_solve - solve system V*x = b or V'*x = b
226.1696 +*
226.1697 +*  SYNOPSIS
226.1698 +*
226.1699 +*  #include "glpluf.h"
226.1700 +*  void luf_v_solve(LUF *luf, int tr, double x[]);
226.1701 +*
226.1702 +*  DESCRIPTION
226.1703 +*
226.1704 +*  The routine luf_v_solve solves either the system V*x = b (if the
226.1705 +*  flag tr is zero) or the system V'*x = b (if the flag tr is non-zero),
226.1706 +*  where the matrix V is a component of LU-factorization specified by
226.1707 +*  the parameter luf, V' is a matrix transposed to V.
226.1708 +*
226.1709 +*  On entry the array x should contain elements of the right-hand side
226.1710 +*  vector b in locations x[1], ..., x[n], where n is the order of the
226.1711 +*  matrix V. On exit this array will contain elements of the solution
226.1712 +*  vector x in the same locations. */
226.1713 +
226.1714 +void luf_v_solve(LUF *luf, int tr, double x[])
226.1715 +{     int n = luf->n;
226.1716 +      int *vr_ptr = luf->vr_ptr;
226.1717 +      int *vr_len = luf->vr_len;
226.1718 +      double *vr_piv = luf->vr_piv;
226.1719 +      int *vc_ptr = luf->vc_ptr;
226.1720 +      int *vc_len = luf->vc_len;
226.1721 +      int *pp_row = luf->pp_row;
226.1722 +      int *qq_col = luf->qq_col;
226.1723 +      int *sv_ind = luf->sv_ind;
226.1724 +      double *sv_val = luf->sv_val;
226.1725 +      double *b = luf->work;
226.1726 +      int i, j, k, beg, end, ptr;
226.1727 +      double temp;
226.1728 +      if (!luf->valid)
226.1729 +         xfault("luf_v_solve: LU-factorization is not valid\n");
226.1730 +      for (k = 1; k <= n; k++) b[k] = x[k], x[k] = 0.0;
226.1731 +      if (!tr)
226.1732 +      {  /* solve the system V*x = b */
226.1733 +         for (k = n; k >= 1; k--)
226.1734 +         {  i = pp_row[k], j = qq_col[k];
226.1735 +            temp = b[i];
226.1736 +            if (temp != 0.0)
226.1737 +            {  x[j] = (temp /= vr_piv[i]);
226.1738 +               beg = vc_ptr[j];
226.1739 +               end = beg + vc_len[j] - 1;
226.1740 +               for (ptr = beg; ptr <= end; ptr++)
226.1741 +                  b[sv_ind[ptr]] -= sv_val[ptr] * temp;
226.1742 +            }
226.1743 +         }
226.1744 +      }
226.1745 +      else
226.1746 +      {  /* solve the system V'*x = b */
226.1747 +         for (k = 1; k <= n; k++)
226.1748 +         {  i = pp_row[k], j = qq_col[k];
226.1749 +            temp = b[j];
226.1750 +            if (temp != 0.0)
226.1751 +            {  x[i] = (temp /= vr_piv[i]);
226.1752 +               beg = vr_ptr[i];
226.1753 +               end = beg + vr_len[i] - 1;
226.1754 +               for (ptr = beg; ptr <= end; ptr++)
226.1755 +                  b[sv_ind[ptr]] -= sv_val[ptr] * temp;
226.1756 +            }
226.1757 +         }
226.1758 +      }
226.1759 +      return;
226.1760 +}
226.1761 +
226.1762 +/***********************************************************************
226.1763 +*  NAME
226.1764 +*
226.1765 +*  luf_a_solve - solve system A*x = b or A'*x = b
226.1766 +*
226.1767 +*  SYNOPSIS
226.1768 +*
226.1769 +*  #include "glpluf.h"
226.1770 +*  void luf_a_solve(LUF *luf, int tr, double x[]);
226.1771 +*
226.1772 +*  DESCRIPTION
226.1773 +*
226.1774 +*  The routine luf_a_solve solves either the system A*x = b (if the
226.1775 +*  flag tr is zero) or the system A'*x = b (if the flag tr is non-zero),
226.1776 +*  where the parameter luf specifies LU-factorization of the matrix A,
226.1777 +*  A' is a matrix transposed to A.
226.1778 +*
226.1779 +*  On entry the array x should contain elements of the right-hand side
226.1780 +*  vector b in locations x[1], ..., x[n], where n is the order of the
226.1781 +*  matrix A. On exit this array will contain elements of the solution
226.1782 +*  vector x in the same locations. */
226.1783 +
226.1784 +void luf_a_solve(LUF *luf, int tr, double x[])
226.1785 +{     if (!luf->valid)
226.1786 +         xfault("luf_a_solve: LU-factorization is not valid\n");
226.1787 +      if (!tr)
226.1788 +      {  /* A = F*V, therefore inv(A) = inv(V)*inv(F) */
226.1789 +         luf_f_solve(luf, 0, x);
226.1790 +         luf_v_solve(luf, 0, x);
226.1791 +      }
226.1792 +      else
226.1793 +      {  /* A' = V'*F', therefore inv(A') = inv(F')*inv(V') */
226.1794 +         luf_v_solve(luf, 1, x);
226.1795 +         luf_f_solve(luf, 1, x);
226.1796 +      }
226.1797 +      return;
226.1798 +}
226.1799 +
226.1800 +/***********************************************************************
226.1801 +*  NAME
226.1802 +*
226.1803 +*  luf_delete_it - delete LU-factorization
226.1804 +*
226.1805 +*  SYNOPSIS
226.1806 +*
226.1807 +*  #include "glpluf.h"
226.1808 +*  void luf_delete_it(LUF *luf);
226.1809 +*
226.1810 +*  DESCRIPTION
226.1811 +*
226.1812 +*  The routine luf_delete deletes LU-factorization specified by the
226.1813 +*  parameter luf and frees all the memory allocated to this program
226.1814 +*  object. */
226.1815 +
226.1816 +void luf_delete_it(LUF *luf)
226.1817 +{     if (luf->fr_ptr != NULL) xfree(luf->fr_ptr);
226.1818 +      if (luf->fr_len != NULL) xfree(luf->fr_len);
226.1819 +      if (luf->fc_ptr != NULL) xfree(luf->fc_ptr);
226.1820 +      if (luf->fc_len != NULL) xfree(luf->fc_len);
226.1821 +      if (luf->vr_ptr != NULL) xfree(luf->vr_ptr);
226.1822 +      if (luf->vr_len != NULL) xfree(luf->vr_len);
226.1823 +      if (luf->vr_cap != NULL) xfree(luf->vr_cap);
226.1824 +      if (luf->vr_piv != NULL) xfree(luf->vr_piv);
226.1825 +      if (luf->vc_ptr != NULL) xfree(luf->vc_ptr);
226.1826 +      if (luf->vc_len != NULL) xfree(luf->vc_len);
226.1827 +      if (luf->vc_cap != NULL) xfree(luf->vc_cap);
226.1828 +      if (luf->pp_row != NULL) xfree(luf->pp_row);
226.1829 +      if (luf->pp_col != NULL) xfree(luf->pp_col);
226.1830 +      if (luf->qq_row != NULL) xfree(luf->qq_row);
226.1831 +      if (luf->qq_col != NULL) xfree(luf->qq_col);
226.1832 +      if (luf->sv_ind != NULL) xfree(luf->sv_ind);
226.1833 +      if (luf->sv_val != NULL) xfree(luf->sv_val);
226.1834 +      if (luf->sv_prev != NULL) xfree(luf->sv_prev);
226.1835 +      if (luf->sv_next != NULL) xfree(luf->sv_next);
226.1836 +      if (luf->vr_max != NULL) xfree(luf->vr_max);
226.1837 +      if (luf->rs_head != NULL) xfree(luf->rs_head);
226.1838 +      if (luf->rs_prev != NULL) xfree(luf->rs_prev);
226.1839 +      if (luf->rs_next != NULL) xfree(luf->rs_next);
226.1840 +      if (luf->cs_head != NULL) xfree(luf->cs_head);
226.1841 +      if (luf->cs_prev != NULL) xfree(luf->cs_prev);
226.1842 +      if (luf->cs_next != NULL) xfree(luf->cs_next);
226.1843 +      if (luf->flag != NULL) xfree(luf->flag);
226.1844 +      if (luf->work != NULL) xfree(luf->work);
226.1845 +      xfree(luf);
226.1846 +      return;
226.1847 +}
226.1848 +
226.1849 +/* eof */
   227.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   227.2 +++ b/src/glpluf.h	Mon Dec 06 13:09:21 2010 +0100
   227.3 @@ -0,0 +1,326 @@
   227.4 +/* glpluf.h (LU-factorization) */
   227.5 +
   227.6 +/***********************************************************************
   227.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   227.8 +*
   227.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  227.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  227.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  227.12 +*  E-mail: <mao@gnu.org>.
  227.13 +*
  227.14 +*  GLPK is free software: you can redistribute it and/or modify it
  227.15 +*  under the terms of the GNU General Public License as published by
  227.16 +*  the Free Software Foundation, either version 3 of the License, or
  227.17 +*  (at your option) any later version.
  227.18 +*
  227.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  227.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  227.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  227.22 +*  License for more details.
  227.23 +*
  227.24 +*  You should have received a copy of the GNU General Public License
  227.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  227.26 +***********************************************************************/
  227.27 +
  227.28 +#ifndef GLPLUF_H
  227.29 +#define GLPLUF_H
  227.30 +
  227.31 +/***********************************************************************
  227.32 +*  The structure LUF defines LU-factorization of a square matrix A and
  227.33 +*  is the following quartet:
  227.34 +*
  227.35 +*     [A] = (F, V, P, Q),                                            (1)
  227.36 +*
  227.37 +*  where F and V are such matrices that
  227.38 +*
  227.39 +*     A = F * V,                                                     (2)
  227.40 +*
  227.41 +*  and P and Q are such permutation matrices that the matrix
  227.42 +*
  227.43 +*     L = P * F * inv(P)                                             (3)
  227.44 +*
  227.45 +*  is lower triangular with unity diagonal, and the matrix
  227.46 +*
  227.47 +*     U = P * V * Q                                                  (4)
  227.48 +*
  227.49 +*  is upper triangular. All the matrices have the order n.
  227.50 +*
  227.51 +*  Matrices F and V are stored in row- and column-wise sparse format
  227.52 +*  as row and column linked lists of non-zero elements. Unity elements
  227.53 +*  on the main diagonal of matrix F are not stored. Pivot elements of
  227.54 +*  matrix V (which correspond to diagonal elements of matrix U) are
  227.55 +*  stored separately in an ordinary array.
  227.56 +*
  227.57 +*  Permutation matrices P and Q are stored in ordinary arrays in both
  227.58 +*  row- and column-like formats.
  227.59 +*
  227.60 +*  Matrices L and U are completely defined by matrices F, V, P, and Q
  227.61 +*  and therefore not stored explicitly.
  227.62 +*
  227.63 +*  The factorization (1)-(4) is a version of LU-factorization. Indeed,
  227.64 +*  from (3) and (4) it follows that:
  227.65 +*
  227.66 +*     F = inv(P) * L * P,
  227.67 +*
  227.68 +*     U = inv(P) * U * inv(Q),
  227.69 +*
  227.70 +*  and substitution into (2) leads to:
  227.71 +*
  227.72 +*     A = F * V = inv(P) * L * U * inv(Q).
  227.73 +*
  227.74 +*  For more details see the program documentation. */
  227.75 +
  227.76 +typedef struct LUF LUF;
  227.77 +
  227.78 +struct LUF
  227.79 +{     /* LU-factorization of a square matrix */
  227.80 +      int n_max;
  227.81 +      /* maximal value of n (increased automatically, if necessary) */
  227.82 +      int n;
  227.83 +      /* the order of matrices A, F, V, P, Q */
  227.84 +      int valid;
  227.85 +      /* the factorization is valid only if this flag is set */
  227.86 +      /*--------------------------------------------------------------*/
  227.87 +      /* matrix F in row-wise format */
  227.88 +      int *fr_ptr; /* int fr_ptr[1+n_max]; */
  227.89 +      /* fr_ptr[i], i = 1,...,n, is a pointer to the first element of
  227.90 +         i-th row in SVA */
  227.91 +      int *fr_len; /* int fr_len[1+n_max]; */
  227.92 +      /* fr_len[i], i = 1,...,n, is the number of elements in i-th row
  227.93 +         (except unity diagonal element) */
  227.94 +      /*--------------------------------------------------------------*/
  227.95 +      /* matrix F in column-wise format */
  227.96 +      int *fc_ptr; /* int fc_ptr[1+n_max]; */
  227.97 +      /* fc_ptr[j], j = 1,...,n, is a pointer to the first element of
  227.98 +         j-th column in SVA */
  227.99 +      int *fc_len; /* int fc_len[1+n_max]; */
 227.100 +      /* fc_len[j], j = 1,...,n, is the number of elements in j-th
 227.101 +         column (except unity diagonal element) */
 227.102 +      /*--------------------------------------------------------------*/
 227.103 +      /* matrix V in row-wise format */
 227.104 +      int *vr_ptr; /* int vr_ptr[1+n_max]; */
 227.105 +      /* vr_ptr[i], i = 1,...,n, is a pointer to the first element of
 227.106 +         i-th row in SVA */
 227.107 +      int *vr_len; /* int vr_len[1+n_max]; */
 227.108 +      /* vr_len[i], i = 1,...,n, is the number of elements in i-th row
 227.109 +         (except pivot element) */
 227.110 +      int *vr_cap; /* int vr_cap[1+n_max]; */
 227.111 +      /* vr_cap[i], i = 1,...,n, is the capacity of i-th row, i.e.
 227.112 +         maximal number of elements which can be stored in the row
 227.113 +         without relocating it, vr_cap[i] >= vr_len[i] */
 227.114 +      double *vr_piv; /* double vr_piv[1+n_max]; */
 227.115 +      /* vr_piv[p], p = 1,...,n, is the pivot element v[p,q] which
 227.116 +         corresponds to a diagonal element of matrix U = P*V*Q */
 227.117 +      /*--------------------------------------------------------------*/
 227.118 +      /* matrix V in column-wise format */
 227.119 +      int *vc_ptr; /* int vc_ptr[1+n_max]; */
 227.120 +      /* vc_ptr[j], j = 1,...,n, is a pointer to the first element of
 227.121 +         j-th column in SVA */
 227.122 +      int *vc_len; /* int vc_len[1+n_max]; */
 227.123 +      /* vc_len[j], j = 1,...,n, is the number of elements in j-th
 227.124 +         column (except pivot element) */
 227.125 +      int *vc_cap; /* int vc_cap[1+n_max]; */
 227.126 +      /* vc_cap[j], j = 1,...,n, is the capacity of j-th column, i.e.
 227.127 +         maximal number of elements which can be stored in the column
 227.128 +         without relocating it, vc_cap[j] >= vc_len[j] */
 227.129 +      /*--------------------------------------------------------------*/
 227.130 +      /* matrix P */
 227.131 +      int *pp_row; /* int pp_row[1+n_max]; */
 227.132 +      /* pp_row[i] = j means that P[i,j] = 1 */
 227.133 +      int *pp_col; /* int pp_col[1+n_max]; */
 227.134 +      /* pp_col[j] = i means that P[i,j] = 1 */
 227.135 +      /* if i-th row or column of matrix F is i'-th row or column of
 227.136 +         matrix L, or if i-th row of matrix V is i'-th row of matrix U,
 227.137 +         then pp_row[i'] = i and pp_col[i] = i' */
 227.138 +      /*--------------------------------------------------------------*/
 227.139 +      /* matrix Q */
 227.140 +      int *qq_row; /* int qq_row[1+n_max]; */
 227.141 +      /* qq_row[i] = j means that Q[i,j] = 1 */
 227.142 +      int *qq_col; /* int qq_col[1+n_max]; */
 227.143 +      /* qq_col[j] = i means that Q[i,j] = 1 */
 227.144 +      /* if j-th column of matrix V is j'-th column of matrix U, then
 227.145 +         qq_row[j] = j' and qq_col[j'] = j */
 227.146 +      /*--------------------------------------------------------------*/
 227.147 +      /* the Sparse Vector Area (SVA) is a set of locations used to
 227.148 +         store sparse vectors representing rows and columns of matrices
 227.149 +         F and V; each location is a doublet (ind, val), where ind is
 227.150 +         an index, and val is a numerical value of a sparse vector
 227.151 +         element; in the whole each sparse vector is a set of adjacent
 227.152 +         locations defined by a pointer to the first element and the
 227.153 +         number of elements; these pointer and number are stored in the
 227.154 +         corresponding matrix data structure (see above); the left part
 227.155 +         of SVA is used to store rows and columns of matrix V, and its
 227.156 +         right part is used to store rows and columns of matrix F; the
 227.157 +         middle part of SVA contains free (unused) locations */
 227.158 +      int sv_size;
 227.159 +      /* the size of SVA, in locations; all locations are numbered by
 227.160 +         integers 1, ..., n, and location 0 is not used; if necessary,
 227.161 +         the SVA size is automatically increased */
 227.162 +      int sv_beg, sv_end;
 227.163 +      /* SVA partitioning pointers:
 227.164 +         locations from 1 to sv_beg-1 belong to the left part
 227.165 +         locations from sv_beg to sv_end-1 belong to the middle part
 227.166 +         locations from sv_end to sv_size belong to the right part
 227.167 +         the size of the middle part is (sv_end - sv_beg) */
 227.168 +      int *sv_ind; /* sv_ind[1+sv_size]; */
 227.169 +      /* sv_ind[k], 1 <= k <= sv_size, is the index field of k-th
 227.170 +         location */
 227.171 +      double *sv_val; /* sv_val[1+sv_size]; */
 227.172 +      /* sv_val[k], 1 <= k <= sv_size, is the value field of k-th
 227.173 +         location */
 227.174 +      /*--------------------------------------------------------------*/
 227.175 +      /* in order to efficiently defragment the left part of SVA there
 227.176 +         is a doubly linked list of rows and columns of matrix V, where
 227.177 +         rows are numbered by 1, ..., n, while columns are numbered by
 227.178 +         n+1, ..., n+n, that allows uniquely identifying each row and
 227.179 +         column of V by only one integer; in this list rows and columns
 227.180 +         are ordered by ascending their pointers vr_ptr and vc_ptr */
 227.181 +      int sv_head;
 227.182 +      /* the number of leftmost row/column */
 227.183 +      int sv_tail;
 227.184 +      /* the number of rightmost row/column */
 227.185 +      int *sv_prev; /* int sv_prev[1+n_max+n_max]; */
 227.186 +      /* sv_prev[k], k = 1,...,n+n, is the number of a row/column which
 227.187 +         precedes k-th row/column */
 227.188 +      int *sv_next; /* int sv_next[1+n_max+n_max]; */
 227.189 +      /* sv_next[k], k = 1,...,n+n, is the number of a row/column which
 227.190 +         succedes k-th row/column */
 227.191 +      /*--------------------------------------------------------------*/
 227.192 +      /* working segment (used only during factorization) */
 227.193 +      double *vr_max; /* int vr_max[1+n_max]; */
 227.194 +      /* vr_max[i], 1 <= i <= n, is used only if i-th row of matrix V
 227.195 +         is active (i.e. belongs to the active submatrix), and is the
 227.196 +         largest magnitude of elements in i-th row; if vr_max[i] < 0,
 227.197 +         the largest magnitude is not known yet and should be computed
 227.198 +         by the pivoting routine */
 227.199 +      /*--------------------------------------------------------------*/
 227.200 +      /* in order to efficiently implement Markowitz strategy and Duff
 227.201 +         search technique there are two families {R[0], R[1], ..., R[n]}
 227.202 +         and {C[0], C[1], ..., C[n]}; member R[k] is the set of active
 227.203 +         rows of matrix V, which have k non-zeros, and member C[k] is
 227.204 +         the set of active columns of V, which have k non-zeros in the
 227.205 +         active submatrix (i.e. in the active rows); each set R[k] and
 227.206 +         C[k] is implemented as a separate doubly linked list */
 227.207 +      int *rs_head; /* int rs_head[1+n_max]; */
 227.208 +      /* rs_head[k], 0 <= k <= n, is the number of first active row,
 227.209 +         which has k non-zeros */
 227.210 +      int *rs_prev; /* int rs_prev[1+n_max]; */
 227.211 +      /* rs_prev[i], 1 <= i <= n, is the number of previous row, which
 227.212 +         has the same number of non-zeros as i-th row */
 227.213 +      int *rs_next; /* int rs_next[1+n_max]; */
 227.214 +      /* rs_next[i], 1 <= i <= n, is the number of next row, which has
 227.215 +         the same number of non-zeros as i-th row */
 227.216 +      int *cs_head; /* int cs_head[1+n_max]; */
 227.217 +      /* cs_head[k], 0 <= k <= n, is the number of first active column,
 227.218 +         which has k non-zeros (in the active rows) */
 227.219 +      int *cs_prev; /* int cs_prev[1+n_max]; */
 227.220 +      /* cs_prev[j], 1 <= j <= n, is the number of previous column,
 227.221 +         which has the same number of non-zeros (in the active rows) as
 227.222 +         j-th column */
 227.223 +      int *cs_next; /* int cs_next[1+n_max]; */
 227.224 +      /* cs_next[j], 1 <= j <= n, is the number of next column, which
 227.225 +         has the same number of non-zeros (in the active rows) as j-th
 227.226 +         column */
 227.227 +      /* (end of working segment) */
 227.228 +      /*--------------------------------------------------------------*/
 227.229 +      /* working arrays */
 227.230 +      int *flag; /* int flag[1+n_max]; */
 227.231 +      /* integer working array */
 227.232 +      double *work; /* double work[1+n_max]; */
 227.233 +      /* floating-point working array */
 227.234 +      /*--------------------------------------------------------------*/
 227.235 +      /* control parameters */
 227.236 +      int new_sva;
 227.237 +      /* new required size of the sparse vector area, in locations; set
 227.238 +         automatically by the factorizing routine */
 227.239 +      double piv_tol;
 227.240 +      /* threshold pivoting tolerance, 0 < piv_tol < 1; element v[i,j]
 227.241 +         of the active submatrix fits to be pivot if it satisfies to the
 227.242 +         stability criterion |v[i,j]| >= piv_tol * max |v[i,*]|, i.e. if
 227.243 +         it is not very small in the magnitude among other elements in
 227.244 +         the same row; decreasing this parameter gives better sparsity
 227.245 +         at the expense of numerical accuracy and vice versa */
 227.246 +      int piv_lim;
 227.247 +      /* maximal allowable number of pivot candidates to be considered;
 227.248 +         if piv_lim pivot candidates have been considered, the pivoting
 227.249 +         routine terminates the search with the best candidate found */
 227.250 +      int suhl;
 227.251 +      /* if this flag is set, the pivoting routine applies a heuristic
 227.252 +         proposed by Uwe Suhl: if a column of the active submatrix has
 227.253 +         no eligible pivot candidates (i.e. all its elements do not
 227.254 +         satisfy to the stability criterion), the routine excludes it
 227.255 +         from futher consideration until it becomes column singleton;
 227.256 +         in many cases this allows reducing the time needed for pivot
 227.257 +         searching */
 227.258 +      double eps_tol;
 227.259 +      /* epsilon tolerance; each element of the active submatrix, whose
 227.260 +         magnitude is less than eps_tol, is replaced by exact zero */
 227.261 +      double max_gro;
 227.262 +      /* maximal allowable growth of elements of matrix V during all
 227.263 +         the factorization process; if on some eliminaion step the ratio
 227.264 +         big_v / max_a (see below) becomes greater than max_gro, matrix
 227.265 +         A is considered as ill-conditioned (assuming that the pivoting
 227.266 +         tolerance piv_tol has an appropriate value) */
 227.267 +      /*--------------------------------------------------------------*/
 227.268 +      /* some statistics */
 227.269 +      int nnz_a;
 227.270 +      /* the number of non-zeros in matrix A */
 227.271 +      int nnz_f;
 227.272 +      /* the number of non-zeros in matrix F (except diagonal elements,
 227.273 +         which are not stored) */
 227.274 +      int nnz_v;
 227.275 +      /* the number of non-zeros in matrix V (except its pivot elements,
 227.276 +         which are stored in a separate array) */
 227.277 +      double max_a;
 227.278 +      /* the largest magnitude of elements of matrix A */
 227.279 +      double big_v;
 227.280 +      /* the largest magnitude of elements of matrix V appeared in the
 227.281 +         active submatrix during all the factorization process */
 227.282 +      int rank;
 227.283 +      /* estimated rank of matrix A */
 227.284 +};
 227.285 +
 227.286 +/* return codes: */
 227.287 +#define LUF_ESING    1  /* singular matrix */
 227.288 +#define LUF_ECOND    2  /* ill-conditioned matrix */
 227.289 +
 227.290 +#define luf_create_it _glp_luf_create_it
 227.291 +LUF *luf_create_it(void);
 227.292 +/* create LU-factorization */
 227.293 +
 227.294 +#define luf_defrag_sva _glp_luf_defrag_sva
 227.295 +void luf_defrag_sva(LUF *luf);
 227.296 +/* defragment the sparse vector area */
 227.297 +
 227.298 +#define luf_enlarge_row _glp_luf_enlarge_row
 227.299 +int luf_enlarge_row(LUF *luf, int i, int cap);
 227.300 +/* enlarge row capacity */
 227.301 +
 227.302 +#define luf_enlarge_col _glp_luf_enlarge_col
 227.303 +int luf_enlarge_col(LUF *luf, int j, int cap);
 227.304 +/* enlarge column capacity */
 227.305 +
 227.306 +#define luf_factorize _glp_luf_factorize
 227.307 +int luf_factorize(LUF *luf, int n, int (*col)(void *info, int j,
 227.308 +      int ind[], double val[]), void *info);
 227.309 +/* compute LU-factorization */
 227.310 +
 227.311 +#define luf_f_solve _glp_luf_f_solve
 227.312 +void luf_f_solve(LUF *luf, int tr, double x[]);
 227.313 +/* solve system F*x = b or F'*x = b */
 227.314 +
 227.315 +#define luf_v_solve _glp_luf_v_solve
 227.316 +void luf_v_solve(LUF *luf, int tr, double x[]);
 227.317 +/* solve system V*x = b or V'*x = b */
 227.318 +
 227.319 +#define luf_a_solve _glp_luf_a_solve
 227.320 +void luf_a_solve(LUF *luf, int tr, double x[]);
 227.321 +/* solve system A*x = b or A'*x = b */
 227.322 +
 227.323 +#define luf_delete_it _glp_luf_delete_it
 227.324 +void luf_delete_it(LUF *luf);
 227.325 +/* delete LU-factorization */
 227.326 +
 227.327 +#endif
 227.328 +
 227.329 +/* eof */
   228.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   228.2 +++ b/src/glplux.c	Mon Dec 06 13:09:21 2010 +0100
   228.3 @@ -0,0 +1,1028 @@
   228.4 +/* glplux.c */
   228.5 +
   228.6 +/***********************************************************************
   228.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   228.8 +*
   228.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  228.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  228.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  228.12 +*  E-mail: <mao@gnu.org>.
  228.13 +*
  228.14 +*  GLPK is free software: you can redistribute it and/or modify it
  228.15 +*  under the terms of the GNU General Public License as published by
  228.16 +*  the Free Software Foundation, either version 3 of the License, or
  228.17 +*  (at your option) any later version.
  228.18 +*
  228.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  228.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  228.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  228.22 +*  License for more details.
  228.23 +*
  228.24 +*  You should have received a copy of the GNU General Public License
  228.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  228.26 +***********************************************************************/
  228.27 +
  228.28 +#include "glplux.h"
  228.29 +#define xfault xerror
  228.30 +#define dmp_create_poolx(size) dmp_create_pool()
  228.31 +
  228.32 +/*----------------------------------------------------------------------
  228.33 +// lux_create - create LU-factorization.
  228.34 +//
  228.35 +// SYNOPSIS
  228.36 +//
  228.37 +// #include "glplux.h"
  228.38 +// LUX *lux_create(int n);
  228.39 +//
  228.40 +// DESCRIPTION
  228.41 +//
  228.42 +// The routine lux_create creates LU-factorization data structure for
  228.43 +// a matrix of the order n. Initially the factorization corresponds to
  228.44 +// the unity matrix (F = V = P = Q = I, so A = I).
  228.45 +//
  228.46 +// RETURNS
  228.47 +//
  228.48 +// The routine returns a pointer to the created LU-factorization data
  228.49 +// structure, which represents the unity matrix of the order n. */
  228.50 +
  228.51 +LUX *lux_create(int n)
  228.52 +{     LUX *lux;
  228.53 +      int k;
  228.54 +      if (n < 1)
  228.55 +         xfault("lux_create: n = %d; invalid parameter\n", n);
  228.56 +      lux = xmalloc(sizeof(LUX));
  228.57 +      lux->n = n;
  228.58 +      lux->pool = dmp_create_poolx(sizeof(LUXELM));
  228.59 +      lux->F_row = xcalloc(1+n, sizeof(LUXELM *));
  228.60 +      lux->F_col = xcalloc(1+n, sizeof(LUXELM *));
  228.61 +      lux->V_piv = xcalloc(1+n, sizeof(mpq_t));
  228.62 +      lux->V_row = xcalloc(1+n, sizeof(LUXELM *));
  228.63 +      lux->V_col = xcalloc(1+n, sizeof(LUXELM *));
  228.64 +      lux->P_row = xcalloc(1+n, sizeof(int));
  228.65 +      lux->P_col = xcalloc(1+n, sizeof(int));
  228.66 +      lux->Q_row = xcalloc(1+n, sizeof(int));
  228.67 +      lux->Q_col = xcalloc(1+n, sizeof(int));
  228.68 +      for (k = 1; k <= n; k++)
  228.69 +      {  lux->F_row[k] = lux->F_col[k] = NULL;
  228.70 +         mpq_init(lux->V_piv[k]);
  228.71 +         mpq_set_si(lux->V_piv[k], 1, 1);
  228.72 +         lux->V_row[k] = lux->V_col[k] = NULL;
  228.73 +         lux->P_row[k] = lux->P_col[k] = k;
  228.74 +         lux->Q_row[k] = lux->Q_col[k] = k;
  228.75 +      }
  228.76 +      lux->rank = n;
  228.77 +      return lux;
  228.78 +}
  228.79 +
  228.80 +/*----------------------------------------------------------------------
  228.81 +// initialize - initialize LU-factorization data structures.
  228.82 +//
  228.83 +// This routine initializes data structures for subsequent computing
  228.84 +// the LU-factorization of a given matrix A, which is specified by the
  228.85 +// formal routine col. On exit V = A and F = P = Q = I, where I is the
  228.86 +// unity matrix. */
  228.87 +
  228.88 +static void initialize(LUX *lux, int (*col)(void *info, int j,
  228.89 +      int ind[], mpq_t val[]), void *info, LUXWKA *wka)
  228.90 +{     int n = lux->n;
  228.91 +      DMP *pool = lux->pool;
  228.92 +      LUXELM **F_row = lux->F_row;
  228.93 +      LUXELM **F_col = lux->F_col;
  228.94 +      mpq_t *V_piv = lux->V_piv;
  228.95 +      LUXELM **V_row = lux->V_row;
  228.96 +      LUXELM **V_col = lux->V_col;
  228.97 +      int *P_row = lux->P_row;
  228.98 +      int *P_col = lux->P_col;
  228.99 +      int *Q_row = lux->Q_row;
 228.100 +      int *Q_col = lux->Q_col;
 228.101 +      int *R_len = wka->R_len;
 228.102 +      int *R_head = wka->R_head;
 228.103 +      int *R_prev = wka->R_prev;
 228.104 +      int *R_next = wka->R_next;
 228.105 +      int *C_len = wka->C_len;
 228.106 +      int *C_head = wka->C_head;
 228.107 +      int *C_prev = wka->C_prev;
 228.108 +      int *C_next = wka->C_next;
 228.109 +      LUXELM *fij, *vij;
 228.110 +      int i, j, k, len, *ind;
 228.111 +      mpq_t *val;
 228.112 +      /* F := I */
 228.113 +      for (i = 1; i <= n; i++)
 228.114 +      {  while (F_row[i] != NULL)
 228.115 +         {  fij = F_row[i], F_row[i] = fij->r_next;
 228.116 +            mpq_clear(fij->val);
 228.117 +            dmp_free_atom(pool, fij, sizeof(LUXELM));
 228.118 +         }
 228.119 +      }
 228.120 +      for (j = 1; j <= n; j++) F_col[j] = NULL;
 228.121 +      /* V := 0 */
 228.122 +      for (k = 1; k <= n; k++) mpq_set_si(V_piv[k], 0, 1);
 228.123 +      for (i = 1; i <= n; i++)
 228.124 +      {  while (V_row[i] != NULL)
 228.125 +         {  vij = V_row[i], V_row[i] = vij->r_next;
 228.126 +            mpq_clear(vij->val);
 228.127 +            dmp_free_atom(pool, vij, sizeof(LUXELM));
 228.128 +         }
 228.129 +      }
 228.130 +      for (j = 1; j <= n; j++) V_col[j] = NULL;
 228.131 +      /* V := A */
 228.132 +      ind = xcalloc(1+n, sizeof(int));
 228.133 +      val = xcalloc(1+n, sizeof(mpq_t));
 228.134 +      for (k = 1; k <= n; k++) mpq_init(val[k]);
 228.135 +      for (j = 1; j <= n; j++)
 228.136 +      {  /* obtain j-th column of matrix A */
 228.137 +         len = col(info, j, ind, val);
 228.138 +         if (!(0 <= len && len <= n))
 228.139 +            xfault("lux_decomp: j = %d: len = %d; invalid column length"
 228.140 +               "\n", j, len);
 228.141 +         /* copy elements of j-th column to matrix V */
 228.142 +         for (k = 1; k <= len; k++)
 228.143 +         {  /* get row index of a[i,j] */
 228.144 +            i = ind[k];
 228.145 +            if (!(1 <= i && i <= n))
 228.146 +               xfault("lux_decomp: j = %d: i = %d; row index out of ran"
 228.147 +                  "ge\n", j, i);
 228.148 +            /* check for duplicate indices */
 228.149 +            if (V_row[i] != NULL && V_row[i]->j == j)
 228.150 +               xfault("lux_decomp: j = %d: i = %d; duplicate row indice"
 228.151 +                  "s not allowed\n", j, i);
 228.152 +            /* check for zero value */
 228.153 +            if (mpq_sgn(val[k]) == 0)
 228.154 +               xfault("lux_decomp: j = %d: i = %d; zero elements not al"
 228.155 +                  "lowed\n", j, i);
 228.156 +            /* add new element v[i,j] = a[i,j] to V */
 228.157 +            vij = dmp_get_atom(pool, sizeof(LUXELM));
 228.158 +            vij->i = i, vij->j = j;
 228.159 +            mpq_init(vij->val);
 228.160 +            mpq_set(vij->val, val[k]);
 228.161 +            vij->r_prev = NULL;
 228.162 +            vij->r_next = V_row[i];
 228.163 +            vij->c_prev = NULL;
 228.164 +            vij->c_next = V_col[j];
 228.165 +            if (vij->r_next != NULL) vij->r_next->r_prev = vij;
 228.166 +            if (vij->c_next != NULL) vij->c_next->c_prev = vij;
 228.167 +            V_row[i] = V_col[j] = vij;
 228.168 +         }
 228.169 +      }
 228.170 +      xfree(ind);
 228.171 +      for (k = 1; k <= n; k++) mpq_clear(val[k]);
 228.172 +      xfree(val);
 228.173 +      /* P := Q := I */
 228.174 +      for (k = 1; k <= n; k++)
 228.175 +         P_row[k] = P_col[k] = Q_row[k] = Q_col[k] = k;
 228.176 +      /* the rank of A and V is not determined yet */
 228.177 +      lux->rank = -1;
 228.178 +      /* initially the entire matrix V is active */
 228.179 +      /* determine its row lengths */
 228.180 +      for (i = 1; i <= n; i++)
 228.181 +      {  len = 0;
 228.182 +         for (vij = V_row[i]; vij != NULL; vij = vij->r_next) len++;
 228.183 +         R_len[i] = len;
 228.184 +      }
 228.185 +      /* build linked lists of active rows */
 228.186 +      for (len = 0; len <= n; len++) R_head[len] = 0;
 228.187 +      for (i = 1; i <= n; i++)
 228.188 +      {  len = R_len[i];
 228.189 +         R_prev[i] = 0;
 228.190 +         R_next[i] = R_head[len];
 228.191 +         if (R_next[i] != 0) R_prev[R_next[i]] = i;
 228.192 +         R_head[len] = i;
 228.193 +      }
 228.194 +      /* determine its column lengths */
 228.195 +      for (j = 1; j <= n; j++)
 228.196 +      {  len = 0;
 228.197 +         for (vij = V_col[j]; vij != NULL; vij = vij->c_next) len++;
 228.198 +         C_len[j] = len;
 228.199 +      }
 228.200 +      /* build linked lists of active columns */
 228.201 +      for (len = 0; len <= n; len++) C_head[len] = 0;
 228.202 +      for (j = 1; j <= n; j++)
 228.203 +      {  len = C_len[j];
 228.204 +         C_prev[j] = 0;
 228.205 +         C_next[j] = C_head[len];
 228.206 +         if (C_next[j] != 0) C_prev[C_next[j]] = j;
 228.207 +         C_head[len] = j;
 228.208 +      }
 228.209 +      return;
 228.210 +}
 228.211 +
 228.212 +/*----------------------------------------------------------------------
 228.213 +// find_pivot - choose a pivot element.
 228.214 +//
 228.215 +// This routine chooses a pivot element v[p,q] in the active submatrix
 228.216 +// of matrix U = P*V*Q.
 228.217 +//
 228.218 +// It is assumed that on entry the matrix U has the following partially
 228.219 +// triangularized form:
 228.220 +//
 228.221 +//       1       k         n
 228.222 +//    1  x x x x x x x x x x
 228.223 +//       . x x x x x x x x x
 228.224 +//       . . x x x x x x x x
 228.225 +//       . . . x x x x x x x
 228.226 +//    k  . . . . * * * * * *
 228.227 +//       . . . . * * * * * *
 228.228 +//       . . . . * * * * * *
 228.229 +//       . . . . * * * * * *
 228.230 +//       . . . . * * * * * *
 228.231 +//    n  . . . . * * * * * *
 228.232 +//
 228.233 +// where rows and columns k, k+1, ..., n belong to the active submatrix
 228.234 +// (elements of the active submatrix are marked by '*').
 228.235 +//
 228.236 +// Since the matrix U = P*V*Q is not stored, the routine works with the
 228.237 +// matrix V. It is assumed that the row-wise representation corresponds
 228.238 +// to the matrix V, but the column-wise representation corresponds to
 228.239 +// the active submatrix of the matrix V, i.e. elements of the matrix V,
 228.240 +// which does not belong to the active submatrix, are missing from the
 228.241 +// column linked lists. It is also assumed that each active row of the
 228.242 +// matrix V is in the set R[len], where len is number of non-zeros in
 228.243 +// the row, and each active column of the matrix V is in the set C[len],
 228.244 +// where len is number of non-zeros in the column (in the latter case
 228.245 +// only elements of the active submatrix are counted; such elements are
 228.246 +// marked by '*' on the figure above).
 228.247 +//
 228.248 +// Due to exact arithmetic any non-zero element of the active submatrix
 228.249 +// can be chosen as a pivot. However, to keep sparsity of the matrix V
 228.250 +// the routine uses Markowitz strategy, trying to choose such element
 228.251 +// v[p,q], which has smallest Markowitz cost (nr[p]-1) * (nc[q]-1),
 228.252 +// where nr[p] and nc[q] are the number of non-zero elements, resp., in
 228.253 +// p-th row and in q-th column of the active submatrix.
 228.254 +//
 228.255 +// In order to reduce the search, i.e. not to walk through all elements
 228.256 +// of the active submatrix, the routine exploits a technique proposed by
 228.257 +// I.Duff. This technique is based on using the sets R[len] and C[len]
 228.258 +// of active rows and columns.
 228.259 +//
 228.260 +// On exit the routine returns a pointer to a pivot v[p,q] chosen, or
 228.261 +// NULL, if the active submatrix is empty. */
 228.262 +
 228.263 +static LUXELM *find_pivot(LUX *lux, LUXWKA *wka)
 228.264 +{     int n = lux->n;
 228.265 +      LUXELM **V_row = lux->V_row;
 228.266 +      LUXELM **V_col = lux->V_col;
 228.267 +      int *R_len = wka->R_len;
 228.268 +      int *R_head = wka->R_head;
 228.269 +      int *R_next = wka->R_next;
 228.270 +      int *C_len = wka->C_len;
 228.271 +      int *C_head = wka->C_head;
 228.272 +      int *C_next = wka->C_next;
 228.273 +      LUXELM *piv, *some, *vij;
 228.274 +      int i, j, len, min_len, ncand, piv_lim = 5;
 228.275 +      double best, cost;
 228.276 +      /* nothing is chosen so far */
 228.277 +      piv = NULL, best = DBL_MAX, ncand = 0;
 228.278 +      /* if in the active submatrix there is a column that has the only
 228.279 +         non-zero (column singleton), choose it as a pivot */
 228.280 +      j = C_head[1];
 228.281 +      if (j != 0)
 228.282 +      {  xassert(C_len[j] == 1);
 228.283 +         piv = V_col[j];
 228.284 +         xassert(piv != NULL && piv->c_next == NULL);
 228.285 +         goto done;
 228.286 +      }
 228.287 +      /* if in the active submatrix there is a row that has the only
 228.288 +         non-zero (row singleton), choose it as a pivot */
 228.289 +      i = R_head[1];
 228.290 +      if (i != 0)
 228.291 +      {  xassert(R_len[i] == 1);
 228.292 +         piv = V_row[i];
 228.293 +         xassert(piv != NULL && piv->r_next == NULL);
 228.294 +         goto done;
 228.295 +      }
 228.296 +      /* there are no singletons in the active submatrix; walk through
 228.297 +         other non-empty rows and columns */
 228.298 +      for (len = 2; len <= n; len++)
 228.299 +      {  /* consider active columns having len non-zeros */
 228.300 +         for (j = C_head[len]; j != 0; j = C_next[j])
 228.301 +         {  /* j-th column has len non-zeros */
 228.302 +            /* find an element in the row of minimal length */
 228.303 +            some = NULL, min_len = INT_MAX;
 228.304 +            for (vij = V_col[j]; vij != NULL; vij = vij->c_next)
 228.305 +            {  if (min_len > R_len[vij->i])
 228.306 +                  some = vij, min_len = R_len[vij->i];
 228.307 +               /* if Markowitz cost of this element is not greater than
 228.308 +                  (len-1)**2, it can be chosen right now; this heuristic
 228.309 +                  reduces the search and works well in many cases */
 228.310 +               if (min_len <= len)
 228.311 +               {  piv = some;
 228.312 +                  goto done;
 228.313 +               }
 228.314 +            }
 228.315 +            /* j-th column has been scanned */
 228.316 +            /* the minimal element found is a next pivot candidate */
 228.317 +            xassert(some != NULL);
 228.318 +            ncand++;
 228.319 +            /* compute its Markowitz cost */
 228.320 +            cost = (double)(min_len - 1) * (double)(len - 1);
 228.321 +            /* choose between the current candidate and this element */
 228.322 +            if (cost < best) piv = some, best = cost;
 228.323 +            /* if piv_lim candidates have been considered, there is a
 228.324 +               doubt that a much better candidate exists; therefore it
 228.325 +               is the time to terminate the search */
 228.326 +            if (ncand == piv_lim) goto done;
 228.327 +         }
 228.328 +         /* now consider active rows having len non-zeros */
 228.329 +         for (i = R_head[len]; i != 0; i = R_next[i])
 228.330 +         {  /* i-th row has len non-zeros */
 228.331 +            /* find an element in the column of minimal length */
 228.332 +            some = NULL, min_len = INT_MAX;
 228.333 +            for (vij = V_row[i]; vij != NULL; vij = vij->r_next)
 228.334 +            {  if (min_len > C_len[vij->j])
 228.335 +                  some = vij, min_len = C_len[vij->j];
 228.336 +               /* if Markowitz cost of this element is not greater than
 228.337 +                  (len-1)**2, it can be chosen right now; this heuristic
 228.338 +                  reduces the search and works well in many cases */
 228.339 +               if (min_len <= len)
 228.340 +               {  piv = some;
 228.341 +                  goto done;
 228.342 +               }
 228.343 +            }
 228.344 +            /* i-th row has been scanned */
 228.345 +            /* the minimal element found is a next pivot candidate */
 228.346 +            xassert(some != NULL);
 228.347 +            ncand++;
 228.348 +            /* compute its Markowitz cost */
 228.349 +            cost = (double)(len - 1) * (double)(min_len - 1);
 228.350 +            /* choose between the current candidate and this element */
 228.351 +            if (cost < best) piv = some, best = cost;
 228.352 +            /* if piv_lim candidates have been considered, there is a
 228.353 +               doubt that a much better candidate exists; therefore it
 228.354 +               is the time to terminate the search */
 228.355 +            if (ncand == piv_lim) goto done;
 228.356 +         }
 228.357 +      }
 228.358 +done: /* bring the pivot v[p,q] to the factorizing routine */
 228.359 +      return piv;
 228.360 +}
 228.361 +
 228.362 +/*----------------------------------------------------------------------
 228.363 +// eliminate - perform gaussian elimination.
 228.364 +//
 228.365 +// This routine performs elementary gaussian transformations in order
 228.366 +// to eliminate subdiagonal elements in the k-th column of the matrix
 228.367 +// U = P*V*Q using the pivot element u[k,k], where k is the number of
 228.368 +// the current elimination step.
 228.369 +//
 228.370 +// The parameter piv specifies the pivot element v[p,q] = u[k,k].
 228.371 +//
 228.372 +// Each time when the routine applies the elementary transformation to
 228.373 +// a non-pivot row of the matrix V, it stores the corresponding element
 228.374 +// to the matrix F in order to keep the main equality A = F*V.
 228.375 +//
 228.376 +// The routine assumes that on entry the matrices L = P*F*inv(P) and
 228.377 +// U = P*V*Q are the following:
 228.378 +//
 228.379 +//       1       k                  1       k         n
 228.380 +//    1  1 . . . . . . . . .     1  x x x x x x x x x x
 228.381 +//       x 1 . . . . . . . .        . x x x x x x x x x
 228.382 +//       x x 1 . . . . . . .        . . x x x x x x x x
 228.383 +//       x x x 1 . . . . . .        . . . x x x x x x x
 228.384 +//    k  x x x x 1 . . . . .     k  . . . . * * * * * *
 228.385 +//       x x x x _ 1 . . . .        . . . . # * * * * *
 228.386 +//       x x x x _ . 1 . . .        . . . . # * * * * *
 228.387 +//       x x x x _ . . 1 . .        . . . . # * * * * *
 228.388 +//       x x x x _ . . . 1 .        . . . . # * * * * *
 228.389 +//    n  x x x x _ . . . . 1     n  . . . . # * * * * *
 228.390 +//
 228.391 +//            matrix L                   matrix U
 228.392 +//
 228.393 +// where rows and columns of the matrix U with numbers k, k+1, ..., n
 228.394 +// form the active submatrix (eliminated elements are marked by '#' and
 228.395 +// other elements of the active submatrix are marked by '*'). Note that
 228.396 +// each eliminated non-zero element u[i,k] of the matrix U gives the
 228.397 +// corresponding element l[i,k] of the matrix L (marked by '_').
 228.398 +//
 228.399 +// Actually all operations are performed on the matrix V. Should note
 228.400 +// that the row-wise representation corresponds to the matrix V, but the
 228.401 +// column-wise representation corresponds to the active submatrix of the
 228.402 +// matrix V, i.e. elements of the matrix V, which doesn't belong to the
 228.403 +// active submatrix, are missing from the column linked lists.
 228.404 +//
 228.405 +// Let u[k,k] = v[p,q] be the pivot. In order to eliminate subdiagonal
 228.406 +// elements u[i',k] = v[i,q], i' = k+1, k+2, ..., n, the routine applies
 228.407 +// the following elementary gaussian transformations:
 228.408 +//
 228.409 +//    (i-th row of V) := (i-th row of V) - f[i,p] * (p-th row of V),
 228.410 +//
 228.411 +// where f[i,p] = v[i,q] / v[p,q] is a gaussian multiplier.
 228.412 +//
 228.413 +// Additionally, in order to keep the main equality A = F*V, each time
 228.414 +// when the routine applies the transformation to i-th row of the matrix
 228.415 +// V, it also adds f[i,p] as a new element to the matrix F.
 228.416 +//
 228.417 +// IMPORTANT: On entry the working arrays flag and work should contain
 228.418 +// zeros. This status is provided by the routine on exit. */
 228.419 +
 228.420 +static void eliminate(LUX *lux, LUXWKA *wka, LUXELM *piv, int flag[],
 228.421 +      mpq_t work[])
 228.422 +{     DMP *pool = lux->pool;
 228.423 +      LUXELM **F_row = lux->F_row;
 228.424 +      LUXELM **F_col = lux->F_col;
 228.425 +      mpq_t *V_piv = lux->V_piv;
 228.426 +      LUXELM **V_row = lux->V_row;
 228.427 +      LUXELM **V_col = lux->V_col;
 228.428 +      int *R_len = wka->R_len;
 228.429 +      int *R_head = wka->R_head;
 228.430 +      int *R_prev = wka->R_prev;
 228.431 +      int *R_next = wka->R_next;
 228.432 +      int *C_len = wka->C_len;
 228.433 +      int *C_head = wka->C_head;
 228.434 +      int *C_prev = wka->C_prev;
 228.435 +      int *C_next = wka->C_next;
 228.436 +      LUXELM *fip, *vij, *vpj, *viq, *next;
 228.437 +      mpq_t temp;
 228.438 +      int i, j, p, q;
 228.439 +      mpq_init(temp);
 228.440 +      /* determine row and column indices of the pivot v[p,q] */
 228.441 +      xassert(piv != NULL);
 228.442 +      p = piv->i, q = piv->j;
 228.443 +      /* remove p-th (pivot) row from the active set; it will never
 228.444 +         return there */
 228.445 +      if (R_prev[p] == 0)
 228.446 +         R_head[R_len[p]] = R_next[p];
 228.447 +      else
 228.448 +         R_next[R_prev[p]] = R_next[p];
 228.449 +      if (R_next[p] == 0)
 228.450 +         ;
 228.451 +      else
 228.452 +         R_prev[R_next[p]] = R_prev[p];
 228.453 +      /* remove q-th (pivot) column from the active set; it will never
 228.454 +         return there */
 228.455 +      if (C_prev[q] == 0)
 228.456 +         C_head[C_len[q]] = C_next[q];
 228.457 +      else
 228.458 +         C_next[C_prev[q]] = C_next[q];
 228.459 +      if (C_next[q] == 0)
 228.460 +         ;
 228.461 +      else
 228.462 +         C_prev[C_next[q]] = C_prev[q];
 228.463 +      /* store the pivot value in a separate array */
 228.464 +      mpq_set(V_piv[p], piv->val);
 228.465 +      /* remove the pivot from p-th row */
 228.466 +      if (piv->r_prev == NULL)
 228.467 +         V_row[p] = piv->r_next;
 228.468 +      else
 228.469 +         piv->r_prev->r_next = piv->r_next;
 228.470 +      if (piv->r_next == NULL)
 228.471 +         ;
 228.472 +      else
 228.473 +         piv->r_next->r_prev = piv->r_prev;
 228.474 +      R_len[p]--;
 228.475 +      /* remove the pivot from q-th column */
 228.476 +      if (piv->c_prev == NULL)
 228.477 +         V_col[q] = piv->c_next;
 228.478 +      else
 228.479 +         piv->c_prev->c_next = piv->c_next;
 228.480 +      if (piv->c_next == NULL)
 228.481 +         ;
 228.482 +      else
 228.483 +         piv->c_next->c_prev = piv->c_prev;
 228.484 +      C_len[q]--;
 228.485 +      /* free the space occupied by the pivot */
 228.486 +      mpq_clear(piv->val);
 228.487 +      dmp_free_atom(pool, piv, sizeof(LUXELM));
 228.488 +      /* walk through p-th (pivot) row, which already does not contain
 228.489 +         the pivot v[p,q], and do the following... */
 228.490 +      for (vpj = V_row[p]; vpj != NULL; vpj = vpj->r_next)
 228.491 +      {  /* get column index of v[p,j] */
 228.492 +         j = vpj->j;
 228.493 +         /* store v[p,j] in the working array */
 228.494 +         flag[j] = 1;
 228.495 +         mpq_set(work[j], vpj->val);
 228.496 +         /* remove j-th column from the active set; it will return there
 228.497 +            later with a new length */
 228.498 +         if (C_prev[j] == 0)
 228.499 +            C_head[C_len[j]] = C_next[j];
 228.500 +         else
 228.501 +            C_next[C_prev[j]] = C_next[j];
 228.502 +         if (C_next[j] == 0)
 228.503 +            ;
 228.504 +         else
 228.505 +            C_prev[C_next[j]] = C_prev[j];
 228.506 +         /* v[p,j] leaves the active submatrix, so remove it from j-th
 228.507 +            column; however, v[p,j] is kept in p-th row */
 228.508 +         if (vpj->c_prev == NULL)
 228.509 +            V_col[j] = vpj->c_next;
 228.510 +         else
 228.511 +            vpj->c_prev->c_next = vpj->c_next;
 228.512 +         if (vpj->c_next == NULL)
 228.513 +            ;
 228.514 +         else
 228.515 +            vpj->c_next->c_prev = vpj->c_prev;
 228.516 +         C_len[j]--;
 228.517 +      }
 228.518 +      /* now walk through q-th (pivot) column, which already does not
 228.519 +         contain the pivot v[p,q], and perform gaussian elimination */
 228.520 +      while (V_col[q] != NULL)
 228.521 +      {  /* element v[i,q] has to be eliminated */
 228.522 +         viq = V_col[q];
 228.523 +         /* get row index of v[i,q] */
 228.524 +         i = viq->i;
 228.525 +         /* remove i-th row from the active set; later it will return
 228.526 +            there with a new length */
 228.527 +         if (R_prev[i] == 0)
 228.528 +            R_head[R_len[i]] = R_next[i];
 228.529 +         else
 228.530 +            R_next[R_prev[i]] = R_next[i];
 228.531 +         if (R_next[i] == 0)
 228.532 +            ;
 228.533 +         else
 228.534 +            R_prev[R_next[i]] = R_prev[i];
 228.535 +         /* compute gaussian multiplier f[i,p] = v[i,q] / v[p,q] and
 228.536 +            store it in the matrix F */
 228.537 +         fip = dmp_get_atom(pool, sizeof(LUXELM));
 228.538 +         fip->i = i, fip->j = p;
 228.539 +         mpq_init(fip->val);
 228.540 +         mpq_div(fip->val, viq->val, V_piv[p]);
 228.541 +         fip->r_prev = NULL;
 228.542 +         fip->r_next = F_row[i];
 228.543 +         fip->c_prev = NULL;
 228.544 +         fip->c_next = F_col[p];
 228.545 +         if (fip->r_next != NULL) fip->r_next->r_prev = fip;
 228.546 +         if (fip->c_next != NULL) fip->c_next->c_prev = fip;
 228.547 +         F_row[i] = F_col[p] = fip;
 228.548 +         /* v[i,q] has to be eliminated, so remove it from i-th row */
 228.549 +         if (viq->r_prev == NULL)
 228.550 +            V_row[i] = viq->r_next;
 228.551 +         else
 228.552 +            viq->r_prev->r_next = viq->r_next;
 228.553 +         if (viq->r_next == NULL)
 228.554 +            ;
 228.555 +         else
 228.556 +            viq->r_next->r_prev = viq->r_prev;
 228.557 +         R_len[i]--;
 228.558 +         /* and also from q-th column */
 228.559 +         V_col[q] = viq->c_next;
 228.560 +         C_len[q]--;
 228.561 +         /* free the space occupied by v[i,q] */
 228.562 +         mpq_clear(viq->val);
 228.563 +         dmp_free_atom(pool, viq, sizeof(LUXELM));
 228.564 +         /* perform gaussian transformation:
 228.565 +            (i-th row) := (i-th row) - f[i,p] * (p-th row)
 228.566 +            note that now p-th row, which is in the working array,
 228.567 +            does not contain the pivot v[p,q], and i-th row does not
 228.568 +            contain the element v[i,q] to be eliminated */
 228.569 +         /* walk through i-th row and transform existing non-zero
 228.570 +            elements */
 228.571 +         for (vij = V_row[i]; vij != NULL; vij = next)
 228.572 +         {  next = vij->r_next;
 228.573 +            /* get column index of v[i,j] */
 228.574 +            j = vij->j;
 228.575 +            /* v[i,j] := v[i,j] - f[i,p] * v[p,j] */
 228.576 +            if (flag[j])
 228.577 +            {  /* v[p,j] != 0 */
 228.578 +               flag[j] = 0;
 228.579 +               mpq_mul(temp, fip->val, work[j]);
 228.580 +               mpq_sub(vij->val, vij->val, temp);
 228.581 +               if (mpq_sgn(vij->val) == 0)
 228.582 +               {  /* new v[i,j] is zero, so remove it from the active
 228.583 +                     submatrix */
 228.584 +                  /* remove v[i,j] from i-th row */
 228.585 +                  if (vij->r_prev == NULL)
 228.586 +                     V_row[i] = vij->r_next;
 228.587 +                  else
 228.588 +                     vij->r_prev->r_next = vij->r_next;
 228.589 +                  if (vij->r_next == NULL)
 228.590 +                     ;
 228.591 +                  else
 228.592 +                     vij->r_next->r_prev = vij->r_prev;
 228.593 +                  R_len[i]--;
 228.594 +                  /* remove v[i,j] from j-th column */
 228.595 +                  if (vij->c_prev == NULL)
 228.596 +                     V_col[j] = vij->c_next;
 228.597 +                  else
 228.598 +                     vij->c_prev->c_next = vij->c_next;
 228.599 +                  if (vij->c_next == NULL)
 228.600 +                     ;
 228.601 +                  else
 228.602 +                     vij->c_next->c_prev = vij->c_prev;
 228.603 +                  C_len[j]--;
 228.604 +                  /* free the space occupied by v[i,j] */
 228.605 +                  mpq_clear(vij->val);
 228.606 +                  dmp_free_atom(pool, vij, sizeof(LUXELM));
 228.607 +               }
 228.608 +            }
 228.609 +         }
 228.610 +         /* now flag is the pattern of the set v[p,*] \ v[i,*] */
 228.611 +         /* walk through p-th (pivot) row and create new elements in
 228.612 +            i-th row, which appear due to fill-in */
 228.613 +         for (vpj = V_row[p]; vpj != NULL; vpj = vpj->r_next)
 228.614 +         {  j = vpj->j;
 228.615 +            if (flag[j])
 228.616 +            {  /* create new non-zero v[i,j] = 0 - f[i,p] * v[p,j] and
 228.617 +                  add it to i-th row and j-th column */
 228.618 +               vij = dmp_get_atom(pool, sizeof(LUXELM));
 228.619 +               vij->i = i, vij->j = j;
 228.620 +               mpq_init(vij->val);
 228.621 +               mpq_mul(vij->val, fip->val, work[j]);
 228.622 +               mpq_neg(vij->val, vij->val);
 228.623 +               vij->r_prev = NULL;
 228.624 +               vij->r_next = V_row[i];
 228.625 +               vij->c_prev = NULL;
 228.626 +               vij->c_next = V_col[j];
 228.627 +               if (vij->r_next != NULL) vij->r_next->r_prev = vij;
 228.628 +               if (vij->c_next != NULL) vij->c_next->c_prev = vij;
 228.629 +               V_row[i] = V_col[j] = vij;
 228.630 +               R_len[i]++, C_len[j]++;
 228.631 +            }
 228.632 +            else
 228.633 +            {  /* there is no fill-in, because v[i,j] already exists in
 228.634 +                  i-th row; restore the flag, which was reset before */
 228.635 +               flag[j] = 1;
 228.636 +            }
 228.637 +         }
 228.638 +         /* now i-th row has been completely transformed and can return
 228.639 +            to the active set with a new length */
 228.640 +         R_prev[i] = 0;
 228.641 +         R_next[i] = R_head[R_len[i]];
 228.642 +         if (R_next[i] != 0) R_prev[R_next[i]] = i;
 228.643 +         R_head[R_len[i]] = i;
 228.644 +      }
 228.645 +      /* at this point q-th (pivot) column must be empty */
 228.646 +      xassert(C_len[q] == 0);
 228.647 +      /* walk through p-th (pivot) row again and do the following... */
 228.648 +      for (vpj = V_row[p]; vpj != NULL; vpj = vpj->r_next)
 228.649 +      {  /* get column index of v[p,j] */
 228.650 +         j = vpj->j;
 228.651 +         /* erase v[p,j] from the working array */
 228.652 +         flag[j] = 0;
 228.653 +         mpq_set_si(work[j], 0, 1);
 228.654 +         /* now j-th column has been completely transformed, so it can
 228.655 +            return to the active list with a new length */
 228.656 +         C_prev[j] = 0;
 228.657 +         C_next[j] = C_head[C_len[j]];
 228.658 +         if (C_next[j] != 0) C_prev[C_next[j]] = j;
 228.659 +         C_head[C_len[j]] = j;
 228.660 +      }
 228.661 +      mpq_clear(temp);
 228.662 +      /* return to the factorizing routine */
 228.663 +      return;
 228.664 +}
 228.665 +
 228.666 +/*----------------------------------------------------------------------
 228.667 +// lux_decomp - compute LU-factorization.
 228.668 +//
 228.669 +// SYNOPSIS
 228.670 +//
 228.671 +// #include "glplux.h"
 228.672 +// int lux_decomp(LUX *lux, int (*col)(void *info, int j, int ind[],
 228.673 +//    mpq_t val[]), void *info);
 228.674 +//
 228.675 +// DESCRIPTION
 228.676 +//
 228.677 +// The routine lux_decomp computes LU-factorization of a given square
 228.678 +// matrix A.
 228.679 +//
 228.680 +// The parameter lux specifies LU-factorization data structure built by
 228.681 +// means of the routine lux_create.
 228.682 +//
 228.683 +// The formal routine col specifies the original matrix A. In order to
 228.684 +// obtain j-th column of the matrix A the routine lux_decomp calls the
 228.685 +// routine col with the parameter j (1 <= j <= n, where n is the order
 228.686 +// of A). In response the routine col should store row indices and
 228.687 +// numerical values of non-zero elements of j-th column of A to the
 228.688 +// locations ind[1], ..., ind[len] and val[1], ..., val[len], resp.,
 228.689 +// where len is the number of non-zeros in j-th column, which should be
 228.690 +// returned on exit. Neiter zero nor duplicate elements are allowed.
 228.691 +//
 228.692 +// The parameter info is a transit pointer passed to the formal routine
 228.693 +// col; it can be used for various purposes.
 228.694 +//
 228.695 +// RETURNS
 228.696 +//
 228.697 +// The routine lux_decomp returns the singularity flag. Zero flag means
 228.698 +// that the original matrix A is non-singular while non-zero flag means
 228.699 +// that A is (exactly!) singular.
 228.700 +//
 228.701 +// Note that LU-factorization is valid in both cases, however, in case
 228.702 +// of singularity some rows of the matrix V (including pivot elements)
 228.703 +// will be empty.
 228.704 +//
 228.705 +// REPAIRING SINGULAR MATRIX
 228.706 +//
 228.707 +// If the routine lux_decomp returns non-zero flag, it provides all
 228.708 +// necessary information that can be used for "repairing" the matrix A,
 228.709 +// where "repairing" means replacing linearly dependent columns of the
 228.710 +// matrix A by appropriate columns of the unity matrix. This feature is
 228.711 +// needed when the routine lux_decomp is used for reinverting the basis
 228.712 +// matrix within the simplex method procedure.
 228.713 +//
 228.714 +// On exit linearly dependent columns of the matrix U have the numbers
 228.715 +// rank+1, rank+2, ..., n, where rank is the exact rank of the matrix A
 228.716 +// stored by the routine to the member lux->rank. The correspondence
 228.717 +// between columns of A and U is the same as between columns of V and U.
 228.718 +// Thus, linearly dependent columns of the matrix A have the numbers
 228.719 +// Q_col[rank+1], Q_col[rank+2], ..., Q_col[n], where Q_col is an array
 228.720 +// representing the permutation matrix Q in column-like format. It is
 228.721 +// understood that each j-th linearly dependent column of the matrix U
 228.722 +// should be replaced by the unity vector, where all elements are zero
 228.723 +// except the unity diagonal element u[j,j]. On the other hand j-th row
 228.724 +// of the matrix U corresponds to the row of the matrix V (and therefore
 228.725 +// of the matrix A) with the number P_row[j], where P_row is an array
 228.726 +// representing the permutation matrix P in row-like format. Thus, each
 228.727 +// j-th linearly dependent column of the matrix U should be replaced by
 228.728 +// a column of the unity matrix with the number P_row[j].
 228.729 +//
 228.730 +// The code that repairs the matrix A may look like follows:
 228.731 +//
 228.732 +//    for (j = rank+1; j <= n; j++)
 228.733 +//    {  replace column Q_col[j] of the matrix A by column P_row[j] of
 228.734 +//       the unity matrix;
 228.735 +//    }
 228.736 +//
 228.737 +// where rank, P_row, and Q_col are members of the structure LUX. */
 228.738 +
 228.739 +int lux_decomp(LUX *lux, int (*col)(void *info, int j, int ind[],
 228.740 +      mpq_t val[]), void *info)
 228.741 +{     int n = lux->n;
 228.742 +      LUXELM **V_row = lux->V_row;
 228.743 +      LUXELM **V_col = lux->V_col;
 228.744 +      int *P_row = lux->P_row;
 228.745 +      int *P_col = lux->P_col;
 228.746 +      int *Q_row = lux->Q_row;
 228.747 +      int *Q_col = lux->Q_col;
 228.748 +      LUXELM *piv, *vij;
 228.749 +      LUXWKA *wka;
 228.750 +      int i, j, k, p, q, t, *flag;
 228.751 +      mpq_t *work;
 228.752 +      /* allocate working area */
 228.753 +      wka = xmalloc(sizeof(LUXWKA));
 228.754 +      wka->R_len = xcalloc(1+n, sizeof(int));
 228.755 +      wka->R_head = xcalloc(1+n, sizeof(int));
 228.756 +      wka->R_prev = xcalloc(1+n, sizeof(int));
 228.757 +      wka->R_next = xcalloc(1+n, sizeof(int));
 228.758 +      wka->C_len = xcalloc(1+n, sizeof(int));
 228.759 +      wka->C_head = xcalloc(1+n, sizeof(int));
 228.760 +      wka->C_prev = xcalloc(1+n, sizeof(int));
 228.761 +      wka->C_next = xcalloc(1+n, sizeof(int));
 228.762 +      /* initialize LU-factorization data structures */
 228.763 +      initialize(lux, col, info, wka);
 228.764 +      /* allocate working arrays */
 228.765 +      flag = xcalloc(1+n, sizeof(int));
 228.766 +      work = xcalloc(1+n, sizeof(mpq_t));
 228.767 +      for (k = 1; k <= n; k++)
 228.768 +      {  flag[k] = 0;
 228.769 +         mpq_init(work[k]);
 228.770 +      }
 228.771 +      /* main elimination loop */
 228.772 +      for (k = 1; k <= n; k++)
 228.773 +      {  /* choose a pivot element v[p,q] */
 228.774 +         piv = find_pivot(lux, wka);
 228.775 +         if (piv == NULL)
 228.776 +         {  /* no pivot can be chosen, because the active submatrix is
 228.777 +               empty */
 228.778 +            break;
 228.779 +         }
 228.780 +         /* determine row and column indices of the pivot element */
 228.781 +         p = piv->i, q = piv->j;
 228.782 +         /* let v[p,q] correspond to u[i',j']; permute k-th and i'-th
 228.783 +            rows and k-th and j'-th columns of the matrix U = P*V*Q to
 228.784 +            move the element u[i',j'] to the position u[k,k] */
 228.785 +         i = P_col[p], j = Q_row[q];
 228.786 +         xassert(k <= i && i <= n && k <= j && j <= n);
 228.787 +         /* permute k-th and i-th rows of the matrix U */
 228.788 +         t = P_row[k];
 228.789 +         P_row[i] = t, P_col[t] = i;
 228.790 +         P_row[k] = p, P_col[p] = k;
 228.791 +         /* permute k-th and j-th columns of the matrix U */
 228.792 +         t = Q_col[k];
 228.793 +         Q_col[j] = t, Q_row[t] = j;
 228.794 +         Q_col[k] = q, Q_row[q] = k;
 228.795 +         /* eliminate subdiagonal elements of k-th column of the matrix
 228.796 +            U = P*V*Q using the pivot element u[k,k] = v[p,q] */
 228.797 +         eliminate(lux, wka, piv, flag, work);
 228.798 +      }
 228.799 +      /* determine the rank of A (and V) */
 228.800 +      lux->rank = k - 1;
 228.801 +      /* free working arrays */
 228.802 +      xfree(flag);
 228.803 +      for (k = 1; k <= n; k++) mpq_clear(work[k]);
 228.804 +      xfree(work);
 228.805 +      /* build column lists of the matrix V using its row lists */
 228.806 +      for (j = 1; j <= n; j++)
 228.807 +         xassert(V_col[j] == NULL);
 228.808 +      for (i = 1; i <= n; i++)
 228.809 +      {  for (vij = V_row[i]; vij != NULL; vij = vij->r_next)
 228.810 +         {  j = vij->j;
 228.811 +            vij->c_prev = NULL;
 228.812 +            vij->c_next = V_col[j];
 228.813 +            if (vij->c_next != NULL) vij->c_next->c_prev = vij;
 228.814 +            V_col[j] = vij;
 228.815 +         }
 228.816 +      }
 228.817 +      /* free working area */
 228.818 +      xfree(wka->R_len);
 228.819 +      xfree(wka->R_head);
 228.820 +      xfree(wka->R_prev);
 228.821 +      xfree(wka->R_next);
 228.822 +      xfree(wka->C_len);
 228.823 +      xfree(wka->C_head);
 228.824 +      xfree(wka->C_prev);
 228.825 +      xfree(wka->C_next);
 228.826 +      xfree(wka);
 228.827 +      /* return to the calling program */
 228.828 +      return (lux->rank < n);
 228.829 +}
 228.830 +
 228.831 +/*----------------------------------------------------------------------
 228.832 +// lux_f_solve - solve system F*x = b or F'*x = b.
 228.833 +//
 228.834 +// SYNOPSIS
 228.835 +//
 228.836 +// #include "glplux.h"
 228.837 +// void lux_f_solve(LUX *lux, int tr, mpq_t x[]);
 228.838 +//
 228.839 +// DESCRIPTION
 228.840 +//
 228.841 +// The routine lux_f_solve solves either the system F*x = b (if the
 228.842 +// flag tr is zero) or the system F'*x = b (if the flag tr is non-zero),
 228.843 +// where the matrix F is a component of LU-factorization specified by
 228.844 +// the parameter lux, F' is a matrix transposed to F.
 228.845 +//
 228.846 +// On entry the array x should contain elements of the right-hand side
 228.847 +// vector b in locations x[1], ..., x[n], where n is the order of the
 228.848 +// matrix F. On exit this array will contain elements of the solution
 228.849 +// vector x in the same locations. */
 228.850 +
 228.851 +void lux_f_solve(LUX *lux, int tr, mpq_t x[])
 228.852 +{     int n = lux->n;
 228.853 +      LUXELM **F_row = lux->F_row;
 228.854 +      LUXELM **F_col = lux->F_col;
 228.855 +      int *P_row = lux->P_row;
 228.856 +      LUXELM *fik, *fkj;
 228.857 +      int i, j, k;
 228.858 +      mpq_t temp;
 228.859 +      mpq_init(temp);
 228.860 +      if (!tr)
 228.861 +      {  /* solve the system F*x = b */
 228.862 +         for (j = 1; j <= n; j++)
 228.863 +         {  k = P_row[j];
 228.864 +            if (mpq_sgn(x[k]) != 0)
 228.865 +            {  for (fik = F_col[k]; fik != NULL; fik = fik->c_next)
 228.866 +               {  mpq_mul(temp, fik->val, x[k]);
 228.867 +                  mpq_sub(x[fik->i], x[fik->i], temp);
 228.868 +               }
 228.869 +            }
 228.870 +         }
 228.871 +      }
 228.872 +      else
 228.873 +      {  /* solve the system F'*x = b */
 228.874 +         for (i = n; i >= 1; i--)
 228.875 +         {  k = P_row[i];
 228.876 +            if (mpq_sgn(x[k]) != 0)
 228.877 +            {  for (fkj = F_row[k]; fkj != NULL; fkj = fkj->r_next)
 228.878 +               {  mpq_mul(temp, fkj->val, x[k]);
 228.879 +                  mpq_sub(x[fkj->j], x[fkj->j], temp);
 228.880 +               }
 228.881 +            }
 228.882 +         }
 228.883 +      }
 228.884 +      mpq_clear(temp);
 228.885 +      return;
 228.886 +}
 228.887 +
 228.888 +/*----------------------------------------------------------------------
 228.889 +// lux_v_solve - solve system V*x = b or V'*x = b.
 228.890 +//
 228.891 +// SYNOPSIS
 228.892 +//
 228.893 +// #include "glplux.h"
 228.894 +// void lux_v_solve(LUX *lux, int tr, double x[]);
 228.895 +//
 228.896 +// DESCRIPTION
 228.897 +//
 228.898 +// The routine lux_v_solve solves either the system V*x = b (if the
 228.899 +// flag tr is zero) or the system V'*x = b (if the flag tr is non-zero),
 228.900 +// where the matrix V is a component of LU-factorization specified by
 228.901 +// the parameter lux, V' is a matrix transposed to V.
 228.902 +//
 228.903 +// On entry the array x should contain elements of the right-hand side
 228.904 +// vector b in locations x[1], ..., x[n], where n is the order of the
 228.905 +// matrix V. On exit this array will contain elements of the solution
 228.906 +// vector x in the same locations. */
 228.907 +
 228.908 +void lux_v_solve(LUX *lux, int tr, mpq_t x[])
 228.909 +{     int n = lux->n;
 228.910 +      mpq_t *V_piv = lux->V_piv;
 228.911 +      LUXELM **V_row = lux->V_row;
 228.912 +      LUXELM **V_col = lux->V_col;
 228.913 +      int *P_row = lux->P_row;
 228.914 +      int *Q_col = lux->Q_col;
 228.915 +      LUXELM *vij;
 228.916 +      int i, j, k;
 228.917 +      mpq_t *b, temp;
 228.918 +      b = xcalloc(1+n, sizeof(mpq_t));
 228.919 +      for (k = 1; k <= n; k++)
 228.920 +         mpq_init(b[k]), mpq_set(b[k], x[k]), mpq_set_si(x[k], 0, 1);
 228.921 +      mpq_init(temp);
 228.922 +      if (!tr)
 228.923 +      {  /* solve the system V*x = b */
 228.924 +         for (k = n; k >= 1; k--)
 228.925 +         {  i = P_row[k], j = Q_col[k];
 228.926 +            if (mpq_sgn(b[i]) != 0)
 228.927 +            {  mpq_set(x[j], b[i]);
 228.928 +               mpq_div(x[j], x[j], V_piv[i]);
 228.929 +               for (vij = V_col[j]; vij != NULL; vij = vij->c_next)
 228.930 +               {  mpq_mul(temp, vij->val, x[j]);
 228.931 +                  mpq_sub(b[vij->i], b[vij->i], temp);
 228.932 +               }
 228.933 +            }
 228.934 +         }
 228.935 +      }
 228.936 +      else
 228.937 +      {  /* solve the system V'*x = b */
 228.938 +         for (k = 1; k <= n; k++)
 228.939 +         {  i = P_row[k], j = Q_col[k];
 228.940 +            if (mpq_sgn(b[j]) != 0)
 228.941 +            {  mpq_set(x[i], b[j]);
 228.942 +               mpq_div(x[i], x[i], V_piv[i]);
 228.943 +               for (vij = V_row[i]; vij != NULL; vij = vij->r_next)
 228.944 +               {  mpq_mul(temp, vij->val, x[i]);
 228.945 +                  mpq_sub(b[vij->j], b[vij->j], temp);
 228.946 +               }
 228.947 +            }
 228.948 +         }
 228.949 +      }
 228.950 +      for (k = 1; k <= n; k++) mpq_clear(b[k]);
 228.951 +      mpq_clear(temp);
 228.952 +      xfree(b);
 228.953 +      return;
 228.954 +}
 228.955 +
 228.956 +/*----------------------------------------------------------------------
 228.957 +// lux_solve - solve system A*x = b or A'*x = b.
 228.958 +//
 228.959 +// SYNOPSIS
 228.960 +//
 228.961 +// #include "glplux.h"
 228.962 +// void lux_solve(LUX *lux, int tr, mpq_t x[]);
 228.963 +//
 228.964 +// DESCRIPTION
 228.965 +//
 228.966 +// The routine lux_solve solves either the system A*x = b (if the flag
 228.967 +// tr is zero) or the system A'*x = b (if the flag tr is non-zero),
 228.968 +// where the parameter lux specifies LU-factorization of the matrix A,
 228.969 +// A' is a matrix transposed to A.
 228.970 +//
 228.971 +// On entry the array x should contain elements of the right-hand side
 228.972 +// vector b in locations x[1], ..., x[n], where n is the order of the
 228.973 +// matrix A. On exit this array will contain elements of the solution
 228.974 +// vector x in the same locations. */
 228.975 +
 228.976 +void lux_solve(LUX *lux, int tr, mpq_t x[])
 228.977 +{     if (lux->rank < lux->n)
 228.978 +         xfault("lux_solve: LU-factorization has incomplete rank\n");
 228.979 +      if (!tr)
 228.980 +      {  /* A = F*V, therefore inv(A) = inv(V)*inv(F) */
 228.981 +         lux_f_solve(lux, 0, x);
 228.982 +         lux_v_solve(lux, 0, x);
 228.983 +      }
 228.984 +      else
 228.985 +      {  /* A' = V'*F', therefore inv(A') = inv(F')*inv(V') */
 228.986 +         lux_v_solve(lux, 1, x);
 228.987 +         lux_f_solve(lux, 1, x);
 228.988 +      }
 228.989 +      return;
 228.990 +}
 228.991 +
 228.992 +/*----------------------------------------------------------------------
 228.993 +// lux_delete - delete LU-factorization.
 228.994 +//
 228.995 +// SYNOPSIS
 228.996 +//
 228.997 +// #include "glplux.h"
 228.998 +// void lux_delete(LUX *lux);
 228.999 +//
228.1000 +// DESCRIPTION
228.1001 +//
228.1002 +// The routine lux_delete deletes LU-factorization data structure,
228.1003 +// which the parameter lux points to, freeing all the memory allocated
228.1004 +// to this object. */
228.1005 +
228.1006 +void lux_delete(LUX *lux)
228.1007 +{     int n = lux->n;
228.1008 +      LUXELM *fij, *vij;
228.1009 +      int i;
228.1010 +      for (i = 1; i <= n; i++)
228.1011 +      {  for (fij = lux->F_row[i]; fij != NULL; fij = fij->r_next)
228.1012 +            mpq_clear(fij->val);
228.1013 +         mpq_clear(lux->V_piv[i]);
228.1014 +         for (vij = lux->V_row[i]; vij != NULL; vij = vij->r_next)
228.1015 +            mpq_clear(vij->val);
228.1016 +      }
228.1017 +      dmp_delete_pool(lux->pool);
228.1018 +      xfree(lux->F_row);
228.1019 +      xfree(lux->F_col);
228.1020 +      xfree(lux->V_piv);
228.1021 +      xfree(lux->V_row);
228.1022 +      xfree(lux->V_col);
228.1023 +      xfree(lux->P_row);
228.1024 +      xfree(lux->P_col);
228.1025 +      xfree(lux->Q_row);
228.1026 +      xfree(lux->Q_col);
228.1027 +      xfree(lux);
228.1028 +      return;
228.1029 +}
228.1030 +
228.1031 +/* eof */
   229.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   229.2 +++ b/src/glplux.h	Mon Dec 06 13:09:21 2010 +0100
   229.3 @@ -0,0 +1,221 @@
   229.4 +/* glplux.h (LU-factorization, bignum arithmetic) */
   229.5 +
   229.6 +/***********************************************************************
   229.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   229.8 +*
   229.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  229.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  229.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  229.12 +*  E-mail: <mao@gnu.org>.
  229.13 +*
  229.14 +*  GLPK is free software: you can redistribute it and/or modify it
  229.15 +*  under the terms of the GNU General Public License as published by
  229.16 +*  the Free Software Foundation, either version 3 of the License, or
  229.17 +*  (at your option) any later version.
  229.18 +*
  229.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  229.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  229.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  229.22 +*  License for more details.
  229.23 +*
  229.24 +*  You should have received a copy of the GNU General Public License
  229.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  229.26 +***********************************************************************/
  229.27 +
  229.28 +#ifndef GLPLUX_H
  229.29 +#define GLPLUX_H
  229.30 +
  229.31 +#include "glpdmp.h"
  229.32 +#include "glpgmp.h"
  229.33 +
  229.34 +/*----------------------------------------------------------------------
  229.35 +// The structure LUX defines LU-factorization of a square matrix A,
  229.36 +// which is the following quartet:
  229.37 +//
  229.38 +//    [A] = (F, V, P, Q),                                            (1)
  229.39 +//
  229.40 +// where F and V are such matrices that
  229.41 +//
  229.42 +//    A = F * V,                                                     (2)
  229.43 +//
  229.44 +// and P and Q are such permutation matrices that the matrix
  229.45 +//
  229.46 +//    L = P * F * inv(P)                                             (3)
  229.47 +//
  229.48 +// is lower triangular with unity diagonal, and the matrix
  229.49 +//
  229.50 +//    U = P * V * Q                                                  (4)
  229.51 +//
  229.52 +// is upper triangular. All the matrices have the order n.
  229.53 +//
  229.54 +// The matrices F and V are stored in row/column-wise sparse format as
  229.55 +// row and column linked lists of non-zero elements. Unity elements on
  229.56 +// the main diagonal of the matrix F are not stored. Pivot elements of
  229.57 +// the matrix V (that correspond to diagonal elements of the matrix U)
  229.58 +// are also missing from the row and column lists and stored separately
  229.59 +// in an ordinary array.
  229.60 +//
  229.61 +// The permutation matrices P and Q are stored as ordinary arrays using
  229.62 +// both row- and column-like formats.
  229.63 +//
  229.64 +// The matrices L and U being completely defined by the matrices F, V,
  229.65 +// P, and Q are not stored explicitly.
  229.66 +//
  229.67 +// It is easy to show that the factorization (1)-(3) is some version of
  229.68 +// LU-factorization. Indeed, from (3) and (4) it follows that:
  229.69 +//
  229.70 +//    F = inv(P) * L * P,
  229.71 +//
  229.72 +//    V = inv(P) * U * inv(Q),
  229.73 +//
  229.74 +// and substitution into (2) gives:
  229.75 +//
  229.76 +//    A = F * V = inv(P) * L * U * inv(Q).
  229.77 +//
  229.78 +// For more details see the program documentation. */
  229.79 +
  229.80 +typedef struct LUX LUX;
  229.81 +typedef struct LUXELM LUXELM;
  229.82 +typedef struct LUXWKA LUXWKA;
  229.83 +
  229.84 +struct LUX
  229.85 +{     /* LU-factorization of a square matrix */
  229.86 +      int n;
  229.87 +      /* the order of matrices A, F, V, P, Q */
  229.88 +      DMP *pool;
  229.89 +      /* memory pool for elements of matrices F and V */
  229.90 +      LUXELM **F_row; /* LUXELM *F_row[1+n]; */
  229.91 +      /* F_row[0] is not used;
  229.92 +         F_row[i], 1 <= i <= n, is a pointer to the list of elements in
  229.93 +         i-th row of matrix F (diagonal elements are not stored) */
  229.94 +      LUXELM **F_col; /* LUXELM *F_col[1+n]; */
  229.95 +      /* F_col[0] is not used;
  229.96 +         F_col[j], 1 <= j <= n, is a pointer to the list of elements in
  229.97 +         j-th column of matrix F (diagonal elements are not stored) */
  229.98 +      mpq_t *V_piv; /* mpq_t V_piv[1+n]; */
  229.99 +      /* V_piv[0] is not used;
 229.100 +         V_piv[p], 1 <= p <= n, is a pivot element v[p,q] corresponding
 229.101 +         to a diagonal element u[k,k] of matrix U = P*V*Q (used on k-th
 229.102 +         elimination step, k = 1, 2, ..., n) */
 229.103 +      LUXELM **V_row; /* LUXELM *V_row[1+n]; */
 229.104 +      /* V_row[0] is not used;
 229.105 +         V_row[i], 1 <= i <= n, is a pointer to the list of elements in
 229.106 +         i-th row of matrix V (except pivot elements) */
 229.107 +      LUXELM **V_col; /* LUXELM *V_col[1+n]; */
 229.108 +      /* V_col[0] is not used;
 229.109 +         V_col[j], 1 <= j <= n, is a pointer to the list of elements in
 229.110 +         j-th column of matrix V (except pivot elements) */
 229.111 +      int *P_row; /* int P_row[1+n]; */
 229.112 +      /* P_row[0] is not used;
 229.113 +         P_row[i] = j means that p[i,j] = 1, where p[i,j] is an element
 229.114 +         of permutation matrix P */
 229.115 +      int *P_col; /* int P_col[1+n]; */
 229.116 +      /* P_col[0] is not used;
 229.117 +         P_col[j] = i means that p[i,j] = 1, where p[i,j] is an element
 229.118 +         of permutation matrix P */
 229.119 +      /* if i-th row or column of matrix F is i'-th row or column of
 229.120 +         matrix L = P*F*inv(P), or if i-th row of matrix V is i'-th row
 229.121 +         of matrix U = P*V*Q, then P_row[i'] = i and P_col[i] = i' */
 229.122 +      int *Q_row; /* int Q_row[1+n]; */
 229.123 +      /* Q_row[0] is not used;
 229.124 +         Q_row[i] = j means that q[i,j] = 1, where q[i,j] is an element
 229.125 +         of permutation matrix Q */
 229.126 +      int *Q_col; /* int Q_col[1+n]; */
 229.127 +      /* Q_col[0] is not used;
 229.128 +         Q_col[j] = i means that q[i,j] = 1, where q[i,j] is an element
 229.129 +         of permutation matrix Q */
 229.130 +      /* if j-th column of matrix V is j'-th column of matrix U = P*V*Q,
 229.131 +         then Q_row[j] = j' and Q_col[j'] = j */
 229.132 +      int rank;
 229.133 +      /* the (exact) rank of matrices A and V */
 229.134 +};
 229.135 +
 229.136 +struct LUXELM
 229.137 +{     /* element of matrix F or V */
 229.138 +      int i;
 229.139 +      /* row index, 1 <= i <= m */
 229.140 +      int j;
 229.141 +      /* column index, 1 <= j <= n */
 229.142 +      mpq_t val;
 229.143 +      /* numeric (non-zero) element value */
 229.144 +      LUXELM *r_prev;
 229.145 +      /* pointer to previous element in the same row */
 229.146 +      LUXELM *r_next;
 229.147 +      /* pointer to next element in the same row */
 229.148 +      LUXELM *c_prev;
 229.149 +      /* pointer to previous element in the same column */
 229.150 +      LUXELM *c_next;
 229.151 +      /* pointer to next element in the same column */
 229.152 +};
 229.153 +
 229.154 +struct LUXWKA
 229.155 +{     /* working area (used only during factorization) */
 229.156 +      /* in order to efficiently implement Markowitz strategy and Duff
 229.157 +         search technique there are two families {R[0], R[1], ..., R[n]}
 229.158 +         and {C[0], C[1], ..., C[n]}; member R[k] is a set of active
 229.159 +         rows of matrix V having k non-zeros, and member C[k] is a set
 229.160 +         of active columns of matrix V having k non-zeros (in the active
 229.161 +         submatrix); each set R[k] and C[k] is implemented as a separate
 229.162 +         doubly linked list */
 229.163 +      int *R_len; /* int R_len[1+n]; */
 229.164 +      /* R_len[0] is not used;
 229.165 +         R_len[i], 1 <= i <= n, is the number of non-zero elements in
 229.166 +         i-th row of matrix V (that is the length of i-th row) */
 229.167 +      int *R_head; /* int R_head[1+n]; */
 229.168 +      /* R_head[k], 0 <= k <= n, is the number of a first row, which is
 229.169 +         active and whose length is k */
 229.170 +      int *R_prev; /* int R_prev[1+n]; */
 229.171 +      /* R_prev[0] is not used;
 229.172 +         R_prev[i], 1 <= i <= n, is the number of a previous row, which
 229.173 +         is active and has the same length as i-th row */
 229.174 +      int *R_next; /* int R_next[1+n]; */
 229.175 +      /* R_prev[0] is not used;
 229.176 +         R_prev[i], 1 <= i <= n, is the number of a next row, which is
 229.177 +         active and has the same length as i-th row */
 229.178 +      int *C_len; /* int C_len[1+n]; */
 229.179 +      /* C_len[0] is not used;
 229.180 +         C_len[j], 1 <= j <= n, is the number of non-zero elements in
 229.181 +         j-th column of the active submatrix of matrix V (that is the
 229.182 +         length of j-th column in the active submatrix) */
 229.183 +      int *C_head; /* int C_head[1+n]; */
 229.184 +      /* C_head[k], 0 <= k <= n, is the number of a first column, which
 229.185 +         is active and whose length is k */
 229.186 +      int *C_prev; /* int C_prev[1+n]; */
 229.187 +      /* C_prev[0] is not used;
 229.188 +         C_prev[j], 1 <= j <= n, is the number of a previous column,
 229.189 +         which is active and has the same length as j-th column */
 229.190 +      int *C_next; /* int C_next[1+n]; */
 229.191 +      /* C_next[0] is not used;
 229.192 +         C_next[j], 1 <= j <= n, is the number of a next column, which
 229.193 +         is active and has the same length as j-th column */
 229.194 +};
 229.195 +
 229.196 +#define lux_create            _glp_lux_create
 229.197 +#define lux_decomp            _glp_lux_decomp
 229.198 +#define lux_f_solve           _glp_lux_f_solve
 229.199 +#define lux_v_solve           _glp_lux_v_solve
 229.200 +#define lux_solve             _glp_lux_solve
 229.201 +#define lux_delete            _glp_lux_delete
 229.202 +
 229.203 +LUX *lux_create(int n);
 229.204 +/* create LU-factorization */
 229.205 +
 229.206 +int lux_decomp(LUX *lux, int (*col)(void *info, int j, int ind[],
 229.207 +      mpq_t val[]), void *info);
 229.208 +/* compute LU-factorization */
 229.209 +
 229.210 +void lux_f_solve(LUX *lux, int tr, mpq_t x[]);
 229.211 +/* solve system F*x = b or F'*x = b */
 229.212 +
 229.213 +void lux_v_solve(LUX *lux, int tr, mpq_t x[]);
 229.214 +/* solve system V*x = b or V'*x = b */
 229.215 +
 229.216 +void lux_solve(LUX *lux, int tr, mpq_t x[]);
 229.217 +/* solve system A*x = b or A'*x = b */
 229.218 +
 229.219 +void lux_delete(LUX *lux);
 229.220 +/* delete LU-factorization */
 229.221 +
 229.222 +#endif
 229.223 +
 229.224 +/* eof */
   230.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   230.2 +++ b/src/glpmat.c	Mon Dec 06 13:09:21 2010 +0100
   230.3 @@ -0,0 +1,924 @@
   230.4 +/* glpmat.c */
   230.5 +
   230.6 +/***********************************************************************
   230.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   230.8 +*
   230.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  230.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  230.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  230.12 +*  E-mail: <mao@gnu.org>.
  230.13 +*
  230.14 +*  GLPK is free software: you can redistribute it and/or modify it
  230.15 +*  under the terms of the GNU General Public License as published by
  230.16 +*  the Free Software Foundation, either version 3 of the License, or
  230.17 +*  (at your option) any later version.
  230.18 +*
  230.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  230.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  230.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  230.22 +*  License for more details.
  230.23 +*
  230.24 +*  You should have received a copy of the GNU General Public License
  230.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  230.26 +***********************************************************************/
  230.27 +
  230.28 +#include "glpenv.h"
  230.29 +#include "glpmat.h"
  230.30 +#include "glpqmd.h"
  230.31 +#include "amd/amd.h"
  230.32 +#include "colamd/colamd.h"
  230.33 +
  230.34 +/*----------------------------------------------------------------------
  230.35 +-- check_fvs - check sparse vector in full-vector storage format.
  230.36 +--
  230.37 +-- SYNOPSIS
  230.38 +--
  230.39 +-- #include "glpmat.h"
  230.40 +-- int check_fvs(int n, int nnz, int ind[], double vec[]);
  230.41 +--
  230.42 +-- DESCRIPTION
  230.43 +--
  230.44 +-- The routine check_fvs checks if a given vector of dimension n in
  230.45 +-- full-vector storage format has correct representation.
  230.46 +--
  230.47 +-- RETURNS
  230.48 +--
  230.49 +-- The routine returns one of the following codes:
  230.50 +--
  230.51 +-- 0 - the vector is correct;
  230.52 +-- 1 - the number of elements (n) is negative;
  230.53 +-- 2 - the number of non-zero elements (nnz) is negative;
  230.54 +-- 3 - some element index is out of range;
  230.55 +-- 4 - some element index is duplicate;
  230.56 +-- 5 - some non-zero element is out of pattern. */
  230.57 +
  230.58 +int check_fvs(int n, int nnz, int ind[], double vec[])
  230.59 +{     int i, t, ret, *flag = NULL;
  230.60 +      /* check the number of elements */
  230.61 +      if (n < 0)
  230.62 +      {  ret = 1;
  230.63 +         goto done;
  230.64 +      }
  230.65 +      /* check the number of non-zero elements */
  230.66 +      if (nnz < 0)
  230.67 +      {  ret = 2;
  230.68 +         goto done;
  230.69 +      }
  230.70 +      /* check vector indices */
  230.71 +      flag = xcalloc(1+n, sizeof(int));
  230.72 +      for (i = 1; i <= n; i++) flag[i] = 0;
  230.73 +      for (t = 1; t <= nnz; t++)
  230.74 +      {  i = ind[t];
  230.75 +         if (!(1 <= i && i <= n))
  230.76 +         {  ret = 3;
  230.77 +            goto done;
  230.78 +         }
  230.79 +         if (flag[i])
  230.80 +         {  ret = 4;
  230.81 +            goto done;
  230.82 +         }
  230.83 +         flag[i] = 1;
  230.84 +      }
  230.85 +      /* check vector elements */
  230.86 +      for (i = 1; i <= n; i++)
  230.87 +      {  if (!flag[i] && vec[i] != 0.0)
  230.88 +         {  ret = 5;
  230.89 +            goto done;
  230.90 +         }
  230.91 +      }
  230.92 +      /* the vector is ok */
  230.93 +      ret = 0;
  230.94 +done: if (flag != NULL) xfree(flag);
  230.95 +      return ret;
  230.96 +}
  230.97 +
  230.98 +/*----------------------------------------------------------------------
  230.99 +-- check_pattern - check pattern of sparse matrix.
 230.100 +--
 230.101 +-- SYNOPSIS
 230.102 +--
 230.103 +-- #include "glpmat.h"
 230.104 +-- int check_pattern(int m, int n, int A_ptr[], int A_ind[]);
 230.105 +--
 230.106 +-- DESCRIPTION
 230.107 +--
 230.108 +-- The routine check_pattern checks the pattern of a given mxn matrix
 230.109 +-- in storage-by-rows format.
 230.110 +--
 230.111 +-- RETURNS
 230.112 +--
 230.113 +-- The routine returns one of the following codes:
 230.114 +--
 230.115 +-- 0 - the pattern is correct;
 230.116 +-- 1 - the number of rows (m) is negative;
 230.117 +-- 2 - the number of columns (n) is negative;
 230.118 +-- 3 - A_ptr[1] is not 1;
 230.119 +-- 4 - some column index is out of range;
 230.120 +-- 5 - some column indices are duplicate. */
 230.121 +
 230.122 +int check_pattern(int m, int n, int A_ptr[], int A_ind[])
 230.123 +{     int i, j, ptr, ret, *flag = NULL;
 230.124 +      /* check the number of rows */
 230.125 +      if (m < 0)
 230.126 +      {  ret = 1;
 230.127 +         goto done;
 230.128 +      }
 230.129 +      /* check the number of columns */
 230.130 +      if (n < 0)
 230.131 +      {  ret = 2;
 230.132 +         goto done;
 230.133 +      }
 230.134 +      /* check location A_ptr[1] */
 230.135 +      if (A_ptr[1] != 1)
 230.136 +      {  ret = 3;
 230.137 +         goto done;
 230.138 +      }
 230.139 +      /* check row patterns */
 230.140 +      flag = xcalloc(1+n, sizeof(int));
 230.141 +      for (j = 1; j <= n; j++) flag[j] = 0;
 230.142 +      for (i = 1; i <= m; i++)
 230.143 +      {  /* check pattern of row i */
 230.144 +         for (ptr = A_ptr[i]; ptr < A_ptr[i+1]; ptr++)
 230.145 +         {  j = A_ind[ptr];
 230.146 +            /* check column index */
 230.147 +            if (!(1 <= j && j <= n))
 230.148 +            {  ret = 4;
 230.149 +               goto done;
 230.150 +            }
 230.151 +            /* check for duplication */
 230.152 +            if (flag[j])
 230.153 +            {  ret = 5;
 230.154 +               goto done;
 230.155 +            }
 230.156 +            flag[j] = 1;
 230.157 +         }
 230.158 +         /* clear flags */
 230.159 +         for (ptr = A_ptr[i]; ptr < A_ptr[i+1]; ptr++)
 230.160 +         {  j = A_ind[ptr];
 230.161 +            flag[j] = 0;
 230.162 +         }
 230.163 +      }
 230.164 +      /* the pattern is ok */
 230.165 +      ret = 0;
 230.166 +done: if (flag != NULL) xfree(flag);
 230.167 +      return ret;
 230.168 +}
 230.169 +
 230.170 +/*----------------------------------------------------------------------
 230.171 +-- transpose - transpose sparse matrix.
 230.172 +--
 230.173 +-- *Synopsis*
 230.174 +--
 230.175 +-- #include "glpmat.h"
 230.176 +-- void transpose(int m, int n, int A_ptr[], int A_ind[],
 230.177 +--    double A_val[], int AT_ptr[], int AT_ind[], double AT_val[]);
 230.178 +--
 230.179 +-- *Description*
 230.180 +--
 230.181 +-- For a given mxn sparse matrix A the routine transpose builds a nxm
 230.182 +-- sparse matrix A' which is a matrix transposed to A.
 230.183 +--
 230.184 +-- The arrays A_ptr, A_ind, and A_val specify a given mxn matrix A to
 230.185 +-- be transposed in storage-by-rows format. The parameter A_val can be
 230.186 +-- NULL, in which case numeric values are not copied. The arrays A_ptr,
 230.187 +-- A_ind, and A_val are not changed on exit.
 230.188 +--
 230.189 +-- On entry the arrays AT_ptr, AT_ind, and AT_val must be allocated,
 230.190 +-- but their content is ignored. On exit the routine stores a resultant
 230.191 +-- nxm matrix A' in these arrays in storage-by-rows format. Note that
 230.192 +-- if the parameter A_val is NULL, the array AT_val is not used.
 230.193 +--
 230.194 +-- The routine transpose has a side effect that elements in rows of the
 230.195 +-- resultant matrix A' follow in ascending their column indices. */
 230.196 +
 230.197 +void transpose(int m, int n, int A_ptr[], int A_ind[], double A_val[],
 230.198 +      int AT_ptr[], int AT_ind[], double AT_val[])
 230.199 +{     int i, j, t, beg, end, pos, len;
 230.200 +      /* determine row lengths of resultant matrix */
 230.201 +      for (j = 1; j <= n; j++) AT_ptr[j] = 0;
 230.202 +      for (i = 1; i <= m; i++)
 230.203 +      {  beg = A_ptr[i], end = A_ptr[i+1];
 230.204 +         for (t = beg; t < end; t++) AT_ptr[A_ind[t]]++;
 230.205 +      }
 230.206 +      /* set up row pointers of resultant matrix */
 230.207 +      pos = 1;
 230.208 +      for (j = 1; j <= n; j++)
 230.209 +         len = AT_ptr[j], pos += len, AT_ptr[j] = pos;
 230.210 +      AT_ptr[n+1] = pos;
 230.211 +      /* build resultant matrix */
 230.212 +      for (i = m; i >= 1; i--)
 230.213 +      {  beg = A_ptr[i], end = A_ptr[i+1];
 230.214 +         for (t = beg; t < end; t++)
 230.215 +         {  pos = --AT_ptr[A_ind[t]];
 230.216 +            AT_ind[pos] = i;
 230.217 +            if (A_val != NULL) AT_val[pos] = A_val[t];
 230.218 +         }
 230.219 +      }
 230.220 +      return;
 230.221 +}
 230.222 +
 230.223 +/*----------------------------------------------------------------------
 230.224 +-- adat_symbolic - compute S = P*A*D*A'*P' (symbolic phase).
 230.225 +--
 230.226 +-- *Synopsis*
 230.227 +--
 230.228 +-- #include "glpmat.h"
 230.229 +-- int *adat_symbolic(int m, int n, int P_per[], int A_ptr[],
 230.230 +--    int A_ind[], int S_ptr[]);
 230.231 +--
 230.232 +-- *Description*
 230.233 +--
 230.234 +-- The routine adat_symbolic implements the symbolic phase to compute
 230.235 +-- symmetric matrix S = P*A*D*A'*P', where P is a permutation matrix,
 230.236 +-- A is a given sparse matrix, D is a diagonal matrix, A' is a matrix
 230.237 +-- transposed to A, P' is an inverse of P.
 230.238 +--
 230.239 +-- The parameter m is the number of rows in A and the order of P.
 230.240 +--
 230.241 +-- The parameter n is the number of columns in A and the order of D.
 230.242 +--
 230.243 +-- The array P_per specifies permutation matrix P. It is not changed on
 230.244 +-- exit.
 230.245 +--
 230.246 +-- The arrays A_ptr and A_ind specify the pattern of matrix A. They are
 230.247 +-- not changed on exit.
 230.248 +--
 230.249 +-- On exit the routine stores the pattern of upper triangular part of
 230.250 +-- matrix S without diagonal elements in the arrays S_ptr and S_ind in
 230.251 +-- storage-by-rows format. The array S_ptr should be allocated on entry,
 230.252 +-- however, its content is ignored. The array S_ind is allocated by the
 230.253 +-- routine itself which returns a pointer to it.
 230.254 +--
 230.255 +-- *Returns*
 230.256 +--
 230.257 +-- The routine returns a pointer to the array S_ind. */
 230.258 +
 230.259 +int *adat_symbolic(int m, int n, int P_per[], int A_ptr[], int A_ind[],
 230.260 +      int S_ptr[])
 230.261 +{     int i, j, t, ii, jj, tt, k, size, len;
 230.262 +      int *S_ind, *AT_ptr, *AT_ind, *ind, *map, *temp;
 230.263 +      /* build the pattern of A', which is a matrix transposed to A, to
 230.264 +         efficiently access A in column-wise manner */
 230.265 +      AT_ptr = xcalloc(1+n+1, sizeof(int));
 230.266 +      AT_ind = xcalloc(A_ptr[m+1], sizeof(int));
 230.267 +      transpose(m, n, A_ptr, A_ind, NULL, AT_ptr, AT_ind, NULL);
 230.268 +      /* allocate the array S_ind */
 230.269 +      size = A_ptr[m+1] - 1;
 230.270 +      if (size < m) size = m;
 230.271 +      S_ind = xcalloc(1+size, sizeof(int));
 230.272 +      /* allocate and initialize working arrays */
 230.273 +      ind = xcalloc(1+m, sizeof(int));
 230.274 +      map = xcalloc(1+m, sizeof(int));
 230.275 +      for (jj = 1; jj <= m; jj++) map[jj] = 0;
 230.276 +      /* compute pattern of S; note that symbolically S = B*B', where
 230.277 +         B = P*A, B' is matrix transposed to B */
 230.278 +      S_ptr[1] = 1;
 230.279 +      for (ii = 1; ii <= m; ii++)
 230.280 +      {  /* compute pattern of ii-th row of S */
 230.281 +         len = 0;
 230.282 +         i = P_per[ii]; /* i-th row of A = ii-th row of B */
 230.283 +         for (t = A_ptr[i]; t < A_ptr[i+1]; t++)
 230.284 +         {  k = A_ind[t];
 230.285 +            /* walk through k-th column of A */
 230.286 +            for (tt = AT_ptr[k]; tt < AT_ptr[k+1]; tt++)
 230.287 +            {  j = AT_ind[tt];
 230.288 +               jj = P_per[m+j]; /* j-th row of A = jj-th row of B */
 230.289 +               /* a[i,k] != 0 and a[j,k] != 0 ergo s[ii,jj] != 0 */
 230.290 +               if (ii < jj && !map[jj]) ind[++len] = jj, map[jj] = 1;
 230.291 +            }
 230.292 +         }
 230.293 +         /* now (ind) is pattern of ii-th row of S */
 230.294 +         S_ptr[ii+1] = S_ptr[ii] + len;
 230.295 +         /* at least (S_ptr[ii+1] - 1) locations should be available in
 230.296 +            the array S_ind */
 230.297 +         if (S_ptr[ii+1] - 1 > size)
 230.298 +         {  temp = S_ind;
 230.299 +            size += size;
 230.300 +            S_ind = xcalloc(1+size, sizeof(int));
 230.301 +            memcpy(&S_ind[1], &temp[1], (S_ptr[ii] - 1) * sizeof(int));
 230.302 +            xfree(temp);
 230.303 +         }
 230.304 +         xassert(S_ptr[ii+1] - 1 <= size);
 230.305 +         /* (ii-th row of S) := (ind) */
 230.306 +         memcpy(&S_ind[S_ptr[ii]], &ind[1], len * sizeof(int));
 230.307 +         /* clear the row pattern map */
 230.308 +         for (t = 1; t <= len; t++) map[ind[t]] = 0;
 230.309 +      }
 230.310 +      /* free working arrays */
 230.311 +      xfree(AT_ptr);
 230.312 +      xfree(AT_ind);
 230.313 +      xfree(ind);
 230.314 +      xfree(map);
 230.315 +      /* reallocate the array S_ind to free unused locations */
 230.316 +      temp = S_ind;
 230.317 +      size = S_ptr[m+1] - 1;
 230.318 +      S_ind = xcalloc(1+size, sizeof(int));
 230.319 +      memcpy(&S_ind[1], &temp[1], size * sizeof(int));
 230.320 +      xfree(temp);
 230.321 +      return S_ind;
 230.322 +}
 230.323 +
 230.324 +/*----------------------------------------------------------------------
 230.325 +-- adat_numeric - compute S = P*A*D*A'*P' (numeric phase).
 230.326 +--
 230.327 +-- *Synopsis*
 230.328 +--
 230.329 +-- #include "glpmat.h"
 230.330 +-- void adat_numeric(int m, int n, int P_per[],
 230.331 +--    int A_ptr[], int A_ind[], double A_val[], double D_diag[],
 230.332 +--    int S_ptr[], int S_ind[], double S_val[], double S_diag[]);
 230.333 +--
 230.334 +-- *Description*
 230.335 +--
 230.336 +-- The routine adat_numeric implements the numeric phase to compute
 230.337 +-- symmetric matrix S = P*A*D*A'*P', where P is a permutation matrix,
 230.338 +-- A is a given sparse matrix, D is a diagonal matrix, A' is a matrix
 230.339 +-- transposed to A, P' is an inverse of P.
 230.340 +--
 230.341 +-- The parameter m is the number of rows in A and the order of P.
 230.342 +--
 230.343 +-- The parameter n is the number of columns in A and the order of D.
 230.344 +--
 230.345 +-- The matrix P is specified in the array P_per, which is not changed
 230.346 +-- on exit.
 230.347 +--
 230.348 +-- The matrix A is specified in the arrays A_ptr, A_ind, and A_val in
 230.349 +-- storage-by-rows format. These arrays are not changed on exit.
 230.350 +--
 230.351 +-- Diagonal elements of the matrix D are specified in the array D_diag,
 230.352 +-- where D_diag[0] is not used, D_diag[i] = d[i,i] for i = 1, ..., n.
 230.353 +-- The array D_diag is not changed on exit.
 230.354 +--
 230.355 +-- The pattern of the upper triangular part of the matrix S without
 230.356 +-- diagonal elements (previously computed by the routine adat_symbolic)
 230.357 +-- is specified in the arrays S_ptr and S_ind, which are not changed on
 230.358 +-- exit. Numeric values of non-diagonal elements of S are stored in
 230.359 +-- corresponding locations of the array S_val, and values of diagonal
 230.360 +-- elements of S are stored in locations S_diag[1], ..., S_diag[n]. */
 230.361 +
 230.362 +void adat_numeric(int m, int n, int P_per[],
 230.363 +      int A_ptr[], int A_ind[], double A_val[], double D_diag[],
 230.364 +      int S_ptr[], int S_ind[], double S_val[], double S_diag[])
 230.365 +{     int i, j, t, ii, jj, tt, beg, end, beg1, end1, k;
 230.366 +      double sum, *work;
 230.367 +      work = xcalloc(1+n, sizeof(double));
 230.368 +      for (j = 1; j <= n; j++) work[j] = 0.0;
 230.369 +      /* compute S = B*D*B', where B = P*A, B' is a matrix transposed
 230.370 +         to B */
 230.371 +      for (ii = 1; ii <= m; ii++)
 230.372 +      {  i = P_per[ii]; /* i-th row of A = ii-th row of B */
 230.373 +         /* (work) := (i-th row of A) */
 230.374 +         beg = A_ptr[i], end = A_ptr[i+1];
 230.375 +         for (t = beg; t < end; t++)
 230.376 +            work[A_ind[t]] = A_val[t];
 230.377 +         /* compute ii-th row of S */
 230.378 +         beg = S_ptr[ii], end = S_ptr[ii+1];
 230.379 +         for (t = beg; t < end; t++)
 230.380 +         {  jj = S_ind[t];
 230.381 +            j = P_per[jj]; /* j-th row of A = jj-th row of B */
 230.382 +            /* s[ii,jj] := sum a[i,k] * d[k,k] * a[j,k] */
 230.383 +            sum = 0.0;
 230.384 +            beg1 = A_ptr[j], end1 = A_ptr[j+1];
 230.385 +            for (tt = beg1; tt < end1; tt++)
 230.386 +            {  k = A_ind[tt];
 230.387 +               sum += work[k] * D_diag[k] * A_val[tt];
 230.388 +            }
 230.389 +            S_val[t] = sum;
 230.390 +         }
 230.391 +         /* s[ii,ii] := sum a[i,k] * d[k,k] * a[i,k] */
 230.392 +         sum = 0.0;
 230.393 +         beg = A_ptr[i], end = A_ptr[i+1];
 230.394 +         for (t = beg; t < end; t++)
 230.395 +         {  k = A_ind[t];
 230.396 +            sum += A_val[t] * D_diag[k] * A_val[t];
 230.397 +            work[k] = 0.0;
 230.398 +         }
 230.399 +         S_diag[ii] = sum;
 230.400 +      }
 230.401 +      xfree(work);
 230.402 +      return;
 230.403 +}
 230.404 +
 230.405 +/*----------------------------------------------------------------------
 230.406 +-- min_degree - minimum degree ordering.
 230.407 +--
 230.408 +-- *Synopsis*
 230.409 +--
 230.410 +-- #include "glpmat.h"
 230.411 +-- void min_degree(int n, int A_ptr[], int A_ind[], int P_per[]);
 230.412 +--
 230.413 +-- *Description*
 230.414 +--
 230.415 +-- The routine min_degree uses the minimum degree ordering algorithm
 230.416 +-- to find a permutation matrix P for a given sparse symmetric positive
 230.417 +-- matrix A which minimizes the number of non-zeros in upper triangular
 230.418 +-- factor U for Cholesky factorization P*A*P' = U'*U.
 230.419 +--
 230.420 +-- The parameter n is the order of matrices A and P.
 230.421 +--
 230.422 +-- The pattern of the given matrix A is specified on entry in the arrays
 230.423 +-- A_ptr and A_ind in storage-by-rows format. Only the upper triangular
 230.424 +-- part without diagonal elements (which all are assumed to be non-zero)
 230.425 +-- should be specified as if A were upper triangular. The arrays A_ptr
 230.426 +-- and A_ind are not changed on exit.
 230.427 +--
 230.428 +-- The permutation matrix P is stored by the routine in the array P_per
 230.429 +-- on exit.
 230.430 +--
 230.431 +-- *Algorithm*
 230.432 +--
 230.433 +-- The routine min_degree is based on some subroutines from the package
 230.434 +-- SPARSPAK (see comments in the module glpqmd). */
 230.435 +
 230.436 +void min_degree(int n, int A_ptr[], int A_ind[], int P_per[])
 230.437 +{     int i, j, ne, t, pos, len;
 230.438 +      int *xadj, *adjncy, *deg, *marker, *rchset, *nbrhd, *qsize,
 230.439 +         *qlink, nofsub;
 230.440 +      /* determine number of non-zeros in complete pattern */
 230.441 +      ne = A_ptr[n+1] - 1;
 230.442 +      ne += ne;
 230.443 +      /* allocate working arrays */
 230.444 +      xadj = xcalloc(1+n+1, sizeof(int));
 230.445 +      adjncy = xcalloc(1+ne, sizeof(int));
 230.446 +      deg = xcalloc(1+n, sizeof(int));
 230.447 +      marker = xcalloc(1+n, sizeof(int));
 230.448 +      rchset = xcalloc(1+n, sizeof(int));
 230.449 +      nbrhd = xcalloc(1+n, sizeof(int));
 230.450 +      qsize = xcalloc(1+n, sizeof(int));
 230.451 +      qlink = xcalloc(1+n, sizeof(int));
 230.452 +      /* determine row lengths in complete pattern */
 230.453 +      for (i = 1; i <= n; i++) xadj[i] = 0;
 230.454 +      for (i = 1; i <= n; i++)
 230.455 +      {  for (t = A_ptr[i]; t < A_ptr[i+1]; t++)
 230.456 +         {  j = A_ind[t];
 230.457 +            xassert(i < j && j <= n);
 230.458 +            xadj[i]++, xadj[j]++;
 230.459 +         }
 230.460 +      }
 230.461 +      /* set up row pointers for complete pattern */
 230.462 +      pos = 1;
 230.463 +      for (i = 1; i <= n; i++)
 230.464 +         len = xadj[i], pos += len, xadj[i] = pos;
 230.465 +      xadj[n+1] = pos;
 230.466 +      xassert(pos - 1 == ne);
 230.467 +      /* construct complete pattern */
 230.468 +      for (i = 1; i <= n; i++)
 230.469 +      {  for (t = A_ptr[i]; t < A_ptr[i+1]; t++)
 230.470 +         {  j = A_ind[t];
 230.471 +            adjncy[--xadj[i]] = j, adjncy[--xadj[j]] = i;
 230.472 +         }
 230.473 +      }
 230.474 +      /* call the main minimimum degree ordering routine */
 230.475 +      genqmd(&n, xadj, adjncy, P_per, P_per + n, deg, marker, rchset,
 230.476 +         nbrhd, qsize, qlink, &nofsub);
 230.477 +      /* make sure that permutation matrix P is correct */
 230.478 +      for (i = 1; i <= n; i++)
 230.479 +      {  j = P_per[i];
 230.480 +         xassert(1 <= j && j <= n);
 230.481 +         xassert(P_per[n+j] == i);
 230.482 +      }
 230.483 +      /* free working arrays */
 230.484 +      xfree(xadj);
 230.485 +      xfree(adjncy);
 230.486 +      xfree(deg);
 230.487 +      xfree(marker);
 230.488 +      xfree(rchset);
 230.489 +      xfree(nbrhd);
 230.490 +      xfree(qsize);
 230.491 +      xfree(qlink);
 230.492 +      return;
 230.493 +}
 230.494 +
 230.495 +/**********************************************************************/
 230.496 +
 230.497 +void amd_order1(int n, int A_ptr[], int A_ind[], int P_per[])
 230.498 +{     /* approximate minimum degree ordering (AMD) */
 230.499 +      int k, ret;
 230.500 +      double Control[AMD_CONTROL], Info[AMD_INFO];
 230.501 +      /* get the default parameters */
 230.502 +      amd_defaults(Control);
 230.503 +#if 0
 230.504 +      /* and print them */
 230.505 +      amd_control(Control);
 230.506 +#endif
 230.507 +      /* make all indices 0-based */
 230.508 +      for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]--;
 230.509 +      for (k = 1; k <= n+1; k++) A_ptr[k]--;
 230.510 +      /* call the ordering routine */
 230.511 +      ret = amd_order(n, &A_ptr[1], &A_ind[1], &P_per[1], Control, Info)
 230.512 +         ;
 230.513 +#if 0
 230.514 +      amd_info(Info);
 230.515 +#endif
 230.516 +      xassert(ret == AMD_OK || ret == AMD_OK_BUT_JUMBLED);
 230.517 +      /* retsore 1-based indices */
 230.518 +      for (k = 1; k <= n+1; k++) A_ptr[k]++;
 230.519 +      for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]++;
 230.520 +      /* patch up permutation matrix */
 230.521 +      memset(&P_per[n+1], 0, n * sizeof(int));
 230.522 +      for (k = 1; k <= n; k++)
 230.523 +      {  P_per[k]++;
 230.524 +         xassert(1 <= P_per[k] && P_per[k] <= n);
 230.525 +         xassert(P_per[n+P_per[k]] == 0);
 230.526 +         P_per[n+P_per[k]] = k;
 230.527 +      }
 230.528 +      return;
 230.529 +}
 230.530 +
 230.531 +/**********************************************************************/
 230.532 +
 230.533 +static void *allocate(size_t n, size_t size)
 230.534 +{     void *ptr;
 230.535 +      ptr = xcalloc(n, size);
 230.536 +      memset(ptr, 0, n * size);
 230.537 +      return ptr;
 230.538 +}
 230.539 +
 230.540 +static void release(void *ptr)
 230.541 +{     xfree(ptr);
 230.542 +      return;
 230.543 +}
 230.544 +
 230.545 +void symamd_ord(int n, int A_ptr[], int A_ind[], int P_per[])
 230.546 +{     /* approximate minimum degree ordering (SYMAMD) */
 230.547 +      int k, ok;
 230.548 +      int stats[COLAMD_STATS];
 230.549 +      /* make all indices 0-based */
 230.550 +      for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]--;
 230.551 +      for (k = 1; k <= n+1; k++) A_ptr[k]--;
 230.552 +      /* call the ordering routine */
 230.553 +      ok = symamd(n, &A_ind[1], &A_ptr[1], &P_per[1], NULL, stats,
 230.554 +         allocate, release);
 230.555 +#if 0
 230.556 +      symamd_report(stats);
 230.557 +#endif
 230.558 +      xassert(ok);
 230.559 +      /* restore 1-based indices */
 230.560 +      for (k = 1; k <= n+1; k++) A_ptr[k]++;
 230.561 +      for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]++;
 230.562 +      /* patch up permutation matrix */
 230.563 +      memset(&P_per[n+1], 0, n * sizeof(int));
 230.564 +      for (k = 1; k <= n; k++)
 230.565 +      {  P_per[k]++;
 230.566 +         xassert(1 <= P_per[k] && P_per[k] <= n);
 230.567 +         xassert(P_per[n+P_per[k]] == 0);
 230.568 +         P_per[n+P_per[k]] = k;
 230.569 +      }
 230.570 +      return;
 230.571 +}
 230.572 +
 230.573 +/*----------------------------------------------------------------------
 230.574 +-- chol_symbolic - compute Cholesky factorization (symbolic phase).
 230.575 +--
 230.576 +-- *Synopsis*
 230.577 +--
 230.578 +-- #include "glpmat.h"
 230.579 +-- int *chol_symbolic(int n, int A_ptr[], int A_ind[], int U_ptr[]);
 230.580 +--
 230.581 +-- *Description*
 230.582 +--
 230.583 +-- The routine chol_symbolic implements the symbolic phase of Cholesky
 230.584 +-- factorization A = U'*U, where A is a given sparse symmetric positive
 230.585 +-- definite matrix, U is a resultant upper triangular factor, U' is a
 230.586 +-- matrix transposed to U.
 230.587 +--
 230.588 +-- The parameter n is the order of matrices A and U.
 230.589 +--
 230.590 +-- The pattern of the given matrix A is specified on entry in the arrays
 230.591 +-- A_ptr and A_ind in storage-by-rows format. Only the upper triangular
 230.592 +-- part without diagonal elements (which all are assumed to be non-zero)
 230.593 +-- should be specified as if A were upper triangular. The arrays A_ptr
 230.594 +-- and A_ind are not changed on exit.
 230.595 +--
 230.596 +-- The pattern of the matrix U without diagonal elements (which all are
 230.597 +-- assumed to be non-zero) is stored on exit from the routine in the
 230.598 +-- arrays U_ptr and U_ind in storage-by-rows format. The array U_ptr
 230.599 +-- should be allocated on entry, however, its content is ignored. The
 230.600 +-- array U_ind is allocated by the routine which returns a pointer to it
 230.601 +-- on exit.
 230.602 +--
 230.603 +-- *Returns*
 230.604 +--
 230.605 +-- The routine returns a pointer to the array U_ind.
 230.606 +--
 230.607 +-- *Method*
 230.608 +--
 230.609 +-- The routine chol_symbolic computes the pattern of the matrix U in a
 230.610 +-- row-wise manner. No pivoting is used.
 230.611 +--
 230.612 +-- It is known that to compute the pattern of row k of the matrix U we
 230.613 +-- need to merge the pattern of row k of the matrix A and the patterns
 230.614 +-- of each row i of U, where u[i,k] is non-zero (these rows are already
 230.615 +-- computed and placed above row k).
 230.616 +--
 230.617 +-- However, to reduce the number of rows to be merged the routine uses
 230.618 +-- an advanced algorithm proposed in:
 230.619 +--
 230.620 +-- D.J.Rose, R.E.Tarjan, and G.S.Lueker. Algorithmic aspects of vertex
 230.621 +-- elimination on graphs. SIAM J. Comput. 5, 1976, 266-83.
 230.622 +--
 230.623 +-- The authors of the cited paper show that we have the same result if
 230.624 +-- we merge row k of the matrix A and such rows of the matrix U (among
 230.625 +-- rows 1, ..., k-1) whose leftmost non-diagonal non-zero element is
 230.626 +-- placed in k-th column. This feature signficantly reduces the number
 230.627 +-- of rows to be merged, especially on the final steps, where rows of
 230.628 +-- the matrix U become quite dense.
 230.629 +--
 230.630 +-- To determine rows, which should be merged on k-th step, for a fixed
 230.631 +-- time the routine uses linked lists of row numbers of the matrix U.
 230.632 +-- Location head[k] contains the number of a first row, whose leftmost
 230.633 +-- non-diagonal non-zero element is placed in column k, and location
 230.634 +-- next[i] contains the number of a next row with the same property as
 230.635 +-- row i. */
 230.636 +
 230.637 +int *chol_symbolic(int n, int A_ptr[], int A_ind[], int U_ptr[])
 230.638 +{     int i, j, k, t, len, size, beg, end, min_j, *U_ind, *head, *next,
 230.639 +         *ind, *map, *temp;
 230.640 +      /* initially we assume that on computing the pattern of U fill-in
 230.641 +         will double the number of non-zeros in A */
 230.642 +      size = A_ptr[n+1] - 1;
 230.643 +      if (size < n) size = n;
 230.644 +      size += size;
 230.645 +      U_ind = xcalloc(1+size, sizeof(int));
 230.646 +      /* allocate and initialize working arrays */
 230.647 +      head = xcalloc(1+n, sizeof(int));
 230.648 +      for (i = 1; i <= n; i++) head[i] = 0;
 230.649 +      next = xcalloc(1+n, sizeof(int));
 230.650 +      ind = xcalloc(1+n, sizeof(int));
 230.651 +      map = xcalloc(1+n, sizeof(int));
 230.652 +      for (j = 1; j <= n; j++) map[j] = 0;
 230.653 +      /* compute the pattern of matrix U */
 230.654 +      U_ptr[1] = 1;
 230.655 +      for (k = 1; k <= n; k++)
 230.656 +      {  /* compute the pattern of k-th row of U, which is the union of
 230.657 +            k-th row of A and those rows of U (among 1, ..., k-1) whose
 230.658 +            leftmost non-diagonal non-zero is placed in k-th column */
 230.659 +         /* (ind) := (k-th row of A) */
 230.660 +         len = A_ptr[k+1] - A_ptr[k];
 230.661 +         memcpy(&ind[1], &A_ind[A_ptr[k]], len * sizeof(int));
 230.662 +         for (t = 1; t <= len; t++)
 230.663 +         {  j = ind[t];
 230.664 +            xassert(k < j && j <= n);
 230.665 +            map[j] = 1;
 230.666 +         }
 230.667 +         /* walk through rows of U whose leftmost non-diagonal non-zero
 230.668 +            is placed in k-th column */
 230.669 +         for (i = head[k]; i != 0; i = next[i])
 230.670 +         {  /* (ind) := (ind) union (i-th row of U) */
 230.671 +            beg = U_ptr[i], end = U_ptr[i+1];
 230.672 +            for (t = beg; t < end; t++)
 230.673 +            {  j = U_ind[t];
 230.674 +               if (j > k && !map[j]) ind[++len] = j, map[j] = 1;
 230.675 +            }
 230.676 +         }
 230.677 +         /* now (ind) is the pattern of k-th row of U */
 230.678 +         U_ptr[k+1] = U_ptr[k] + len;
 230.679 +         /* at least (U_ptr[k+1] - 1) locations should be available in
 230.680 +            the array U_ind */
 230.681 +         if (U_ptr[k+1] - 1 > size)
 230.682 +         {  temp = U_ind;
 230.683 +            size += size;
 230.684 +            U_ind = xcalloc(1+size, sizeof(int));
 230.685 +            memcpy(&U_ind[1], &temp[1], (U_ptr[k] - 1) * sizeof(int));
 230.686 +            xfree(temp);
 230.687 +         }
 230.688 +         xassert(U_ptr[k+1] - 1 <= size);
 230.689 +         /* (k-th row of U) := (ind) */
 230.690 +         memcpy(&U_ind[U_ptr[k]], &ind[1], len * sizeof(int));
 230.691 +         /* determine column index of leftmost non-diagonal non-zero in
 230.692 +            k-th row of U and clear the row pattern map */
 230.693 +         min_j = n + 1;
 230.694 +         for (t = 1; t <= len; t++)
 230.695 +         {  j = ind[t], map[j] = 0;
 230.696 +            if (min_j > j) min_j = j;
 230.697 +         }
 230.698 +         /* include k-th row into corresponding linked list */
 230.699 +         if (min_j <= n) next[k] = head[min_j], head[min_j] = k;
 230.700 +      }
 230.701 +      /* free working arrays */
 230.702 +      xfree(head);
 230.703 +      xfree(next);
 230.704 +      xfree(ind);
 230.705 +      xfree(map);
 230.706 +      /* reallocate the array U_ind to free unused locations */
 230.707 +      temp = U_ind;
 230.708 +      size = U_ptr[n+1] - 1;
 230.709 +      U_ind = xcalloc(1+size, sizeof(int));
 230.710 +      memcpy(&U_ind[1], &temp[1], size * sizeof(int));
 230.711 +      xfree(temp);
 230.712 +      return U_ind;
 230.713 +}
 230.714 +
 230.715 +/*----------------------------------------------------------------------
 230.716 +-- chol_numeric - compute Cholesky factorization (numeric phase).
 230.717 +--
 230.718 +-- *Synopsis*
 230.719 +--
 230.720 +-- #include "glpmat.h"
 230.721 +-- int chol_numeric(int n,
 230.722 +--    int A_ptr[], int A_ind[], double A_val[], double A_diag[],
 230.723 +--    int U_ptr[], int U_ind[], double U_val[], double U_diag[]);
 230.724 +--
 230.725 +-- *Description*
 230.726 +--
 230.727 +-- The routine chol_symbolic implements the numeric phase of Cholesky
 230.728 +-- factorization A = U'*U, where A is a given sparse symmetric positive
 230.729 +-- definite matrix, U is a resultant upper triangular factor, U' is a
 230.730 +-- matrix transposed to U.
 230.731 +--
 230.732 +-- The parameter n is the order of matrices A and U.
 230.733 +--
 230.734 +-- Upper triangular part of the matrix A without diagonal elements is
 230.735 +-- specified in the arrays A_ptr, A_ind, and A_val in storage-by-rows
 230.736 +-- format. Diagonal elements of A are specified in the array A_diag,
 230.737 +-- where A_diag[0] is not used, A_diag[i] = a[i,i] for i = 1, ..., n.
 230.738 +-- The arrays A_ptr, A_ind, A_val, and A_diag are not changed on exit.
 230.739 +--
 230.740 +-- The pattern of the matrix U without diagonal elements (previously
 230.741 +-- computed with the routine chol_symbolic) is specified in the arrays
 230.742 +-- U_ptr and U_ind, which are not changed on exit. Numeric values of
 230.743 +-- non-diagonal elements of U are stored in corresponding locations of
 230.744 +-- the array U_val, and values of diagonal elements of U are stored in
 230.745 +-- locations U_diag[1], ..., U_diag[n].
 230.746 +--
 230.747 +-- *Returns*
 230.748 +--
 230.749 +-- The routine returns the number of non-positive diagonal elements of
 230.750 +-- the matrix U which have been replaced by a huge positive number (see
 230.751 +-- the method description below). Zero return code means the matrix A
 230.752 +-- has been successfully factorized.
 230.753 +--
 230.754 +-- *Method*
 230.755 +--
 230.756 +-- The routine chol_numeric computes the matrix U in a row-wise manner
 230.757 +-- using standard gaussian elimination technique. No pivoting is used.
 230.758 +--
 230.759 +-- Initially the routine sets U = A, and before k-th elimination step
 230.760 +-- the matrix U is the following:
 230.761 +--
 230.762 +--       1       k         n
 230.763 +--    1  x x x x x x x x x x
 230.764 +--       . x x x x x x x x x
 230.765 +--       . . x x x x x x x x
 230.766 +--       . . . x x x x x x x
 230.767 +--    k  . . . . * * * * * *
 230.768 +--       . . . . * * * * * *
 230.769 +--       . . . . * * * * * *
 230.770 +--       . . . . * * * * * *
 230.771 +--       . . . . * * * * * *
 230.772 +--    n  . . . . * * * * * *
 230.773 +--
 230.774 +-- where 'x' are elements of already computed rows, '*' are elements of
 230.775 +-- the active submatrix. (Note that the lower triangular part of the
 230.776 +-- active submatrix being symmetric is not stored and diagonal elements
 230.777 +-- are stored separately in the array U_diag.)
 230.778 +--
 230.779 +-- The matrix A is assumed to be positive definite. However, if it is
 230.780 +-- close to semi-definite, on some elimination step a pivot u[k,k] may
 230.781 +-- happen to be non-positive due to round-off errors. In this case the
 230.782 +-- routine uses a technique proposed in:
 230.783 +--
 230.784 +-- S.J.Wright. The Cholesky factorization in interior-point and barrier
 230.785 +-- methods. Preprint MCS-P600-0596, Mathematics and Computer Science
 230.786 +-- Division, Argonne National Laboratory, Argonne, Ill., May 1996.
 230.787 +--
 230.788 +-- The routine just replaces non-positive u[k,k] by a huge positive
 230.789 +-- number. This involves non-diagonal elements in k-th row of U to be
 230.790 +-- close to zero that, in turn, involves k-th component of a solution
 230.791 +-- vector to be close to zero. Note, however, that this technique works
 230.792 +-- only if the system A*x = b is consistent. */
 230.793 +
 230.794 +int chol_numeric(int n,
 230.795 +      int A_ptr[], int A_ind[], double A_val[], double A_diag[],
 230.796 +      int U_ptr[], int U_ind[], double U_val[], double U_diag[])
 230.797 +{     int i, j, k, t, t1, beg, end, beg1, end1, count = 0;
 230.798 +      double ukk, uki, *work;
 230.799 +      work = xcalloc(1+n, sizeof(double));
 230.800 +      for (j = 1; j <= n; j++) work[j] = 0.0;
 230.801 +      /* U := (upper triangle of A) */
 230.802 +      /* note that the upper traingle of A is a subset of U */
 230.803 +      for (i = 1; i <= n; i++)
 230.804 +      {  beg = A_ptr[i], end = A_ptr[i+1];
 230.805 +         for (t = beg; t < end; t++)
 230.806 +            j = A_ind[t], work[j] = A_val[t];
 230.807 +         beg = U_ptr[i], end = U_ptr[i+1];
 230.808 +         for (t = beg; t < end; t++)
 230.809 +            j = U_ind[t], U_val[t] = work[j], work[j] = 0.0;
 230.810 +         U_diag[i] = A_diag[i];
 230.811 +      }
 230.812 +      /* main elimination loop */
 230.813 +      for (k = 1; k <= n; k++)
 230.814 +      {  /* transform k-th row of U */
 230.815 +         ukk = U_diag[k];
 230.816 +         if (ukk > 0.0)
 230.817 +            U_diag[k] = ukk = sqrt(ukk);
 230.818 +         else
 230.819 +            U_diag[k] = ukk = DBL_MAX, count++;
 230.820 +         /* (work) := (transformed k-th row) */
 230.821 +         beg = U_ptr[k], end = U_ptr[k+1];
 230.822 +         for (t = beg; t < end; t++)
 230.823 +            work[U_ind[t]] = (U_val[t] /= ukk);
 230.824 +         /* transform other rows of U */
 230.825 +         for (t = beg; t < end; t++)
 230.826 +         {  i = U_ind[t];
 230.827 +            xassert(i > k);
 230.828 +            /* (i-th row) := (i-th row) - u[k,i] * (k-th row) */
 230.829 +            uki = work[i];
 230.830 +            beg1 = U_ptr[i], end1 = U_ptr[i+1];
 230.831 +            for (t1 = beg1; t1 < end1; t1++)
 230.832 +               U_val[t1] -= uki * work[U_ind[t1]];
 230.833 +            U_diag[i] -= uki * uki;
 230.834 +         }
 230.835 +         /* (work) := 0 */
 230.836 +         for (t = beg; t < end; t++)
 230.837 +            work[U_ind[t]] = 0.0;
 230.838 +      }
 230.839 +      xfree(work);
 230.840 +      return count;
 230.841 +}
 230.842 +
 230.843 +/*----------------------------------------------------------------------
 230.844 +-- u_solve - solve upper triangular system U*x = b.
 230.845 +--
 230.846 +-- *Synopsis*
 230.847 +--
 230.848 +-- #include "glpmat.h"
 230.849 +-- void u_solve(int n, int U_ptr[], int U_ind[], double U_val[],
 230.850 +--    double U_diag[], double x[]);
 230.851 +--
 230.852 +-- *Description*
 230.853 +--
 230.854 +-- The routine u_solve solves an linear system U*x = b, where U is an
 230.855 +-- upper triangular matrix.
 230.856 +--
 230.857 +-- The parameter n is the order of matrix U.
 230.858 +--
 230.859 +-- The matrix U without diagonal elements is specified in the arrays
 230.860 +-- U_ptr, U_ind, and U_val in storage-by-rows format. Diagonal elements
 230.861 +-- of U are specified in the array U_diag, where U_diag[0] is not used,
 230.862 +-- U_diag[i] = u[i,i] for i = 1, ..., n. All these four arrays are not
 230.863 +-- changed on exit.
 230.864 +--
 230.865 +-- The right-hand side vector b is specified on entry in the array x,
 230.866 +-- where x[0] is not used, and x[i] = b[i] for i = 1, ..., n. On exit
 230.867 +-- the routine stores computed components of the vector of unknowns x
 230.868 +-- in the array x in the same manner. */
 230.869 +
 230.870 +void u_solve(int n, int U_ptr[], int U_ind[], double U_val[],
 230.871 +      double U_diag[], double x[])
 230.872 +{     int i, t, beg, end;
 230.873 +      double temp;
 230.874 +      for (i = n; i >= 1; i--)
 230.875 +      {  temp = x[i];
 230.876 +         beg = U_ptr[i], end = U_ptr[i+1];
 230.877 +         for (t = beg; t < end; t++)
 230.878 +            temp -= U_val[t] * x[U_ind[t]];
 230.879 +         xassert(U_diag[i] != 0.0);
 230.880 +         x[i] = temp / U_diag[i];
 230.881 +      }
 230.882 +      return;
 230.883 +}
 230.884 +
 230.885 +/*----------------------------------------------------------------------
 230.886 +-- ut_solve - solve lower triangular system U'*x = b.
 230.887 +--
 230.888 +-- *Synopsis*
 230.889 +--
 230.890 +-- #include "glpmat.h"
 230.891 +-- void ut_solve(int n, int U_ptr[], int U_ind[], double U_val[],
 230.892 +--    double U_diag[], double x[]);
 230.893 +--
 230.894 +-- *Description*
 230.895 +--
 230.896 +-- The routine ut_solve solves an linear system U'*x = b, where U is a
 230.897 +-- matrix transposed to an upper triangular matrix.
 230.898 +--
 230.899 +-- The parameter n is the order of matrix U.
 230.900 +--
 230.901 +-- The matrix U without diagonal elements is specified in the arrays
 230.902 +-- U_ptr, U_ind, and U_val in storage-by-rows format. Diagonal elements
 230.903 +-- of U are specified in the array U_diag, where U_diag[0] is not used,
 230.904 +-- U_diag[i] = u[i,i] for i = 1, ..., n. All these four arrays are not
 230.905 +-- changed on exit.
 230.906 +--
 230.907 +-- The right-hand side vector b is specified on entry in the array x,
 230.908 +-- where x[0] is not used, and x[i] = b[i] for i = 1, ..., n. On exit
 230.909 +-- the routine stores computed components of the vector of unknowns x
 230.910 +-- in the array x in the same manner. */
 230.911 +
 230.912 +void ut_solve(int n, int U_ptr[], int U_ind[], double U_val[],
 230.913 +      double U_diag[], double x[])
 230.914 +{     int i, t, beg, end;
 230.915 +      double temp;
 230.916 +      for (i = 1; i <= n; i++)
 230.917 +      {  xassert(U_diag[i] != 0.0);
 230.918 +         temp = (x[i] /= U_diag[i]);
 230.919 +         if (temp == 0.0) continue;
 230.920 +         beg = U_ptr[i], end = U_ptr[i+1];
 230.921 +         for (t = beg; t < end; t++)
 230.922 +            x[U_ind[t]] -= U_val[t] * temp;
 230.923 +      }
 230.924 +      return;
 230.925 +}
 230.926 +
 230.927 +/* eof */
   231.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   231.2 +++ b/src/glpmat.h	Mon Dec 06 13:09:21 2010 +0100
   231.3 @@ -0,0 +1,198 @@
   231.4 +/* glpmat.h (linear algebra routines) */
   231.5 +
   231.6 +/***********************************************************************
   231.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   231.8 +*
   231.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  231.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  231.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  231.12 +*  E-mail: <mao@gnu.org>.
  231.13 +*
  231.14 +*  GLPK is free software: you can redistribute it and/or modify it
  231.15 +*  under the terms of the GNU General Public License as published by
  231.16 +*  the Free Software Foundation, either version 3 of the License, or
  231.17 +*  (at your option) any later version.
  231.18 +*
  231.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  231.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  231.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  231.22 +*  License for more details.
  231.23 +*
  231.24 +*  You should have received a copy of the GNU General Public License
  231.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  231.26 +***********************************************************************/
  231.27 +
  231.28 +#ifndef GLPMAT_H
  231.29 +#define GLPMAT_H
  231.30 +
  231.31 +/***********************************************************************
  231.32 +*  FULL-VECTOR STORAGE
  231.33 +* 
  231.34 +*  For a sparse vector x having n elements, ne of which are non-zero,
  231.35 +*  the full-vector storage format uses two arrays x_ind and x_vec, which
  231.36 +*  are set up as follows:
  231.37 +* 
  231.38 +*  x_ind is an integer array of length [1+ne]. Location x_ind[0] is
  231.39 +*  not used, and locations x_ind[1], ..., x_ind[ne] contain indices of
  231.40 +*  non-zero elements in vector x.
  231.41 +* 
  231.42 +*  x_vec is a floating-point array of length [1+n]. Location x_vec[0]
  231.43 +*  is not used, and locations x_vec[1], ..., x_vec[n] contain numeric
  231.44 +*  values of ALL elements in vector x, including its zero elements.
  231.45 +* 
  231.46 +*  Let, for example, the following sparse vector x be given:
  231.47 +* 
  231.48 +*     (0, 1, 0, 0, 2, 3, 0, 4)
  231.49 +* 
  231.50 +*  Then the arrays are:
  231.51 +* 
  231.52 +*     x_ind = { X; 2, 5, 6, 8 }
  231.53 +* 
  231.54 +*     x_vec = { X; 0, 1, 0, 0, 2, 3, 0, 4 }
  231.55 +* 
  231.56 +*  COMPRESSED-VECTOR STORAGE
  231.57 +* 
  231.58 +*  For a sparse vector x having n elements, ne of which are non-zero,
  231.59 +*  the compressed-vector storage format uses two arrays x_ind and x_vec,
  231.60 +*  which are set up as follows:
  231.61 +* 
  231.62 +*  x_ind is an integer array of length [1+ne]. Location x_ind[0] is
  231.63 +*  not used, and locations x_ind[1], ..., x_ind[ne] contain indices of
  231.64 +*  non-zero elements in vector x.
  231.65 +* 
  231.66 +*  x_vec is a floating-point array of length [1+ne]. Location x_vec[0]
  231.67 +*  is not used, and locations x_vec[1], ..., x_vec[ne] contain numeric
  231.68 +*  values of corresponding non-zero elements in vector x.
  231.69 +* 
  231.70 +*  Let, for example, the following sparse vector x be given:
  231.71 +* 
  231.72 +*     (0, 1, 0, 0, 2, 3, 0, 4)
  231.73 +* 
  231.74 +*  Then the arrays are:
  231.75 +*
  231.76 +*     x_ind = { X; 2, 5, 6, 8 }
  231.77 +* 
  231.78 +*     x_vec = { X; 1, 2, 3, 4 }
  231.79 +* 
  231.80 +*  STORAGE-BY-ROWS
  231.81 +* 
  231.82 +*  For a sparse matrix A, which has m rows, n columns, and ne non-zero
  231.83 +*  elements the storage-by-rows format uses three arrays A_ptr, A_ind,
  231.84 +*  and A_val, which are set up as follows:
  231.85 +* 
  231.86 +*  A_ptr is an integer array of length [1+m+1] also called "row pointer
  231.87 +*  array". It contains the relative starting positions of each row of A
  231.88 +*  in the arrays A_ind and A_val, i.e. element A_ptr[i], 1 <= i <= m,
  231.89 +*  indicates where row i begins in the arrays A_ind and A_val. If all
  231.90 +*  elements in row i are zero, then A_ptr[i] = A_ptr[i+1]. Location
  231.91 +*  A_ptr[0] is not used, location A_ptr[1] must contain 1, and location
  231.92 +*  A_ptr[m+1] must contain ne+1 that indicates the position after the
  231.93 +*  last element in the arrays A_ind and A_val.
  231.94 +* 
  231.95 +*  A_ind is an integer array of length [1+ne]. Location A_ind[0] is not
  231.96 +*  used, and locations A_ind[1], ..., A_ind[ne] contain column indices
  231.97 +*  of (non-zero) elements in matrix A.
  231.98 +*
  231.99 +*  A_val is a floating-point array of length [1+ne]. Location A_val[0]
 231.100 +*  is not used, and locations A_val[1], ..., A_val[ne] contain numeric
 231.101 +*  values of non-zero elements in matrix A.
 231.102 +* 
 231.103 +*  Non-zero elements of matrix A are stored contiguously, and the rows
 231.104 +*  of matrix A are stored consecutively from 1 to m in the arrays A_ind
 231.105 +*  and A_val. The elements in each row of A may be stored in any order
 231.106 +*  in A_ind and A_val. Note that elements with duplicate column indices
 231.107 +*  are not allowed.
 231.108 +* 
 231.109 +*  Let, for example, the following sparse matrix A be given:
 231.110 +* 
 231.111 +*     | 11  . 13  .  .  . |
 231.112 +*     | 21 22  . 24  .  . |
 231.113 +*     |  . 32 33  .  .  . |
 231.114 +*     |  .  . 43 44  . 46 |
 231.115 +*     |  .  .  .  .  .  . |
 231.116 +*     | 61 62  .  .  . 66 |
 231.117 +* 
 231.118 +*  Then the arrays are:
 231.119 +* 
 231.120 +*     A_ptr = { X; 1, 3, 6, 8, 11, 11; 14 }
 231.121 +*
 231.122 +*     A_ind = { X;  1,  3;  4,  2,  1;  2,  3;  4,  3,  6;  1,  2,  6 }
 231.123 +* 
 231.124 +*     A_val = { X; 11, 13; 24, 22, 21; 32, 33; 44, 43, 46; 61, 62, 66 }
 231.125 +* 
 231.126 +*  PERMUTATION MATRICES
 231.127 +* 
 231.128 +*  Let P be a permutation matrix of the order n. It is represented as
 231.129 +*  an integer array P_per of length [1+n+n] as follows: if p[i,j] = 1,
 231.130 +*  then P_per[i] = j and P_per[n+j] = i. Location P_per[0] is not used.
 231.131 +* 
 231.132 +*  Let A' = P*A. If i-th row of A corresponds to i'-th row of A', then
 231.133 +*  P_per[i'] = i and P_per[n+i] = i'.
 231.134 +* 
 231.135 +*  References:
 231.136 +* 
 231.137 +*  1. Gustavson F.G. Some basic techniques for solving sparse systems of
 231.138 +*     linear equations. In Rose and Willoughby (1972), pp. 41-52.
 231.139 +* 
 231.140 +*  2. Basic Linear Algebra Subprograms Technical (BLAST) Forum Standard.
 231.141 +*     University of Tennessee (2001). */
 231.142 +
 231.143 +#define check_fvs _glp_mat_check_fvs
 231.144 +int check_fvs(int n, int nnz, int ind[], double vec[]);
 231.145 +/* check sparse vector in full-vector storage format */
 231.146 +
 231.147 +#define check_pattern _glp_mat_check_pattern
 231.148 +int check_pattern(int m, int n, int A_ptr[], int A_ind[]);
 231.149 +/* check pattern of sparse matrix */
 231.150 +
 231.151 +#define transpose _glp_mat_transpose
 231.152 +void transpose(int m, int n, int A_ptr[], int A_ind[], double A_val[],
 231.153 +      int AT_ptr[], int AT_ind[], double AT_val[]);
 231.154 +/* transpose sparse matrix */
 231.155 +
 231.156 +#define adat_symbolic _glp_mat_adat_symbolic
 231.157 +int *adat_symbolic(int m, int n, int P_per[], int A_ptr[], int A_ind[],
 231.158 +      int S_ptr[]);
 231.159 +/* compute S = P*A*D*A'*P' (symbolic phase) */
 231.160 +
 231.161 +#define adat_numeric _glp_mat_adat_numeric
 231.162 +void adat_numeric(int m, int n, int P_per[],
 231.163 +      int A_ptr[], int A_ind[], double A_val[], double D_diag[],
 231.164 +      int S_ptr[], int S_ind[], double S_val[], double S_diag[]);
 231.165 +/* compute S = P*A*D*A'*P' (numeric phase) */
 231.166 +
 231.167 +#define min_degree _glp_mat_min_degree
 231.168 +void min_degree(int n, int A_ptr[], int A_ind[], int P_per[]);
 231.169 +/* minimum degree ordering */
 231.170 +
 231.171 +#define amd_order1 _glp_mat_amd_order1
 231.172 +void amd_order1(int n, int A_ptr[], int A_ind[], int P_per[]);
 231.173 +/* approximate minimum degree ordering (AMD) */
 231.174 +
 231.175 +#define symamd_ord _glp_mat_symamd_ord
 231.176 +void symamd_ord(int n, int A_ptr[], int A_ind[], int P_per[]);
 231.177 +/* approximate minimum degree ordering (SYMAMD) */
 231.178 +
 231.179 +#define chol_symbolic _glp_mat_chol_symbolic
 231.180 +int *chol_symbolic(int n, int A_ptr[], int A_ind[], int U_ptr[]);
 231.181 +/* compute Cholesky factorization (symbolic phase) */
 231.182 +
 231.183 +#define chol_numeric _glp_mat_chol_numeric
 231.184 +int chol_numeric(int n,
 231.185 +      int A_ptr[], int A_ind[], double A_val[], double A_diag[],
 231.186 +      int U_ptr[], int U_ind[], double U_val[], double U_diag[]);
 231.187 +/* compute Cholesky factorization (numeric phase) */
 231.188 +
 231.189 +#define u_solve _glp_mat_u_solve
 231.190 +void u_solve(int n, int U_ptr[], int U_ind[], double U_val[],
 231.191 +      double U_diag[], double x[]);
 231.192 +/* solve upper triangular system U*x = b */
 231.193 +
 231.194 +#define ut_solve _glp_mat_ut_solve
 231.195 +void ut_solve(int n, int U_ptr[], int U_ind[], double U_val[],
 231.196 +      double U_diag[], double x[]);
 231.197 +/* solve lower triangular system U'*x = b */
 231.198 +
 231.199 +#endif
 231.200 +
 231.201 +/* eof */
   232.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   232.2 +++ b/src/glpmpl.h	Mon Dec 06 13:09:21 2010 +0100
   232.3 @@ -0,0 +1,2583 @@
   232.4 +/* glpmpl.h (GNU MathProg translator) */
   232.5 +
   232.6 +/***********************************************************************
   232.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   232.8 +*
   232.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  232.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  232.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  232.12 +*  E-mail: <mao@gnu.org>.
  232.13 +*
  232.14 +*  GLPK is free software: you can redistribute it and/or modify it
  232.15 +*  under the terms of the GNU General Public License as published by
  232.16 +*  the Free Software Foundation, either version 3 of the License, or
  232.17 +*  (at your option) any later version.
  232.18 +*
  232.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  232.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  232.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  232.22 +*  License for more details.
  232.23 +*
  232.24 +*  You should have received a copy of the GNU General Public License
  232.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  232.26 +***********************************************************************/
  232.27 +
  232.28 +#ifndef GLPMPL_H
  232.29 +#define GLPMPL_H
  232.30 +
  232.31 +#include "glpavl.h"
  232.32 +#include "glprng.h"
  232.33 +
  232.34 +typedef struct MPL MPL;
  232.35 +typedef char STRING;
  232.36 +typedef struct SYMBOL SYMBOL;
  232.37 +typedef struct TUPLE TUPLE;
  232.38 +typedef struct ARRAY ELEMSET;
  232.39 +typedef struct ELEMVAR ELEMVAR;
  232.40 +typedef struct FORMULA FORMULA;
  232.41 +typedef struct ELEMCON ELEMCON;
  232.42 +typedef union VALUE VALUE;
  232.43 +typedef struct ARRAY ARRAY;
  232.44 +typedef struct MEMBER MEMBER;
  232.45 +#if 1
  232.46 +/* many C compilers have DOMAIN declared in <math.h> :( */
  232.47 +#undef DOMAIN
  232.48 +#define DOMAIN DOMAIN1
  232.49 +#endif
  232.50 +typedef struct DOMAIN DOMAIN;
  232.51 +typedef struct DOMAIN_BLOCK DOMAIN_BLOCK;
  232.52 +typedef struct DOMAIN_SLOT DOMAIN_SLOT;
  232.53 +typedef struct SET SET;
  232.54 +typedef struct WITHIN WITHIN;
  232.55 +typedef struct GADGET GADGET;
  232.56 +typedef struct PARAMETER PARAMETER;
  232.57 +typedef struct CONDITION CONDITION;
  232.58 +typedef struct VARIABLE VARIABLE;
  232.59 +typedef struct CONSTRAINT CONSTRAINT;
  232.60 +typedef struct TABLE TABLE;
  232.61 +typedef struct TABARG TABARG;
  232.62 +typedef struct TABFLD TABFLD;
  232.63 +typedef struct TABIN TABIN;
  232.64 +typedef struct TABOUT TABOUT;
  232.65 +typedef struct TABDCA TABDCA;
  232.66 +typedef union OPERANDS OPERANDS;
  232.67 +typedef struct ARG_LIST ARG_LIST;
  232.68 +typedef struct CODE CODE;
  232.69 +typedef struct CHECK CHECK;
  232.70 +typedef struct DISPLAY DISPLAY;
  232.71 +typedef struct DISPLAY1 DISPLAY1;
  232.72 +typedef struct PRINTF PRINTF;
  232.73 +typedef struct PRINTF1 PRINTF1;
  232.74 +typedef struct FOR FOR;
  232.75 +typedef struct STATEMENT STATEMENT;
  232.76 +typedef struct TUPLE SLICE;
  232.77 +
  232.78 +/**********************************************************************/
  232.79 +/* * *                    TRANSLATOR DATABASE                     * * */
  232.80 +/**********************************************************************/
  232.81 +
  232.82 +#define A_BINARY        101   /* something binary */
  232.83 +#define A_CHECK         102   /* check statement */
  232.84 +#define A_CONSTRAINT    103   /* model constraint */
  232.85 +#define A_DISPLAY       104   /* display statement */
  232.86 +#define A_ELEMCON       105   /* elemental constraint/objective */
  232.87 +#define A_ELEMSET       106   /* elemental set */
  232.88 +#define A_ELEMVAR       107   /* elemental variable */
  232.89 +#define A_EXPRESSION    108   /* expression */
  232.90 +#define A_FOR           109   /* for statement */
  232.91 +#define A_FORMULA       110   /* formula */
  232.92 +#define A_INDEX         111   /* dummy index */
  232.93 +#define A_INPUT         112   /* input table */
  232.94 +#define A_INTEGER       113   /* something integer */
  232.95 +#define A_LOGICAL       114   /* something logical */
  232.96 +#define A_MAXIMIZE      115   /* objective has to be maximized */
  232.97 +#define A_MINIMIZE      116   /* objective has to be minimized */
  232.98 +#define A_NONE          117   /* nothing */
  232.99 +#define A_NUMERIC       118   /* something numeric */
 232.100 +#define A_OUTPUT        119   /* output table */
 232.101 +#define A_PARAMETER     120   /* model parameter */
 232.102 +#define A_PRINTF        121   /* printf statement */
 232.103 +#define A_SET           122   /* model set */
 232.104 +#define A_SOLVE         123   /* solve statement */
 232.105 +#define A_SYMBOLIC      124   /* something symbolic */
 232.106 +#define A_TABLE         125   /* data table */
 232.107 +#define A_TUPLE         126   /* n-tuple */
 232.108 +#define A_VARIABLE      127   /* model variable */
 232.109 +
 232.110 +#define MAX_LENGTH 100
 232.111 +/* maximal length of any symbolic value (this includes symbolic names,
 232.112 +   numeric and string literals, and all symbolic values that may appear
 232.113 +   during the evaluation phase) */
 232.114 +
 232.115 +#define CONTEXT_SIZE 60
 232.116 +/* size of the context queue, in characters */
 232.117 +
 232.118 +#define OUTBUF_SIZE 1024
 232.119 +/* size of the output buffer, in characters */
 232.120 +
 232.121 +struct MPL
 232.122 +{     /* translator database */
 232.123 +      /*--------------------------------------------------------------*/
 232.124 +      /* scanning segment */
 232.125 +      int line;
 232.126 +      /* number of the current text line */
 232.127 +      int c;
 232.128 +      /* the current character or EOF */
 232.129 +      int token;
 232.130 +      /* the current token: */
 232.131 +#define T_EOF           201   /* end of file */
 232.132 +#define T_NAME          202   /* symbolic name (model section only) */
 232.133 +#define T_SYMBOL        203   /* symbol (data section only) */
 232.134 +#define T_NUMBER        204   /* numeric literal */
 232.135 +#define T_STRING        205   /* string literal */
 232.136 +#define T_AND           206   /* and && */
 232.137 +#define T_BY            207   /* by */
 232.138 +#define T_CROSS         208   /* cross */
 232.139 +#define T_DIFF          209   /* diff */
 232.140 +#define T_DIV           210   /* div */
 232.141 +#define T_ELSE          211   /* else */
 232.142 +#define T_IF            212   /* if */
 232.143 +#define T_IN            213   /* in */
 232.144 +#define T_INFINITY      214   /* Infinity */
 232.145 +#define T_INTER         215   /* inter */
 232.146 +#define T_LESS          216   /* less */
 232.147 +#define T_MOD           217   /* mod */
 232.148 +#define T_NOT           218   /* not ! */
 232.149 +#define T_OR            219   /* or || */
 232.150 +#define T_SPTP          220   /* s.t. */
 232.151 +#define T_SYMDIFF       221   /* symdiff */
 232.152 +#define T_THEN          222   /* then */
 232.153 +#define T_UNION         223   /* union */
 232.154 +#define T_WITHIN        224   /* within */
 232.155 +#define T_PLUS          225   /* + */
 232.156 +#define T_MINUS         226   /* - */
 232.157 +#define T_ASTERISK      227   /* * */
 232.158 +#define T_SLASH         228   /* / */
 232.159 +#define T_POWER         229   /* ^ ** */
 232.160 +#define T_LT            230   /* <  */
 232.161 +#define T_LE            231   /* <= */
 232.162 +#define T_EQ            232   /* = == */
 232.163 +#define T_GE            233   /* >= */
 232.164 +#define T_GT            234   /* >  */
 232.165 +#define T_NE            235   /* <> != */
 232.166 +#define T_CONCAT        236   /* & */
 232.167 +#define T_BAR           237   /* | */
 232.168 +#define T_POINT         238   /* . */
 232.169 +#define T_COMMA         239   /* , */
 232.170 +#define T_COLON         240   /* : */
 232.171 +#define T_SEMICOLON     241   /* ; */
 232.172 +#define T_ASSIGN        242   /* := */
 232.173 +#define T_DOTS          243   /* .. */
 232.174 +#define T_LEFT          244   /* ( */
 232.175 +#define T_RIGHT         245   /* ) */
 232.176 +#define T_LBRACKET      246   /* [ */
 232.177 +#define T_RBRACKET      247   /* ] */
 232.178 +#define T_LBRACE        248   /* { */
 232.179 +#define T_RBRACE        249   /* } */
 232.180 +#define T_APPEND        250   /* >> */
 232.181 +#define T_TILDE         251   /* ~ */
 232.182 +#define T_INPUT         252   /* <- */
 232.183 +      int imlen;
 232.184 +      /* length of the current token */
 232.185 +      char *image; /* char image[MAX_LENGTH+1]; */
 232.186 +      /* image of the current token */
 232.187 +      double value;
 232.188 +      /* value of the current token (for T_NUMBER only) */
 232.189 +      int b_token;
 232.190 +      /* the previous token */
 232.191 +      int b_imlen;
 232.192 +      /* length of the previous token */
 232.193 +      char *b_image; /* char b_image[MAX_LENGTH+1]; */
 232.194 +      /* image of the previous token */
 232.195 +      double b_value;
 232.196 +      /* value of the previous token (if token is T_NUMBER) */
 232.197 +      int f_dots;
 232.198 +      /* if this flag is set, the next token should be recognized as
 232.199 +         T_DOTS, not as T_POINT */
 232.200 +      int f_scan;
 232.201 +      /* if this flag is set, the next token is already scanned */
 232.202 +      int f_token;
 232.203 +      /* the next token */
 232.204 +      int f_imlen;
 232.205 +      /* length of the next token */
 232.206 +      char *f_image; /* char f_image[MAX_LENGTH+1]; */
 232.207 +      /* image of the next token */
 232.208 +      double f_value;
 232.209 +      /* value of the next token (if token is T_NUMBER) */
 232.210 +      char *context; /* char context[CONTEXT_SIZE]; */
 232.211 +      /* context circular queue (not null-terminated!) */
 232.212 +      int c_ptr;
 232.213 +      /* pointer to the current position in the context queue */
 232.214 +      int flag_d;
 232.215 +      /* if this flag is set, the data section is being processed */
 232.216 +      /*--------------------------------------------------------------*/
 232.217 +      /* translating segment */
 232.218 +      DMP *pool;
 232.219 +      /* memory pool used to allocate all data instances created during
 232.220 +         the translation phase */
 232.221 +      AVL *tree;
 232.222 +      /* symbolic name table:
 232.223 +         node.type = A_INDEX     => node.link -> DOMAIN_SLOT
 232.224 +         node.type = A_SET       => node.link -> SET
 232.225 +         node.type = A_PARAMETER => node.link -> PARAMETER
 232.226 +         node.type = A_VARIABLE  => node.link -> VARIABLE
 232.227 +         node.type = A_CONSTRANT => node.link -> CONSTRAINT */
 232.228 +      STATEMENT *model;
 232.229 +      /* linked list of model statements in the original order */
 232.230 +      int flag_x;
 232.231 +      /* if this flag is set, the current token being left parenthesis
 232.232 +         begins a slice that allows recognizing any undeclared symbolic
 232.233 +         names as dummy indices; this flag is automatically reset once
 232.234 +         the next token has been scanned */
 232.235 +      int as_within;
 232.236 +      /* the warning "in understood as within" has been issued */
 232.237 +      int as_in;
 232.238 +      /* the warning "within understood as in" has been issued */
 232.239 +      int as_binary;
 232.240 +      /* the warning "logical understood as binary" has been issued */
 232.241 +      int flag_s;
 232.242 +      /* if this flag is set, the solve statement has been parsed */
 232.243 +      /*--------------------------------------------------------------*/
 232.244 +      /* common segment */
 232.245 +      DMP *strings;
 232.246 +      /* memory pool to allocate STRING data structures */
 232.247 +      DMP *symbols;
 232.248 +      /* memory pool to allocate SYMBOL data structures */
 232.249 +      DMP *tuples;
 232.250 +      /* memory pool to allocate TUPLE data structures */
 232.251 +      DMP *arrays;
 232.252 +      /* memory pool to allocate ARRAY data structures */
 232.253 +      DMP *members;
 232.254 +      /* memory pool to allocate MEMBER data structures */
 232.255 +      DMP *elemvars;
 232.256 +      /* memory pool to allocate ELEMVAR data structures */
 232.257 +      DMP *formulae;
 232.258 +      /* memory pool to allocate FORMULA data structures */
 232.259 +      DMP *elemcons;
 232.260 +      /* memory pool to allocate ELEMCON data structures */
 232.261 +      ARRAY *a_list;
 232.262 +      /* linked list of all arrays in the database */
 232.263 +      char *sym_buf; /* char sym_buf[255+1]; */
 232.264 +      /* working buffer used by the routine format_symbol */
 232.265 +      char *tup_buf; /* char tup_buf[255+1]; */
 232.266 +      /* working buffer used by the routine format_tuple */
 232.267 +      /*--------------------------------------------------------------*/
 232.268 +      /* generating/postsolving segment */
 232.269 +      RNG *rand;
 232.270 +      /* pseudo-random number generator */
 232.271 +      int flag_p;
 232.272 +      /* if this flag is set, the postsolving phase is in effect */
 232.273 +      STATEMENT *stmt;
 232.274 +      /* model statement being currently executed */
 232.275 +      TABDCA *dca;
 232.276 +      /* pointer to table driver communication area for table statement
 232.277 +         currently executed */
 232.278 +      int m;
 232.279 +      /* number of rows in the problem, m >= 0 */
 232.280 +      int n;
 232.281 +      /* number of columns in the problem, n >= 0 */
 232.282 +      ELEMCON **row; /* ELEMCON *row[1+m]; */
 232.283 +      /* row[0] is not used;
 232.284 +         row[i] is elemental constraint or objective, which corresponds
 232.285 +         to i-th row of the problem, 1 <= i <= m */
 232.286 +      ELEMVAR **col; /* ELEMVAR *col[1+n]; */
 232.287 +      /* col[0] is not used;
 232.288 +         col[j] is elemental variable, which corresponds to j-th column
 232.289 +         of the problem, 1 <= j <= n */
 232.290 +      /*--------------------------------------------------------------*/
 232.291 +      /* input/output segment */
 232.292 +      XFILE *in_fp;
 232.293 +      /* stream assigned to the input text file */
 232.294 +      char *in_file;
 232.295 +      /* name of the input text file */
 232.296 +      XFILE *out_fp;
 232.297 +      /* stream assigned to the output text file used to write all data
 232.298 +         produced by display and printf statements; NULL means the data
 232.299 +         should be sent to stdout via the routine xprintf */
 232.300 +      char *out_file;
 232.301 +      /* name of the output text file */
 232.302 +#if 0 /* 08/XI-2009 */
 232.303 +      char *out_buf; /* char out_buf[OUTBUF_SIZE] */
 232.304 +      /* buffer to accumulate output data */
 232.305 +      int out_cnt;
 232.306 +      /* count of data bytes stored in the output buffer */
 232.307 +#endif
 232.308 +      XFILE *prt_fp;
 232.309 +      /* stream assigned to the print text file; may be NULL */
 232.310 +      char *prt_file;
 232.311 +      /* name of the output print file */
 232.312 +      /*--------------------------------------------------------------*/
 232.313 +      /* solver interface segment */
 232.314 +      jmp_buf jump;
 232.315 +      /* jump address for non-local go to in case of error */
 232.316 +      int phase;
 232.317 +      /* phase of processing:
 232.318 +         0 - database is being or has been initialized
 232.319 +         1 - model section is being or has been read
 232.320 +         2 - data section is being or has been read
 232.321 +         3 - model is being or has been generated/postsolved
 232.322 +         4 - model processing error has occurred */
 232.323 +      char *mod_file;
 232.324 +      /* name of the input text file, which contains model section */
 232.325 +      char *mpl_buf; /* char mpl_buf[255+1]; */
 232.326 +      /* working buffer used by some interface routines */
 232.327 +};
 232.328 +
 232.329 +/**********************************************************************/
 232.330 +/* * *                  PROCESSING MODEL SECTION                  * * */
 232.331 +/**********************************************************************/
 232.332 +
 232.333 +#define alloc(type) ((type *)dmp_get_atomv(mpl->pool, sizeof(type)))
 232.334 +/* allocate atom of given type */
 232.335 +
 232.336 +#define enter_context _glp_mpl_enter_context
 232.337 +void enter_context(MPL *mpl);
 232.338 +/* enter current token into context queue */
 232.339 +
 232.340 +#define print_context _glp_mpl_print_context
 232.341 +void print_context(MPL *mpl);
 232.342 +/* print current content of context queue */
 232.343 +
 232.344 +#define get_char _glp_mpl_get_char
 232.345 +void get_char(MPL *mpl);
 232.346 +/* scan next character from input text file */
 232.347 +
 232.348 +#define append_char _glp_mpl_append_char
 232.349 +void append_char(MPL *mpl);
 232.350 +/* append character to current token */
 232.351 +
 232.352 +#define get_token _glp_mpl_get_token
 232.353 +void get_token(MPL *mpl);
 232.354 +/* scan next token from input text file */
 232.355 +
 232.356 +#define unget_token _glp_mpl_unget_token
 232.357 +void unget_token(MPL *mpl);
 232.358 +/* return current token back to input stream */
 232.359 +
 232.360 +#define is_keyword _glp_mpl_is_keyword
 232.361 +int is_keyword(MPL *mpl, char *keyword);
 232.362 +/* check if current token is given non-reserved keyword */
 232.363 +
 232.364 +#define is_reserved _glp_mpl_is_reserved
 232.365 +int is_reserved(MPL *mpl);
 232.366 +/* check if current token is reserved keyword */
 232.367 +
 232.368 +#define make_code _glp_mpl_make_code
 232.369 +CODE *make_code(MPL *mpl, int op, OPERANDS *arg, int type, int dim);
 232.370 +/* generate pseudo-code (basic routine) */
 232.371 +
 232.372 +#define make_unary _glp_mpl_make_unary
 232.373 +CODE *make_unary(MPL *mpl, int op, CODE *x, int type, int dim);
 232.374 +/* generate pseudo-code for unary operation */
 232.375 +
 232.376 +#define make_binary _glp_mpl_make_binary
 232.377 +CODE *make_binary(MPL *mpl, int op, CODE *x, CODE *y, int type,
 232.378 +      int dim);
 232.379 +/* generate pseudo-code for binary operation */
 232.380 +
 232.381 +#define make_ternary _glp_mpl_make_ternary
 232.382 +CODE *make_ternary(MPL *mpl, int op, CODE *x, CODE *y, CODE *z,
 232.383 +      int type, int dim);
 232.384 +/* generate pseudo-code for ternary operation */
 232.385 +
 232.386 +#define numeric_literal _glp_mpl_numeric_literal
 232.387 +CODE *numeric_literal(MPL *mpl);
 232.388 +/* parse reference to numeric literal */
 232.389 +
 232.390 +#define string_literal _glp_mpl_string_literal
 232.391 +CODE *string_literal(MPL *mpl);
 232.392 +/* parse reference to string literal */
 232.393 +
 232.394 +#define create_arg_list _glp_mpl_create_arg_list
 232.395 +ARG_LIST *create_arg_list(MPL *mpl);
 232.396 +/* create empty operands list */
 232.397 +
 232.398 +#define expand_arg_list _glp_mpl_expand_arg_list
 232.399 +ARG_LIST *expand_arg_list(MPL *mpl, ARG_LIST *list, CODE *x);
 232.400 +/* append operand to operands list */
 232.401 +
 232.402 +#define arg_list_len _glp_mpl_arg_list_len
 232.403 +int arg_list_len(MPL *mpl, ARG_LIST *list);
 232.404 +/* determine length of operands list */
 232.405 +
 232.406 +#define subscript_list _glp_mpl_subscript_list
 232.407 +ARG_LIST *subscript_list(MPL *mpl);
 232.408 +/* parse subscript list */
 232.409 +
 232.410 +#define object_reference _glp_mpl_object_reference
 232.411 +CODE *object_reference(MPL *mpl);
 232.412 +/* parse reference to named object */
 232.413 +
 232.414 +#define numeric_argument _glp_mpl_numeric_argument
 232.415 +CODE *numeric_argument(MPL *mpl, char *func);
 232.416 +/* parse argument passed to built-in function */
 232.417 +
 232.418 +#define symbolic_argument _glp_mpl_symbolic_argument
 232.419 +CODE *symbolic_argument(MPL *mpl, char *func);
 232.420 +
 232.421 +#define elemset_argument _glp_mpl_elemset_argument
 232.422 +CODE *elemset_argument(MPL *mpl, char *func);
 232.423 +
 232.424 +#define function_reference _glp_mpl_function_reference
 232.425 +CODE *function_reference(MPL *mpl);
 232.426 +/* parse reference to built-in function */
 232.427 +
 232.428 +#define create_domain _glp_mpl_create_domain
 232.429 +DOMAIN *create_domain(MPL *mpl);
 232.430 +/* create empty domain */
 232.431 +
 232.432 +#define create_block _glp_mpl_create_block
 232.433 +DOMAIN_BLOCK *create_block(MPL *mpl);
 232.434 +/* create empty domain block */
 232.435 +
 232.436 +#define append_block _glp_mpl_append_block
 232.437 +void append_block(MPL *mpl, DOMAIN *domain, DOMAIN_BLOCK *block);
 232.438 +/* append domain block to specified domain */
 232.439 +
 232.440 +#define append_slot _glp_mpl_append_slot
 232.441 +DOMAIN_SLOT *append_slot(MPL *mpl, DOMAIN_BLOCK *block, char *name,
 232.442 +      CODE *code);
 232.443 +/* create and append new slot to domain block */
 232.444 +
 232.445 +#define expression_list _glp_mpl_expression_list
 232.446 +CODE *expression_list(MPL *mpl);
 232.447 +/* parse expression list */
 232.448 +
 232.449 +#define literal_set _glp_mpl_literal_set
 232.450 +CODE *literal_set(MPL *mpl, CODE *code);
 232.451 +/* parse literal set */
 232.452 +
 232.453 +#define indexing_expression _glp_mpl_indexing_expression
 232.454 +DOMAIN *indexing_expression(MPL *mpl);
 232.455 +/* parse indexing expression */
 232.456 +
 232.457 +#define close_scope _glp_mpl_close_scope
 232.458 +void close_scope(MPL *mpl, DOMAIN *domain);
 232.459 +/* close scope of indexing expression */
 232.460 +
 232.461 +#define iterated_expression _glp_mpl_iterated_expression
 232.462 +CODE *iterated_expression(MPL *mpl);
 232.463 +/* parse iterated expression */
 232.464 +
 232.465 +#define domain_arity _glp_mpl_domain_arity
 232.466 +int domain_arity(MPL *mpl, DOMAIN *domain);
 232.467 +/* determine arity of domain */
 232.468 +
 232.469 +#define set_expression _glp_mpl_set_expression
 232.470 +CODE *set_expression(MPL *mpl);
 232.471 +/* parse set expression */
 232.472 +
 232.473 +#define branched_expression _glp_mpl_branched_expression
 232.474 +CODE *branched_expression(MPL *mpl);
 232.475 +/* parse conditional expression */
 232.476 +
 232.477 +#define primary_expression _glp_mpl_primary_expression
 232.478 +CODE *primary_expression(MPL *mpl);
 232.479 +/* parse primary expression */
 232.480 +
 232.481 +#define error_preceding _glp_mpl_error_preceding
 232.482 +void error_preceding(MPL *mpl, char *opstr);
 232.483 +/* raise error if preceding operand has wrong type */
 232.484 +
 232.485 +#define error_following _glp_mpl_error_following
 232.486 +void error_following(MPL *mpl, char *opstr);
 232.487 +/* raise error if following operand has wrong type */
 232.488 +
 232.489 +#define error_dimension _glp_mpl_error_dimension
 232.490 +void error_dimension(MPL *mpl, char *opstr, int dim1, int dim2);
 232.491 +/* raise error if operands have different dimension */
 232.492 +
 232.493 +#define expression_0 _glp_mpl_expression_0
 232.494 +CODE *expression_0(MPL *mpl);
 232.495 +/* parse expression of level 0 */
 232.496 +
 232.497 +#define expression_1 _glp_mpl_expression_1
 232.498 +CODE *expression_1(MPL *mpl);
 232.499 +/* parse expression of level 1 */
 232.500 +
 232.501 +#define expression_2 _glp_mpl_expression_2
 232.502 +CODE *expression_2(MPL *mpl);
 232.503 +/* parse expression of level 2 */
 232.504 +
 232.505 +#define expression_3 _glp_mpl_expression_3
 232.506 +CODE *expression_3(MPL *mpl);
 232.507 +/* parse expression of level 3 */
 232.508 +
 232.509 +#define expression_4 _glp_mpl_expression_4
 232.510 +CODE *expression_4(MPL *mpl);
 232.511 +/* parse expression of level 4 */
 232.512 +
 232.513 +#define expression_5 _glp_mpl_expression_5
 232.514 +CODE *expression_5(MPL *mpl);
 232.515 +/* parse expression of level 5 */
 232.516 +
 232.517 +#define expression_6 _glp_mpl_expression_6
 232.518 +CODE *expression_6(MPL *mpl);
 232.519 +/* parse expression of level 6 */
 232.520 +
 232.521 +#define expression_7 _glp_mpl_expression_7
 232.522 +CODE *expression_7(MPL *mpl);
 232.523 +/* parse expression of level 7 */
 232.524 +
 232.525 +#define expression_8 _glp_mpl_expression_8
 232.526 +CODE *expression_8(MPL *mpl);
 232.527 +/* parse expression of level 8 */
 232.528 +
 232.529 +#define expression_9 _glp_mpl_expression_9
 232.530 +CODE *expression_9(MPL *mpl);
 232.531 +/* parse expression of level 9 */
 232.532 +
 232.533 +#define expression_10 _glp_mpl_expression_10
 232.534 +CODE *expression_10(MPL *mpl);
 232.535 +/* parse expression of level 10 */
 232.536 +
 232.537 +#define expression_11 _glp_mpl_expression_11
 232.538 +CODE *expression_11(MPL *mpl);
 232.539 +/* parse expression of level 11 */
 232.540 +
 232.541 +#define expression_12 _glp_mpl_expression_12
 232.542 +CODE *expression_12(MPL *mpl);
 232.543 +/* parse expression of level 12 */
 232.544 +
 232.545 +#define expression_13 _glp_mpl_expression_13
 232.546 +CODE *expression_13(MPL *mpl);
 232.547 +/* parse expression of level 13 */
 232.548 +
 232.549 +#define set_statement _glp_mpl_set_statement
 232.550 +SET *set_statement(MPL *mpl);
 232.551 +/* parse set statement */
 232.552 +
 232.553 +#define parameter_statement _glp_mpl_parameter_statement
 232.554 +PARAMETER *parameter_statement(MPL *mpl);
 232.555 +/* parse parameter statement */
 232.556 +
 232.557 +#define variable_statement _glp_mpl_variable_statement
 232.558 +VARIABLE *variable_statement(MPL *mpl);
 232.559 +/* parse variable statement */
 232.560 +
 232.561 +#define constraint_statement _glp_mpl_constraint_statement
 232.562 +CONSTRAINT *constraint_statement(MPL *mpl);
 232.563 +/* parse constraint statement */
 232.564 +
 232.565 +#define objective_statement _glp_mpl_objective_statement
 232.566 +CONSTRAINT *objective_statement(MPL *mpl);
 232.567 +/* parse objective statement */
 232.568 +
 232.569 +#define table_statement _glp_mpl_table_statement
 232.570 +TABLE *table_statement(MPL *mpl);
 232.571 +/* parse table statement */
 232.572 +
 232.573 +#define solve_statement _glp_mpl_solve_statement
 232.574 +void *solve_statement(MPL *mpl);
 232.575 +/* parse solve statement */
 232.576 +
 232.577 +#define check_statement _glp_mpl_check_statement
 232.578 +CHECK *check_statement(MPL *mpl);
 232.579 +/* parse check statement */
 232.580 +
 232.581 +#define display_statement _glp_mpl_display_statement
 232.582 +DISPLAY *display_statement(MPL *mpl);
 232.583 +/* parse display statement */
 232.584 +
 232.585 +#define printf_statement _glp_mpl_printf_statement
 232.586 +PRINTF *printf_statement(MPL *mpl);
 232.587 +/* parse printf statement */
 232.588 +
 232.589 +#define for_statement _glp_mpl_for_statement
 232.590 +FOR *for_statement(MPL *mpl);
 232.591 +/* parse for statement */
 232.592 +
 232.593 +#define end_statement _glp_mpl_end_statement
 232.594 +void end_statement(MPL *mpl);
 232.595 +/* parse end statement */
 232.596 +
 232.597 +#define simple_statement _glp_mpl_simple_statement
 232.598 +STATEMENT *simple_statement(MPL *mpl, int spec);
 232.599 +/* parse simple statement */
 232.600 +
 232.601 +#define model_section _glp_mpl_model_section
 232.602 +void model_section(MPL *mpl);
 232.603 +/* parse model section */
 232.604 +
 232.605 +/**********************************************************************/
 232.606 +/* * *                  PROCESSING DATA SECTION                   * * */
 232.607 +/**********************************************************************/
 232.608 +
 232.609 +#if 2 + 2 == 5
 232.610 +struct SLICE /* see TUPLE */
 232.611 +{     /* component of slice; the slice itself is associated with its
 232.612 +         first component; slices are similar to n-tuples with exception
 232.613 +         that some slice components (which are indicated by asterisks)
 232.614 +         don't refer to any symbols */
 232.615 +      SYMBOL *sym;
 232.616 +      /* symbol, which this component refers to; can be NULL */
 232.617 +      SLICE *next;
 232.618 +      /* the next component of slice */
 232.619 +};
 232.620 +#endif
 232.621 +
 232.622 +#define create_slice _glp_mpl_create_slice
 232.623 +SLICE *create_slice(MPL *mpl);
 232.624 +/* create slice */
 232.625 +
 232.626 +#define expand_slice _glp_mpl_expand_slice
 232.627 +SLICE *expand_slice
 232.628 +(     MPL *mpl,
 232.629 +      SLICE *slice,           /* destroyed */
 232.630 +      SYMBOL *sym             /* destroyed */
 232.631 +);
 232.632 +/* append new component to slice */
 232.633 +
 232.634 +#define slice_dimen _glp_mpl_slice_dimen
 232.635 +int slice_dimen
 232.636 +(     MPL *mpl,
 232.637 +      SLICE *slice            /* not changed */
 232.638 +);
 232.639 +/* determine dimension of slice */
 232.640 +
 232.641 +#define slice_arity _glp_mpl_slice_arity
 232.642 +int slice_arity
 232.643 +(     MPL *mpl,
 232.644 +      SLICE *slice            /* not changed */
 232.645 +);
 232.646 +/* determine arity of slice */
 232.647 +
 232.648 +#define fake_slice _glp_mpl_fake_slice
 232.649 +SLICE *fake_slice(MPL *mpl, int dim);
 232.650 +/* create fake slice of all asterisks */
 232.651 +
 232.652 +#define delete_slice _glp_mpl_delete_slice
 232.653 +void delete_slice
 232.654 +(     MPL *mpl,
 232.655 +      SLICE *slice            /* destroyed */
 232.656 +);
 232.657 +/* delete slice */
 232.658 +
 232.659 +#define is_number _glp_mpl_is_number
 232.660 +int is_number(MPL *mpl);
 232.661 +/* check if current token is number */
 232.662 +
 232.663 +#define is_symbol _glp_mpl_is_symbol
 232.664 +int is_symbol(MPL *mpl);
 232.665 +/* check if current token is symbol */
 232.666 +
 232.667 +#define is_literal _glp_mpl_is_literal
 232.668 +int is_literal(MPL *mpl, char *literal);
 232.669 +/* check if current token is given symbolic literal */
 232.670 +
 232.671 +#define read_number _glp_mpl_read_number
 232.672 +double read_number(MPL *mpl);
 232.673 +/* read number */
 232.674 +
 232.675 +#define read_symbol _glp_mpl_read_symbol
 232.676 +SYMBOL *read_symbol(MPL *mpl);
 232.677 +/* read symbol */
 232.678 +
 232.679 +#define read_slice _glp_mpl_read_slice
 232.680 +SLICE *read_slice
 232.681 +(     MPL *mpl,
 232.682 +      char *name,             /* not changed */
 232.683 +      int dim
 232.684 +);
 232.685 +/* read slice */
 232.686 +
 232.687 +#define select_set _glp_mpl_select_set
 232.688 +SET *select_set
 232.689 +(     MPL *mpl,
 232.690 +      char *name              /* not changed */
 232.691 +);
 232.692 +/* select set to saturate it with elemental sets */
 232.693 +
 232.694 +#define simple_format _glp_mpl_simple_format
 232.695 +void simple_format
 232.696 +(     MPL *mpl,
 232.697 +      SET *set,               /* not changed */
 232.698 +      MEMBER *memb,           /* modified */
 232.699 +      SLICE *slice            /* not changed */
 232.700 +);
 232.701 +/* read set data block in simple format */
 232.702 +
 232.703 +#define matrix_format _glp_mpl_matrix_format
 232.704 +void matrix_format
 232.705 +(     MPL *mpl,
 232.706 +      SET *set,               /* not changed */
 232.707 +      MEMBER *memb,           /* modified */
 232.708 +      SLICE *slice,           /* not changed */
 232.709 +      int tr
 232.710 +);
 232.711 +/* read set data block in matrix format */
 232.712 +
 232.713 +#define set_data _glp_mpl_set_data
 232.714 +void set_data(MPL *mpl);
 232.715 +/* read set data */
 232.716 +
 232.717 +#define select_parameter _glp_mpl_select_parameter
 232.718 +PARAMETER *select_parameter
 232.719 +(     MPL *mpl,
 232.720 +      char *name              /* not changed */
 232.721 +);
 232.722 +/* select parameter to saturate it with data */
 232.723 +
 232.724 +#define set_default _glp_mpl_set_default
 232.725 +void set_default
 232.726 +(     MPL *mpl,
 232.727 +      PARAMETER *par,         /* not changed */
 232.728 +      SYMBOL *altval          /* destroyed */
 232.729 +);
 232.730 +/* set default parameter value */
 232.731 +
 232.732 +#define read_value _glp_mpl_read_value
 232.733 +MEMBER *read_value
 232.734 +(     MPL *mpl,
 232.735 +      PARAMETER *par,         /* not changed */
 232.736 +      TUPLE *tuple            /* destroyed */
 232.737 +);
 232.738 +/* read value and assign it to parameter member */
 232.739 +
 232.740 +#define plain_format _glp_mpl_plain_format
 232.741 +void plain_format
 232.742 +(     MPL *mpl,
 232.743 +      PARAMETER *par,         /* not changed */
 232.744 +      SLICE *slice            /* not changed */
 232.745 +);
 232.746 +/* read parameter data block in plain format */
 232.747 +
 232.748 +#define tabular_format _glp_mpl_tabular_format
 232.749 +void tabular_format
 232.750 +(     MPL *mpl,
 232.751 +      PARAMETER *par,         /* not changed */
 232.752 +      SLICE *slice,           /* not changed */
 232.753 +      int tr
 232.754 +);
 232.755 +/* read parameter data block in tabular format */
 232.756 +
 232.757 +#define tabbing_format _glp_mpl_tabbing_format
 232.758 +void tabbing_format
 232.759 +(     MPL *mpl,
 232.760 +      SYMBOL *altval          /* not changed */
 232.761 +);
 232.762 +/* read parameter data block in tabbing format */
 232.763 +
 232.764 +#define parameter_data _glp_mpl_parameter_data
 232.765 +void parameter_data(MPL *mpl);
 232.766 +/* read parameter data */
 232.767 +
 232.768 +#define data_section _glp_mpl_data_section
 232.769 +void data_section(MPL *mpl);
 232.770 +/* read data section */
 232.771 +
 232.772 +/**********************************************************************/
 232.773 +/* * *                   FLOATING-POINT NUMBERS                   * * */
 232.774 +/**********************************************************************/
 232.775 +
 232.776 +#define fp_add _glp_mpl_fp_add
 232.777 +double fp_add(MPL *mpl, double x, double y);
 232.778 +/* floating-point addition */
 232.779 +
 232.780 +#define fp_sub _glp_mpl_fp_sub
 232.781 +double fp_sub(MPL *mpl, double x, double y);
 232.782 +/* floating-point subtraction */
 232.783 +
 232.784 +#define fp_less _glp_mpl_fp_less
 232.785 +double fp_less(MPL *mpl, double x, double y);
 232.786 +/* floating-point non-negative subtraction */
 232.787 +
 232.788 +#define fp_mul _glp_mpl_fp_mul
 232.789 +double fp_mul(MPL *mpl, double x, double y);
 232.790 +/* floating-point multiplication */
 232.791 +
 232.792 +#define fp_div _glp_mpl_fp_div
 232.793 +double fp_div(MPL *mpl, double x, double y);
 232.794 +/* floating-point division */
 232.795 +
 232.796 +#define fp_idiv _glp_mpl_fp_idiv
 232.797 +double fp_idiv(MPL *mpl, double x, double y);
 232.798 +/* floating-point quotient of exact division */
 232.799 +
 232.800 +#define fp_mod _glp_mpl_fp_mod
 232.801 +double fp_mod(MPL *mpl, double x, double y);
 232.802 +/* floating-point remainder of exact division */
 232.803 +
 232.804 +#define fp_power _glp_mpl_fp_power
 232.805 +double fp_power(MPL *mpl, double x, double y);
 232.806 +/* floating-point exponentiation (raise to power) */
 232.807 +
 232.808 +#define fp_exp _glp_mpl_fp_exp
 232.809 +double fp_exp(MPL *mpl, double x);
 232.810 +/* floating-point base-e exponential */
 232.811 +
 232.812 +#define fp_log _glp_mpl_fp_log
 232.813 +double fp_log(MPL *mpl, double x);
 232.814 +/* floating-point natural logarithm */
 232.815 +
 232.816 +#define fp_log10 _glp_mpl_fp_log10
 232.817 +double fp_log10(MPL *mpl, double x);
 232.818 +/* floating-point common (decimal) logarithm */
 232.819 +
 232.820 +#define fp_sqrt _glp_mpl_fp_sqrt
 232.821 +double fp_sqrt(MPL *mpl, double x);
 232.822 +/* floating-point square root */
 232.823 +
 232.824 +#define fp_sin _glp_mpl_fp_sin
 232.825 +double fp_sin(MPL *mpl, double x);
 232.826 +/* floating-point trigonometric sine */
 232.827 +
 232.828 +#define fp_cos _glp_mpl_fp_cos
 232.829 +double fp_cos(MPL *mpl, double x);
 232.830 +/* floating-point trigonometric cosine */
 232.831 +
 232.832 +#define fp_atan _glp_mpl_fp_atan
 232.833 +double fp_atan(MPL *mpl, double x);
 232.834 +/* floating-point trigonometric arctangent */
 232.835 +
 232.836 +#define fp_atan2 _glp_mpl_fp_atan2
 232.837 +double fp_atan2(MPL *mpl, double y, double x);
 232.838 +/* floating-point trigonometric arctangent */
 232.839 +
 232.840 +#define fp_round _glp_mpl_fp_round
 232.841 +double fp_round(MPL *mpl, double x, double n);
 232.842 +/* round floating-point value to n fractional digits */
 232.843 +
 232.844 +#define fp_trunc _glp_mpl_fp_trunc
 232.845 +double fp_trunc(MPL *mpl, double x, double n);
 232.846 +/* truncate floating-point value to n fractional digits */
 232.847 +
 232.848 +/**********************************************************************/
 232.849 +/* * *              PSEUDO-RANDOM NUMBER GENERATORS               * * */
 232.850 +/**********************************************************************/
 232.851 +
 232.852 +#define fp_irand224 _glp_mpl_fp_irand224
 232.853 +double fp_irand224(MPL *mpl);
 232.854 +/* pseudo-random integer in the range [0, 2^24) */
 232.855 +
 232.856 +#define fp_uniform01 _glp_mpl_fp_uniform01
 232.857 +double fp_uniform01(MPL *mpl);
 232.858 +/* pseudo-random number in the range [0, 1) */
 232.859 +
 232.860 +#define fp_uniform _glp_mpl_uniform
 232.861 +double fp_uniform(MPL *mpl, double a, double b);
 232.862 +/* pseudo-random number in the range [a, b) */
 232.863 +
 232.864 +#define fp_normal01 _glp_mpl_fp_normal01
 232.865 +double fp_normal01(MPL *mpl);
 232.866 +/* Gaussian random variate with mu = 0 and sigma = 1 */
 232.867 +
 232.868 +#define fp_normal _glp_mpl_fp_normal
 232.869 +double fp_normal(MPL *mpl, double mu, double sigma);
 232.870 +/* Gaussian random variate with specified mu and sigma */
 232.871 +
 232.872 +/**********************************************************************/
 232.873 +/* * *                         DATE/TIME                          * * */
 232.874 +/**********************************************************************/
 232.875 +
 232.876 +#define fn_gmtime _glp_mpl_fn_gmtime
 232.877 +double fn_gmtime(MPL *mpl);
 232.878 +/* obtain the current calendar time (UTC) */
 232.879 +
 232.880 +#define fn_str2time _glp_mpl_fn_str2time
 232.881 +double fn_str2time(MPL *mpl, const char *str, const char *fmt);
 232.882 +/* convert character string to the calendar time */
 232.883 +
 232.884 +#define fn_time2str _glp_mpl_fn_time2str
 232.885 +void fn_time2str(MPL *mpl, char *str, double t, const char *fmt);
 232.886 +/* convert the calendar time to character string */
 232.887 +
 232.888 +/**********************************************************************/
 232.889 +/* * *                     CHARACTER STRINGS                      * * */
 232.890 +/**********************************************************************/
 232.891 +
 232.892 +#define create_string _glp_mpl_create_string
 232.893 +STRING *create_string
 232.894 +(     MPL *mpl,
 232.895 +      char buf[MAX_LENGTH+1]  /* not changed */
 232.896 +);
 232.897 +/* create character string */
 232.898 +
 232.899 +#define copy_string _glp_mpl_copy_string
 232.900 +STRING *copy_string
 232.901 +(     MPL *mpl,
 232.902 +      STRING *str             /* not changed */
 232.903 +);
 232.904 +/* make copy of character string */
 232.905 +
 232.906 +#define compare_strings _glp_mpl_compare_strings
 232.907 +int compare_strings
 232.908 +(     MPL *mpl,
 232.909 +      STRING *str1,           /* not changed */
 232.910 +      STRING *str2            /* not changed */
 232.911 +);
 232.912 +/* compare one character string with another */
 232.913 +
 232.914 +#define fetch_string _glp_mpl_fetch_string
 232.915 +char *fetch_string
 232.916 +(     MPL *mpl,
 232.917 +      STRING *str,            /* not changed */
 232.918 +      char buf[MAX_LENGTH+1]  /* modified */
 232.919 +);
 232.920 +/* extract content of character string */
 232.921 +
 232.922 +#define delete_string _glp_mpl_delete_string
 232.923 +void delete_string
 232.924 +(     MPL *mpl,
 232.925 +      STRING *str             /* destroyed */
 232.926 +);
 232.927 +/* delete character string */
 232.928 +
 232.929 +/**********************************************************************/
 232.930 +/* * *                          SYMBOLS                           * * */
 232.931 +/**********************************************************************/
 232.932 +
 232.933 +struct SYMBOL
 232.934 +{     /* symbol (numeric or abstract quantity) */
 232.935 +      double num;
 232.936 +      /* numeric value of symbol (used only if str == NULL) */
 232.937 +      STRING *str;
 232.938 +      /* abstract value of symbol (used only if str != NULL) */
 232.939 +};
 232.940 +
 232.941 +#define create_symbol_num _glp_mpl_create_symbol_num
 232.942 +SYMBOL *create_symbol_num(MPL *mpl, double num);
 232.943 +/* create symbol of numeric type */
 232.944 +
 232.945 +#define create_symbol_str _glp_mpl_create_symbol_str
 232.946 +SYMBOL *create_symbol_str
 232.947 +(     MPL *mpl,
 232.948 +      STRING *str             /* destroyed */
 232.949 +);
 232.950 +/* create symbol of abstract type */
 232.951 +
 232.952 +#define copy_symbol _glp_mpl_copy_symbol
 232.953 +SYMBOL *copy_symbol
 232.954 +(     MPL *mpl,
 232.955 +      SYMBOL *sym             /* not changed */
 232.956 +);
 232.957 +/* make copy of symbol */
 232.958 +
 232.959 +#define compare_symbols _glp_mpl_compare_symbols
 232.960 +int compare_symbols
 232.961 +(     MPL *mpl,
 232.962 +      SYMBOL *sym1,           /* not changed */
 232.963 +      SYMBOL *sym2            /* not changed */
 232.964 +);
 232.965 +/* compare one symbol with another */
 232.966 +
 232.967 +#define delete_symbol _glp_mpl_delete_symbol
 232.968 +void delete_symbol
 232.969 +(     MPL *mpl,
 232.970 +      SYMBOL *sym             /* destroyed */
 232.971 +);
 232.972 +/* delete symbol */
 232.973 +
 232.974 +#define format_symbol _glp_mpl_format_symbol
 232.975 +char *format_symbol
 232.976 +(     MPL *mpl,
 232.977 +      SYMBOL *sym             /* not changed */
 232.978 +);
 232.979 +/* format symbol for displaying or printing */
 232.980 +
 232.981 +#define concat_symbols _glp_mpl_concat_symbols
 232.982 +SYMBOL *concat_symbols
 232.983 +(     MPL *mpl,
 232.984 +      SYMBOL *sym1,           /* destroyed */
 232.985 +      SYMBOL *sym2            /* destroyed */
 232.986 +);
 232.987 +/* concatenate one symbol with another */
 232.988 +
 232.989 +/**********************************************************************/
 232.990 +/* * *                          N-TUPLES                          * * */
 232.991 +/**********************************************************************/
 232.992 +
 232.993 +struct TUPLE
 232.994 +{     /* component of n-tuple; the n-tuple itself is associated with
 232.995 +         its first component; (note that 0-tuple has no components) */
 232.996 +      SYMBOL *sym;
 232.997 +      /* symbol, which the component refers to; cannot be NULL */
 232.998 +      TUPLE *next;
 232.999 +      /* the next component of n-tuple */
232.1000 +};
232.1001 +
232.1002 +#define create_tuple _glp_mpl_create_tuple
232.1003 +TUPLE *create_tuple(MPL *mpl);
232.1004 +/* create n-tuple */
232.1005 +
232.1006 +#define expand_tuple _glp_mpl_expand_tuple
232.1007 +TUPLE *expand_tuple
232.1008 +(     MPL *mpl,
232.1009 +      TUPLE *tuple,           /* destroyed */
232.1010 +      SYMBOL *sym             /* destroyed */
232.1011 +);
232.1012 +/* append symbol to n-tuple */
232.1013 +
232.1014 +#define tuple_dimen _glp_mpl_tuple_dimen
232.1015 +int tuple_dimen
232.1016 +(     MPL *mpl,
232.1017 +      TUPLE *tuple            /* not changed */
232.1018 +);
232.1019 +/* determine dimension of n-tuple */
232.1020 +
232.1021 +#define copy_tuple _glp_mpl_copy_tuple
232.1022 +TUPLE *copy_tuple
232.1023 +(     MPL *mpl,
232.1024 +      TUPLE *tuple            /* not changed */
232.1025 +);
232.1026 +/* make copy of n-tuple */
232.1027 +
232.1028 +#define compare_tuples _glp_mpl_compare_tuples
232.1029 +int compare_tuples
232.1030 +(     MPL *mpl,
232.1031 +      TUPLE *tuple1,          /* not changed */
232.1032 +      TUPLE *tuple2           /* not changed */
232.1033 +);
232.1034 +/* compare one n-tuple with another */
232.1035 +
232.1036 +#define build_subtuple _glp_mpl_build_subtuple
232.1037 +TUPLE *build_subtuple
232.1038 +(     MPL *mpl,
232.1039 +      TUPLE *tuple,           /* not changed */
232.1040 +      int dim
232.1041 +);
232.1042 +/* build subtuple of given n-tuple */
232.1043 +
232.1044 +#define delete_tuple _glp_mpl_delete_tuple
232.1045 +void delete_tuple
232.1046 +(     MPL *mpl,
232.1047 +      TUPLE *tuple            /* destroyed */
232.1048 +);
232.1049 +/* delete n-tuple */
232.1050 +
232.1051 +#define format_tuple _glp_mpl_format_tuple
232.1052 +char *format_tuple
232.1053 +(     MPL *mpl,
232.1054 +      int c,
232.1055 +      TUPLE *tuple            /* not changed */
232.1056 +);
232.1057 +/* format n-tuple for displaying or printing */
232.1058 +
232.1059 +/**********************************************************************/
232.1060 +/* * *                       ELEMENTAL SETS                       * * */
232.1061 +/**********************************************************************/
232.1062 +
232.1063 +#if 2 + 2 == 5
232.1064 +struct ELEMSET /* see ARRAY */
232.1065 +{     /* elemental set of n-tuples; formally it is a "value" assigned
232.1066 +         to members of model sets (like numbers and symbols, which are
232.1067 +         values assigned to members of model parameters); note that a
232.1068 +         simple model set is not an elemental set, it is 0-dimensional
232.1069 +         array, the only member of which (if it exists) is assigned an
232.1070 +         elemental set */
232.1071 +#endif
232.1072 +
232.1073 +#define create_elemset _glp_mpl_create_elemset
232.1074 +ELEMSET *create_elemset(MPL *mpl, int dim);
232.1075 +/* create elemental set */
232.1076 +
232.1077 +#define find_tuple _glp_mpl_find_tuple
232.1078 +MEMBER *find_tuple
232.1079 +(     MPL *mpl,
232.1080 +      ELEMSET *set,           /* not changed */
232.1081 +      TUPLE *tuple            /* not changed */
232.1082 +);
232.1083 +/* check if elemental set contains given n-tuple */
232.1084 +
232.1085 +#define add_tuple _glp_mpl_add_tuple
232.1086 +MEMBER *add_tuple
232.1087 +(     MPL *mpl,
232.1088 +      ELEMSET *set,           /* modified */
232.1089 +      TUPLE *tuple            /* destroyed */
232.1090 +);
232.1091 +/* add new n-tuple to elemental set */
232.1092 +
232.1093 +#define check_then_add _glp_mpl_check_then_add
232.1094 +MEMBER *check_then_add
232.1095 +(     MPL *mpl,
232.1096 +      ELEMSET *set,           /* modified */
232.1097 +      TUPLE *tuple            /* destroyed */
232.1098 +);
232.1099 +/* check and add new n-tuple to elemental set */
232.1100 +
232.1101 +#define copy_elemset _glp_mpl_copy_elemset
232.1102 +ELEMSET *copy_elemset
232.1103 +(     MPL *mpl,
232.1104 +      ELEMSET *set            /* not changed */
232.1105 +);
232.1106 +/* make copy of elemental set */
232.1107 +
232.1108 +#define delete_elemset _glp_mpl_delete_elemset
232.1109 +void delete_elemset
232.1110 +(     MPL *mpl,
232.1111 +      ELEMSET *set            /* destroyed */
232.1112 +);
232.1113 +/* delete elemental set */
232.1114 +
232.1115 +#define arelset_size _glp_mpl_arelset_size
232.1116 +int arelset_size(MPL *mpl, double t0, double tf, double dt);
232.1117 +/* compute size of "arithmetic" elemental set */
232.1118 +
232.1119 +#define arelset_member _glp_mpl_arelset_member
232.1120 +double arelset_member(MPL *mpl, double t0, double tf, double dt, int j);
232.1121 +/* compute member of "arithmetic" elemental set */
232.1122 +
232.1123 +#define create_arelset _glp_mpl_create_arelset
232.1124 +ELEMSET *create_arelset(MPL *mpl, double t0, double tf, double dt);
232.1125 +/* create "arithmetic" elemental set */
232.1126 +
232.1127 +#define set_union _glp_mpl_set_union
232.1128 +ELEMSET *set_union
232.1129 +(     MPL *mpl,
232.1130 +      ELEMSET *X,             /* destroyed */
232.1131 +      ELEMSET *Y              /* destroyed */
232.1132 +);
232.1133 +/* union of two elemental sets */
232.1134 +
232.1135 +#define set_diff _glp_mpl_set_diff
232.1136 +ELEMSET *set_diff
232.1137 +(     MPL *mpl,
232.1138 +      ELEMSET *X,             /* destroyed */
232.1139 +      ELEMSET *Y              /* destroyed */
232.1140 +);
232.1141 +/* difference between two elemental sets */
232.1142 +
232.1143 +#define set_symdiff _glp_mpl_set_symdiff
232.1144 +ELEMSET *set_symdiff
232.1145 +(     MPL *mpl,
232.1146 +      ELEMSET *X,             /* destroyed */
232.1147 +      ELEMSET *Y              /* destroyed */
232.1148 +);
232.1149 +/* symmetric difference between two elemental sets */
232.1150 +
232.1151 +#define set_inter _glp_mpl_set_inter
232.1152 +ELEMSET *set_inter
232.1153 +(     MPL *mpl,
232.1154 +      ELEMSET *X,             /* destroyed */
232.1155 +      ELEMSET *Y              /* destroyed */
232.1156 +);
232.1157 +/* intersection of two elemental sets */
232.1158 +
232.1159 +#define set_cross _glp_mpl_set_cross
232.1160 +ELEMSET *set_cross
232.1161 +(     MPL *mpl,
232.1162 +      ELEMSET *X,             /* destroyed */
232.1163 +      ELEMSET *Y              /* destroyed */
232.1164 +);
232.1165 +/* cross (Cartesian) product of two elemental sets */
232.1166 +
232.1167 +/**********************************************************************/
232.1168 +/* * *                    ELEMENTAL VARIABLES                     * * */
232.1169 +/**********************************************************************/
232.1170 +
232.1171 +struct ELEMVAR
232.1172 +{     /* elemental variable; formally it is a "value" assigned to
232.1173 +         members of model variables (like numbers and symbols, which
232.1174 +         are values assigned to members of model parameters) */
232.1175 +      int j;
232.1176 +      /* LP column number assigned to this elemental variable */
232.1177 +      VARIABLE *var;
232.1178 +      /* model variable, which contains this elemental variable */
232.1179 +      MEMBER *memb;
232.1180 +      /* array member, which is assigned this elemental variable */
232.1181 +      double lbnd;
232.1182 +      /* lower bound */
232.1183 +      double ubnd;
232.1184 +      /* upper bound */
232.1185 +      double temp;
232.1186 +      /* working quantity used in operations on linear forms; normally
232.1187 +         it contains floating-point zero */
232.1188 +#if 1 /* 15/V-2010 */
232.1189 +      int stat;
232.1190 +      double prim, dual;
232.1191 +      /* solution components provided by the solver */
232.1192 +#endif
232.1193 +};
232.1194 +
232.1195 +/**********************************************************************/
232.1196 +/* * *                        LINEAR FORMS                        * * */
232.1197 +/**********************************************************************/
232.1198 +
232.1199 +struct FORMULA
232.1200 +{     /* term of linear form c * x, where c is a coefficient, x is an
232.1201 +         elemental variable; the linear form itself is the sum of terms
232.1202 +         and is associated with its first term; (note that the linear
232.1203 +         form may be empty that means the sum is equal to zero) */
232.1204 +      double coef;
232.1205 +      /* coefficient at elemental variable or constant term */
232.1206 +      ELEMVAR *var;
232.1207 +      /* reference to elemental variable; NULL means constant term */
232.1208 +      FORMULA *next;
232.1209 +      /* the next term of linear form */
232.1210 +};
232.1211 +
232.1212 +#define constant_term _glp_mpl_constant_term
232.1213 +FORMULA *constant_term(MPL *mpl, double coef);
232.1214 +/* create constant term */
232.1215 +
232.1216 +#define single_variable _glp_mpl_single_variable
232.1217 +FORMULA *single_variable
232.1218 +(     MPL *mpl,
232.1219 +      ELEMVAR *var            /* referenced */
232.1220 +);
232.1221 +/* create single variable */
232.1222 +
232.1223 +#define copy_formula _glp_mpl_copy_formula
232.1224 +FORMULA *copy_formula
232.1225 +(     MPL *mpl,
232.1226 +      FORMULA *form           /* not changed */
232.1227 +);
232.1228 +/* make copy of linear form */
232.1229 +
232.1230 +#define delete_formula _glp_mpl_delete_formula
232.1231 +void delete_formula
232.1232 +(     MPL *mpl,
232.1233 +      FORMULA *form           /* destroyed */
232.1234 +);
232.1235 +/* delete linear form */
232.1236 +
232.1237 +#define linear_comb _glp_mpl_linear_comb
232.1238 +FORMULA *linear_comb
232.1239 +(     MPL *mpl,
232.1240 +      double a, FORMULA *fx,  /* destroyed */
232.1241 +      double b, FORMULA *fy   /* destroyed */
232.1242 +);
232.1243 +/* linear combination of two linear forms */
232.1244 +
232.1245 +#define remove_constant _glp_mpl_remove_constant
232.1246 +FORMULA *remove_constant
232.1247 +(     MPL *mpl,
232.1248 +      FORMULA *form,          /* destroyed */
232.1249 +      double *coef            /* modified */
232.1250 +);
232.1251 +/* remove constant term from linear form */
232.1252 +
232.1253 +#define reduce_terms _glp_mpl_reduce_terms
232.1254 +FORMULA *reduce_terms
232.1255 +(     MPL *mpl,
232.1256 +      FORMULA *form           /* destroyed */
232.1257 +);
232.1258 +/* reduce identical terms in linear form */
232.1259 +
232.1260 +/**********************************************************************/
232.1261 +/* * *                   ELEMENTAL CONSTRAINTS                    * * */
232.1262 +/**********************************************************************/
232.1263 +
232.1264 +struct ELEMCON
232.1265 +{     /* elemental constraint; formally it is a "value" assigned to
232.1266 +         members of model constraints (like numbers or symbols, which
232.1267 +         are values assigned to members of model parameters) */
232.1268 +      int i;
232.1269 +      /* LP row number assigned to this elemental constraint */
232.1270 +      CONSTRAINT *con;
232.1271 +      /* model constraint, which contains this elemental constraint */
232.1272 +      MEMBER *memb;
232.1273 +      /* array member, which is assigned this elemental constraint */
232.1274 +      FORMULA *form;
232.1275 +      /* linear form */
232.1276 +      double lbnd;
232.1277 +      /* lower bound */
232.1278 +      double ubnd;
232.1279 +      /* upper bound */
232.1280 +#if 1 /* 15/V-2010 */
232.1281 +      int stat;
232.1282 +      double prim, dual;
232.1283 +      /* solution components provided by the solver */
232.1284 +#endif
232.1285 +};
232.1286 +
232.1287 +/**********************************************************************/
232.1288 +/* * *                       GENERIC VALUES                       * * */
232.1289 +/**********************************************************************/
232.1290 +
232.1291 +union VALUE
232.1292 +{     /* generic value, which can be assigned to object member or be a
232.1293 +         result of evaluation of expression */
232.1294 +      /* indicator that specifies the particular type of generic value
232.1295 +         is stored in the corresponding array or pseudo-code descriptor
232.1296 +         and can be one of the following:
232.1297 +         A_NONE     - no value
232.1298 +         A_NUMERIC  - floating-point number
232.1299 +         A_SYMBOLIC - symbol
232.1300 +         A_LOGICAL  - logical value
232.1301 +         A_TUPLE    - n-tuple
232.1302 +         A_ELEMSET  - elemental set
232.1303 +         A_ELEMVAR  - elemental variable
232.1304 +         A_FORMULA  - linear form
232.1305 +         A_ELEMCON  - elemental constraint */
232.1306 +      void *none;    /* null */
232.1307 +      double num;    /* value */
232.1308 +      SYMBOL *sym;   /* value */
232.1309 +      int bit;       /* value */
232.1310 +      TUPLE *tuple;  /* value */
232.1311 +      ELEMSET *set;  /* value */
232.1312 +      ELEMVAR *var;  /* reference */
232.1313 +      FORMULA *form; /* value */
232.1314 +      ELEMCON *con;  /* reference */
232.1315 +};
232.1316 +
232.1317 +#define delete_value _glp_mpl_delete_value
232.1318 +void delete_value
232.1319 +(     MPL *mpl,
232.1320 +      int type,
232.1321 +      VALUE *value            /* content destroyed */
232.1322 +);
232.1323 +/* delete generic value */
232.1324 +
232.1325 +/**********************************************************************/
232.1326 +/* * *                SYMBOLICALLY INDEXED ARRAYS                 * * */
232.1327 +/**********************************************************************/
232.1328 +
232.1329 +struct ARRAY
232.1330 +{     /* multi-dimensional array, a set of members indexed over simple
232.1331 +         or compound sets of symbols; arrays are used to represent the
232.1332 +         contents of model objects (i.e. sets, parameters, variables,
232.1333 +         constraints, and objectives); arrays also are used as "values"
232.1334 +         that are assigned to members of set objects, in which case the
232.1335 +         array itself represents an elemental set */
232.1336 +      int type;
232.1337 +      /* type of generic values assigned to the array members:
232.1338 +         A_NONE     - none (members have no assigned values)
232.1339 +         A_NUMERIC  - floating-point numbers
232.1340 +         A_SYMBOLIC - symbols
232.1341 +         A_ELEMSET  - elemental sets
232.1342 +         A_ELEMVAR  - elemental variables
232.1343 +         A_ELEMCON  - elemental constraints */
232.1344 +      int dim;
232.1345 +      /* dimension of the array that determines number of components in
232.1346 +         n-tuples for all members of the array, dim >= 0; dim = 0 means
232.1347 +         the array is 0-dimensional */
232.1348 +      int size;
232.1349 +      /* size of the array, i.e. number of its members */
232.1350 +      MEMBER *head;
232.1351 +      /* the first array member; NULL means the array is empty */
232.1352 +      MEMBER *tail;
232.1353 +      /* the last array member; NULL means the array is empty */
232.1354 +      AVL *tree;
232.1355 +      /* the search tree intended to find array members for logarithmic
232.1356 +         time; NULL means the search tree doesn't exist */
232.1357 +      ARRAY *prev;
232.1358 +      /* the previous array in the translator database */
232.1359 +      ARRAY *next;
232.1360 +      /* the next array in the translator database */
232.1361 +};
232.1362 +
232.1363 +struct MEMBER
232.1364 +{     /* array member */
232.1365 +      TUPLE *tuple;
232.1366 +      /* n-tuple, which identifies the member; number of its components
232.1367 +         is the same for all members within the array and determined by
232.1368 +         the array dimension; duplicate members are not allowed */
232.1369 +      MEMBER *next;
232.1370 +      /* the next array member */
232.1371 +      VALUE value;
232.1372 +      /* generic value assigned to the member */
232.1373 +};
232.1374 +
232.1375 +#define create_array _glp_mpl_create_array
232.1376 +ARRAY *create_array(MPL *mpl, int type, int dim);
232.1377 +/* create array */
232.1378 +
232.1379 +#define find_member _glp_mpl_find_member
232.1380 +MEMBER *find_member
232.1381 +(     MPL *mpl,
232.1382 +      ARRAY *array,           /* not changed */
232.1383 +      TUPLE *tuple            /* not changed */
232.1384 +);
232.1385 +/* find array member with given n-tuple */
232.1386 +
232.1387 +#define add_member _glp_mpl_add_member
232.1388 +MEMBER *add_member
232.1389 +(     MPL *mpl,
232.1390 +      ARRAY *array,           /* modified */
232.1391 +      TUPLE *tuple            /* destroyed */
232.1392 +);
232.1393 +/* add new member to array */
232.1394 +
232.1395 +#define delete_array _glp_mpl_delete_array
232.1396 +void delete_array
232.1397 +(     MPL *mpl,
232.1398 +      ARRAY *array            /* destroyed */
232.1399 +);
232.1400 +/* delete array */
232.1401 +
232.1402 +/**********************************************************************/
232.1403 +/* * *                 DOMAINS AND DUMMY INDICES                  * * */
232.1404 +/**********************************************************************/
232.1405 +
232.1406 +struct DOMAIN
232.1407 +{     /* domain (a simple or compound set); syntactically domain looks
232.1408 +         like '{ i in I, (j,k) in S, t in T : <predicate> }'; domains
232.1409 +         are used to define sets, over which model objects are indexed,
232.1410 +         and also as constituents of iterated operators */
232.1411 +      DOMAIN_BLOCK *list;
232.1412 +      /* linked list of domain blocks (in the example above such blocks
232.1413 +         are 'i in I', '(j,k) in S', and 't in T'); this list cannot be
232.1414 +         empty */
232.1415 +      CODE *code;
232.1416 +      /* pseudo-code for computing the logical predicate, which follows
232.1417 +         the colon; NULL means no predicate is specified */
232.1418 +};
232.1419 +
232.1420 +struct DOMAIN_BLOCK
232.1421 +{     /* domain block; syntactically domain blocks look like 'i in I',
232.1422 +         '(j,k) in S', and 't in T' in the example above (in the sequel
232.1423 +         sets like I, S, and T are called basic sets) */
232.1424 +      DOMAIN_SLOT *list;
232.1425 +      /* linked list of domain slots (i.e. indexing positions); number
232.1426 +         of slots in this list is the same as dimension of n-tuples in
232.1427 +         the basic set; this list cannot be empty */
232.1428 +      CODE *code;
232.1429 +      /* pseudo-code for computing basic set; cannot be NULL */
232.1430 +      TUPLE *backup;
232.1431 +      /* if this n-tuple is not empty, current values of dummy indices
232.1432 +         in the domain block are the same as components of this n-tuple
232.1433 +         (note that this n-tuple may have larger dimension than number
232.1434 +         of dummy indices in this block, in which case extra components
232.1435 +         are ignored); this n-tuple is used to restore former values of
232.1436 +         dummy indices, if they were changed due to recursive calls to
232.1437 +         the domain block */
232.1438 +      DOMAIN_BLOCK *next;
232.1439 +      /* the next block in the same domain */
232.1440 +};
232.1441 +
232.1442 +struct DOMAIN_SLOT
232.1443 +{     /* domain slot; it specifies an individual indexing position and
232.1444 +         defines the corresponding dummy index */
232.1445 +      char *name;
232.1446 +      /* symbolic name of the dummy index; null pointer means the dummy
232.1447 +         index is not explicitly specified */
232.1448 +      CODE *code;
232.1449 +      /* pseudo-code for computing symbolic value, at which the dummy
232.1450 +         index is bound; NULL means the dummy index is free within the
232.1451 +         domain scope */
232.1452 +      SYMBOL *value;
232.1453 +      /* current value assigned to the dummy index; NULL means no value
232.1454 +         is assigned at the moment */
232.1455 +      CODE *list;
232.1456 +      /* linked list of pseudo-codes with operation O_INDEX referring
232.1457 +         to this slot; this linked list is used to invalidate resultant
232.1458 +         values of the operation, which depend on this dummy index */
232.1459 +      DOMAIN_SLOT *next;
232.1460 +      /* the next slot in the same domain block */
232.1461 +};
232.1462 +
232.1463 +#define assign_dummy_index _glp_mpl_assign_dummy_index
232.1464 +void assign_dummy_index
232.1465 +(     MPL *mpl,
232.1466 +      DOMAIN_SLOT *slot,      /* modified */
232.1467 +      SYMBOL *value           /* not changed */
232.1468 +);
232.1469 +/* assign new value to dummy index */
232.1470 +
232.1471 +#define update_dummy_indices _glp_mpl_update_dummy_indices
232.1472 +void update_dummy_indices
232.1473 +(     MPL *mpl,
232.1474 +      DOMAIN_BLOCK *block     /* not changed */
232.1475 +);
232.1476 +/* update current values of dummy indices */
232.1477 +
232.1478 +#define enter_domain_block _glp_mpl_enter_domain_block
232.1479 +int enter_domain_block
232.1480 +(     MPL *mpl,
232.1481 +      DOMAIN_BLOCK *block,    /* not changed */
232.1482 +      TUPLE *tuple,           /* not changed */
232.1483 +      void *info, void (*func)(MPL *mpl, void *info)
232.1484 +);
232.1485 +/* enter domain block */
232.1486 +
232.1487 +#define eval_within_domain _glp_mpl_eval_within_domain
232.1488 +int eval_within_domain
232.1489 +(     MPL *mpl,
232.1490 +      DOMAIN *domain,         /* not changed */
232.1491 +      TUPLE *tuple,           /* not changed */
232.1492 +      void *info, void (*func)(MPL *mpl, void *info)
232.1493 +);
232.1494 +/* perform evaluation within domain scope */
232.1495 +
232.1496 +#define loop_within_domain _glp_mpl_loop_within_domain
232.1497 +void loop_within_domain
232.1498 +(     MPL *mpl,
232.1499 +      DOMAIN *domain,         /* not changed */
232.1500 +      void *info, int (*func)(MPL *mpl, void *info)
232.1501 +);
232.1502 +/* perform iterations within domain scope */
232.1503 +
232.1504 +#define out_of_domain _glp_mpl_out_of_domain
232.1505 +void out_of_domain
232.1506 +(     MPL *mpl,
232.1507 +      char *name,             /* not changed */
232.1508 +      TUPLE *tuple            /* not changed */
232.1509 +);
232.1510 +/* raise domain exception */
232.1511 +
232.1512 +#define get_domain_tuple _glp_mpl_get_domain_tuple
232.1513 +TUPLE *get_domain_tuple
232.1514 +(     MPL *mpl,
232.1515 +      DOMAIN *domain          /* not changed */
232.1516 +);
232.1517 +/* obtain current n-tuple from domain */
232.1518 +
232.1519 +#define clean_domain _glp_mpl_clean_domain
232.1520 +void clean_domain(MPL *mpl, DOMAIN *domain);
232.1521 +/* clean domain */
232.1522 +
232.1523 +/**********************************************************************/
232.1524 +/* * *                         MODEL SETS                         * * */
232.1525 +/**********************************************************************/
232.1526 +
232.1527 +struct SET
232.1528 +{     /* model set */
232.1529 +      char *name;
232.1530 +      /* symbolic name; cannot be NULL */
232.1531 +      char *alias;
232.1532 +      /* alias; NULL means alias is not specified */
232.1533 +      int dim; /* aka arity */
232.1534 +      /* dimension (number of subscripts); dim = 0 means 0-dimensional
232.1535 +         (unsubscripted) set, dim > 0 means set of sets */
232.1536 +      DOMAIN *domain;
232.1537 +      /* subscript domain; NULL for 0-dimensional set */
232.1538 +      int dimen;
232.1539 +      /* dimension of n-tuples, which members of this set consist of
232.1540 +         (note that the model set itself is an array of elemental sets,
232.1541 +         which are its members; so, don't confuse this dimension with
232.1542 +         dimension of the model set); always non-zero */
232.1543 +      WITHIN *within;
232.1544 +      /* list of supersets, which restrict each member of the set to be
232.1545 +         in every superset from this list; this list can be empty */
232.1546 +      CODE *assign;
232.1547 +      /* pseudo-code for computing assigned value; can be NULL */
232.1548 +      CODE *option;
232.1549 +      /* pseudo-code for computing default value; can be NULL */
232.1550 +      GADGET *gadget;
232.1551 +      /* plain set used to initialize the array of sets; can be NULL */
232.1552 +      int data;
232.1553 +      /* data status flag:
232.1554 +         0 - no data are provided in the data section
232.1555 +         1 - data are provided, but not checked yet
232.1556 +         2 - data are provided and have been checked */
232.1557 +      ARRAY *array;
232.1558 +      /* array of members, which are assigned elemental sets */
232.1559 +};
232.1560 +
232.1561 +struct WITHIN
232.1562 +{     /* restricting superset list entry */
232.1563 +      CODE *code;
232.1564 +      /* pseudo-code for computing the superset; cannot be NULL */
232.1565 +      WITHIN *next;
232.1566 +      /* the next entry for the same set or parameter */
232.1567 +};
232.1568 +
232.1569 +struct GADGET
232.1570 +{     /* plain set used to initialize the array of sets with data */
232.1571 +      SET *set;
232.1572 +      /* pointer to plain set; cannot be NULL */
232.1573 +      int ind[20]; /* ind[dim+dimen]; */
232.1574 +      /* permutation of integers 1, 2, ..., dim+dimen */
232.1575 +};
232.1576 +
232.1577 +#define check_elem_set _glp_mpl_check_elem_set
232.1578 +void check_elem_set
232.1579 +(     MPL *mpl,
232.1580 +      SET *set,               /* not changed */
232.1581 +      TUPLE *tuple,           /* not changed */
232.1582 +      ELEMSET *refer          /* not changed */
232.1583 +);
232.1584 +/* check elemental set assigned to set member */
232.1585 +
232.1586 +#define take_member_set _glp_mpl_take_member_set
232.1587 +ELEMSET *take_member_set      /* returns reference, not value */
232.1588 +(     MPL *mpl,
232.1589 +      SET *set,               /* not changed */
232.1590 +      TUPLE *tuple            /* not changed */
232.1591 +);
232.1592 +/* obtain elemental set assigned to set member */
232.1593 +
232.1594 +#define eval_member_set _glp_mpl_eval_member_set
232.1595 +ELEMSET *eval_member_set      /* returns reference, not value */
232.1596 +(     MPL *mpl,
232.1597 +      SET *set,               /* not changed */
232.1598 +      TUPLE *tuple            /* not changed */
232.1599 +);
232.1600 +/* evaluate elemental set assigned to set member */
232.1601 +
232.1602 +#define eval_whole_set _glp_mpl_eval_whole_set
232.1603 +void eval_whole_set(MPL *mpl, SET *set);
232.1604 +/* evaluate model set over entire domain */
232.1605 +
232.1606 +#define clean_set _glp_mpl_clean_set
232.1607 +void clean_set(MPL *mpl, SET *set);
232.1608 +/* clean model set */
232.1609 +
232.1610 +/**********************************************************************/
232.1611 +/* * *                      MODEL PARAMETERS                      * * */
232.1612 +/**********************************************************************/
232.1613 +
232.1614 +struct PARAMETER
232.1615 +{     /* model parameter */
232.1616 +      char *name;
232.1617 +      /* symbolic name; cannot be NULL */
232.1618 +      char *alias;
232.1619 +      /* alias; NULL means alias is not specified */
232.1620 +      int dim; /* aka arity */
232.1621 +      /* dimension (number of subscripts); dim = 0 means 0-dimensional
232.1622 +         (unsubscripted) parameter */
232.1623 +      DOMAIN *domain;
232.1624 +      /* subscript domain; NULL for 0-dimensional parameter */
232.1625 +      int type;
232.1626 +      /* parameter type:
232.1627 +         A_NUMERIC  - numeric
232.1628 +         A_INTEGER  - integer
232.1629 +         A_BINARY   - binary
232.1630 +         A_SYMBOLIC - symbolic */
232.1631 +      CONDITION *cond;
232.1632 +      /* list of conditions, which restrict each parameter member to
232.1633 +         satisfy to every condition from this list; this list is used
232.1634 +         only for numeric parameters and can be empty */
232.1635 +      WITHIN *in;
232.1636 +      /* list of supersets, which restrict each parameter member to be
232.1637 +         in every superset from this list; this list is used only for
232.1638 +         symbolic parameters and can be empty */
232.1639 +      CODE *assign;
232.1640 +      /* pseudo-code for computing assigned value; can be NULL */
232.1641 +      CODE *option;
232.1642 +      /* pseudo-code for computing default value; can be NULL */
232.1643 +      int data;
232.1644 +      /* data status flag:
232.1645 +         0 - no data are provided in the data section
232.1646 +         1 - data are provided, but not checked yet
232.1647 +         2 - data are provided and have been checked */
232.1648 +      SYMBOL *defval;
232.1649 +      /* default value provided in the data section; can be NULL */
232.1650 +      ARRAY *array;
232.1651 +      /* array of members, which are assigned numbers or symbols */
232.1652 +};
232.1653 +
232.1654 +struct CONDITION
232.1655 +{     /* restricting condition list entry */
232.1656 +      int rho;
232.1657 +      /* flag that specifies the form of the condition:
232.1658 +         O_LT - less than
232.1659 +         O_LE - less than or equal to
232.1660 +         O_EQ - equal to
232.1661 +         O_GE - greater than or equal to
232.1662 +         O_GT - greater than
232.1663 +         O_NE - not equal to */
232.1664 +      CODE *code;
232.1665 +      /* pseudo-code for computing the reference value */
232.1666 +      CONDITION *next;
232.1667 +      /* the next entry for the same parameter */
232.1668 +};
232.1669 +
232.1670 +#define check_value_num _glp_mpl_check_value_num
232.1671 +void check_value_num
232.1672 +(     MPL *mpl,
232.1673 +      PARAMETER *par,         /* not changed */
232.1674 +      TUPLE *tuple,           /* not changed */
232.1675 +      double value
232.1676 +);
232.1677 +/* check numeric value assigned to parameter member */
232.1678 +
232.1679 +#define take_member_num _glp_mpl_take_member_num
232.1680 +double take_member_num
232.1681 +(     MPL *mpl,
232.1682 +      PARAMETER *par,         /* not changed */
232.1683 +      TUPLE *tuple            /* not changed */
232.1684 +);
232.1685 +/* obtain numeric value assigned to parameter member */
232.1686 +
232.1687 +#define eval_member_num _glp_mpl_eval_member_num
232.1688 +double eval_member_num
232.1689 +(     MPL *mpl,
232.1690 +      PARAMETER *par,         /* not changed */
232.1691 +      TUPLE *tuple            /* not changed */
232.1692 +);
232.1693 +/* evaluate numeric value assigned to parameter member */
232.1694 +
232.1695 +#define check_value_sym _glp_mpl_check_value_sym
232.1696 +void check_value_sym
232.1697 +(     MPL *mpl,
232.1698 +      PARAMETER *par,         /* not changed */
232.1699 +      TUPLE *tuple,           /* not changed */
232.1700 +      SYMBOL *value           /* not changed */
232.1701 +);
232.1702 +/* check symbolic value assigned to parameter member */
232.1703 +
232.1704 +#define take_member_sym _glp_mpl_take_member_sym
232.1705 +SYMBOL *take_member_sym       /* returns value, not reference */
232.1706 +(     MPL *mpl,
232.1707 +      PARAMETER *par,         /* not changed */
232.1708 +      TUPLE *tuple            /* not changed */
232.1709 +);
232.1710 +/* obtain symbolic value assigned to parameter member */
232.1711 +
232.1712 +#define eval_member_sym _glp_mpl_eval_member_sym
232.1713 +SYMBOL *eval_member_sym       /* returns value, not reference */
232.1714 +(     MPL *mpl,
232.1715 +      PARAMETER *par,         /* not changed */
232.1716 +      TUPLE *tuple            /* not changed */
232.1717 +);
232.1718 +/* evaluate symbolic value assigned to parameter member */
232.1719 +
232.1720 +#define eval_whole_par _glp_mpl_eval_whole_par
232.1721 +void eval_whole_par(MPL *mpl, PARAMETER *par);
232.1722 +/* evaluate model parameter over entire domain */
232.1723 +
232.1724 +#define clean_parameter _glp_mpl_clean_parameter
232.1725 +void clean_parameter(MPL *mpl, PARAMETER *par);
232.1726 +/* clean model parameter */
232.1727 +
232.1728 +/**********************************************************************/
232.1729 +/* * *                      MODEL VARIABLES                       * * */
232.1730 +/**********************************************************************/
232.1731 +
232.1732 +struct VARIABLE
232.1733 +{     /* model variable */
232.1734 +      char *name;
232.1735 +      /* symbolic name; cannot be NULL */
232.1736 +      char *alias;
232.1737 +      /* alias; NULL means alias is not specified */
232.1738 +      int dim; /* aka arity */
232.1739 +      /* dimension (number of subscripts); dim = 0 means 0-dimensional
232.1740 +         (unsubscripted) variable */
232.1741 +      DOMAIN *domain;
232.1742 +      /* subscript domain; NULL for 0-dimensional variable */
232.1743 +      int type;
232.1744 +      /* variable type:
232.1745 +         A_NUMERIC - continuous
232.1746 +         A_INTEGER - integer
232.1747 +         A_BINARY  - binary */
232.1748 +      CODE *lbnd;
232.1749 +      /* pseudo-code for computing lower bound; NULL means lower bound
232.1750 +         is not specified */
232.1751 +      CODE *ubnd;
232.1752 +      /* pseudo-code for computing upper bound; NULL means upper bound
232.1753 +         is not specified */
232.1754 +      /* if both the pointers lbnd and ubnd refer to the same code, the
232.1755 +         variable is fixed at the corresponding value */
232.1756 +      ARRAY *array;
232.1757 +      /* array of members, which are assigned elemental variables */
232.1758 +};
232.1759 +
232.1760 +#define take_member_var _glp_mpl_take_member_var
232.1761 +ELEMVAR *take_member_var      /* returns reference */
232.1762 +(     MPL *mpl,
232.1763 +      VARIABLE *var,          /* not changed */
232.1764 +      TUPLE *tuple            /* not changed */
232.1765 +);
232.1766 +/* obtain reference to elemental variable */
232.1767 +
232.1768 +#define eval_member_var _glp_mpl_eval_member_var
232.1769 +ELEMVAR *eval_member_var      /* returns reference */
232.1770 +(     MPL *mpl,
232.1771 +      VARIABLE *var,          /* not changed */
232.1772 +      TUPLE *tuple            /* not changed */
232.1773 +);
232.1774 +/* evaluate reference to elemental variable */
232.1775 +
232.1776 +#define eval_whole_var _glp_mpl_eval_whole_var
232.1777 +void eval_whole_var(MPL *mpl, VARIABLE *var);
232.1778 +/* evaluate model variable over entire domain */
232.1779 +
232.1780 +#define clean_variable _glp_mpl_clean_variable
232.1781 +void clean_variable(MPL *mpl, VARIABLE *var);
232.1782 +/* clean model variable */
232.1783 +
232.1784 +/**********************************************************************/
232.1785 +/* * *              MODEL CONSTRAINTS AND OBJECTIVES              * * */
232.1786 +/**********************************************************************/
232.1787 +
232.1788 +struct CONSTRAINT
232.1789 +{     /* model constraint or objective */
232.1790 +      char *name;
232.1791 +      /* symbolic name; cannot be NULL */
232.1792 +      char *alias;
232.1793 +      /* alias; NULL means alias is not specified */
232.1794 +      int dim; /* aka arity */
232.1795 +      /* dimension (number of subscripts); dim = 0 means 0-dimensional
232.1796 +         (unsubscripted) constraint */
232.1797 +      DOMAIN *domain;
232.1798 +      /* subscript domain; NULL for 0-dimensional constraint */
232.1799 +      int type;
232.1800 +      /* constraint type:
232.1801 +         A_CONSTRAINT - constraint
232.1802 +         A_MINIMIZE   - objective (minimization)
232.1803 +         A_MAXIMIZE   - objective (maximization) */
232.1804 +      CODE *code;
232.1805 +      /* pseudo-code for computing main linear form; cannot be NULL */
232.1806 +      CODE *lbnd;
232.1807 +      /* pseudo-code for computing lower bound; NULL means lower bound
232.1808 +         is not specified */
232.1809 +      CODE *ubnd;
232.1810 +      /* pseudo-code for computing upper bound; NULL means upper bound
232.1811 +         is not specified */
232.1812 +      /* if both the pointers lbnd and ubnd refer to the same code, the
232.1813 +         constraint has the form of equation */
232.1814 +      ARRAY *array;
232.1815 +      /* array of members, which are assigned elemental constraints */
232.1816 +};
232.1817 +
232.1818 +#define take_member_con _glp_mpl_take_member_con
232.1819 +ELEMCON *take_member_con      /* returns reference */
232.1820 +(     MPL *mpl,
232.1821 +      CONSTRAINT *con,        /* not changed */
232.1822 +      TUPLE *tuple            /* not changed */
232.1823 +);
232.1824 +/* obtain reference to elemental constraint */
232.1825 +
232.1826 +#define eval_member_con _glp_mpl_eval_member_con
232.1827 +ELEMCON *eval_member_con      /* returns reference */
232.1828 +(     MPL *mpl,
232.1829 +      CONSTRAINT *con,        /* not changed */
232.1830 +      TUPLE *tuple            /* not changed */
232.1831 +);
232.1832 +/* evaluate reference to elemental constraint */
232.1833 +
232.1834 +#define eval_whole_con _glp_mpl_eval_whole_con
232.1835 +void eval_whole_con(MPL *mpl, CONSTRAINT *con);
232.1836 +/* evaluate model constraint over entire domain */
232.1837 +
232.1838 +#define clean_constraint _glp_mpl_clean_constraint
232.1839 +void clean_constraint(MPL *mpl, CONSTRAINT *con);
232.1840 +/* clean model constraint */
232.1841 +
232.1842 +/**********************************************************************/
232.1843 +/* * *                        DATA TABLES                         * * */
232.1844 +/**********************************************************************/
232.1845 +
232.1846 +struct TABLE
232.1847 +{     /* data table */
232.1848 +      char *name;
232.1849 +      /* symbolic name; cannot be NULL */
232.1850 +      char *alias;
232.1851 +      /* alias; NULL means alias is not specified */
232.1852 +      int type;
232.1853 +      /* table type:
232.1854 +         A_INPUT  - input table
232.1855 +         A_OUTPUT - output table */
232.1856 +      TABARG *arg;
232.1857 +      /* argument list; cannot be empty */
232.1858 +      union
232.1859 +      {  struct
232.1860 +         {  SET *set;
232.1861 +            /* input set; NULL means the set is not specified */
232.1862 +            TABFLD *fld;
232.1863 +            /* field list; cannot be empty */
232.1864 +            TABIN *list;
232.1865 +            /* input list; can be empty */
232.1866 +         } in;
232.1867 +         struct
232.1868 +         {  DOMAIN *domain;
232.1869 +            /* subscript domain; cannot be NULL */
232.1870 +            TABOUT *list;
232.1871 +            /* output list; cannot be empty */
232.1872 +         } out;
232.1873 +      } u;
232.1874 +};
232.1875 +
232.1876 +struct TABARG
232.1877 +{     /* table argument list entry */
232.1878 +      CODE *code;
232.1879 +      /* pseudo-code for computing the argument */
232.1880 +      TABARG *next;
232.1881 +      /* next entry for the same table */
232.1882 +};
232.1883 +
232.1884 +struct TABFLD
232.1885 +{     /* table field list entry */
232.1886 +      char *name;
232.1887 +      /* field name; cannot be NULL */
232.1888 +      TABFLD *next;
232.1889 +      /* next entry for the same table */
232.1890 +};
232.1891 +
232.1892 +struct TABIN
232.1893 +{     /* table input list entry */
232.1894 +      PARAMETER *par;
232.1895 +      /* parameter to be read; cannot be NULL */
232.1896 +      char *name;
232.1897 +      /* column name; cannot be NULL */
232.1898 +      TABIN *next;
232.1899 +      /* next entry for the same table */
232.1900 +};
232.1901 +
232.1902 +struct TABOUT
232.1903 +{     /* table output list entry */
232.1904 +      CODE *code;
232.1905 +      /* pseudo-code for computing the value to be written */
232.1906 +      char *name;
232.1907 +      /* column name; cannot be NULL */
232.1908 +      TABOUT *next;
232.1909 +      /* next entry for the same table */
232.1910 +};
232.1911 +
232.1912 +struct TABDCA
232.1913 +{     /* table driver communication area */
232.1914 +      int id;
232.1915 +      /* driver identifier (set by mpl_tab_drv_open) */
232.1916 +      void *link;
232.1917 +      /* driver link pointer (set by mpl_tab_drv_open) */
232.1918 +      int na;
232.1919 +      /* number of arguments */
232.1920 +      char **arg; /* char *arg[1+ns]; */
232.1921 +      /* arg[k], 1 <= k <= ns, is pointer to k-th argument */
232.1922 +      int nf;
232.1923 +      /* number of fields */
232.1924 +      char **name; /* char *name[1+nc]; */
232.1925 +      /* name[k], 1 <= k <= nc, is name of k-th field */
232.1926 +      int *type; /* int type[1+nc]; */
232.1927 +      /* type[k], 1 <= k <= nc, is type of k-th field:
232.1928 +         '?' - value not assigned
232.1929 +         'N' - number
232.1930 +         'S' - character string */
232.1931 +      double *num; /* double num[1+nc]; */
232.1932 +      /* num[k], 1 <= k <= nc, is numeric value of k-th field */
232.1933 +      char **str;
232.1934 +      /* str[k], 1 <= k <= nc, is string value of k-th field */
232.1935 +};
232.1936 +
232.1937 +#define mpl_tab_num_args _glp_mpl_tab_num_args
232.1938 +int mpl_tab_num_args(TABDCA *dca);
232.1939 +
232.1940 +#define mpl_tab_get_arg _glp_mpl_tab_get_arg
232.1941 +const char *mpl_tab_get_arg(TABDCA *dca, int k);
232.1942 +
232.1943 +#define mpl_tab_num_flds _glp_mpl_tab_num_flds
232.1944 +int mpl_tab_num_flds(TABDCA *dca);
232.1945 +
232.1946 +#define mpl_tab_get_name _glp_mpl_tab_get_name
232.1947 +const char *mpl_tab_get_name(TABDCA *dca, int k);
232.1948 +
232.1949 +#define mpl_tab_get_type _glp_mpl_tab_get_type
232.1950 +int mpl_tab_get_type(TABDCA *dca, int k);
232.1951 +
232.1952 +#define mpl_tab_get_num _glp_mpl_tab_get_num
232.1953 +double mpl_tab_get_num(TABDCA *dca, int k);
232.1954 +
232.1955 +#define mpl_tab_get_str _glp_mpl_tab_get_str
232.1956 +const char *mpl_tab_get_str(TABDCA *dca, int k);
232.1957 +
232.1958 +#define mpl_tab_set_num _glp_mpl_tab_set_num
232.1959 +void mpl_tab_set_num(TABDCA *dca, int k, double num);
232.1960 +
232.1961 +#define mpl_tab_set_str _glp_mpl_tab_set_str
232.1962 +void mpl_tab_set_str(TABDCA *dca, int k, const char *str);
232.1963 +
232.1964 +#define mpl_tab_drv_open _glp_mpl_tab_drv_open
232.1965 +void mpl_tab_drv_open(MPL *mpl, int mode);
232.1966 +
232.1967 +#define mpl_tab_drv_read _glp_mpl_tab_drv_read
232.1968 +int mpl_tab_drv_read(MPL *mpl);
232.1969 +
232.1970 +#define mpl_tab_drv_write _glp_mpl_tab_drv_write
232.1971 +void mpl_tab_drv_write(MPL *mpl);
232.1972 +
232.1973 +#define mpl_tab_drv_close _glp_mpl_tab_drv_close
232.1974 +void mpl_tab_drv_close(MPL *mpl);
232.1975 +
232.1976 +/**********************************************************************/
232.1977 +/* * *                        PSEUDO-CODE                         * * */
232.1978 +/**********************************************************************/
232.1979 +
232.1980 +union OPERANDS
232.1981 +{     /* operands that participate in pseudo-code operation (choice of
232.1982 +         particular operands depends on the operation code) */
232.1983 +      /*--------------------------------------------------------------*/
232.1984 +      double num;             /* O_NUMBER */
232.1985 +      /* floaing-point number to be taken */
232.1986 +      /*--------------------------------------------------------------*/
232.1987 +      char *str;              /* O_STRING */
232.1988 +      /* character string to be taken */
232.1989 +      /*--------------------------------------------------------------*/
232.1990 +      struct                  /* O_INDEX */
232.1991 +      {  DOMAIN_SLOT *slot;
232.1992 +         /* domain slot, which contains dummy index to be taken */
232.1993 +         CODE *next;
232.1994 +         /* the next pseudo-code with op = O_INDEX, which refers to the
232.1995 +            same slot as this one; pointer to the beginning of this list
232.1996 +            is stored in the corresponding domain slot */
232.1997 +      } index;
232.1998 +      /*--------------------------------------------------------------*/
232.1999 +      struct                  /* O_MEMNUM, O_MEMSYM */
232.2000 +      {  PARAMETER *par;
232.2001 +         /* model parameter, which contains member to be taken */
232.2002 +         ARG_LIST *list;
232.2003 +         /* list of subscripts; NULL for 0-dimensional parameter */
232.2004 +      } par;
232.2005 +      /*--------------------------------------------------------------*/
232.2006 +      struct                  /* O_MEMSET */
232.2007 +      {  SET *set;
232.2008 +         /* model set, which contains member to be taken */
232.2009 +         ARG_LIST *list;
232.2010 +         /* list of subscripts; NULL for 0-dimensional set */
232.2011 +      } set;
232.2012 +      /*--------------------------------------------------------------*/
232.2013 +      struct                  /* O_MEMVAR */
232.2014 +      {  VARIABLE *var;
232.2015 +         /* model variable, which contains member to be taken */
232.2016 +         ARG_LIST *list;
232.2017 +         /* list of subscripts; NULL for 0-dimensional variable */
232.2018 +#if 1 /* 15/V-2010 */
232.2019 +         int suff;
232.2020 +         /* suffix specified: */
232.2021 +#define DOT_NONE        0x00  /* none     (means variable itself) */
232.2022 +#define DOT_LB          0x01  /* .lb      (lower bound) */
232.2023 +#define DOT_UB          0x02  /* .ub      (upper bound) */
232.2024 +#define DOT_STATUS      0x03  /* .status  (status) */
232.2025 +#define DOT_VAL         0x04  /* .val     (primal value) */
232.2026 +#define DOT_DUAL        0x05  /* .dual    (dual value) */
232.2027 +#endif
232.2028 +      } var;
232.2029 +#if 1 /* 15/V-2010 */
232.2030 +      /*--------------------------------------------------------------*/
232.2031 +      struct                  /* O_MEMCON */
232.2032 +      {  CONSTRAINT *con;
232.2033 +         /* model constraint, which contains member to be taken */
232.2034 +         ARG_LIST *list;
232.2035 +         /* list of subscripys; NULL for 0-dimensional constraint */
232.2036 +         int suff;
232.2037 +         /* suffix specified (see O_MEMVAR above) */
232.2038 +      } con;
232.2039 +#endif
232.2040 +      /*--------------------------------------------------------------*/
232.2041 +      ARG_LIST *list;         /* O_TUPLE, O_MAKE, n-ary operations */
232.2042 +      /* list of operands */
232.2043 +      /*--------------------------------------------------------------*/
232.2044 +      DOMAIN_BLOCK *slice;    /* O_SLICE */
232.2045 +      /* domain block, which specifies slice (i.e. n-tuple that contains
232.2046 +         free dummy indices); this operation is never evaluated */
232.2047 +      /*--------------------------------------------------------------*/
232.2048 +      struct                  /* unary, binary, ternary operations */
232.2049 +      {  CODE *x;
232.2050 +         /* pseudo-code for computing first operand */
232.2051 +         CODE *y;
232.2052 +         /* pseudo-code for computing second operand */
232.2053 +         CODE *z;
232.2054 +         /* pseudo-code for computing third operand */
232.2055 +      } arg;
232.2056 +      /*--------------------------------------------------------------*/
232.2057 +      struct                  /* iterated operations */
232.2058 +      {  DOMAIN *domain;
232.2059 +         /* domain, over which the operation is performed */
232.2060 +         CODE *x;
232.2061 +         /* pseudo-code for computing "integrand" */
232.2062 +      } loop;
232.2063 +      /*--------------------------------------------------------------*/
232.2064 +};
232.2065 +
232.2066 +struct ARG_LIST
232.2067 +{     /* operands list entry */
232.2068 +      CODE *x;
232.2069 +      /* pseudo-code for computing operand */
232.2070 +      ARG_LIST *next;
232.2071 +      /* the next operand of the same operation */
232.2072 +};
232.2073 +
232.2074 +struct CODE
232.2075 +{     /* pseudo-code (internal form of expressions) */
232.2076 +      int op;
232.2077 +      /* operation code: */
232.2078 +#define O_NUMBER        301   /* take floating-point number */
232.2079 +#define O_STRING        302   /* take character string */
232.2080 +#define O_INDEX         303   /* take dummy index */
232.2081 +#define O_MEMNUM        304   /* take member of numeric parameter */
232.2082 +#define O_MEMSYM        305   /* take member of symbolic parameter */
232.2083 +#define O_MEMSET        306   /* take member of set */
232.2084 +#define O_MEMVAR        307   /* take member of variable */
232.2085 +#define O_MEMCON        308   /* take member of constraint */
232.2086 +#define O_TUPLE         309   /* make n-tuple */
232.2087 +#define O_MAKE          310   /* make elemental set of n-tuples */
232.2088 +#define O_SLICE         311   /* define domain block (dummy op) */
232.2089 +                              /* 0-ary operations --------------------*/
232.2090 +#define O_IRAND224      312   /* pseudo-random in [0, 2^24-1] */
232.2091 +#define O_UNIFORM01     313   /* pseudo-random in [0, 1) */
232.2092 +#define O_NORMAL01      314   /* gaussian random, mu = 0, sigma = 1 */
232.2093 +#define O_GMTIME        315   /* current calendar time (UTC) */
232.2094 +                              /* unary operations --------------------*/
232.2095 +#define O_CVTNUM        316   /* conversion to numeric */
232.2096 +#define O_CVTSYM        317   /* conversion to symbolic */
232.2097 +#define O_CVTLOG        318   /* conversion to logical */
232.2098 +#define O_CVTTUP        319   /* conversion to 1-tuple */
232.2099 +#define O_CVTLFM        320   /* conversion to linear form */
232.2100 +#define O_PLUS          321   /* unary plus */
232.2101 +#define O_MINUS         322   /* unary minus */
232.2102 +#define O_NOT           323   /* negation (logical "not") */
232.2103 +#define O_ABS           324   /* absolute value */
232.2104 +#define O_CEIL          325   /* round upward ("ceiling of x") */
232.2105 +#define O_FLOOR         326   /* round downward ("floor of x") */
232.2106 +#define O_EXP           327   /* base-e exponential */
232.2107 +#define O_LOG           328   /* natural logarithm */
232.2108 +#define O_LOG10         329   /* common (decimal) logarithm */
232.2109 +#define O_SQRT          330   /* square root */
232.2110 +#define O_SIN           331   /* trigonometric sine */
232.2111 +#define O_COS           332   /* trigonometric cosine */
232.2112 +#define O_ATAN          333   /* trigonometric arctangent */
232.2113 +#define O_ROUND         334   /* round to nearest integer */
232.2114 +#define O_TRUNC         335   /* truncate to nearest integer */
232.2115 +#define O_CARD          336   /* cardinality of set */
232.2116 +#define O_LENGTH        337   /* length of symbolic value */
232.2117 +                              /* binary operations -------------------*/
232.2118 +#define O_ADD           338   /* addition */
232.2119 +#define O_SUB           339   /* subtraction */
232.2120 +#define O_LESS          340   /* non-negative subtraction */
232.2121 +#define O_MUL           341   /* multiplication */
232.2122 +#define O_DIV           342   /* division */
232.2123 +#define O_IDIV          343   /* quotient of exact division */
232.2124 +#define O_MOD           344   /* remainder of exact division */
232.2125 +#define O_POWER         345   /* exponentiation (raise to power) */
232.2126 +#define O_ATAN2         346   /* trigonometric arctangent */
232.2127 +#define O_ROUND2        347   /* round to n fractional digits */
232.2128 +#define O_TRUNC2        348   /* truncate to n fractional digits */
232.2129 +#define O_UNIFORM       349   /* pseudo-random in [a, b) */
232.2130 +#define O_NORMAL        350   /* gaussian random, given mu and sigma */
232.2131 +#define O_CONCAT        351   /* concatenation */
232.2132 +#define O_LT            352   /* comparison on 'less than' */
232.2133 +#define O_LE            353   /* comparison on 'not greater than' */
232.2134 +#define O_EQ            354   /* comparison on 'equal to' */
232.2135 +#define O_GE            355   /* comparison on 'not less than' */
232.2136 +#define O_GT            356   /* comparison on 'greater than' */
232.2137 +#define O_NE            357   /* comparison on 'not equal to' */
232.2138 +#define O_AND           358   /* conjunction (logical "and") */
232.2139 +#define O_OR            359   /* disjunction (logical "or") */
232.2140 +#define O_UNION         360   /* union */
232.2141 +#define O_DIFF          361   /* difference */
232.2142 +#define O_SYMDIFF       362   /* symmetric difference */
232.2143 +#define O_INTER         363   /* intersection */
232.2144 +#define O_CROSS         364   /* cross (Cartesian) product */
232.2145 +#define O_IN            365   /* test on 'x in Y' */
232.2146 +#define O_NOTIN         366   /* test on 'x not in Y' */
232.2147 +#define O_WITHIN        367   /* test on 'X within Y' */
232.2148 +#define O_NOTWITHIN     368   /* test on 'X not within Y' */
232.2149 +#define O_SUBSTR        369   /* substring */
232.2150 +#define O_STR2TIME      370   /* convert string to time */
232.2151 +#define O_TIME2STR      371   /* convert time to string */
232.2152 +                              /* ternary operations ------------------*/
232.2153 +#define O_DOTS          372   /* build "arithmetic" set */
232.2154 +#define O_FORK          373   /* if-then-else */
232.2155 +#define O_SUBSTR3       374   /* substring */
232.2156 +                              /* n-ary operations --------------------*/
232.2157 +#define O_MIN           375   /* minimal value (n-ary) */
232.2158 +#define O_MAX           376   /* maximal value (n-ary) */
232.2159 +                              /* iterated operations -----------------*/
232.2160 +#define O_SUM           377   /* summation */
232.2161 +#define O_PROD          378   /* multiplication */
232.2162 +#define O_MINIMUM       379   /* minimum */
232.2163 +#define O_MAXIMUM       380   /* maximum */
232.2164 +#define O_FORALL        381   /* conjunction (A-quantification) */
232.2165 +#define O_EXISTS        382   /* disjunction (E-quantification) */
232.2166 +#define O_SETOF         383   /* compute elemental set */
232.2167 +#define O_BUILD         384   /* build elemental set */
232.2168 +      OPERANDS arg;
232.2169 +      /* operands that participate in the operation */
232.2170 +      int type;
232.2171 +      /* type of the resultant value:
232.2172 +         A_NUMERIC  - numeric
232.2173 +         A_SYMBOLIC - symbolic
232.2174 +         A_LOGICAL  - logical
232.2175 +         A_TUPLE    - n-tuple
232.2176 +         A_ELEMSET  - elemental set
232.2177 +         A_FORMULA  - linear form */
232.2178 +      int dim;
232.2179 +      /* dimension of the resultant value; for A_TUPLE and A_ELEMSET it
232.2180 +         is the dimension of the corresponding n-tuple(s) and cannot be
232.2181 +         zero; for other resultant types it is always zero */
232.2182 +      CODE *up;
232.2183 +      /* parent pseudo-code, which refers to this pseudo-code as to its
232.2184 +         operand; NULL means this pseudo-code has no parent and defines
232.2185 +         an expression, which is not contained in another expression */
232.2186 +      int vflag;
232.2187 +      /* volatile flag; being set this flag means that this operation
232.2188 +         has a side effect; for primary expressions this flag is set
232.2189 +         directly by corresponding parsing routines (for example, if
232.2190 +         primary expression is a reference to a function that generates
232.2191 +         pseudo-random numbers); in other cases this flag is inherited
232.2192 +         from operands */
232.2193 +      int valid;
232.2194 +      /* if this flag is set, the resultant value, which is a temporary
232.2195 +         result of evaluating this operation on particular values of
232.2196 +         operands, is valid; if this flag is clear, the resultant value
232.2197 +         doesn't exist and therefore not valid; having been evaluated
232.2198 +         the resultant value is stored here and not destroyed until the
232.2199 +         dummy indices, which this value depends on, have been changed
232.2200 +         (and if it doesn't depend on dummy indices at all, it is never
232.2201 +         destroyed); thus, if the resultant value is valid, evaluating
232.2202 +         routine can immediately take its copy not computing the result
232.2203 +         from scratch; this mechanism is similar to moving invariants
232.2204 +         out of loops and allows improving efficiency at the expense of
232.2205 +         some extra memory needed to keep temporary results */
232.2206 +      /* however, if the volatile flag (see above) is set, even if the
232.2207 +         resultant value is valid, evaluating routine computes it as if
232.2208 +         it were not valid, i.e. caching is not used in this case */
232.2209 +      VALUE value;
232.2210 +      /* resultant value in generic format */
232.2211 +};
232.2212 +
232.2213 +#define eval_numeric _glp_mpl_eval_numeric
232.2214 +double eval_numeric(MPL *mpl, CODE *code);
232.2215 +/* evaluate pseudo-code to determine numeric value */
232.2216 +
232.2217 +#define eval_symbolic _glp_mpl_eval_symbolic
232.2218 +SYMBOL *eval_symbolic(MPL *mpl, CODE *code);
232.2219 +/* evaluate pseudo-code to determine symbolic value */
232.2220 +
232.2221 +#define eval_logical _glp_mpl_eval_logical
232.2222 +int eval_logical(MPL *mpl, CODE *code);
232.2223 +/* evaluate pseudo-code to determine logical value */
232.2224 +
232.2225 +#define eval_tuple _glp_mpl_eval_tuple
232.2226 +TUPLE *eval_tuple(MPL *mpl, CODE *code);
232.2227 +/* evaluate pseudo-code to construct n-tuple */
232.2228 +
232.2229 +#define eval_elemset _glp_mpl_eval_elemset
232.2230 +ELEMSET *eval_elemset(MPL *mpl, CODE *code);
232.2231 +/* evaluate pseudo-code to construct elemental set */
232.2232 +
232.2233 +#define is_member _glp_mpl_is_member
232.2234 +int is_member(MPL *mpl, CODE *code, TUPLE *tuple);
232.2235 +/* check if n-tuple is in set specified by pseudo-code */
232.2236 +
232.2237 +#define eval_formula _glp_mpl_eval_formula
232.2238 +FORMULA *eval_formula(MPL *mpl, CODE *code);
232.2239 +/* evaluate pseudo-code to construct linear form */
232.2240 +
232.2241 +#define clean_code _glp_mpl_clean_code
232.2242 +void clean_code(MPL *mpl, CODE *code);
232.2243 +/* clean pseudo-code */
232.2244 +
232.2245 +/**********************************************************************/
232.2246 +/* * *                      MODEL STATEMENTS                      * * */
232.2247 +/**********************************************************************/
232.2248 +
232.2249 +struct CHECK
232.2250 +{     /* check statement */
232.2251 +      DOMAIN *domain;
232.2252 +      /* subscript domain; NULL means domain is not used */
232.2253 +      CODE *code;
232.2254 +      /* code for computing the predicate to be checked */
232.2255 +};
232.2256 +
232.2257 +struct DISPLAY
232.2258 +{     /* display statement */
232.2259 +      DOMAIN *domain;
232.2260 +      /* subscript domain; NULL means domain is not used */
232.2261 +      DISPLAY1 *list;
232.2262 +      /* display list; cannot be empty */
232.2263 +};
232.2264 +
232.2265 +struct DISPLAY1
232.2266 +{     /* display list entry */
232.2267 +      int type;
232.2268 +      /* item type:
232.2269 +         A_INDEX      - dummy index
232.2270 +         A_SET        - model set
232.2271 +         A_PARAMETER  - model parameter
232.2272 +         A_VARIABLE   - model variable
232.2273 +         A_CONSTRAINT - model constraint/objective
232.2274 +         A_EXPRESSION - expression */
232.2275 +      union
232.2276 +      {  DOMAIN_SLOT *slot;
232.2277 +         SET *set;
232.2278 +         PARAMETER *par;
232.2279 +         VARIABLE *var;
232.2280 +         CONSTRAINT *con;
232.2281 +         CODE *code;
232.2282 +      } u;
232.2283 +      /* item to be displayed */
232.2284 +#if 0 /* 15/V-2010 */
232.2285 +      ARG_LIST *list;
232.2286 +      /* optional subscript list (for constraint/objective only) */
232.2287 +#endif
232.2288 +      DISPLAY1 *next;
232.2289 +      /* the next entry for the same statement */
232.2290 +};
232.2291 +
232.2292 +struct PRINTF
232.2293 +{     /* printf statement */
232.2294 +      DOMAIN *domain;
232.2295 +      /* subscript domain; NULL means domain is not used */
232.2296 +      CODE *fmt;
232.2297 +      /* pseudo-code for computing format string */
232.2298 +      PRINTF1 *list;
232.2299 +      /* printf list; can be empty */
232.2300 +      CODE *fname;
232.2301 +      /* pseudo-code for computing filename to redirect the output;
232.2302 +         NULL means the output goes to stdout */
232.2303 +      int app;
232.2304 +      /* if this flag is set, the output is appended */
232.2305 +};
232.2306 +
232.2307 +struct PRINTF1
232.2308 +{     /* printf list entry */
232.2309 +      CODE *code;
232.2310 +      /* pseudo-code for computing value to be printed */
232.2311 +      PRINTF1 *next;
232.2312 +      /* the next entry for the same statement */
232.2313 +};
232.2314 +
232.2315 +struct FOR
232.2316 +{     /* for statement */
232.2317 +      DOMAIN *domain;
232.2318 +      /* subscript domain; cannot be NULL */
232.2319 +      STATEMENT *list;
232.2320 +      /* linked list of model statements within this for statement in
232.2321 +         the original order */
232.2322 +};
232.2323 +
232.2324 +struct STATEMENT
232.2325 +{     /* model statement */
232.2326 +      int line;
232.2327 +      /* number of source text line, where statement begins */
232.2328 +      int type;
232.2329 +      /* statement type:
232.2330 +         A_SET        - set statement
232.2331 +         A_PARAMETER  - parameter statement
232.2332 +         A_VARIABLE   - variable statement
232.2333 +         A_CONSTRAINT - constraint/objective statement
232.2334 +         A_TABLE      - table statement
232.2335 +         A_SOLVE      - solve statement
232.2336 +         A_CHECK      - check statement
232.2337 +         A_DISPLAY    - display statement
232.2338 +         A_PRINTF     - printf statement
232.2339 +         A_FOR        - for statement */
232.2340 +      union
232.2341 +      {  SET *set;
232.2342 +         PARAMETER *par;
232.2343 +         VARIABLE *var;
232.2344 +         CONSTRAINT *con;
232.2345 +         TABLE *tab;
232.2346 +         void *slv; /* currently not used (set to NULL) */
232.2347 +         CHECK *chk;
232.2348 +         DISPLAY *dpy;
232.2349 +         PRINTF *prt;
232.2350 +         FOR *fur;
232.2351 +      } u;
232.2352 +      /* specific part of statement */
232.2353 +      STATEMENT *next;
232.2354 +      /* the next statement; in this list statements follow in the same
232.2355 +         order as they appear in the model section */
232.2356 +};
232.2357 +
232.2358 +#define execute_table _glp_mpl_execute_table
232.2359 +void execute_table(MPL *mpl, TABLE *tab);
232.2360 +/* execute table statement */
232.2361 +
232.2362 +#define free_dca _glp_mpl_free_dca
232.2363 +void free_dca(MPL *mpl);
232.2364 +/* free table driver communucation area */
232.2365 +
232.2366 +#define clean_table _glp_mpl_clean_table
232.2367 +void clean_table(MPL *mpl, TABLE *tab);
232.2368 +/* clean table statement */
232.2369 +
232.2370 +#define execute_check _glp_mpl_execute_check
232.2371 +void execute_check(MPL *mpl, CHECK *chk);
232.2372 +/* execute check statement */
232.2373 +
232.2374 +#define clean_check _glp_mpl_clean_check
232.2375 +void clean_check(MPL *mpl, CHECK *chk);
232.2376 +/* clean check statement */
232.2377 +
232.2378 +#define execute_display _glp_mpl_execute_display
232.2379 +void execute_display(MPL *mpl, DISPLAY *dpy);
232.2380 +/* execute display statement */
232.2381 +
232.2382 +#define clean_display _glp_mpl_clean_display
232.2383 +void clean_display(MPL *mpl, DISPLAY *dpy);
232.2384 +/* clean display statement */
232.2385 +
232.2386 +#define execute_printf _glp_mpl_execute_printf
232.2387 +void execute_printf(MPL *mpl, PRINTF *prt);
232.2388 +/* execute printf statement */
232.2389 +
232.2390 +#define clean_printf _glp_mpl_clean_printf
232.2391 +void clean_printf(MPL *mpl, PRINTF *prt);
232.2392 +/* clean printf statement */
232.2393 +
232.2394 +#define execute_for _glp_mpl_execute_for
232.2395 +void execute_for(MPL *mpl, FOR *fur);
232.2396 +/* execute for statement */
232.2397 +
232.2398 +#define clean_for _glp_mpl_clean_for
232.2399 +void clean_for(MPL *mpl, FOR *fur);
232.2400 +/* clean for statement */
232.2401 +
232.2402 +#define execute_statement _glp_mpl_execute_statement
232.2403 +void execute_statement(MPL *mpl, STATEMENT *stmt);
232.2404 +/* execute specified model statement */
232.2405 +
232.2406 +#define clean_statement _glp_mpl_clean_statement
232.2407 +void clean_statement(MPL *mpl, STATEMENT *stmt);
232.2408 +/* clean specified model statement */
232.2409 +
232.2410 +/**********************************************************************/
232.2411 +/* * *              GENERATING AND POSTSOLVING MODEL              * * */
232.2412 +/**********************************************************************/
232.2413 +
232.2414 +#define alloc_content _glp_mpl_alloc_content
232.2415 +void alloc_content(MPL *mpl);
232.2416 +/* allocate content arrays for all model objects */
232.2417 +
232.2418 +#define generate_model _glp_mpl_generate_model
232.2419 +void generate_model(MPL *mpl);
232.2420 +/* generate model */
232.2421 +
232.2422 +#define build_problem _glp_mpl_build_problem
232.2423 +void build_problem(MPL *mpl);
232.2424 +/* build problem instance */
232.2425 +
232.2426 +#define postsolve_model _glp_mpl_postsolve_model
232.2427 +void postsolve_model(MPL *mpl);
232.2428 +/* postsolve model */
232.2429 +
232.2430 +#define clean_model _glp_mpl_clean_model
232.2431 +void clean_model(MPL *mpl);
232.2432 +/* clean model content */
232.2433 +
232.2434 +/**********************************************************************/
232.2435 +/* * *                        INPUT/OUTPUT                        * * */
232.2436 +/**********************************************************************/
232.2437 +
232.2438 +#define open_input _glp_mpl_open_input
232.2439 +void open_input(MPL *mpl, char *file);
232.2440 +/* open input text file */
232.2441 +
232.2442 +#define read_char _glp_mpl_read_char
232.2443 +int read_char(MPL *mpl);
232.2444 +/* read next character from input text file */
232.2445 +
232.2446 +#define close_input _glp_mpl_close_input
232.2447 +void close_input(MPL *mpl);
232.2448 +/* close input text file */
232.2449 +
232.2450 +#define open_output _glp_mpl_open_output
232.2451 +void open_output(MPL *mpl, char *file);
232.2452 +/* open output text file */
232.2453 +
232.2454 +#define write_char _glp_mpl_write_char
232.2455 +void write_char(MPL *mpl, int c);
232.2456 +/* write next character to output text file */
232.2457 +
232.2458 +#define write_text _glp_mpl_write_text
232.2459 +void write_text(MPL *mpl, char *fmt, ...);
232.2460 +/* format and write text to output text file */
232.2461 +
232.2462 +#define flush_output _glp_mpl_flush_output
232.2463 +void flush_output(MPL *mpl);
232.2464 +/* finalize writing data to output text file */
232.2465 +
232.2466 +/**********************************************************************/
232.2467 +/* * *                      SOLVER INTERFACE                      * * */
232.2468 +/**********************************************************************/
232.2469 +
232.2470 +#define MPL_FR          401   /* free (unbounded) */
232.2471 +#define MPL_LO          402   /* lower bound */
232.2472 +#define MPL_UP          403   /* upper bound */
232.2473 +#define MPL_DB          404   /* both lower and upper bounds */
232.2474 +#define MPL_FX          405   /* fixed */
232.2475 +
232.2476 +#define MPL_ST          411   /* constraint */
232.2477 +#define MPL_MIN         412   /* objective (minimization) */
232.2478 +#define MPL_MAX         413   /* objective (maximization) */
232.2479 +
232.2480 +#define MPL_NUM         421   /* continuous */
232.2481 +#define MPL_INT         422   /* integer */
232.2482 +#define MPL_BIN         423   /* binary */
232.2483 +
232.2484 +#define error _glp_mpl_error
232.2485 +void error(MPL *mpl, char *fmt, ...);
232.2486 +/* print error message and terminate model processing */
232.2487 +
232.2488 +#define warning _glp_mpl_warning
232.2489 +void warning(MPL *mpl, char *fmt, ...);
232.2490 +/* print warning message and continue model processing */
232.2491 +
232.2492 +#define mpl_initialize _glp_mpl_initialize
232.2493 +MPL *mpl_initialize(void);
232.2494 +/* create and initialize translator database */
232.2495 +
232.2496 +#define mpl_read_model _glp_mpl_read_model
232.2497 +int mpl_read_model(MPL *mpl, char *file, int skip_data);
232.2498 +/* read model section and optional data section */
232.2499 +
232.2500 +#define mpl_read_data _glp_mpl_read_data
232.2501 +int mpl_read_data(MPL *mpl, char *file);
232.2502 +/* read data section */
232.2503 +
232.2504 +#define mpl_generate _glp_mpl_generate
232.2505 +int mpl_generate(MPL *mpl, char *file);
232.2506 +/* generate model */
232.2507 +
232.2508 +#define mpl_get_prob_name _glp_mpl_get_prob_name
232.2509 +char *mpl_get_prob_name(MPL *mpl);
232.2510 +/* obtain problem (model) name */
232.2511 +
232.2512 +#define mpl_get_num_rows _glp_mpl_get_num_rows
232.2513 +int mpl_get_num_rows(MPL *mpl);
232.2514 +/* determine number of rows */
232.2515 +
232.2516 +#define mpl_get_num_cols _glp_mpl_get_num_cols
232.2517 +int mpl_get_num_cols(MPL *mpl);
232.2518 +/* determine number of columns */
232.2519 +
232.2520 +#define mpl_get_row_name _glp_mpl_get_row_name
232.2521 +char *mpl_get_row_name(MPL *mpl, int i);
232.2522 +/* obtain row name */
232.2523 +
232.2524 +#define mpl_get_row_kind _glp_mpl_get_row_kind
232.2525 +int mpl_get_row_kind(MPL *mpl, int i);
232.2526 +/* determine row kind */
232.2527 +
232.2528 +#define mpl_get_row_bnds _glp_mpl_get_row_bnds
232.2529 +int mpl_get_row_bnds(MPL *mpl, int i, double *lb, double *ub);
232.2530 +/* obtain row bounds */
232.2531 +
232.2532 +#define mpl_get_mat_row _glp_mpl_get_mat_row
232.2533 +int mpl_get_mat_row(MPL *mpl, int i, int ndx[], double val[]);
232.2534 +/* obtain row of the constraint matrix */
232.2535 +
232.2536 +#define mpl_get_row_c0 _glp_mpl_get_row_c0
232.2537 +double mpl_get_row_c0(MPL *mpl, int i);
232.2538 +/* obtain constant term of free row */
232.2539 +
232.2540 +#define mpl_get_col_name _glp_mpl_get_col_name
232.2541 +char *mpl_get_col_name(MPL *mpl, int j);
232.2542 +/* obtain column name */
232.2543 +
232.2544 +#define mpl_get_col_kind _glp_mpl_get_col_kind
232.2545 +int mpl_get_col_kind(MPL *mpl, int j);
232.2546 +/* determine column kind */
232.2547 +
232.2548 +#define mpl_get_col_bnds _glp_mpl_get_col_bnds
232.2549 +int mpl_get_col_bnds(MPL *mpl, int j, double *lb, double *ub);
232.2550 +/* obtain column bounds */
232.2551 +
232.2552 +#define mpl_has_solve_stmt _glp_mpl_has_solve_stmt
232.2553 +int mpl_has_solve_stmt(MPL *mpl);
232.2554 +/* check if model has solve statement */
232.2555 +
232.2556 +#if 1 /* 15/V-2010 */
232.2557 +#define mpl_put_row_soln _glp_mpl_put_row_soln
232.2558 +void mpl_put_row_soln(MPL *mpl, int i, int stat, double prim,
232.2559 +      double dual);
232.2560 +/* store row (constraint/objective) solution components */
232.2561 +#endif
232.2562 +
232.2563 +#if 1 /* 15/V-2010 */
232.2564 +#define mpl_put_col_soln _glp_mpl_put_col_soln
232.2565 +void mpl_put_col_soln(MPL *mpl, int j, int stat, double prim,
232.2566 +      double dual);
232.2567 +/* store column (variable) solution components */
232.2568 +#endif
232.2569 +
232.2570 +#if 0 /* 15/V-2010 */
232.2571 +#define mpl_put_col_value _glp_mpl_put_col_value
232.2572 +void mpl_put_col_value(MPL *mpl, int j, double val);
232.2573 +/* store column value */
232.2574 +#endif
232.2575 +
232.2576 +#define mpl_postsolve _glp_mpl_postsolve
232.2577 +int mpl_postsolve(MPL *mpl);
232.2578 +/* postsolve model */
232.2579 +
232.2580 +#define mpl_terminate _glp_mpl_terminate
232.2581 +void mpl_terminate(MPL *mpl);
232.2582 +/* free all resources used by translator */
232.2583 +
232.2584 +#endif
232.2585 +
232.2586 +/* eof */
   233.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   233.2 +++ b/src/glpmpl01.c	Mon Dec 06 13:09:21 2010 +0100
   233.3 @@ -0,0 +1,4715 @@
   233.4 +/* glpmpl01.c */
   233.5 +
   233.6 +/***********************************************************************
   233.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   233.8 +*
   233.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  233.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  233.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  233.12 +*  E-mail: <mao@gnu.org>.
  233.13 +*
  233.14 +*  GLPK is free software: you can redistribute it and/or modify it
  233.15 +*  under the terms of the GNU General Public License as published by
  233.16 +*  the Free Software Foundation, either version 3 of the License, or
  233.17 +*  (at your option) any later version.
  233.18 +*
  233.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  233.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  233.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  233.22 +*  License for more details.
  233.23 +*
  233.24 +*  You should have received a copy of the GNU General Public License
  233.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  233.26 +***********************************************************************/
  233.27 +
  233.28 +#define _GLPSTD_STDIO
  233.29 +#include "glpmpl.h"
  233.30 +#define dmp_get_atomv dmp_get_atom
  233.31 +
  233.32 +/**********************************************************************/
  233.33 +/* * *                  PROCESSING MODEL SECTION                  * * */
  233.34 +/**********************************************************************/
  233.35 +
  233.36 +/*----------------------------------------------------------------------
  233.37 +-- enter_context - enter current token into context queue.
  233.38 +--
  233.39 +-- This routine enters the current token into the context queue. */
  233.40 +
  233.41 +void enter_context(MPL *mpl)
  233.42 +{     char *image, *s;
  233.43 +      if (mpl->token == T_EOF)
  233.44 +         image = "_|_";
  233.45 +      else if (mpl->token == T_STRING)
  233.46 +         image = "'...'";
  233.47 +      else
  233.48 +         image = mpl->image;
  233.49 +      xassert(0 <= mpl->c_ptr && mpl->c_ptr < CONTEXT_SIZE);
  233.50 +      mpl->context[mpl->c_ptr++] = ' ';
  233.51 +      if (mpl->c_ptr == CONTEXT_SIZE) mpl->c_ptr = 0;
  233.52 +      for (s = image; *s != '\0'; s++)
  233.53 +      {  mpl->context[mpl->c_ptr++] = *s;
  233.54 +         if (mpl->c_ptr == CONTEXT_SIZE) mpl->c_ptr = 0;
  233.55 +      }
  233.56 +      return;
  233.57 +}
  233.58 +
  233.59 +/*----------------------------------------------------------------------
  233.60 +-- print_context - print current content of context queue.
  233.61 +--
  233.62 +-- This routine prints current content of the context queue. */
  233.63 +
  233.64 +void print_context(MPL *mpl)
  233.65 +{     int c;
  233.66 +      while (mpl->c_ptr > 0)
  233.67 +      {  mpl->c_ptr--;
  233.68 +         c = mpl->context[0];
  233.69 +         memmove(mpl->context, mpl->context+1, CONTEXT_SIZE-1);
  233.70 +         mpl->context[CONTEXT_SIZE-1] = (char)c;
  233.71 +      }
  233.72 +      xprintf("Context: %s%.*s\n", mpl->context[0] == ' ' ? "" : "...",
  233.73 +         CONTEXT_SIZE, mpl->context);
  233.74 +      return;
  233.75 +}
  233.76 +
  233.77 +/*----------------------------------------------------------------------
  233.78 +-- get_char - scan next character from input text file.
  233.79 +--
  233.80 +-- This routine scans a next ASCII character from the input text file.
  233.81 +-- In case of end-of-file, the character is assigned EOF. */
  233.82 +
  233.83 +void get_char(MPL *mpl)
  233.84 +{     int c;
  233.85 +      if (mpl->c == EOF) goto done;
  233.86 +      if (mpl->c == '\n') mpl->line++;
  233.87 +      c = read_char(mpl);
  233.88 +      if (c == EOF)
  233.89 +      {  if (mpl->c == '\n')
  233.90 +            mpl->line--;
  233.91 +         else
  233.92 +            warning(mpl, "final NL missing before end of file");
  233.93 +      }
  233.94 +      else if (c == '\n')
  233.95 +         ;
  233.96 +      else if (isspace(c))
  233.97 +         c = ' ';
  233.98 +      else if (iscntrl(c))
  233.99 +      {  enter_context(mpl);
 233.100 +         error(mpl, "control character 0x%02X not allowed", c);
 233.101 +      }
 233.102 +      mpl->c = c;
 233.103 +done: return;
 233.104 +}
 233.105 +
 233.106 +/*----------------------------------------------------------------------
 233.107 +-- append_char - append character to current token.
 233.108 +--
 233.109 +-- This routine appends the current character to the current token and
 233.110 +-- then scans a next character. */
 233.111 +
 233.112 +void append_char(MPL *mpl)
 233.113 +{     xassert(0 <= mpl->imlen && mpl->imlen <= MAX_LENGTH);
 233.114 +      if (mpl->imlen == MAX_LENGTH)
 233.115 +      {  switch (mpl->token)
 233.116 +         {  case T_NAME:
 233.117 +               enter_context(mpl);
 233.118 +               error(mpl, "symbolic name %s... too long", mpl->image);
 233.119 +            case T_SYMBOL:
 233.120 +               enter_context(mpl);
 233.121 +               error(mpl, "symbol %s... too long", mpl->image);
 233.122 +            case T_NUMBER:
 233.123 +               enter_context(mpl);
 233.124 +               error(mpl, "numeric literal %s... too long", mpl->image);
 233.125 +            case T_STRING:
 233.126 +               enter_context(mpl);
 233.127 +               error(mpl, "string literal too long");
 233.128 +            default:
 233.129 +               xassert(mpl != mpl);
 233.130 +         }
 233.131 +      }
 233.132 +      mpl->image[mpl->imlen++] = (char)mpl->c;
 233.133 +      mpl->image[mpl->imlen] = '\0';
 233.134 +      get_char(mpl);
 233.135 +      return;
 233.136 +}
 233.137 +
 233.138 +/*----------------------------------------------------------------------
 233.139 +-- get_token - scan next token from input text file.
 233.140 +--
 233.141 +-- This routine scans a next token from the input text file using the
 233.142 +-- standard finite automation technique. */
 233.143 +
 233.144 +void get_token(MPL *mpl)
 233.145 +{     /* save the current token */
 233.146 +      mpl->b_token = mpl->token;
 233.147 +      mpl->b_imlen = mpl->imlen;
 233.148 +      strcpy(mpl->b_image, mpl->image);
 233.149 +      mpl->b_value = mpl->value;
 233.150 +      /* if the next token is already scanned, make it current */
 233.151 +      if (mpl->f_scan)
 233.152 +      {  mpl->f_scan = 0;
 233.153 +         mpl->token = mpl->f_token;
 233.154 +         mpl->imlen = mpl->f_imlen;
 233.155 +         strcpy(mpl->image, mpl->f_image);
 233.156 +         mpl->value = mpl->f_value;
 233.157 +         goto done;
 233.158 +      }
 233.159 +loop: /* nothing has been scanned so far */
 233.160 +      mpl->token = 0;
 233.161 +      mpl->imlen = 0;
 233.162 +      mpl->image[0] = '\0';
 233.163 +      mpl->value = 0.0;
 233.164 +      /* skip any uninteresting characters */
 233.165 +      while (mpl->c == ' ' || mpl->c == '\n') get_char(mpl);
 233.166 +      /* recognize and construct the token */
 233.167 +      if (mpl->c == EOF)
 233.168 +      {  /* end-of-file reached */
 233.169 +         mpl->token = T_EOF;
 233.170 +      }
 233.171 +      else if (mpl->c == '#')
 233.172 +      {  /* comment; skip anything until end-of-line */
 233.173 +         while (mpl->c != '\n' && mpl->c != EOF) get_char(mpl);
 233.174 +         goto loop;
 233.175 +      }
 233.176 +      else if (!mpl->flag_d && (isalpha(mpl->c) || mpl->c == '_'))
 233.177 +      {  /* symbolic name or reserved keyword */
 233.178 +         mpl->token = T_NAME;
 233.179 +         while (isalnum(mpl->c) || mpl->c == '_') append_char(mpl);
 233.180 +         if (strcmp(mpl->image, "and") == 0)
 233.181 +            mpl->token = T_AND;
 233.182 +         else if (strcmp(mpl->image, "by") == 0)
 233.183 +            mpl->token = T_BY;
 233.184 +         else if (strcmp(mpl->image, "cross") == 0)
 233.185 +            mpl->token = T_CROSS;
 233.186 +         else if (strcmp(mpl->image, "diff") == 0)
 233.187 +            mpl->token = T_DIFF;
 233.188 +         else if (strcmp(mpl->image, "div") == 0)
 233.189 +            mpl->token = T_DIV;
 233.190 +         else if (strcmp(mpl->image, "else") == 0)
 233.191 +            mpl->token = T_ELSE;
 233.192 +         else if (strcmp(mpl->image, "if") == 0)
 233.193 +            mpl->token = T_IF;
 233.194 +         else if (strcmp(mpl->image, "in") == 0)
 233.195 +            mpl->token = T_IN;
 233.196 +#if 1 /* 21/VII-2006 */
 233.197 +         else if (strcmp(mpl->image, "Infinity") == 0)
 233.198 +            mpl->token = T_INFINITY;
 233.199 +#endif
 233.200 +         else if (strcmp(mpl->image, "inter") == 0)
 233.201 +            mpl->token = T_INTER;
 233.202 +         else if (strcmp(mpl->image, "less") == 0)
 233.203 +            mpl->token = T_LESS;
 233.204 +         else if (strcmp(mpl->image, "mod") == 0)
 233.205 +            mpl->token = T_MOD;
 233.206 +         else if (strcmp(mpl->image, "not") == 0)
 233.207 +            mpl->token = T_NOT;
 233.208 +         else if (strcmp(mpl->image, "or") == 0)
 233.209 +            mpl->token = T_OR;
 233.210 +         else if (strcmp(mpl->image, "s") == 0 && mpl->c == '.')
 233.211 +         {  mpl->token = T_SPTP;
 233.212 +            append_char(mpl);
 233.213 +            if (mpl->c != 't')
 233.214 +sptp:       {  enter_context(mpl);
 233.215 +               error(mpl, "keyword s.t. incomplete");
 233.216 +            }
 233.217 +            append_char(mpl);
 233.218 +            if (mpl->c != '.') goto sptp;
 233.219 +            append_char(mpl);
 233.220 +         }
 233.221 +         else if (strcmp(mpl->image, "symdiff") == 0)
 233.222 +            mpl->token = T_SYMDIFF;
 233.223 +         else if (strcmp(mpl->image, "then") == 0)
 233.224 +            mpl->token = T_THEN;
 233.225 +         else if (strcmp(mpl->image, "union") == 0)
 233.226 +            mpl->token = T_UNION;
 233.227 +         else if (strcmp(mpl->image, "within") == 0)
 233.228 +            mpl->token = T_WITHIN;
 233.229 +      }
 233.230 +      else if (!mpl->flag_d && isdigit(mpl->c))
 233.231 +      {  /* numeric literal */
 233.232 +         mpl->token = T_NUMBER;
 233.233 +         /* scan integer part */
 233.234 +         while (isdigit(mpl->c)) append_char(mpl);
 233.235 +         /* scan optional fractional part */
 233.236 +         if (mpl->c == '.')
 233.237 +         {  append_char(mpl);
 233.238 +            if (mpl->c == '.')
 233.239 +            {  /* hmm, it is not the fractional part, it is dots that
 233.240 +                  follow the integer part */
 233.241 +               mpl->imlen--;
 233.242 +               mpl->image[mpl->imlen] = '\0';
 233.243 +               mpl->f_dots = 1;
 233.244 +               goto conv;
 233.245 +            }
 233.246 +frac:       while (isdigit(mpl->c)) append_char(mpl);
 233.247 +         }
 233.248 +         /* scan optional decimal exponent */
 233.249 +         if (mpl->c == 'e' || mpl->c == 'E')
 233.250 +         {  append_char(mpl);
 233.251 +            if (mpl->c == '+' || mpl->c == '-') append_char(mpl);
 233.252 +            if (!isdigit(mpl->c))
 233.253 +            {  enter_context(mpl);
 233.254 +               error(mpl, "numeric literal %s incomplete", mpl->image);
 233.255 +            }
 233.256 +            while (isdigit(mpl->c)) append_char(mpl);
 233.257 +         }
 233.258 +         /* there must be no letter following the numeric literal */
 233.259 +         if (isalpha(mpl->c) || mpl->c == '_')
 233.260 +         {  enter_context(mpl);
 233.261 +            error(mpl, "symbol %s%c... should be enclosed in quotes",
 233.262 +               mpl->image, mpl->c);
 233.263 +         }
 233.264 +conv:    /* convert numeric literal to floating-point */
 233.265 +         if (str2num(mpl->image, &mpl->value))
 233.266 +err:     {  enter_context(mpl);
 233.267 +            error(mpl, "cannot convert numeric literal %s to floating-p"
 233.268 +               "oint number", mpl->image);
 233.269 +         }
 233.270 +      }
 233.271 +      else if (mpl->c == '\'' || mpl->c == '"')
 233.272 +      {  /* character string */
 233.273 +         int quote = mpl->c;
 233.274 +         mpl->token = T_STRING;
 233.275 +         get_char(mpl);
 233.276 +         for (;;)
 233.277 +         {  if (mpl->c == '\n' || mpl->c == EOF)
 233.278 +            {  enter_context(mpl);
 233.279 +               error(mpl, "unexpected end of line; string literal incom"
 233.280 +                  "plete");
 233.281 +            }
 233.282 +            if (mpl->c == quote)
 233.283 +            {  get_char(mpl);
 233.284 +               if (mpl->c != quote) break;
 233.285 +            }
 233.286 +            append_char(mpl);
 233.287 +         }
 233.288 +      }
 233.289 +      else if (!mpl->flag_d && mpl->c == '+')
 233.290 +         mpl->token = T_PLUS, append_char(mpl);
 233.291 +      else if (!mpl->flag_d && mpl->c == '-')
 233.292 +         mpl->token = T_MINUS, append_char(mpl);
 233.293 +      else if (mpl->c == '*')
 233.294 +      {  mpl->token = T_ASTERISK, append_char(mpl);
 233.295 +         if (mpl->c == '*')
 233.296 +            mpl->token = T_POWER, append_char(mpl);
 233.297 +      }
 233.298 +      else if (mpl->c == '/')
 233.299 +      {  mpl->token = T_SLASH, append_char(mpl);
 233.300 +         if (mpl->c == '*')
 233.301 +         {  /* comment sequence */
 233.302 +            get_char(mpl);
 233.303 +            for (;;)
 233.304 +            {  if (mpl->c == EOF)
 233.305 +               {  /* do not call enter_context at this point */
 233.306 +                  error(mpl, "unexpected end of file; comment sequence "
 233.307 +                     "incomplete");
 233.308 +               }
 233.309 +               else if (mpl->c == '*')
 233.310 +               {  get_char(mpl);
 233.311 +                  if (mpl->c == '/') break;
 233.312 +               }
 233.313 +               else
 233.314 +                  get_char(mpl);
 233.315 +            }
 233.316 +            get_char(mpl);
 233.317 +            goto loop;
 233.318 +         }
 233.319 +      }
 233.320 +      else if (mpl->c == '^')
 233.321 +         mpl->token = T_POWER, append_char(mpl);
 233.322 +      else if (mpl->c == '<')
 233.323 +      {  mpl->token = T_LT, append_char(mpl);
 233.324 +         if (mpl->c == '=')
 233.325 +            mpl->token = T_LE, append_char(mpl);
 233.326 +         else if (mpl->c == '>')
 233.327 +            mpl->token = T_NE, append_char(mpl);
 233.328 +#if 1 /* 11/II-2008 */
 233.329 +         else if (mpl->c == '-')
 233.330 +            mpl->token = T_INPUT, append_char(mpl);
 233.331 +#endif
 233.332 +      }
 233.333 +      else if (mpl->c == '=')
 233.334 +      {  mpl->token = T_EQ, append_char(mpl);
 233.335 +         if (mpl->c == '=') append_char(mpl);
 233.336 +      }
 233.337 +      else if (mpl->c == '>')
 233.338 +      {  mpl->token = T_GT, append_char(mpl);
 233.339 +         if (mpl->c == '=')
 233.340 +            mpl->token = T_GE, append_char(mpl);
 233.341 +#if 1 /* 14/VII-2006 */
 233.342 +         else if (mpl->c == '>')
 233.343 +            mpl->token = T_APPEND, append_char(mpl);
 233.344 +#endif
 233.345 +      }
 233.346 +      else if (mpl->c == '!')
 233.347 +      {  mpl->token = T_NOT, append_char(mpl);
 233.348 +         if (mpl->c == '=')
 233.349 +            mpl->token = T_NE, append_char(mpl);
 233.350 +      }
 233.351 +      else if (mpl->c == '&')
 233.352 +      {  mpl->token = T_CONCAT, append_char(mpl);
 233.353 +         if (mpl->c == '&')
 233.354 +            mpl->token = T_AND, append_char(mpl);
 233.355 +      }
 233.356 +      else if (mpl->c == '|')
 233.357 +      {  mpl->token = T_BAR, append_char(mpl);
 233.358 +         if (mpl->c == '|')
 233.359 +            mpl->token = T_OR, append_char(mpl);
 233.360 +      }
 233.361 +      else if (!mpl->flag_d && mpl->c == '.')
 233.362 +      {  mpl->token = T_POINT, append_char(mpl);
 233.363 +         if (mpl->f_dots)
 233.364 +         {  /* dots; the first dot was read on the previous call to the
 233.365 +               scanner, so the current character is the second dot */
 233.366 +            mpl->token = T_DOTS;
 233.367 +            mpl->imlen = 2;
 233.368 +            strcpy(mpl->image, "..");
 233.369 +            mpl->f_dots = 0;
 233.370 +         }
 233.371 +         else if (mpl->c == '.')
 233.372 +            mpl->token = T_DOTS, append_char(mpl);
 233.373 +         else if (isdigit(mpl->c))
 233.374 +         {  /* numeric literal that begins with the decimal point */
 233.375 +            mpl->token = T_NUMBER, append_char(mpl);
 233.376 +            goto frac;
 233.377 +         }
 233.378 +      }
 233.379 +      else if (mpl->c == ',')
 233.380 +         mpl->token = T_COMMA, append_char(mpl);
 233.381 +      else if (mpl->c == ':')
 233.382 +      {  mpl->token = T_COLON, append_char(mpl);
 233.383 +         if (mpl->c == '=')
 233.384 +            mpl->token = T_ASSIGN, append_char(mpl);
 233.385 +      }
 233.386 +      else if (mpl->c == ';')
 233.387 +         mpl->token = T_SEMICOLON, append_char(mpl);
 233.388 +      else if (mpl->c == '(')
 233.389 +         mpl->token = T_LEFT, append_char(mpl);
 233.390 +      else if (mpl->c == ')')
 233.391 +         mpl->token = T_RIGHT, append_char(mpl);
 233.392 +      else if (mpl->c == '[')
 233.393 +         mpl->token = T_LBRACKET, append_char(mpl);
 233.394 +      else if (mpl->c == ']')
 233.395 +         mpl->token = T_RBRACKET, append_char(mpl);
 233.396 +      else if (mpl->c == '{')
 233.397 +         mpl->token = T_LBRACE, append_char(mpl);
 233.398 +      else if (mpl->c == '}')
 233.399 +         mpl->token = T_RBRACE, append_char(mpl);
 233.400 +#if 1 /* 11/II-2008 */
 233.401 +      else if (mpl->c == '~')
 233.402 +         mpl->token = T_TILDE, append_char(mpl);
 233.403 +#endif
 233.404 +      else if (isalnum(mpl->c) || strchr("+-._", mpl->c) != NULL)
 233.405 +      {  /* symbol */
 233.406 +         xassert(mpl->flag_d);
 233.407 +         mpl->token = T_SYMBOL;
 233.408 +         while (isalnum(mpl->c) || strchr("+-._", mpl->c) != NULL)
 233.409 +            append_char(mpl);
 233.410 +         switch (str2num(mpl->image, &mpl->value))
 233.411 +         {  case 0:
 233.412 +               mpl->token = T_NUMBER;
 233.413 +               break;
 233.414 +            case 1:
 233.415 +               goto err;
 233.416 +            case 2:
 233.417 +               break;
 233.418 +            default:
 233.419 +               xassert(mpl != mpl);
 233.420 +         }
 233.421 +      }
 233.422 +      else
 233.423 +      {  enter_context(mpl);
 233.424 +         error(mpl, "character %c not allowed", mpl->c);
 233.425 +      }
 233.426 +      /* enter the current token into the context queue */
 233.427 +      enter_context(mpl);
 233.428 +      /* reset the flag, which may be set by indexing_expression() and
 233.429 +         is used by expression_list() */
 233.430 +      mpl->flag_x = 0;
 233.431 +done: return;
 233.432 +}
 233.433 +
 233.434 +/*----------------------------------------------------------------------
 233.435 +-- unget_token - return current token back to input stream.
 233.436 +--
 233.437 +-- This routine returns the current token back to the input stream, so
 233.438 +-- the previously scanned token becomes the current one. */
 233.439 +
 233.440 +void unget_token(MPL *mpl)
 233.441 +{     /* save the current token, which becomes the next one */
 233.442 +      xassert(!mpl->f_scan);
 233.443 +      mpl->f_scan = 1;
 233.444 +      mpl->f_token = mpl->token;
 233.445 +      mpl->f_imlen = mpl->imlen;
 233.446 +      strcpy(mpl->f_image, mpl->image);
 233.447 +      mpl->f_value = mpl->value;
 233.448 +      /* restore the previous token, which becomes the current one */
 233.449 +      mpl->token = mpl->b_token;
 233.450 +      mpl->imlen = mpl->b_imlen;
 233.451 +      strcpy(mpl->image, mpl->b_image);
 233.452 +      mpl->value = mpl->b_value;
 233.453 +      return;
 233.454 +}
 233.455 +
 233.456 +/*----------------------------------------------------------------------
 233.457 +-- is_keyword - check if current token is given non-reserved keyword.
 233.458 +--
 233.459 +-- If the current token is given (non-reserved) keyword, this routine
 233.460 +-- returns non-zero. Otherwise zero is returned. */
 233.461 +
 233.462 +int is_keyword(MPL *mpl, char *keyword)
 233.463 +{     return
 233.464 +         mpl->token == T_NAME && strcmp(mpl->image, keyword) == 0;
 233.465 +}
 233.466 +
 233.467 +/*----------------------------------------------------------------------
 233.468 +-- is_reserved - check if current token is reserved keyword.
 233.469 +--
 233.470 +-- If the current token is a reserved keyword, this routine returns
 233.471 +-- non-zero. Otherwise zero is returned. */
 233.472 +
 233.473 +int is_reserved(MPL *mpl)
 233.474 +{     return
 233.475 +         mpl->token == T_AND && mpl->image[0] == 'a' ||
 233.476 +         mpl->token == T_BY ||
 233.477 +         mpl->token == T_CROSS ||
 233.478 +         mpl->token == T_DIFF ||
 233.479 +         mpl->token == T_DIV ||
 233.480 +         mpl->token == T_ELSE ||
 233.481 +         mpl->token == T_IF ||
 233.482 +         mpl->token == T_IN ||
 233.483 +         mpl->token == T_INTER ||
 233.484 +         mpl->token == T_LESS ||
 233.485 +         mpl->token == T_MOD ||
 233.486 +         mpl->token == T_NOT && mpl->image[0] == 'n' ||
 233.487 +         mpl->token == T_OR && mpl->image[0] == 'o' ||
 233.488 +         mpl->token == T_SYMDIFF ||
 233.489 +         mpl->token == T_THEN ||
 233.490 +         mpl->token == T_UNION ||
 233.491 +         mpl->token == T_WITHIN;
 233.492 +}
 233.493 +
 233.494 +/*----------------------------------------------------------------------
 233.495 +-- make_code - generate pseudo-code (basic routine).
 233.496 +--
 233.497 +-- This routine generates specified pseudo-code. It is assumed that all
 233.498 +-- other translator routines use this basic routine. */
 233.499 +
 233.500 +CODE *make_code(MPL *mpl, int op, OPERANDS *arg, int type, int dim)
 233.501 +{     CODE *code;
 233.502 +      DOMAIN *domain;
 233.503 +      DOMAIN_BLOCK *block;
 233.504 +      ARG_LIST *e;
 233.505 +      /* generate pseudo-code */
 233.506 +      code = alloc(CODE);
 233.507 +      code->op = op;
 233.508 +      code->vflag = 0; /* is inherited from operand(s) */
 233.509 +      /* copy operands and also make them referring to the pseudo-code
 233.510 +         being generated, because the latter becomes the parent for all
 233.511 +         its operands */
 233.512 +      memset(&code->arg, '?', sizeof(OPERANDS));
 233.513 +      switch (op)
 233.514 +      {  case O_NUMBER:
 233.515 +            code->arg.num = arg->num;
 233.516 +            break;
 233.517 +         case O_STRING:
 233.518 +            code->arg.str = arg->str;
 233.519 +            break;
 233.520 +         case O_INDEX:
 233.521 +            code->arg.index.slot = arg->index.slot;
 233.522 +            code->arg.index.next = arg->index.next;
 233.523 +            break;
 233.524 +         case O_MEMNUM:
 233.525 +         case O_MEMSYM:
 233.526 +            for (e = arg->par.list; e != NULL; e = e->next)
 233.527 +            {  xassert(e->x != NULL);
 233.528 +               xassert(e->x->up == NULL);
 233.529 +               e->x->up = code;
 233.530 +               code->vflag |= e->x->vflag;
 233.531 +            }
 233.532 +            code->arg.par.par = arg->par.par;
 233.533 +            code->arg.par.list = arg->par.list;
 233.534 +            break;
 233.535 +         case O_MEMSET:
 233.536 +            for (e = arg->set.list; e != NULL; e = e->next)
 233.537 +            {  xassert(e->x != NULL);
 233.538 +               xassert(e->x->up == NULL);
 233.539 +               e->x->up = code;
 233.540 +               code->vflag |= e->x->vflag;
 233.541 +            }
 233.542 +            code->arg.set.set = arg->set.set;
 233.543 +            code->arg.set.list = arg->set.list;
 233.544 +            break;
 233.545 +         case O_MEMVAR:
 233.546 +            for (e = arg->var.list; e != NULL; e = e->next)
 233.547 +            {  xassert(e->x != NULL);
 233.548 +               xassert(e->x->up == NULL);
 233.549 +               e->x->up = code;
 233.550 +               code->vflag |= e->x->vflag;
 233.551 +            }
 233.552 +            code->arg.var.var = arg->var.var;
 233.553 +            code->arg.var.list = arg->var.list;
 233.554 +#if 1 /* 15/V-2010 */
 233.555 +            code->arg.var.suff = arg->var.suff;
 233.556 +#endif
 233.557 +            break;
 233.558 +#if 1 /* 15/V-2010 */
 233.559 +         case O_MEMCON:
 233.560 +            for (e = arg->con.list; e != NULL; e = e->next)
 233.561 +            {  xassert(e->x != NULL);
 233.562 +               xassert(e->x->up == NULL);
 233.563 +               e->x->up = code;
 233.564 +               code->vflag |= e->x->vflag;
 233.565 +            }
 233.566 +            code->arg.con.con = arg->con.con;
 233.567 +            code->arg.con.list = arg->con.list;
 233.568 +            code->arg.con.suff = arg->con.suff;
 233.569 +            break;
 233.570 +#endif
 233.571 +         case O_TUPLE:
 233.572 +         case O_MAKE:
 233.573 +            for (e = arg->list; e != NULL; e = e->next)
 233.574 +            {  xassert(e->x != NULL);
 233.575 +               xassert(e->x->up == NULL);
 233.576 +               e->x->up = code;
 233.577 +               code->vflag |= e->x->vflag;
 233.578 +            }
 233.579 +            code->arg.list = arg->list;
 233.580 +            break;
 233.581 +         case O_SLICE:
 233.582 +            xassert(arg->slice != NULL);
 233.583 +            code->arg.slice = arg->slice;
 233.584 +            break;
 233.585 +         case O_IRAND224:
 233.586 +         case O_UNIFORM01:
 233.587 +         case O_NORMAL01:
 233.588 +         case O_GMTIME:
 233.589 +            code->vflag = 1;
 233.590 +            break;
 233.591 +         case O_CVTNUM:
 233.592 +         case O_CVTSYM:
 233.593 +         case O_CVTLOG:
 233.594 +         case O_CVTTUP:
 233.595 +         case O_CVTLFM:
 233.596 +         case O_PLUS:
 233.597 +         case O_MINUS:
 233.598 +         case O_NOT:
 233.599 +         case O_ABS:
 233.600 +         case O_CEIL:
 233.601 +         case O_FLOOR:
 233.602 +         case O_EXP:
 233.603 +         case O_LOG:
 233.604 +         case O_LOG10:
 233.605 +         case O_SQRT:
 233.606 +         case O_SIN:
 233.607 +         case O_COS:
 233.608 +         case O_ATAN:
 233.609 +         case O_ROUND:
 233.610 +         case O_TRUNC:
 233.611 +         case O_CARD:
 233.612 +         case O_LENGTH:
 233.613 +            /* unary operation */
 233.614 +            xassert(arg->arg.x != NULL);
 233.615 +            xassert(arg->arg.x->up == NULL);
 233.616 +            arg->arg.x->up = code;
 233.617 +            code->vflag |= arg->arg.x->vflag;
 233.618 +            code->arg.arg.x = arg->arg.x;
 233.619 +            break;
 233.620 +         case O_ADD:
 233.621 +         case O_SUB:
 233.622 +         case O_LESS:
 233.623 +         case O_MUL:
 233.624 +         case O_DIV:
 233.625 +         case O_IDIV:
 233.626 +         case O_MOD:
 233.627 +         case O_POWER:
 233.628 +         case O_ATAN2:
 233.629 +         case O_ROUND2:
 233.630 +         case O_TRUNC2:
 233.631 +         case O_UNIFORM:
 233.632 +            if (op == O_UNIFORM) code->vflag = 1;
 233.633 +         case O_NORMAL:
 233.634 +            if (op == O_NORMAL) code->vflag = 1;
 233.635 +         case O_CONCAT:
 233.636 +         case O_LT:
 233.637 +         case O_LE:
 233.638 +         case O_EQ:
 233.639 +         case O_GE:
 233.640 +         case O_GT:
 233.641 +         case O_NE:
 233.642 +         case O_AND:
 233.643 +         case O_OR:
 233.644 +         case O_UNION:
 233.645 +         case O_DIFF:
 233.646 +         case O_SYMDIFF:
 233.647 +         case O_INTER:
 233.648 +         case O_CROSS:
 233.649 +         case O_IN:
 233.650 +         case O_NOTIN:
 233.651 +         case O_WITHIN:
 233.652 +         case O_NOTWITHIN:
 233.653 +         case O_SUBSTR:
 233.654 +         case O_STR2TIME:
 233.655 +         case O_TIME2STR:
 233.656 +            /* binary operation */
 233.657 +            xassert(arg->arg.x != NULL);
 233.658 +            xassert(arg->arg.x->up == NULL);
 233.659 +            arg->arg.x->up = code;
 233.660 +            code->vflag |= arg->arg.x->vflag;
 233.661 +            xassert(arg->arg.y != NULL);
 233.662 +            xassert(arg->arg.y->up == NULL);
 233.663 +            arg->arg.y->up = code;
 233.664 +            code->vflag |= arg->arg.y->vflag;
 233.665 +            code->arg.arg.x = arg->arg.x;
 233.666 +            code->arg.arg.y = arg->arg.y;
 233.667 +            break;
 233.668 +         case O_DOTS:
 233.669 +         case O_FORK:
 233.670 +         case O_SUBSTR3:
 233.671 +            /* ternary operation */
 233.672 +            xassert(arg->arg.x != NULL);
 233.673 +            xassert(arg->arg.x->up == NULL);
 233.674 +            arg->arg.x->up = code;
 233.675 +            code->vflag |= arg->arg.x->vflag;
 233.676 +            xassert(arg->arg.y != NULL);
 233.677 +            xassert(arg->arg.y->up == NULL);
 233.678 +            arg->arg.y->up = code;
 233.679 +            code->vflag |= arg->arg.y->vflag;
 233.680 +            if (arg->arg.z != NULL)
 233.681 +            {  xassert(arg->arg.z->up == NULL);
 233.682 +               arg->arg.z->up = code;
 233.683 +               code->vflag |= arg->arg.z->vflag;
 233.684 +            }
 233.685 +            code->arg.arg.x = arg->arg.x;
 233.686 +            code->arg.arg.y = arg->arg.y;
 233.687 +            code->arg.arg.z = arg->arg.z;
 233.688 +            break;
 233.689 +         case O_MIN:
 233.690 +         case O_MAX:
 233.691 +            /* n-ary operation */
 233.692 +            for (e = arg->list; e != NULL; e = e->next)
 233.693 +            {  xassert(e->x != NULL);
 233.694 +               xassert(e->x->up == NULL);
 233.695 +               e->x->up = code;
 233.696 +               code->vflag |= e->x->vflag;
 233.697 +            }
 233.698 +            code->arg.list = arg->list;
 233.699 +            break;
 233.700 +         case O_SUM:
 233.701 +         case O_PROD:
 233.702 +         case O_MINIMUM:
 233.703 +         case O_MAXIMUM:
 233.704 +         case O_FORALL:
 233.705 +         case O_EXISTS:
 233.706 +         case O_SETOF:
 233.707 +         case O_BUILD:
 233.708 +            /* iterated operation */
 233.709 +            domain = arg->loop.domain;
 233.710 +            xassert(domain != NULL);
 233.711 +            if (domain->code != NULL)
 233.712 +            {  xassert(domain->code->up == NULL);
 233.713 +               domain->code->up = code;
 233.714 +               code->vflag |= domain->code->vflag;
 233.715 +            }
 233.716 +            for (block = domain->list; block != NULL; block =
 233.717 +               block->next)
 233.718 +            {  xassert(block->code != NULL);
 233.719 +               xassert(block->code->up == NULL);
 233.720 +               block->code->up = code;
 233.721 +               code->vflag |= block->code->vflag;
 233.722 +            }
 233.723 +            if (arg->loop.x != NULL)
 233.724 +            {  xassert(arg->loop.x->up == NULL);
 233.725 +               arg->loop.x->up = code;
 233.726 +               code->vflag |= arg->loop.x->vflag;
 233.727 +            }
 233.728 +            code->arg.loop.domain = arg->loop.domain;
 233.729 +            code->arg.loop.x = arg->loop.x;
 233.730 +            break;
 233.731 +         default:
 233.732 +            xassert(op != op);
 233.733 +      }
 233.734 +      /* set other attributes of the pseudo-code */
 233.735 +      code->type = type;
 233.736 +      code->dim = dim;
 233.737 +      code->up = NULL;
 233.738 +      code->valid = 0;
 233.739 +      memset(&code->value, '?', sizeof(VALUE));
 233.740 +      return code;
 233.741 +}
 233.742 +
 233.743 +/*----------------------------------------------------------------------
 233.744 +-- make_unary - generate pseudo-code for unary operation.
 233.745 +--
 233.746 +-- This routine generates pseudo-code for unary operation. */
 233.747 +
 233.748 +CODE *make_unary(MPL *mpl, int op, CODE *x, int type, int dim)
 233.749 +{     CODE *code;
 233.750 +      OPERANDS arg;
 233.751 +      xassert(x != NULL);
 233.752 +      arg.arg.x = x;
 233.753 +      code = make_code(mpl, op, &arg, type, dim);
 233.754 +      return code;
 233.755 +}
 233.756 +
 233.757 +/*----------------------------------------------------------------------
 233.758 +-- make_binary - generate pseudo-code for binary operation.
 233.759 +--
 233.760 +-- This routine generates pseudo-code for binary operation. */
 233.761 +
 233.762 +CODE *make_binary(MPL *mpl, int op, CODE *x, CODE *y, int type,
 233.763 +      int dim)
 233.764 +{     CODE *code;
 233.765 +      OPERANDS arg;
 233.766 +      xassert(x != NULL);
 233.767 +      xassert(y != NULL);
 233.768 +      arg.arg.x = x;
 233.769 +      arg.arg.y = y;
 233.770 +      code = make_code(mpl, op, &arg, type, dim);
 233.771 +      return code;
 233.772 +}
 233.773 +
 233.774 +/*----------------------------------------------------------------------
 233.775 +-- make_ternary - generate pseudo-code for ternary operation.
 233.776 +--
 233.777 +-- This routine generates pseudo-code for ternary operation. */
 233.778 +
 233.779 +CODE *make_ternary(MPL *mpl, int op, CODE *x, CODE *y, CODE *z,
 233.780 +      int type, int dim)
 233.781 +{     CODE *code;
 233.782 +      OPERANDS arg;
 233.783 +      xassert(x != NULL);
 233.784 +      xassert(y != NULL);
 233.785 +      /* third operand can be NULL */
 233.786 +      arg.arg.x = x;
 233.787 +      arg.arg.y = y;
 233.788 +      arg.arg.z = z;
 233.789 +      code = make_code(mpl, op, &arg, type, dim);
 233.790 +      return code;
 233.791 +}
 233.792 +
 233.793 +/*----------------------------------------------------------------------
 233.794 +-- numeric_literal - parse reference to numeric literal.
 233.795 +--
 233.796 +-- This routine parses primary expression using the syntax:
 233.797 +--
 233.798 +-- <primary expression> ::= <numeric literal> */
 233.799 +
 233.800 +CODE *numeric_literal(MPL *mpl)
 233.801 +{     CODE *code;
 233.802 +      OPERANDS arg;
 233.803 +      xassert(mpl->token == T_NUMBER);
 233.804 +      arg.num = mpl->value;
 233.805 +      code = make_code(mpl, O_NUMBER, &arg, A_NUMERIC, 0);
 233.806 +      get_token(mpl /* <numeric literal> */);
 233.807 +      return code;
 233.808 +}
 233.809 +
 233.810 +/*----------------------------------------------------------------------
 233.811 +-- string_literal - parse reference to string literal.
 233.812 +--
 233.813 +-- This routine parses primary expression using the syntax:
 233.814 +--
 233.815 +-- <primary expression> ::= <string literal> */
 233.816 +
 233.817 +CODE *string_literal(MPL *mpl)
 233.818 +{     CODE *code;
 233.819 +      OPERANDS arg;
 233.820 +      xassert(mpl->token == T_STRING);
 233.821 +      arg.str = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
 233.822 +      strcpy(arg.str, mpl->image);
 233.823 +      code = make_code(mpl, O_STRING, &arg, A_SYMBOLIC, 0);
 233.824 +      get_token(mpl /* <string literal> */);
 233.825 +      return code;
 233.826 +}
 233.827 +
 233.828 +/*----------------------------------------------------------------------
 233.829 +-- create_arg_list - create empty operands list.
 233.830 +--
 233.831 +-- This routine creates operands list, which is initially empty. */
 233.832 +
 233.833 +ARG_LIST *create_arg_list(MPL *mpl)
 233.834 +{     ARG_LIST *list;
 233.835 +      xassert(mpl == mpl);
 233.836 +      list = NULL;
 233.837 +      return list;
 233.838 +}
 233.839 +
 233.840 +/*----------------------------------------------------------------------
 233.841 +-- expand_arg_list - append operand to operands list.
 233.842 +--
 233.843 +-- This routine appends new operand to specified operands list. */
 233.844 +
 233.845 +ARG_LIST *expand_arg_list(MPL *mpl, ARG_LIST *list, CODE *x)
 233.846 +{     ARG_LIST *tail, *temp;
 233.847 +      xassert(x != NULL);
 233.848 +      /* create new operands list entry */
 233.849 +      tail = alloc(ARG_LIST);
 233.850 +      tail->x = x;
 233.851 +      tail->next = NULL;
 233.852 +      /* and append it to the operands list */
 233.853 +      if (list == NULL)
 233.854 +         list = tail;
 233.855 +      else
 233.856 +      {  for (temp = list; temp->next != NULL; temp = temp->next);
 233.857 +         temp->next = tail;
 233.858 +      }
 233.859 +      return list;
 233.860 +}
 233.861 +
 233.862 +/*----------------------------------------------------------------------
 233.863 +-- arg_list_len - determine length of operands list.
 233.864 +--
 233.865 +-- This routine returns the number of operands in operands list. */
 233.866 +
 233.867 +int arg_list_len(MPL *mpl, ARG_LIST *list)
 233.868 +{     ARG_LIST *temp;
 233.869 +      int len;
 233.870 +      xassert(mpl == mpl);
 233.871 +      len = 0;
 233.872 +      for (temp = list; temp != NULL; temp = temp->next) len++;
 233.873 +      return len;
 233.874 +}
 233.875 +
 233.876 +/*----------------------------------------------------------------------
 233.877 +-- subscript_list - parse subscript list.
 233.878 +--
 233.879 +-- This routine parses subscript list using the syntax:
 233.880 +--
 233.881 +-- <subscript list> ::= <subscript>
 233.882 +-- <subscript list> ::= <subscript list> , <subscript>
 233.883 +-- <subscript> ::= <expression 5> */
 233.884 +
 233.885 +ARG_LIST *subscript_list(MPL *mpl)
 233.886 +{     ARG_LIST *list;
 233.887 +      CODE *x;
 233.888 +      list = create_arg_list(mpl);
 233.889 +      for (;;)
 233.890 +      {  /* parse subscript expression */
 233.891 +         x = expression_5(mpl);
 233.892 +         /* convert it to symbolic type, if necessary */
 233.893 +         if (x->type == A_NUMERIC)
 233.894 +            x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
 233.895 +         /* check that now the expression is of symbolic type */
 233.896 +         if (x->type != A_SYMBOLIC)
 233.897 +            error(mpl, "subscript expression has invalid type");
 233.898 +         xassert(x->dim == 0);
 233.899 +         /* and append it to the subscript list */
 233.900 +         list = expand_arg_list(mpl, list, x);
 233.901 +         /* check a token that follows the subscript expression */
 233.902 +         if (mpl->token == T_COMMA)
 233.903 +            get_token(mpl /* , */);
 233.904 +         else if (mpl->token == T_RBRACKET)
 233.905 +            break;
 233.906 +         else
 233.907 +            error(mpl, "syntax error in subscript list");
 233.908 +      }
 233.909 +      return list;
 233.910 +}
 233.911 +
 233.912 +#if 1 /* 15/V-2010 */
 233.913 +/*----------------------------------------------------------------------
 233.914 +-- object_reference - parse reference to named object.
 233.915 +--
 233.916 +-- This routine parses primary expression using the syntax:
 233.917 +--
 233.918 +-- <primary expression> ::= <dummy index>
 233.919 +-- <primary expression> ::= <set name>
 233.920 +-- <primary expression> ::= <set name> [ <subscript list> ]
 233.921 +-- <primary expression> ::= <parameter name>
 233.922 +-- <primary expression> ::= <parameter name> [ <subscript list> ]
 233.923 +-- <primary expression> ::= <variable name> <suffix>
 233.924 +-- <primary expression> ::= <variable name> [ <subscript list> ]
 233.925 +--                          <suffix>
 233.926 +-- <primary expression> ::= <constraint name> <suffix>
 233.927 +-- <primary expression> ::= <constraint name> [ <subscript list> ]
 233.928 +--                          <suffix>
 233.929 +-- <dummy index> ::= <symbolic name>
 233.930 +-- <set name> ::= <symbolic name>
 233.931 +-- <parameter name> ::= <symbolic name>
 233.932 +-- <variable name> ::= <symbolic name>
 233.933 +-- <constraint name> ::= <symbolic name>
 233.934 +-- <suffix> ::= <empty> | .lb | .ub | .status | .val | .dual */
 233.935 +
 233.936 +CODE *object_reference(MPL *mpl)
 233.937 +{     AVLNODE *node;
 233.938 +      DOMAIN_SLOT *slot;
 233.939 +      SET *set;
 233.940 +      PARAMETER *par;
 233.941 +      VARIABLE *var;
 233.942 +      CONSTRAINT *con;
 233.943 +      ARG_LIST *list;
 233.944 +      OPERANDS arg;
 233.945 +      CODE *code;
 233.946 +      char *name;
 233.947 +      int dim, suff;
 233.948 +      /* find the object in the symbolic name table */
 233.949 +      xassert(mpl->token == T_NAME);
 233.950 +      node = avl_find_node(mpl->tree, mpl->image);
 233.951 +      if (node == NULL)
 233.952 +         error(mpl, "%s not defined", mpl->image);
 233.953 +      /* check the object type and obtain its dimension */
 233.954 +      switch (avl_get_node_type(node))
 233.955 +      {  case A_INDEX:
 233.956 +            /* dummy index */
 233.957 +            slot = (DOMAIN_SLOT *)avl_get_node_link(node);
 233.958 +            name = slot->name;
 233.959 +            dim = 0;
 233.960 +            break;
 233.961 +         case A_SET:
 233.962 +            /* model set */
 233.963 +            set = (SET *)avl_get_node_link(node);
 233.964 +            name = set->name;
 233.965 +            dim = set->dim;
 233.966 +            /* if a set object is referenced in its own declaration and
 233.967 +               the dimen attribute is not specified yet, use dimen 1 by
 233.968 +               default */
 233.969 +            if (set->dimen == 0) set->dimen = 1;
 233.970 +            break;
 233.971 +         case A_PARAMETER:
 233.972 +            /* model parameter */
 233.973 +            par = (PARAMETER *)avl_get_node_link(node);
 233.974 +            name = par->name;
 233.975 +            dim = par->dim;
 233.976 +            break;
 233.977 +         case A_VARIABLE:
 233.978 +            /* model variable */
 233.979 +            var = (VARIABLE *)avl_get_node_link(node);
 233.980 +            name = var->name;
 233.981 +            dim = var->dim;
 233.982 +            break;
 233.983 +         case A_CONSTRAINT:
 233.984 +            /* model constraint or objective */
 233.985 +            con = (CONSTRAINT *)avl_get_node_link(node);
 233.986 +            name = con->name;
 233.987 +            dim = con->dim;
 233.988 +            break;
 233.989 +         default:
 233.990 +            xassert(node != node);
 233.991 +      }
 233.992 +      get_token(mpl /* <symbolic name> */);
 233.993 +      /* parse optional subscript list */
 233.994 +      if (mpl->token == T_LBRACKET)
 233.995 +      {  /* subscript list is specified */
 233.996 +         if (dim == 0)
 233.997 +            error(mpl, "%s cannot be subscripted", name);
 233.998 +         get_token(mpl /* [ */);
 233.999 +         list = subscript_list(mpl);
233.1000 +         if (dim != arg_list_len(mpl, list))
233.1001 +            error(mpl, "%s must have %d subscript%s rather than %d",
233.1002 +               name, dim, dim == 1 ? "" : "s", arg_list_len(mpl, list));
233.1003 +         xassert(mpl->token == T_RBRACKET);
233.1004 +         get_token(mpl /* ] */);
233.1005 +      }
233.1006 +      else
233.1007 +      {  /* subscript list is not specified */
233.1008 +         if (dim != 0)
233.1009 +            error(mpl, "%s must be subscripted", name);
233.1010 +         list = create_arg_list(mpl);
233.1011 +      }
233.1012 +      /* parse optional suffix */
233.1013 +      if (!mpl->flag_s && avl_get_node_type(node) == A_VARIABLE)
233.1014 +         suff = DOT_NONE;
233.1015 +      else
233.1016 +         suff = DOT_VAL;
233.1017 +      if (mpl->token == T_POINT)
233.1018 +      {  get_token(mpl /* . */);
233.1019 +         if (mpl->token != T_NAME)
233.1020 +            error(mpl, "invalid use of period");
233.1021 +         if (!(avl_get_node_type(node) == A_VARIABLE ||
233.1022 +               avl_get_node_type(node) == A_CONSTRAINT))
233.1023 +            error(mpl, "%s cannot have a suffix", name);
233.1024 +         if (strcmp(mpl->image, "lb") == 0)
233.1025 +            suff = DOT_LB;
233.1026 +         else if (strcmp(mpl->image, "ub") == 0)
233.1027 +            suff = DOT_UB;
233.1028 +         else if (strcmp(mpl->image, "status") == 0)
233.1029 +            suff = DOT_STATUS;
233.1030 +         else if (strcmp(mpl->image, "val") == 0)
233.1031 +            suff = DOT_VAL;
233.1032 +         else if (strcmp(mpl->image, "dual") == 0)
233.1033 +            suff = DOT_DUAL;
233.1034 +         else
233.1035 +            error(mpl, "suffix .%s invalid", mpl->image);
233.1036 +         get_token(mpl /* suffix */);
233.1037 +      }
233.1038 +      /* generate pseudo-code to take value of the object */
233.1039 +      switch (avl_get_node_type(node))
233.1040 +      {  case A_INDEX:
233.1041 +            arg.index.slot = slot;
233.1042 +            arg.index.next = slot->list;
233.1043 +            code = make_code(mpl, O_INDEX, &arg, A_SYMBOLIC, 0);
233.1044 +            slot->list = code;
233.1045 +            break;
233.1046 +         case A_SET:
233.1047 +            arg.set.set = set;
233.1048 +            arg.set.list = list;
233.1049 +            code = make_code(mpl, O_MEMSET, &arg, A_ELEMSET,
233.1050 +               set->dimen);
233.1051 +            break;
233.1052 +         case A_PARAMETER:
233.1053 +            arg.par.par = par;
233.1054 +            arg.par.list = list;
233.1055 +            if (par->type == A_SYMBOLIC)
233.1056 +               code = make_code(mpl, O_MEMSYM, &arg, A_SYMBOLIC, 0);
233.1057 +            else
233.1058 +               code = make_code(mpl, O_MEMNUM, &arg, A_NUMERIC, 0);
233.1059 +            break;
233.1060 +         case A_VARIABLE:
233.1061 +            if (!mpl->flag_s && (suff == DOT_STATUS || suff == DOT_VAL
233.1062 +               || suff == DOT_DUAL))
233.1063 +               error(mpl, "invalid reference to status, primal value, o"
233.1064 +                  "r dual value of variable %s above solve statement",
233.1065 +                  var->name);
233.1066 +            arg.var.var = var;
233.1067 +            arg.var.list = list;
233.1068 +            arg.var.suff = suff;
233.1069 +            code = make_code(mpl, O_MEMVAR, &arg, suff == DOT_NONE ?
233.1070 +               A_FORMULA : A_NUMERIC, 0);
233.1071 +            break;
233.1072 +         case A_CONSTRAINT:
233.1073 +            if (!mpl->flag_s && (suff == DOT_STATUS || suff == DOT_VAL
233.1074 +               || suff == DOT_DUAL))
233.1075 +               error(mpl, "invalid reference to status, primal value, o"
233.1076 +                  "r dual value of %s %s above solve statement",
233.1077 +                  con->type == A_CONSTRAINT ? "constraint" : "objective"
233.1078 +                  , con->name);
233.1079 +            arg.con.con = con;
233.1080 +            arg.con.list = list;
233.1081 +            arg.con.suff = suff;
233.1082 +            code = make_code(mpl, O_MEMCON, &arg, A_NUMERIC, 0);
233.1083 +            break;
233.1084 +         default:
233.1085 +            xassert(node != node);
233.1086 +      }
233.1087 +      return code;
233.1088 +}
233.1089 +#endif
233.1090 +
233.1091 +/*----------------------------------------------------------------------
233.1092 +-- numeric_argument - parse argument passed to built-in function.
233.1093 +--
233.1094 +-- This routine parses an argument passed to numeric built-in function
233.1095 +-- using the syntax:
233.1096 +--
233.1097 +-- <arg> ::= <expression 5> */
233.1098 +
233.1099 +CODE *numeric_argument(MPL *mpl, char *func)
233.1100 +{     CODE *x;
233.1101 +      x = expression_5(mpl);
233.1102 +      /* convert the argument to numeric type, if necessary */
233.1103 +      if (x->type == A_SYMBOLIC)
233.1104 +         x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.1105 +      /* check that now the argument is of numeric type */
233.1106 +      if (x->type != A_NUMERIC)
233.1107 +         error(mpl, "argument for %s has invalid type", func);
233.1108 +      xassert(x->dim == 0);
233.1109 +      return x;
233.1110 +}
233.1111 +
233.1112 +#if 1 /* 15/VII-2006 */
233.1113 +CODE *symbolic_argument(MPL *mpl, char *func)
233.1114 +{     CODE *x;
233.1115 +      x = expression_5(mpl);
233.1116 +      /* convert the argument to symbolic type, if necessary */
233.1117 +      if (x->type == A_NUMERIC)
233.1118 +         x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
233.1119 +      /* check that now the argument is of symbolic type */
233.1120 +      if (x->type != A_SYMBOLIC)
233.1121 +         error(mpl, "argument for %s has invalid type", func);
233.1122 +      xassert(x->dim == 0);
233.1123 +      return x;
233.1124 +}
233.1125 +#endif
233.1126 +
233.1127 +#if 1 /* 15/VII-2006 */
233.1128 +CODE *elemset_argument(MPL *mpl, char *func)
233.1129 +{     CODE *x;
233.1130 +      x = expression_9(mpl);
233.1131 +      if (x->type != A_ELEMSET)
233.1132 +         error(mpl, "argument for %s has invalid type", func);
233.1133 +      xassert(x->dim > 0);
233.1134 +      return x;
233.1135 +}
233.1136 +#endif
233.1137 +
233.1138 +/*----------------------------------------------------------------------
233.1139 +-- function_reference - parse reference to built-in function.
233.1140 +--
233.1141 +-- This routine parses primary expression using the syntax:
233.1142 +--
233.1143 +-- <primary expression> ::= abs ( <arg> )
233.1144 +-- <primary expression> ::= ceil ( <arg> )
233.1145 +-- <primary expression> ::= floor ( <arg> )
233.1146 +-- <primary expression> ::= exp ( <arg> )
233.1147 +-- <primary expression> ::= log ( <arg> )
233.1148 +-- <primary expression> ::= log10 ( <arg> )
233.1149 +-- <primary expression> ::= max ( <arg list> )
233.1150 +-- <primary expression> ::= min ( <arg list> )
233.1151 +-- <primary expression> ::= sqrt ( <arg> )
233.1152 +-- <primary expression> ::= sin ( <arg> )
233.1153 +-- <primary expression> ::= cos ( <arg> )
233.1154 +-- <primary expression> ::= atan ( <arg> )
233.1155 +-- <primary expression> ::= atan2 ( <arg> , <arg> )
233.1156 +-- <primary expression> ::= round ( <arg> )
233.1157 +-- <primary expression> ::= round ( <arg> , <arg> )
233.1158 +-- <primary expression> ::= trunc ( <arg> )
233.1159 +-- <primary expression> ::= trunc ( <arg> , <arg> )
233.1160 +-- <primary expression> ::= Irand224 ( )
233.1161 +-- <primary expression> ::= Uniform01 ( )
233.1162 +-- <primary expression> ::= Uniform ( <arg> , <arg> )
233.1163 +-- <primary expression> ::= Normal01 ( )
233.1164 +-- <primary expression> ::= Normal ( <arg> , <arg> )
233.1165 +-- <primary expression> ::= card ( <arg> )
233.1166 +-- <primary expression> ::= length ( <arg> )
233.1167 +-- <primary expression> ::= substr ( <arg> , <arg> )
233.1168 +-- <primary expression> ::= substr ( <arg> , <arg> , <arg> )
233.1169 +-- <primary expression> ::= str2time ( <arg> , <arg> )
233.1170 +-- <primary expression> ::= time2str ( <arg> , <arg> )
233.1171 +-- <primary expression> ::= gmtime ( )
233.1172 +-- <arg list> ::= <arg>
233.1173 +-- <arg list> ::= <arg list> , <arg> */
233.1174 +
233.1175 +CODE *function_reference(MPL *mpl)
233.1176 +{     CODE *code;
233.1177 +      OPERANDS arg;
233.1178 +      int op;
233.1179 +      char func[15+1];
233.1180 +      /* determine operation code */
233.1181 +      xassert(mpl->token == T_NAME);
233.1182 +      if (strcmp(mpl->image, "abs") == 0)
233.1183 +         op = O_ABS;
233.1184 +      else if (strcmp(mpl->image, "ceil") == 0)
233.1185 +         op = O_CEIL;
233.1186 +      else if (strcmp(mpl->image, "floor") == 0)
233.1187 +         op = O_FLOOR;
233.1188 +      else if (strcmp(mpl->image, "exp") == 0)
233.1189 +         op = O_EXP;
233.1190 +      else if (strcmp(mpl->image, "log") == 0)
233.1191 +         op = O_LOG;
233.1192 +      else if (strcmp(mpl->image, "log10") == 0)
233.1193 +         op = O_LOG10;
233.1194 +      else if (strcmp(mpl->image, "sqrt") == 0)
233.1195 +         op = O_SQRT;
233.1196 +      else if (strcmp(mpl->image, "sin") == 0)
233.1197 +         op = O_SIN;
233.1198 +      else if (strcmp(mpl->image, "cos") == 0)
233.1199 +         op = O_COS;
233.1200 +      else if (strcmp(mpl->image, "atan") == 0)
233.1201 +         op = O_ATAN;
233.1202 +      else if (strcmp(mpl->image, "min") == 0)
233.1203 +         op = O_MIN;
233.1204 +      else if (strcmp(mpl->image, "max") == 0)
233.1205 +         op = O_MAX;
233.1206 +      else if (strcmp(mpl->image, "round") == 0)
233.1207 +         op = O_ROUND;
233.1208 +      else if (strcmp(mpl->image, "trunc") == 0)
233.1209 +         op = O_TRUNC;
233.1210 +      else if (strcmp(mpl->image, "Irand224") == 0)
233.1211 +         op = O_IRAND224;
233.1212 +      else if (strcmp(mpl->image, "Uniform01") == 0)
233.1213 +         op = O_UNIFORM01;
233.1214 +      else if (strcmp(mpl->image, "Uniform") == 0)
233.1215 +         op = O_UNIFORM;
233.1216 +      else if (strcmp(mpl->image, "Normal01") == 0)
233.1217 +         op = O_NORMAL01;
233.1218 +      else if (strcmp(mpl->image, "Normal") == 0)
233.1219 +         op = O_NORMAL;
233.1220 +      else if (strcmp(mpl->image, "card") == 0)
233.1221 +         op = O_CARD;
233.1222 +      else if (strcmp(mpl->image, "length") == 0)
233.1223 +         op = O_LENGTH;
233.1224 +      else if (strcmp(mpl->image, "substr") == 0)
233.1225 +         op = O_SUBSTR;
233.1226 +      else if (strcmp(mpl->image, "str2time") == 0)
233.1227 +         op = O_STR2TIME;
233.1228 +      else if (strcmp(mpl->image, "time2str") == 0)
233.1229 +         op = O_TIME2STR;
233.1230 +      else if (strcmp(mpl->image, "gmtime") == 0)
233.1231 +         op = O_GMTIME;
233.1232 +      else
233.1233 +         error(mpl, "function %s unknown", mpl->image);
233.1234 +      /* save symbolic name of the function */
233.1235 +      strcpy(func, mpl->image);
233.1236 +      xassert(strlen(func) < sizeof(func));
233.1237 +      get_token(mpl /* <symbolic name> */);
233.1238 +      /* check the left parenthesis that follows the function name */
233.1239 +      xassert(mpl->token == T_LEFT);
233.1240 +      get_token(mpl /* ( */);
233.1241 +      /* parse argument list */
233.1242 +      if (op == O_MIN || op == O_MAX)
233.1243 +      {  /* min and max allow arbitrary number of arguments */
233.1244 +         arg.list = create_arg_list(mpl);
233.1245 +         /* parse argument list */
233.1246 +         for (;;)
233.1247 +         {  /* parse argument and append it to the operands list */
233.1248 +            arg.list = expand_arg_list(mpl, arg.list,
233.1249 +               numeric_argument(mpl, func));
233.1250 +            /* check a token that follows the argument */
233.1251 +            if (mpl->token == T_COMMA)
233.1252 +               get_token(mpl /* , */);
233.1253 +            else if (mpl->token == T_RIGHT)
233.1254 +               break;
233.1255 +            else
233.1256 +               error(mpl, "syntax error in argument list for %s", func);
233.1257 +         }
233.1258 +      }
233.1259 +      else if (op == O_IRAND224 || op == O_UNIFORM01 || op ==
233.1260 +         O_NORMAL01 || op == O_GMTIME)
233.1261 +      {  /* Irand224, Uniform01, Normal01, gmtime need no arguments */
233.1262 +         if (mpl->token != T_RIGHT)
233.1263 +            error(mpl, "%s needs no arguments", func);
233.1264 +      }
233.1265 +      else if (op == O_UNIFORM || op == O_NORMAL)
233.1266 +      {  /* Uniform and Normal need two arguments */
233.1267 +         /* parse the first argument */
233.1268 +         arg.arg.x = numeric_argument(mpl, func);
233.1269 +         /* check a token that follows the first argument */
233.1270 +         if (mpl->token == T_COMMA)
233.1271 +            ;
233.1272 +         else if (mpl->token == T_RIGHT)
233.1273 +            error(mpl, "%s needs two arguments", func);
233.1274 +         else
233.1275 +            error(mpl, "syntax error in argument for %s", func);
233.1276 +         get_token(mpl /* , */);
233.1277 +         /* parse the second argument */
233.1278 +         arg.arg.y = numeric_argument(mpl, func);
233.1279 +         /* check a token that follows the second argument */
233.1280 +         if (mpl->token == T_COMMA)
233.1281 +            error(mpl, "%s needs two argument", func);
233.1282 +         else if (mpl->token == T_RIGHT)
233.1283 +            ;
233.1284 +         else
233.1285 +            error(mpl, "syntax error in argument for %s", func);
233.1286 +      }
233.1287 +      else if (op == O_ATAN || op == O_ROUND || op == O_TRUNC)
233.1288 +      {  /* atan, round, and trunc need one or two arguments */
233.1289 +         /* parse the first argument */
233.1290 +         arg.arg.x = numeric_argument(mpl, func);
233.1291 +         /* parse the second argument, if specified */
233.1292 +         if (mpl->token == T_COMMA)
233.1293 +         {  switch (op)
233.1294 +            {  case O_ATAN:  op = O_ATAN2;  break;
233.1295 +               case O_ROUND: op = O_ROUND2; break;
233.1296 +               case O_TRUNC: op = O_TRUNC2; break;
233.1297 +               default: xassert(op != op);
233.1298 +            }
233.1299 +            get_token(mpl /* , */);
233.1300 +            arg.arg.y = numeric_argument(mpl, func);
233.1301 +         }
233.1302 +         /* check a token that follows the last argument */
233.1303 +         if (mpl->token == T_COMMA)
233.1304 +            error(mpl, "%s needs one or two arguments", func);
233.1305 +         else if (mpl->token == T_RIGHT)
233.1306 +            ;
233.1307 +         else
233.1308 +            error(mpl, "syntax error in argument for %s", func);
233.1309 +      }
233.1310 +      else if (op == O_SUBSTR)
233.1311 +      {  /* substr needs two or three arguments */
233.1312 +         /* parse the first argument */
233.1313 +         arg.arg.x = symbolic_argument(mpl, func);
233.1314 +         /* check a token that follows the first argument */
233.1315 +         if (mpl->token == T_COMMA)
233.1316 +            ;
233.1317 +         else if (mpl->token == T_RIGHT)
233.1318 +            error(mpl, "%s needs two or three arguments", func);
233.1319 +         else
233.1320 +            error(mpl, "syntax error in argument for %s", func);
233.1321 +         get_token(mpl /* , */);
233.1322 +         /* parse the second argument */
233.1323 +         arg.arg.y = numeric_argument(mpl, func);
233.1324 +         /* parse the third argument, if specified */
233.1325 +         if (mpl->token == T_COMMA)
233.1326 +         {  op = O_SUBSTR3;
233.1327 +            get_token(mpl /* , */);
233.1328 +            arg.arg.z = numeric_argument(mpl, func);
233.1329 +         }
233.1330 +         /* check a token that follows the last argument */
233.1331 +         if (mpl->token == T_COMMA)
233.1332 +            error(mpl, "%s needs two or three arguments", func);
233.1333 +         else if (mpl->token == T_RIGHT)
233.1334 +            ;
233.1335 +         else
233.1336 +            error(mpl, "syntax error in argument for %s", func);
233.1337 +      }
233.1338 +      else if (op == O_STR2TIME)
233.1339 +      {  /* str2time needs two arguments, both symbolic */
233.1340 +         /* parse the first argument */
233.1341 +         arg.arg.x = symbolic_argument(mpl, func);
233.1342 +         /* check a token that follows the first argument */
233.1343 +         if (mpl->token == T_COMMA)
233.1344 +            ;
233.1345 +         else if (mpl->token == T_RIGHT)
233.1346 +            error(mpl, "%s needs two arguments", func);
233.1347 +         else
233.1348 +            error(mpl, "syntax error in argument for %s", func);
233.1349 +         get_token(mpl /* , */);
233.1350 +         /* parse the second argument */
233.1351 +         arg.arg.y = symbolic_argument(mpl, func);
233.1352 +         /* check a token that follows the second argument */
233.1353 +         if (mpl->token == T_COMMA)
233.1354 +            error(mpl, "%s needs two argument", func);
233.1355 +         else if (mpl->token == T_RIGHT)
233.1356 +            ;
233.1357 +         else
233.1358 +            error(mpl, "syntax error in argument for %s", func);
233.1359 +      }
233.1360 +      else if (op == O_TIME2STR)
233.1361 +      {  /* time2str needs two arguments, numeric and symbolic */
233.1362 +         /* parse the first argument */
233.1363 +         arg.arg.x = numeric_argument(mpl, func);
233.1364 +         /* check a token that follows the first argument */
233.1365 +         if (mpl->token == T_COMMA)
233.1366 +            ;
233.1367 +         else if (mpl->token == T_RIGHT)
233.1368 +            error(mpl, "%s needs two arguments", func);
233.1369 +         else
233.1370 +            error(mpl, "syntax error in argument for %s", func);
233.1371 +         get_token(mpl /* , */);
233.1372 +         /* parse the second argument */
233.1373 +         arg.arg.y = symbolic_argument(mpl, func);
233.1374 +         /* check a token that follows the second argument */
233.1375 +         if (mpl->token == T_COMMA)
233.1376 +            error(mpl, "%s needs two argument", func);
233.1377 +         else if (mpl->token == T_RIGHT)
233.1378 +            ;
233.1379 +         else
233.1380 +            error(mpl, "syntax error in argument for %s", func);
233.1381 +      }
233.1382 +      else
233.1383 +      {  /* other functions need one argument */
233.1384 +         if (op == O_CARD)
233.1385 +            arg.arg.x = elemset_argument(mpl, func);
233.1386 +         else if (op == O_LENGTH)
233.1387 +            arg.arg.x = symbolic_argument(mpl, func);
233.1388 +         else
233.1389 +            arg.arg.x = numeric_argument(mpl, func);
233.1390 +         /* check a token that follows the argument */
233.1391 +         if (mpl->token == T_COMMA)
233.1392 +            error(mpl, "%s needs one argument", func);
233.1393 +         else if (mpl->token == T_RIGHT)
233.1394 +            ;
233.1395 +         else
233.1396 +            error(mpl, "syntax error in argument for %s", func);
233.1397 +      }
233.1398 +      /* make pseudo-code to call the built-in function */
233.1399 +      if (op == O_SUBSTR || op == O_SUBSTR3 || op == O_TIME2STR)
233.1400 +         code = make_code(mpl, op, &arg, A_SYMBOLIC, 0);
233.1401 +      else
233.1402 +         code = make_code(mpl, op, &arg, A_NUMERIC, 0);
233.1403 +      /* the reference ends with the right parenthesis */
233.1404 +      xassert(mpl->token == T_RIGHT);
233.1405 +      get_token(mpl /* ) */);
233.1406 +      return code;
233.1407 +}
233.1408 +
233.1409 +/*----------------------------------------------------------------------
233.1410 +-- create_domain - create empty domain.
233.1411 +--
233.1412 +-- This routine creates empty domain, which is initially empty, i.e.
233.1413 +-- has no domain blocks. */
233.1414 +
233.1415 +DOMAIN *create_domain(MPL *mpl)
233.1416 +{     DOMAIN *domain;
233.1417 +      domain = alloc(DOMAIN);
233.1418 +      domain->list = NULL;
233.1419 +      domain->code = NULL;
233.1420 +      return domain;
233.1421 +}
233.1422 +
233.1423 +/*----------------------------------------------------------------------
233.1424 +-- create_block - create empty domain block.
233.1425 +--
233.1426 +-- This routine creates empty domain block, which is initially empty,
233.1427 +-- i.e. has no domain slots. */
233.1428 +
233.1429 +DOMAIN_BLOCK *create_block(MPL *mpl)
233.1430 +{     DOMAIN_BLOCK *block;
233.1431 +      block = alloc(DOMAIN_BLOCK);
233.1432 +      block->list = NULL;
233.1433 +      block->code = NULL;
233.1434 +      block->backup = NULL;
233.1435 +      block->next = NULL;
233.1436 +      return block;
233.1437 +}
233.1438 +
233.1439 +/*----------------------------------------------------------------------
233.1440 +-- append_block - append domain block to specified domain.
233.1441 +--
233.1442 +-- This routine adds given domain block to the end of the block list of
233.1443 +-- specified domain. */
233.1444 +
233.1445 +void append_block(MPL *mpl, DOMAIN *domain, DOMAIN_BLOCK *block)
233.1446 +{     DOMAIN_BLOCK *temp;
233.1447 +      xassert(mpl == mpl);
233.1448 +      xassert(domain != NULL);
233.1449 +      xassert(block != NULL);
233.1450 +      xassert(block->next == NULL);
233.1451 +      if (domain->list == NULL)
233.1452 +         domain->list = block;
233.1453 +      else
233.1454 +      {  for (temp = domain->list; temp->next != NULL; temp =
233.1455 +            temp->next);
233.1456 +         temp->next = block;
233.1457 +      }
233.1458 +      return;
233.1459 +}
233.1460 +
233.1461 +/*----------------------------------------------------------------------
233.1462 +-- append_slot - create and append new slot to domain block.
233.1463 +--
233.1464 +-- This routine creates new domain slot and adds it to the end of slot
233.1465 +-- list of specified domain block.
233.1466 +--
233.1467 +-- The parameter name is symbolic name of the dummy index associated
233.1468 +-- with the slot (the character string must be allocated). NULL means
233.1469 +-- the dummy index is not explicitly specified.
233.1470 +--
233.1471 +-- The parameter code is pseudo-code for computing symbolic value, at
233.1472 +-- which the dummy index is bounded. NULL means the dummy index is free
233.1473 +-- in the domain scope. */
233.1474 +
233.1475 +DOMAIN_SLOT *append_slot(MPL *mpl, DOMAIN_BLOCK *block, char *name,
233.1476 +      CODE *code)
233.1477 +{     DOMAIN_SLOT *slot, *temp;
233.1478 +      xassert(block != NULL);
233.1479 +      slot = alloc(DOMAIN_SLOT);
233.1480 +      slot->name = name;
233.1481 +      slot->code = code;
233.1482 +      slot->value = NULL;
233.1483 +      slot->list = NULL;
233.1484 +      slot->next = NULL;
233.1485 +      if (block->list == NULL)
233.1486 +         block->list = slot;
233.1487 +      else
233.1488 +      {  for (temp = block->list; temp->next != NULL; temp =
233.1489 +            temp->next);
233.1490 +         temp->next = slot;
233.1491 +      }
233.1492 +      return slot;
233.1493 +}
233.1494 +
233.1495 +/*----------------------------------------------------------------------
233.1496 +-- expression_list - parse expression list.
233.1497 +--
233.1498 +-- This routine parses a list of one or more expressions enclosed into
233.1499 +-- the parentheses using the syntax:
233.1500 +--
233.1501 +-- <primary expression> ::= ( <expression list> )
233.1502 +-- <expression list> ::= <expression 13>
233.1503 +-- <expression list> ::= <expression 13> , <expression list>
233.1504 +--
233.1505 +-- Note that this construction may have three different meanings:
233.1506 +--
233.1507 +-- 1. If <expression list> consists of only one expression, <primary
233.1508 +--    expression> is a parenthesized expression, which may be of any
233.1509 +--    valid type (not necessarily 1-tuple).
233.1510 +--
233.1511 +-- 2. If <expression list> consists of several expressions separated by
233.1512 +--    commae, where no expression is undeclared symbolic name, <primary
233.1513 +--    expression> is a n-tuple.
233.1514 +--
233.1515 +-- 3. If <expression list> consists of several expressions separated by
233.1516 +--    commae, where at least one expression is undeclared symbolic name
233.1517 +--    (that denotes a dummy index), <primary expression> is a slice and
233.1518 +--    can be only used as constituent of indexing expression. */
233.1519 +
233.1520 +#define max_dim 20
233.1521 +/* maximal number of components allowed within parentheses */
233.1522 +
233.1523 +CODE *expression_list(MPL *mpl)
233.1524 +{     CODE *code;
233.1525 +      OPERANDS arg;
233.1526 +      struct { char *name; CODE *code; } list[1+max_dim];
233.1527 +      int flag_x, next_token, dim, j, slice = 0;
233.1528 +      xassert(mpl->token == T_LEFT);
233.1529 +      /* the flag, which allows recognizing undeclared symbolic names
233.1530 +         as dummy indices, will be automatically reset by get_token(),
233.1531 +         so save it before scanning the next token */
233.1532 +      flag_x = mpl->flag_x;
233.1533 +      get_token(mpl /* ( */);
233.1534 +      /* parse <expression list> */
233.1535 +      for (dim = 1; ; dim++)
233.1536 +      {  if (dim > max_dim)
233.1537 +            error(mpl, "too many components within parentheses");
233.1538 +         /* current component of <expression list> can be either dummy
233.1539 +            index or expression */
233.1540 +         if (mpl->token == T_NAME)
233.1541 +         {  /* symbolic name is recognized as dummy index only if:
233.1542 +               the flag, which allows that, is set, and
233.1543 +               the name is followed by comma or right parenthesis, and
233.1544 +               the name is undeclared */
233.1545 +            get_token(mpl /* <symbolic name> */);
233.1546 +            next_token = mpl->token;
233.1547 +            unget_token(mpl);
233.1548 +            if (!(flag_x &&
233.1549 +                  (next_token == T_COMMA || next_token == T_RIGHT) &&
233.1550 +                  avl_find_node(mpl->tree, mpl->image) == NULL))
233.1551 +            {  /* this is not dummy index */
233.1552 +               goto expr;
233.1553 +            }
233.1554 +            /* all dummy indices within the same slice must have unique
233.1555 +               symbolic names */
233.1556 +            for (j = 1; j < dim; j++)
233.1557 +            {  if (list[j].name != NULL && strcmp(list[j].name,
233.1558 +                  mpl->image) == 0)
233.1559 +                  error(mpl, "duplicate dummy index %s not allowed",
233.1560 +                     mpl->image);
233.1561 +            }
233.1562 +            /* current component of <expression list> is dummy index */
233.1563 +            list[dim].name
233.1564 +               = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.1565 +            strcpy(list[dim].name, mpl->image);
233.1566 +            list[dim].code = NULL;
233.1567 +            get_token(mpl /* <symbolic name> */);
233.1568 +            /* <expression list> is a slice, because at least one dummy
233.1569 +               index has appeared */
233.1570 +            slice = 1;
233.1571 +            /* note that the context ( <dummy index> ) is not allowed,
233.1572 +               i.e. in this case <primary expression> is considered as
233.1573 +               a parenthesized expression */
233.1574 +            if (dim == 1 && mpl->token == T_RIGHT)
233.1575 +               error(mpl, "%s not defined", list[dim].name);
233.1576 +         }
233.1577 +         else
233.1578 +expr:    {  /* current component of <expression list> is expression */
233.1579 +            code = expression_13(mpl);
233.1580 +            /* if the current expression is followed by comma or it is
233.1581 +               not the very first expression, entire <expression list>
233.1582 +               is n-tuple or slice, in which case the current expression
233.1583 +               should be converted to symbolic type, if necessary */
233.1584 +            if (mpl->token == T_COMMA || dim > 1)
233.1585 +            {  if (code->type == A_NUMERIC)
233.1586 +                  code = make_unary(mpl, O_CVTSYM, code, A_SYMBOLIC, 0);
233.1587 +               /* now the expression must be of symbolic type */
233.1588 +               if (code->type != A_SYMBOLIC)
233.1589 +                  error(mpl, "component expression has invalid type");
233.1590 +               xassert(code->dim == 0);
233.1591 +            }
233.1592 +            list[dim].name = NULL;
233.1593 +            list[dim].code = code;
233.1594 +         }
233.1595 +         /* check a token that follows the current component */
233.1596 +         if (mpl->token == T_COMMA)
233.1597 +            get_token(mpl /* , */);
233.1598 +         else if (mpl->token == T_RIGHT)
233.1599 +            break;
233.1600 +         else
233.1601 +            error(mpl, "right parenthesis missing where expected");
233.1602 +      }
233.1603 +      /* generate pseudo-code for <primary expression> */
233.1604 +      if (dim == 1 && !slice)
233.1605 +      {  /* <primary expression> is a parenthesized expression */
233.1606 +         code = list[1].code;
233.1607 +      }
233.1608 +      else if (!slice)
233.1609 +      {  /* <primary expression> is a n-tuple */
233.1610 +         arg.list = create_arg_list(mpl);
233.1611 +         for (j = 1; j <= dim; j++)
233.1612 +            arg.list = expand_arg_list(mpl, arg.list, list[j].code);
233.1613 +         code = make_code(mpl, O_TUPLE, &arg, A_TUPLE, dim);
233.1614 +      }
233.1615 +      else
233.1616 +      {  /* <primary expression> is a slice */
233.1617 +         arg.slice = create_block(mpl);
233.1618 +         for (j = 1; j <= dim; j++)
233.1619 +            append_slot(mpl, arg.slice, list[j].name, list[j].code);
233.1620 +         /* note that actually pseudo-codes with op = O_SLICE are never
233.1621 +            evaluated */
233.1622 +         code = make_code(mpl, O_SLICE, &arg, A_TUPLE, dim);
233.1623 +      }
233.1624 +      get_token(mpl /* ) */);
233.1625 +      /* if <primary expression> is a slice, there must be the keyword
233.1626 +         'in', which follows the right parenthesis */
233.1627 +      if (slice && mpl->token != T_IN)
233.1628 +         error(mpl, "keyword in missing where expected");
233.1629 +      /* if the slice flag is set and there is the keyword 'in', which
233.1630 +         follows <primary expression>, the latter must be a slice */
233.1631 +      if (flag_x && mpl->token == T_IN && !slice)
233.1632 +      {  if (dim == 1)
233.1633 +            error(mpl, "syntax error in indexing expression");
233.1634 +         else
233.1635 +            error(mpl, "0-ary slice not allowed");
233.1636 +      }
233.1637 +      return code;
233.1638 +}
233.1639 +
233.1640 +/*----------------------------------------------------------------------
233.1641 +-- literal set - parse literal set.
233.1642 +--
233.1643 +-- This routine parses literal set using the syntax:
233.1644 +--
233.1645 +-- <literal set> ::= { <member list> }
233.1646 +-- <member list> ::= <member expression>
233.1647 +-- <member list> ::= <member list> , <member expression>
233.1648 +-- <member expression> ::= <expression 5>
233.1649 +--
233.1650 +-- It is assumed that the left curly brace and the very first member
233.1651 +-- expression that follows it are already parsed. The right curly brace
233.1652 +-- remains unscanned on exit. */
233.1653 +
233.1654 +CODE *literal_set(MPL *mpl, CODE *code)
233.1655 +{     OPERANDS arg;
233.1656 +      int j;
233.1657 +      xassert(code != NULL);
233.1658 +      arg.list = create_arg_list(mpl);
233.1659 +      /* parse <member list> */
233.1660 +      for (j = 1; ; j++)
233.1661 +      {  /* all member expressions must be n-tuples; so, if the current
233.1662 +            expression is not n-tuple, convert it to 1-tuple */
233.1663 +         if (code->type == A_NUMERIC)
233.1664 +            code = make_unary(mpl, O_CVTSYM, code, A_SYMBOLIC, 0);
233.1665 +         if (code->type == A_SYMBOLIC)
233.1666 +            code = make_unary(mpl, O_CVTTUP, code, A_TUPLE, 1);
233.1667 +         /* now the expression must be n-tuple */
233.1668 +         if (code->type != A_TUPLE)
233.1669 +            error(mpl, "member expression has invalid type");
233.1670 +         /* all member expressions must have identical dimension */
233.1671 +         if (arg.list != NULL && arg.list->x->dim != code->dim)
233.1672 +            error(mpl, "member %d has %d component%s while member %d ha"
233.1673 +               "s %d component%s",
233.1674 +               j-1, arg.list->x->dim, arg.list->x->dim == 1 ? "" : "s",
233.1675 +               j, code->dim, code->dim == 1 ? "" : "s");
233.1676 +         /* append the current expression to the member list */
233.1677 +         arg.list = expand_arg_list(mpl, arg.list, code);
233.1678 +         /* check a token that follows the current expression */
233.1679 +         if (mpl->token == T_COMMA)
233.1680 +            get_token(mpl /* , */);
233.1681 +         else if (mpl->token == T_RBRACE)
233.1682 +            break;
233.1683 +         else
233.1684 +            error(mpl, "syntax error in literal set");
233.1685 +         /* parse the next expression that follows the comma */
233.1686 +         code = expression_5(mpl);
233.1687 +      }
233.1688 +      /* generate pseudo-code for <literal set> */
233.1689 +      code = make_code(mpl, O_MAKE, &arg, A_ELEMSET, arg.list->x->dim);
233.1690 +      return code;
233.1691 +}
233.1692 +
233.1693 +/*----------------------------------------------------------------------
233.1694 +-- indexing_expression - parse indexing expression.
233.1695 +--
233.1696 +-- This routine parses indexing expression using the syntax:
233.1697 +--
233.1698 +-- <indexing expression> ::= <literal set>
233.1699 +-- <indexing expression> ::= { <indexing list> }
233.1700 +-- <indexing expression> ::= { <indexing list> : <logical expression> }
233.1701 +-- <indexing list> ::= <indexing element>
233.1702 +-- <indexing list> ::= <indexing list> , <indexing element>
233.1703 +-- <indexing element> ::= <basic expression>
233.1704 +-- <indexing element> ::= <dummy index> in <basic expression>
233.1705 +-- <indexing element> ::= <slice> in <basic expression>
233.1706 +-- <dummy index> ::= <symbolic name>
233.1707 +-- <slice> ::= ( <expression list> )
233.1708 +-- <basic expression> ::= <expression 9>
233.1709 +-- <logical expression> ::= <expression 13>
233.1710 +--
233.1711 +-- This routine creates domain for <indexing expression>, where each
233.1712 +-- domain block corresponds to <indexing element>, and each domain slot
233.1713 +-- corresponds to individual indexing position. */
233.1714 +
233.1715 +DOMAIN *indexing_expression(MPL *mpl)
233.1716 +{     DOMAIN *domain;
233.1717 +      DOMAIN_BLOCK *block;
233.1718 +      DOMAIN_SLOT *slot;
233.1719 +      CODE *code;
233.1720 +      xassert(mpl->token == T_LBRACE);
233.1721 +      get_token(mpl /* { */);
233.1722 +      if (mpl->token == T_RBRACE)
233.1723 +         error(mpl, "empty indexing expression not allowed");
233.1724 +      /* create domain to be constructed */
233.1725 +      domain = create_domain(mpl);
233.1726 +      /* parse either <member list> or <indexing list> that follows the
233.1727 +         left brace */
233.1728 +      for (;;)
233.1729 +      {  /* domain block for <indexing element> is not created yet */
233.1730 +         block = NULL;
233.1731 +         /* pseudo-code for <basic expression> is not generated yet */
233.1732 +         code = NULL;
233.1733 +         /* check a token, which <indexing element> begins with */
233.1734 +         if (mpl->token == T_NAME)
233.1735 +         {  /* it is a symbolic name */
233.1736 +            int next_token;
233.1737 +            char *name;
233.1738 +            /* symbolic name is recognized as dummy index only if it is
233.1739 +               followed by the keyword 'in' and not declared */
233.1740 +            get_token(mpl /* <symbolic name> */);
233.1741 +            next_token = mpl->token;
233.1742 +            unget_token(mpl);
233.1743 +            if (!(next_token == T_IN &&
233.1744 +                  avl_find_node(mpl->tree, mpl->image) == NULL))
233.1745 +            {  /* this is not dummy index; the symbolic name begins an
233.1746 +                  expression, which is either <basic expression> or the
233.1747 +                  very first <member expression> in <literal set> */
233.1748 +               goto expr;
233.1749 +            }
233.1750 +            /* create domain block with one slot, which is assigned the
233.1751 +               dummy index */
233.1752 +            block = create_block(mpl);
233.1753 +            name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.1754 +            strcpy(name, mpl->image);
233.1755 +            append_slot(mpl, block, name, NULL);
233.1756 +            get_token(mpl /* <symbolic name> */);
233.1757 +            /* the keyword 'in' is already checked above */
233.1758 +            xassert(mpl->token == T_IN);
233.1759 +            get_token(mpl /* in */);
233.1760 +            /* <basic expression> that follows the keyword 'in' will be
233.1761 +               parsed below */
233.1762 +         }
233.1763 +         else if (mpl->token == T_LEFT)
233.1764 +         {  /* it is the left parenthesis; parse expression that begins
233.1765 +               with this parenthesis (the flag is set in order to allow
233.1766 +               recognizing slices; see the routine expression_list) */
233.1767 +            mpl->flag_x = 1;
233.1768 +            code = expression_9(mpl);
233.1769 +            if (code->op != O_SLICE)
233.1770 +            {  /* this is either <basic expression> or the very first
233.1771 +                  <member expression> in <literal set> */
233.1772 +               goto expr;
233.1773 +            }
233.1774 +            /* this is a slice; besides the corresponding domain block
233.1775 +               is already created by expression_list() */
233.1776 +            block = code->arg.slice;
233.1777 +            code = NULL; /* <basic expression> is not parsed yet */
233.1778 +            /* the keyword 'in' following the slice is already checked
233.1779 +               by expression_list() */
233.1780 +            xassert(mpl->token == T_IN);
233.1781 +            get_token(mpl /* in */);
233.1782 +            /* <basic expression> that follows the keyword 'in' will be
233.1783 +               parsed below */
233.1784 +         }
233.1785 +expr:    /* parse expression that follows either the keyword 'in' (in
233.1786 +            which case it can be <basic expression) or the left brace
233.1787 +            (in which case it can be <basic expression> as well as the
233.1788 +            very first <member expression> in <literal set>); note that
233.1789 +            this expression can be already parsed above */
233.1790 +         if (code == NULL) code = expression_9(mpl);
233.1791 +         /* check the type of the expression just parsed */
233.1792 +         if (code->type != A_ELEMSET)
233.1793 +         {  /* it is not <basic expression> and therefore it can only
233.1794 +               be the very first <member expression> in <literal set>;
233.1795 +               however, then there must be no dummy index neither slice
233.1796 +               between the left brace and this expression */
233.1797 +            if (block != NULL)
233.1798 +               error(mpl, "domain expression has invalid type");
233.1799 +            /* parse the rest part of <literal set> and make this set
233.1800 +               be <basic expression>, i.e. the construction {a, b, c}
233.1801 +               is parsed as it were written as {A}, where A = {a, b, c}
233.1802 +               is a temporary elemental set */
233.1803 +            code = literal_set(mpl, code);
233.1804 +         }
233.1805 +         /* now pseudo-code for <basic set> has been built */
233.1806 +         xassert(code != NULL);
233.1807 +         xassert(code->type == A_ELEMSET);
233.1808 +         xassert(code->dim > 0);
233.1809 +         /* if domain block for the current <indexing element> is still
233.1810 +            not created, create it for fake slice of the same dimension
233.1811 +            as <basic set> */
233.1812 +         if (block == NULL)
233.1813 +         {  int j;
233.1814 +            block = create_block(mpl);
233.1815 +            for (j = 1; j <= code->dim; j++)
233.1816 +               append_slot(mpl, block, NULL, NULL);
233.1817 +         }
233.1818 +         /* number of indexing positions in <indexing element> must be
233.1819 +            the same as dimension of n-tuples in basic set */
233.1820 +         {  int dim = 0;
233.1821 +            for (slot = block->list; slot != NULL; slot = slot->next)
233.1822 +               dim++;
233.1823 +            if (dim != code->dim)
233.1824 +               error(mpl,"%d %s specified for set of dimension %d",
233.1825 +                  dim, dim == 1 ? "index" : "indices", code->dim);
233.1826 +         }
233.1827 +         /* store pseudo-code for <basic set> in the domain block */
233.1828 +         xassert(block->code == NULL);
233.1829 +         block->code = code;
233.1830 +         /* and append the domain block to the domain */
233.1831 +         append_block(mpl, domain, block);
233.1832 +         /* the current <indexing element> has been completely parsed;
233.1833 +            include all its dummy indices into the symbolic name table
233.1834 +            to make them available for referencing from expressions;
233.1835 +            implicit declarations of dummy indices remain valid while
233.1836 +            the corresponding domain scope is valid */
233.1837 +         for (slot = block->list; slot != NULL; slot = slot->next)
233.1838 +         if (slot->name != NULL)
233.1839 +         {  AVLNODE *node;
233.1840 +            xassert(avl_find_node(mpl->tree, slot->name) == NULL);
233.1841 +            node = avl_insert_node(mpl->tree, slot->name);
233.1842 +            avl_set_node_type(node, A_INDEX);
233.1843 +            avl_set_node_link(node, (void *)slot);
233.1844 +         }
233.1845 +         /* check a token that follows <indexing element> */
233.1846 +         if (mpl->token == T_COMMA)
233.1847 +            get_token(mpl /* , */);
233.1848 +         else if (mpl->token == T_COLON || mpl->token == T_RBRACE)
233.1849 +            break;
233.1850 +         else
233.1851 +            error(mpl, "syntax error in indexing expression");
233.1852 +      }
233.1853 +      /* parse <logical expression> that follows the colon */
233.1854 +      if (mpl->token == T_COLON)
233.1855 +      {  get_token(mpl /* : */);
233.1856 +         code = expression_13(mpl);
233.1857 +         /* convert the expression to logical type, if necessary */
233.1858 +         if (code->type == A_SYMBOLIC)
233.1859 +            code = make_unary(mpl, O_CVTNUM, code, A_NUMERIC, 0);
233.1860 +         if (code->type == A_NUMERIC)
233.1861 +            code = make_unary(mpl, O_CVTLOG, code, A_LOGICAL, 0);
233.1862 +         /* now the expression must be of logical type */
233.1863 +         if (code->type != A_LOGICAL)
233.1864 +            error(mpl, "expression following colon has invalid type");
233.1865 +         xassert(code->dim == 0);
233.1866 +         domain->code = code;
233.1867 +         /* the right brace must follow the logical expression */
233.1868 +         if (mpl->token != T_RBRACE)
233.1869 +            error(mpl, "syntax error in indexing expression");
233.1870 +      }
233.1871 +      get_token(mpl /* } */);
233.1872 +      return domain;
233.1873 +}
233.1874 +
233.1875 +/*----------------------------------------------------------------------
233.1876 +-- close_scope - close scope of indexing expression.
233.1877 +--
233.1878 +-- The routine closes the scope of indexing expression specified by its
233.1879 +-- domain and thereby makes all dummy indices introduced in the indexing
233.1880 +-- expression no longer available for referencing. */
233.1881 +
233.1882 +void close_scope(MPL *mpl, DOMAIN *domain)
233.1883 +{     DOMAIN_BLOCK *block;
233.1884 +      DOMAIN_SLOT *slot;
233.1885 +      AVLNODE *node;
233.1886 +      xassert(domain != NULL);
233.1887 +      /* remove all dummy indices from the symbolic names table */
233.1888 +      for (block = domain->list; block != NULL; block = block->next)
233.1889 +      {  for (slot = block->list; slot != NULL; slot = slot->next)
233.1890 +         {  if (slot->name != NULL)
233.1891 +            {  node = avl_find_node(mpl->tree, slot->name);
233.1892 +               xassert(node != NULL);
233.1893 +               xassert(avl_get_node_type(node) == A_INDEX);
233.1894 +               avl_delete_node(mpl->tree, node);
233.1895 +            }
233.1896 +         }
233.1897 +      }
233.1898 +      return;
233.1899 +}
233.1900 +
233.1901 +/*----------------------------------------------------------------------
233.1902 +-- iterated_expression - parse iterated expression.
233.1903 +--
233.1904 +-- This routine parses primary expression using the syntax:
233.1905 +--
233.1906 +-- <primary expression> ::= <iterated expression>
233.1907 +-- <iterated expression> ::= sum <indexing expression> <expression 3>
233.1908 +-- <iterated expression> ::= prod <indexing expression> <expression 3>
233.1909 +-- <iterated expression> ::= min <indexing expression> <expression 3>
233.1910 +-- <iterated expression> ::= max <indexing expression> <expression 3>
233.1911 +-- <iterated expression> ::= exists <indexing expression>
233.1912 +--                           <expression 12>
233.1913 +-- <iterated expression> ::= forall <indexing expression>
233.1914 +--                           <expression 12>
233.1915 +-- <iterated expression> ::= setof <indexing expression> <expression 5>
233.1916 +--
233.1917 +-- Note that parsing "integrand" depends on the iterated operator. */
233.1918 +
233.1919 +#if 1 /* 07/IX-2008 */
233.1920 +static void link_up(CODE *code)
233.1921 +{     /* if we have something like sum{(i+1,j,k-1) in E} x[i,j,k],
233.1922 +         where i and k are dummy indices defined out of the iterated
233.1923 +         expression, we should link up pseudo-code for computing i+1
233.1924 +         and k-1 to pseudo-code for computing the iterated expression;
233.1925 +         this is needed to invalidate current value of the iterated
233.1926 +         expression once i or k have been changed */
233.1927 +      DOMAIN_BLOCK *block;
233.1928 +      DOMAIN_SLOT *slot;
233.1929 +      for (block = code->arg.loop.domain->list; block != NULL;
233.1930 +         block = block->next)
233.1931 +      {  for (slot = block->list; slot != NULL; slot = slot->next)
233.1932 +         {  if (slot->code != NULL)
233.1933 +            {  xassert(slot->code->up == NULL);
233.1934 +               slot->code->up = code;
233.1935 +            }
233.1936 +         }
233.1937 +      }
233.1938 +      return;
233.1939 +}
233.1940 +#endif
233.1941 +
233.1942 +CODE *iterated_expression(MPL *mpl)
233.1943 +{     CODE *code;
233.1944 +      OPERANDS arg;
233.1945 +      int op;
233.1946 +      char opstr[8];
233.1947 +      /* determine operation code */
233.1948 +      xassert(mpl->token == T_NAME);
233.1949 +      if (strcmp(mpl->image, "sum") == 0)
233.1950 +         op = O_SUM;
233.1951 +      else if (strcmp(mpl->image, "prod") == 0)
233.1952 +         op = O_PROD;
233.1953 +      else if (strcmp(mpl->image, "min") == 0)
233.1954 +         op = O_MINIMUM;
233.1955 +      else if (strcmp(mpl->image, "max") == 0)
233.1956 +         op = O_MAXIMUM;
233.1957 +      else if (strcmp(mpl->image, "forall") == 0)
233.1958 +         op = O_FORALL;
233.1959 +      else if (strcmp(mpl->image, "exists") == 0)
233.1960 +         op = O_EXISTS;
233.1961 +      else if (strcmp(mpl->image, "setof") == 0)
233.1962 +         op = O_SETOF;
233.1963 +      else
233.1964 +         error(mpl, "operator %s unknown", mpl->image);
233.1965 +      strcpy(opstr, mpl->image);
233.1966 +      xassert(strlen(opstr) < sizeof(opstr));
233.1967 +      get_token(mpl /* <symbolic name> */);
233.1968 +      /* check the left brace that follows the operator name */
233.1969 +      xassert(mpl->token == T_LBRACE);
233.1970 +      /* parse indexing expression that controls iterating */
233.1971 +      arg.loop.domain = indexing_expression(mpl);
233.1972 +      /* parse "integrand" expression and generate pseudo-code */
233.1973 +      switch (op)
233.1974 +      {  case O_SUM:
233.1975 +         case O_PROD:
233.1976 +         case O_MINIMUM:
233.1977 +         case O_MAXIMUM:
233.1978 +            arg.loop.x = expression_3(mpl);
233.1979 +            /* convert the integrand to numeric type, if necessary */
233.1980 +            if (arg.loop.x->type == A_SYMBOLIC)
233.1981 +               arg.loop.x = make_unary(mpl, O_CVTNUM, arg.loop.x,
233.1982 +                  A_NUMERIC, 0);
233.1983 +            /* now the integrand must be of numeric type or linear form
233.1984 +               (the latter is only allowed for the sum operator) */
233.1985 +            if (!(arg.loop.x->type == A_NUMERIC ||
233.1986 +                  op == O_SUM && arg.loop.x->type == A_FORMULA))
233.1987 +err:           error(mpl, "integrand following %s{...} has invalid type"
233.1988 +                  , opstr);
233.1989 +            xassert(arg.loop.x->dim == 0);
233.1990 +            /* generate pseudo-code */
233.1991 +            code = make_code(mpl, op, &arg, arg.loop.x->type, 0);
233.1992 +            break;
233.1993 +         case O_FORALL:
233.1994 +         case O_EXISTS:
233.1995 +            arg.loop.x = expression_12(mpl);
233.1996 +            /* convert the integrand to logical type, if necessary */
233.1997 +            if (arg.loop.x->type == A_SYMBOLIC)
233.1998 +               arg.loop.x = make_unary(mpl, O_CVTNUM, arg.loop.x,
233.1999 +                  A_NUMERIC, 0);
233.2000 +            if (arg.loop.x->type == A_NUMERIC)
233.2001 +               arg.loop.x = make_unary(mpl, O_CVTLOG, arg.loop.x,
233.2002 +                  A_LOGICAL, 0);
233.2003 +            /* now the integrand must be of logical type */
233.2004 +            if (arg.loop.x->type != A_LOGICAL) goto err;
233.2005 +            xassert(arg.loop.x->dim == 0);
233.2006 +            /* generate pseudo-code */
233.2007 +            code = make_code(mpl, op, &arg, A_LOGICAL, 0);
233.2008 +            break;
233.2009 +         case O_SETOF:
233.2010 +            arg.loop.x = expression_5(mpl);
233.2011 +            /* convert the integrand to 1-tuple, if necessary */
233.2012 +            if (arg.loop.x->type == A_NUMERIC)
233.2013 +               arg.loop.x = make_unary(mpl, O_CVTSYM, arg.loop.x,
233.2014 +                  A_SYMBOLIC, 0);
233.2015 +            if (arg.loop.x->type == A_SYMBOLIC)
233.2016 +               arg.loop.x = make_unary(mpl, O_CVTTUP, arg.loop.x,
233.2017 +                  A_TUPLE, 1);
233.2018 +            /* now the integrand must be n-tuple */
233.2019 +            if (arg.loop.x->type != A_TUPLE) goto err;
233.2020 +            xassert(arg.loop.x->dim > 0);
233.2021 +            /* generate pseudo-code */
233.2022 +            code = make_code(mpl, op, &arg, A_ELEMSET, arg.loop.x->dim);
233.2023 +            break;
233.2024 +         default:
233.2025 +            xassert(op != op);
233.2026 +      }
233.2027 +      /* close the scope of the indexing expression */
233.2028 +      close_scope(mpl, arg.loop.domain);
233.2029 +#if 1 /* 07/IX-2008 */
233.2030 +      link_up(code);
233.2031 +#endif
233.2032 +      return code;
233.2033 +}
233.2034 +
233.2035 +/*----------------------------------------------------------------------
233.2036 +-- domain_arity - determine arity of domain.
233.2037 +--
233.2038 +-- This routine returns arity of specified domain, which is number of
233.2039 +-- its free dummy indices. */
233.2040 +
233.2041 +int domain_arity(MPL *mpl, DOMAIN *domain)
233.2042 +{     DOMAIN_BLOCK *block;
233.2043 +      DOMAIN_SLOT *slot;
233.2044 +      int arity;
233.2045 +      xassert(mpl == mpl);
233.2046 +      arity = 0;
233.2047 +      for (block = domain->list; block != NULL; block = block->next)
233.2048 +         for (slot = block->list; slot != NULL; slot = slot->next)
233.2049 +            if (slot->code == NULL) arity++;
233.2050 +      return arity;
233.2051 +}
233.2052 +
233.2053 +/*----------------------------------------------------------------------
233.2054 +-- set_expression - parse set expression.
233.2055 +--
233.2056 +-- This routine parses primary expression using the syntax:
233.2057 +--
233.2058 +-- <primary expression> ::= { }
233.2059 +-- <primary expression> ::= <indexing expression> */
233.2060 +
233.2061 +CODE *set_expression(MPL *mpl)
233.2062 +{     CODE *code;
233.2063 +      OPERANDS arg;
233.2064 +      xassert(mpl->token == T_LBRACE);
233.2065 +      get_token(mpl /* { */);
233.2066 +      /* check a token that follows the left brace */
233.2067 +      if (mpl->token == T_RBRACE)
233.2068 +      {  /* it is the right brace, so the resultant is an empty set of
233.2069 +            dimension 1 */
233.2070 +         arg.list = NULL;
233.2071 +         /* generate pseudo-code to build the resultant set */
233.2072 +         code = make_code(mpl, O_MAKE, &arg, A_ELEMSET, 1);
233.2073 +         get_token(mpl /* } */);
233.2074 +      }
233.2075 +      else
233.2076 +      {  /* the next token begins an indexing expression */
233.2077 +         unget_token(mpl);
233.2078 +         arg.loop.domain = indexing_expression(mpl);
233.2079 +         arg.loop.x = NULL; /* integrand is not used */
233.2080 +         /* close the scope of the indexing expression */
233.2081 +         close_scope(mpl, arg.loop.domain);
233.2082 +         /* generate pseudo-code to build the resultant set */
233.2083 +         code = make_code(mpl, O_BUILD, &arg, A_ELEMSET,
233.2084 +            domain_arity(mpl, arg.loop.domain));
233.2085 +#if 1 /* 07/IX-2008 */
233.2086 +         link_up(code);
233.2087 +#endif
233.2088 +      }
233.2089 +      return code;
233.2090 +}
233.2091 +
233.2092 +/*----------------------------------------------------------------------
233.2093 +-- branched_expression - parse conditional expression.
233.2094 +--
233.2095 +-- This routine parses primary expression using the syntax:
233.2096 +--
233.2097 +-- <primary expression> ::= <branched expression>
233.2098 +-- <branched expression> ::= if <logical expression> then <expression 9>
233.2099 +-- <branched expression> ::= if <logical expression> then <expression 9>
233.2100 +--                           else <expression 9>
233.2101 +-- <logical expression> ::= <expression 13> */
233.2102 +
233.2103 +CODE *branched_expression(MPL *mpl)
233.2104 +{     CODE *code, *x, *y, *z;
233.2105 +      xassert(mpl->token == T_IF);
233.2106 +      get_token(mpl /* if */);
233.2107 +      /* parse <logical expression> that follows 'if' */
233.2108 +      x = expression_13(mpl);
233.2109 +      /* convert the expression to logical type, if necessary */
233.2110 +      if (x->type == A_SYMBOLIC)
233.2111 +         x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2112 +      if (x->type == A_NUMERIC)
233.2113 +         x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
233.2114 +      /* now the expression must be of logical type */
233.2115 +      if (x->type != A_LOGICAL)
233.2116 +         error(mpl, "expression following if has invalid type");
233.2117 +      xassert(x->dim == 0);
233.2118 +      /* the keyword 'then' must follow the logical expression */
233.2119 +      if (mpl->token != T_THEN)
233.2120 +         error(mpl, "keyword then missing where expected");
233.2121 +      get_token(mpl /* then */);
233.2122 +      /* parse <expression> that follows 'then' and check its type */
233.2123 +      y = expression_9(mpl);
233.2124 +      if (!(y->type == A_NUMERIC || y->type == A_SYMBOLIC ||
233.2125 +            y->type == A_ELEMSET || y->type == A_FORMULA))
233.2126 +         error(mpl, "expression following then has invalid type");
233.2127 +      /* if the expression that follows the keyword 'then' is elemental
233.2128 +         set, the keyword 'else' cannot be omitted; otherwise else-part
233.2129 +         is optional */
233.2130 +      if (mpl->token != T_ELSE)
233.2131 +      {  if (y->type == A_ELEMSET)
233.2132 +            error(mpl, "keyword else missing where expected");
233.2133 +         z = NULL;
233.2134 +         goto skip;
233.2135 +      }
233.2136 +      get_token(mpl /* else */);
233.2137 +      /* parse <expression> that follow 'else' and check its type */
233.2138 +      z = expression_9(mpl);
233.2139 +      if (!(z->type == A_NUMERIC || z->type == A_SYMBOLIC ||
233.2140 +            z->type == A_ELEMSET || z->type == A_FORMULA))
233.2141 +         error(mpl, "expression following else has invalid type");
233.2142 +      /* convert to identical types, if necessary */
233.2143 +      if (y->type == A_FORMULA || z->type == A_FORMULA)
233.2144 +      {  if (y->type == A_SYMBOLIC)
233.2145 +            y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2146 +         if (y->type == A_NUMERIC)
233.2147 +            y = make_unary(mpl, O_CVTLFM, y, A_FORMULA, 0);
233.2148 +         if (z->type == A_SYMBOLIC)
233.2149 +            z = make_unary(mpl, O_CVTNUM, z, A_NUMERIC, 0);
233.2150 +         if (z->type == A_NUMERIC)
233.2151 +            z = make_unary(mpl, O_CVTLFM, z, A_FORMULA, 0);
233.2152 +      }
233.2153 +      if (y->type == A_SYMBOLIC || z->type == A_SYMBOLIC)
233.2154 +      {  if (y->type == A_NUMERIC)
233.2155 +            y = make_unary(mpl, O_CVTSYM, y, A_SYMBOLIC, 0);
233.2156 +         if (z->type == A_NUMERIC)
233.2157 +            z = make_unary(mpl, O_CVTSYM, z, A_SYMBOLIC, 0);
233.2158 +      }
233.2159 +      /* now both expressions must have identical types */
233.2160 +      if (y->type != z->type)
233.2161 +         error(mpl, "expressions following then and else have incompati"
233.2162 +            "ble types");
233.2163 +      /* and identical dimensions */
233.2164 +      if (y->dim != z->dim)
233.2165 +         error(mpl, "expressions following then and else have different"
233.2166 +            " dimensions %d and %d, respectively", y->dim, z->dim);
233.2167 +skip: /* generate pseudo-code to perform branching */
233.2168 +      code = make_ternary(mpl, O_FORK, x, y, z, y->type, y->dim);
233.2169 +      return code;
233.2170 +}
233.2171 +
233.2172 +/*----------------------------------------------------------------------
233.2173 +-- primary_expression - parse primary expression.
233.2174 +--
233.2175 +-- This routine parses primary expression using the syntax:
233.2176 +--
233.2177 +-- <primary expression> ::= <numeric literal>
233.2178 +-- <primary expression> ::= Infinity
233.2179 +-- <primary expression> ::= <string literal>
233.2180 +-- <primary expression> ::= <dummy index>
233.2181 +-- <primary expression> ::= <set name>
233.2182 +-- <primary expression> ::= <set name> [ <subscript list> ]
233.2183 +-- <primary expression> ::= <parameter name>
233.2184 +-- <primary expression> ::= <parameter name> [ <subscript list> ]
233.2185 +-- <primary expression> ::= <variable name>
233.2186 +-- <primary expression> ::= <variable name> [ <subscript list> ]
233.2187 +-- <primary expression> ::= <built-in function> ( <argument list> )
233.2188 +-- <primary expression> ::= ( <expression list> )
233.2189 +-- <primary expression> ::= <iterated expression>
233.2190 +-- <primary expression> ::= { }
233.2191 +-- <primary expression> ::= <indexing expression>
233.2192 +-- <primary expression> ::= <branched expression>
233.2193 +--
233.2194 +-- For complete list of syntactic rules for <primary expression> see
233.2195 +-- comments to the corresponding parsing routines. */
233.2196 +
233.2197 +CODE *primary_expression(MPL *mpl)
233.2198 +{     CODE *code;
233.2199 +      if (mpl->token == T_NUMBER)
233.2200 +      {  /* parse numeric literal */
233.2201 +         code = numeric_literal(mpl);
233.2202 +      }
233.2203 +#if 1 /* 21/VII-2006 */
233.2204 +      else if (mpl->token == T_INFINITY)
233.2205 +      {  /* parse "infinity" */
233.2206 +         OPERANDS arg;
233.2207 +         arg.num = DBL_MAX;
233.2208 +         code = make_code(mpl, O_NUMBER, &arg, A_NUMERIC, 0);
233.2209 +         get_token(mpl /* Infinity */);
233.2210 +      }
233.2211 +#endif
233.2212 +      else if (mpl->token == T_STRING)
233.2213 +      {  /* parse string literal */
233.2214 +         code = string_literal(mpl);
233.2215 +      }
233.2216 +      else if (mpl->token == T_NAME)
233.2217 +      {  int next_token;
233.2218 +         get_token(mpl /* <symbolic name> */);
233.2219 +         next_token = mpl->token;
233.2220 +         unget_token(mpl);
233.2221 +         /* check a token that follows <symbolic name> */
233.2222 +         switch (next_token)
233.2223 +         {  case T_LBRACKET:
233.2224 +               /* parse reference to subscripted object */
233.2225 +               code = object_reference(mpl);
233.2226 +               break;
233.2227 +            case T_LEFT:
233.2228 +               /* parse reference to built-in function */
233.2229 +               code = function_reference(mpl);
233.2230 +               break;
233.2231 +            case T_LBRACE:
233.2232 +               /* parse iterated expression */
233.2233 +               code = iterated_expression(mpl);
233.2234 +               break;
233.2235 +            default:
233.2236 +               /* parse reference to unsubscripted object */
233.2237 +               code = object_reference(mpl);
233.2238 +               break;
233.2239 +         }
233.2240 +      }
233.2241 +      else if (mpl->token == T_LEFT)
233.2242 +      {  /* parse parenthesized expression */
233.2243 +         code = expression_list(mpl);
233.2244 +      }
233.2245 +      else if (mpl->token == T_LBRACE)
233.2246 +      {  /* parse set expression */
233.2247 +         code = set_expression(mpl);
233.2248 +      }
233.2249 +      else if (mpl->token == T_IF)
233.2250 +      {  /* parse conditional expression */
233.2251 +         code = branched_expression(mpl);
233.2252 +      }
233.2253 +      else if (is_reserved(mpl))
233.2254 +      {  /* other reserved keywords cannot be used here */
233.2255 +         error(mpl, "invalid use of reserved keyword %s", mpl->image);
233.2256 +      }
233.2257 +      else
233.2258 +         error(mpl, "syntax error in expression");
233.2259 +      return code;
233.2260 +}
233.2261 +
233.2262 +/*----------------------------------------------------------------------
233.2263 +-- error_preceding - raise error if preceding operand has wrong type.
233.2264 +--
233.2265 +-- This routine is called to raise error if operand that precedes some
233.2266 +-- infix operator has invalid type. */
233.2267 +
233.2268 +void error_preceding(MPL *mpl, char *opstr)
233.2269 +{     error(mpl, "operand preceding %s has invalid type", opstr);
233.2270 +      /* no return */
233.2271 +}
233.2272 +
233.2273 +/*----------------------------------------------------------------------
233.2274 +-- error_following - raise error if following operand has wrong type.
233.2275 +--
233.2276 +-- This routine is called to raise error if operand that follows some
233.2277 +-- infix operator has invalid type. */
233.2278 +
233.2279 +void error_following(MPL *mpl, char *opstr)
233.2280 +{     error(mpl, "operand following %s has invalid type", opstr);
233.2281 +      /* no return */
233.2282 +}
233.2283 +
233.2284 +/*----------------------------------------------------------------------
233.2285 +-- error_dimension - raise error if operands have different dimension.
233.2286 +--
233.2287 +-- This routine is called to raise error if two operands of some infix
233.2288 +-- operator have different dimension. */
233.2289 +
233.2290 +void error_dimension(MPL *mpl, char *opstr, int dim1, int dim2)
233.2291 +{     error(mpl, "operands preceding and following %s have different di"
233.2292 +         "mensions %d and %d, respectively", opstr, dim1, dim2);
233.2293 +      /* no return */
233.2294 +}
233.2295 +
233.2296 +/*----------------------------------------------------------------------
233.2297 +-- expression_0 - parse expression of level 0.
233.2298 +--
233.2299 +-- This routine parses expression of level 0 using the syntax:
233.2300 +--
233.2301 +-- <expression 0> ::= <primary expression> */
233.2302 +
233.2303 +CODE *expression_0(MPL *mpl)
233.2304 +{     CODE *code;
233.2305 +      code = primary_expression(mpl);
233.2306 +      return code;
233.2307 +}
233.2308 +
233.2309 +/*----------------------------------------------------------------------
233.2310 +-- expression_1 - parse expression of level 1.
233.2311 +--
233.2312 +-- This routine parses expression of level 1 using the syntax:
233.2313 +--
233.2314 +-- <expression 1> ::= <expression 0>
233.2315 +-- <expression 1> ::= <expression 0> <power> <expression 1>
233.2316 +-- <expression 1> ::= <expression 0> <power> <expression 2>
233.2317 +-- <power> ::= ^ | ** */
233.2318 +
233.2319 +CODE *expression_1(MPL *mpl)
233.2320 +{     CODE *x, *y;
233.2321 +      char opstr[8];
233.2322 +      x = expression_0(mpl);
233.2323 +      if (mpl->token == T_POWER)
233.2324 +      {  strcpy(opstr, mpl->image);
233.2325 +         xassert(strlen(opstr) < sizeof(opstr));
233.2326 +         if (x->type == A_SYMBOLIC)
233.2327 +            x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2328 +         if (x->type != A_NUMERIC)
233.2329 +            error_preceding(mpl, opstr);
233.2330 +         get_token(mpl /* ^ | ** */);
233.2331 +         if (mpl->token == T_PLUS || mpl->token == T_MINUS)
233.2332 +            y = expression_2(mpl);
233.2333 +         else
233.2334 +            y = expression_1(mpl);
233.2335 +         if (y->type == A_SYMBOLIC)
233.2336 +            y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2337 +         if (y->type != A_NUMERIC)
233.2338 +            error_following(mpl, opstr);
233.2339 +         x = make_binary(mpl, O_POWER, x, y, A_NUMERIC, 0);
233.2340 +      }
233.2341 +      return x;
233.2342 +}
233.2343 +
233.2344 +/*----------------------------------------------------------------------
233.2345 +-- expression_2 - parse expression of level 2.
233.2346 +--
233.2347 +-- This routine parses expression of level 2 using the syntax:
233.2348 +--
233.2349 +-- <expression 2> ::= <expression 1>
233.2350 +-- <expression 2> ::= + <expression 1>
233.2351 +-- <expression 2> ::= - <expression 1> */
233.2352 +
233.2353 +CODE *expression_2(MPL *mpl)
233.2354 +{     CODE *x;
233.2355 +      if (mpl->token == T_PLUS)
233.2356 +      {  get_token(mpl /* + */);
233.2357 +         x = expression_1(mpl);
233.2358 +         if (x->type == A_SYMBOLIC)
233.2359 +            x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2360 +         if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
233.2361 +            error_following(mpl, "+");
233.2362 +         x = make_unary(mpl, O_PLUS, x, x->type, 0);
233.2363 +      }
233.2364 +      else if (mpl->token == T_MINUS)
233.2365 +      {  get_token(mpl /* - */);
233.2366 +         x = expression_1(mpl);
233.2367 +         if (x->type == A_SYMBOLIC)
233.2368 +            x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2369 +         if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
233.2370 +            error_following(mpl, "-");
233.2371 +         x = make_unary(mpl, O_MINUS, x, x->type, 0);
233.2372 +      }
233.2373 +      else
233.2374 +         x = expression_1(mpl);
233.2375 +      return x;
233.2376 +}
233.2377 +
233.2378 +/*----------------------------------------------------------------------
233.2379 +-- expression_3 - parse expression of level 3.
233.2380 +--
233.2381 +-- This routine parses expression of level 3 using the syntax:
233.2382 +--
233.2383 +-- <expression 3> ::= <expression 2>
233.2384 +-- <expression 3> ::= <expression 3> * <expression 2>
233.2385 +-- <expression 3> ::= <expression 3> / <expression 2>
233.2386 +-- <expression 3> ::= <expression 3> div <expression 2>
233.2387 +-- <expression 3> ::= <expression 3> mod <expression 2> */
233.2388 +
233.2389 +CODE *expression_3(MPL *mpl)
233.2390 +{     CODE *x, *y;
233.2391 +      x = expression_2(mpl);
233.2392 +      for (;;)
233.2393 +      {  if (mpl->token == T_ASTERISK)
233.2394 +         {  if (x->type == A_SYMBOLIC)
233.2395 +               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2396 +            if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
233.2397 +               error_preceding(mpl, "*");
233.2398 +            get_token(mpl /* * */);
233.2399 +            y = expression_2(mpl);
233.2400 +            if (y->type == A_SYMBOLIC)
233.2401 +               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2402 +            if (!(y->type == A_NUMERIC || y->type == A_FORMULA))
233.2403 +               error_following(mpl, "*");
233.2404 +            if (x->type == A_FORMULA && y->type == A_FORMULA)
233.2405 +               error(mpl, "multiplication of linear forms not allowed");
233.2406 +            if (x->type == A_NUMERIC && y->type == A_NUMERIC)
233.2407 +               x = make_binary(mpl, O_MUL, x, y, A_NUMERIC, 0);
233.2408 +            else
233.2409 +               x = make_binary(mpl, O_MUL, x, y, A_FORMULA, 0);
233.2410 +         }
233.2411 +         else if (mpl->token == T_SLASH)
233.2412 +         {  if (x->type == A_SYMBOLIC)
233.2413 +               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2414 +            if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
233.2415 +               error_preceding(mpl, "/");
233.2416 +            get_token(mpl /* / */);
233.2417 +            y = expression_2(mpl);
233.2418 +            if (y->type == A_SYMBOLIC)
233.2419 +               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2420 +            if (y->type != A_NUMERIC)
233.2421 +               error_following(mpl, "/");
233.2422 +            if (x->type == A_NUMERIC)
233.2423 +               x = make_binary(mpl, O_DIV, x, y, A_NUMERIC, 0);
233.2424 +            else
233.2425 +               x = make_binary(mpl, O_DIV, x, y, A_FORMULA, 0);
233.2426 +         }
233.2427 +         else if (mpl->token == T_DIV)
233.2428 +         {  if (x->type == A_SYMBOLIC)
233.2429 +               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2430 +            if (x->type != A_NUMERIC)
233.2431 +               error_preceding(mpl, "div");
233.2432 +            get_token(mpl /* div */);
233.2433 +            y = expression_2(mpl);
233.2434 +            if (y->type == A_SYMBOLIC)
233.2435 +               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2436 +            if (y->type != A_NUMERIC)
233.2437 +               error_following(mpl, "div");
233.2438 +            x = make_binary(mpl, O_IDIV, x, y, A_NUMERIC, 0);
233.2439 +         }
233.2440 +         else if (mpl->token == T_MOD)
233.2441 +         {  if (x->type == A_SYMBOLIC)
233.2442 +               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2443 +            if (x->type != A_NUMERIC)
233.2444 +               error_preceding(mpl, "mod");
233.2445 +            get_token(mpl /* mod */);
233.2446 +            y = expression_2(mpl);
233.2447 +            if (y->type == A_SYMBOLIC)
233.2448 +               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2449 +            if (y->type != A_NUMERIC)
233.2450 +               error_following(mpl, "mod");
233.2451 +            x = make_binary(mpl, O_MOD, x, y, A_NUMERIC, 0);
233.2452 +         }
233.2453 +         else
233.2454 +            break;
233.2455 +      }
233.2456 +      return x;
233.2457 +}
233.2458 +
233.2459 +/*----------------------------------------------------------------------
233.2460 +-- expression_4 - parse expression of level 4.
233.2461 +--
233.2462 +-- This routine parses expression of level 4 using the syntax:
233.2463 +--
233.2464 +-- <expression 4> ::= <expression 3>
233.2465 +-- <expression 4> ::= <expression 4> + <expression 3>
233.2466 +-- <expression 4> ::= <expression 4> - <expression 3>
233.2467 +-- <expression 4> ::= <expression 4> less <expression 3> */
233.2468 +
233.2469 +CODE *expression_4(MPL *mpl)
233.2470 +{     CODE *x, *y;
233.2471 +      x = expression_3(mpl);
233.2472 +      for (;;)
233.2473 +      {  if (mpl->token == T_PLUS)
233.2474 +         {  if (x->type == A_SYMBOLIC)
233.2475 +               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2476 +            if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
233.2477 +               error_preceding(mpl, "+");
233.2478 +            get_token(mpl /* + */);
233.2479 +            y = expression_3(mpl);
233.2480 +            if (y->type == A_SYMBOLIC)
233.2481 +               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2482 +            if (!(y->type == A_NUMERIC || y->type == A_FORMULA))
233.2483 +               error_following(mpl, "+");
233.2484 +            if (x->type == A_NUMERIC && y->type == A_FORMULA)
233.2485 +               x = make_unary(mpl, O_CVTLFM, x, A_FORMULA, 0);
233.2486 +            if (x->type == A_FORMULA && y->type == A_NUMERIC)
233.2487 +               y = make_unary(mpl, O_CVTLFM, y, A_FORMULA, 0);
233.2488 +            x = make_binary(mpl, O_ADD, x, y, x->type, 0);
233.2489 +         }
233.2490 +         else if (mpl->token == T_MINUS)
233.2491 +         {  if (x->type == A_SYMBOLIC)
233.2492 +               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2493 +            if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
233.2494 +               error_preceding(mpl, "-");
233.2495 +            get_token(mpl /* - */);
233.2496 +            y = expression_3(mpl);
233.2497 +            if (y->type == A_SYMBOLIC)
233.2498 +               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2499 +            if (!(y->type == A_NUMERIC || y->type == A_FORMULA))
233.2500 +               error_following(mpl, "-");
233.2501 +            if (x->type == A_NUMERIC && y->type == A_FORMULA)
233.2502 +               x = make_unary(mpl, O_CVTLFM, x, A_FORMULA, 0);
233.2503 +            if (x->type == A_FORMULA && y->type == A_NUMERIC)
233.2504 +               y = make_unary(mpl, O_CVTLFM, y, A_FORMULA, 0);
233.2505 +            x = make_binary(mpl, O_SUB, x, y, x->type, 0);
233.2506 +         }
233.2507 +         else if (mpl->token == T_LESS)
233.2508 +         {  if (x->type == A_SYMBOLIC)
233.2509 +               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2510 +            if (x->type != A_NUMERIC)
233.2511 +               error_preceding(mpl, "less");
233.2512 +            get_token(mpl /* less */);
233.2513 +            y = expression_3(mpl);
233.2514 +            if (y->type == A_SYMBOLIC)
233.2515 +               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2516 +            if (y->type != A_NUMERIC)
233.2517 +               error_following(mpl, "less");
233.2518 +            x = make_binary(mpl, O_LESS, x, y, A_NUMERIC, 0);
233.2519 +         }
233.2520 +         else
233.2521 +            break;
233.2522 +      }
233.2523 +      return x;
233.2524 +}
233.2525 +
233.2526 +/*----------------------------------------------------------------------
233.2527 +-- expression_5 - parse expression of level 5.
233.2528 +--
233.2529 +-- This routine parses expression of level 5 using the syntax:
233.2530 +--
233.2531 +-- <expression 5> ::= <expression 4>
233.2532 +-- <expression 5> ::= <expression 5> & <expression 4> */
233.2533 +
233.2534 +CODE *expression_5(MPL *mpl)
233.2535 +{     CODE *x, *y;
233.2536 +      x = expression_4(mpl);
233.2537 +      for (;;)
233.2538 +      {  if (mpl->token == T_CONCAT)
233.2539 +         {  if (x->type == A_NUMERIC)
233.2540 +               x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
233.2541 +            if (x->type != A_SYMBOLIC)
233.2542 +               error_preceding(mpl, "&");
233.2543 +            get_token(mpl /* & */);
233.2544 +            y = expression_4(mpl);
233.2545 +            if (y->type == A_NUMERIC)
233.2546 +               y = make_unary(mpl, O_CVTSYM, y, A_SYMBOLIC, 0);
233.2547 +            if (y->type != A_SYMBOLIC)
233.2548 +               error_following(mpl, "&");
233.2549 +            x = make_binary(mpl, O_CONCAT, x, y, A_SYMBOLIC, 0);
233.2550 +         }
233.2551 +         else
233.2552 +            break;
233.2553 +      }
233.2554 +      return x;
233.2555 +}
233.2556 +
233.2557 +/*----------------------------------------------------------------------
233.2558 +-- expression_6 - parse expression of level 6.
233.2559 +--
233.2560 +-- This routine parses expression of level 6 using the syntax:
233.2561 +--
233.2562 +-- <expression 6> ::= <expression 5>
233.2563 +-- <expression 6> ::= <expression 5> .. <expression 5>
233.2564 +-- <expression 6> ::= <expression 5> .. <expression 5> by
233.2565 +--                    <expression 5> */
233.2566 +
233.2567 +CODE *expression_6(MPL *mpl)
233.2568 +{     CODE *x, *y, *z;
233.2569 +      x = expression_5(mpl);
233.2570 +      if (mpl->token == T_DOTS)
233.2571 +      {  if (x->type == A_SYMBOLIC)
233.2572 +            x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2573 +         if (x->type != A_NUMERIC)
233.2574 +            error_preceding(mpl, "..");
233.2575 +         get_token(mpl /* .. */);
233.2576 +         y = expression_5(mpl);
233.2577 +         if (y->type == A_SYMBOLIC)
233.2578 +            y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2579 +         if (y->type != A_NUMERIC)
233.2580 +            error_following(mpl, "..");
233.2581 +         if (mpl->token == T_BY)
233.2582 +         {  get_token(mpl /* by */);
233.2583 +            z = expression_5(mpl);
233.2584 +            if (z->type == A_SYMBOLIC)
233.2585 +               z = make_unary(mpl, O_CVTNUM, z, A_NUMERIC, 0);
233.2586 +            if (z->type != A_NUMERIC)
233.2587 +               error_following(mpl, "by");
233.2588 +         }
233.2589 +         else
233.2590 +            z = NULL;
233.2591 +         x = make_ternary(mpl, O_DOTS, x, y, z, A_ELEMSET, 1);
233.2592 +      }
233.2593 +      return x;
233.2594 +}
233.2595 +
233.2596 +/*----------------------------------------------------------------------
233.2597 +-- expression_7 - parse expression of level 7.
233.2598 +--
233.2599 +-- This routine parses expression of level 7 using the syntax:
233.2600 +--
233.2601 +-- <expression 7> ::= <expression 6>
233.2602 +-- <expression 7> ::= <expression 7> cross <expression 6> */
233.2603 +
233.2604 +CODE *expression_7(MPL *mpl)
233.2605 +{     CODE *x, *y;
233.2606 +      x = expression_6(mpl);
233.2607 +      for (;;)
233.2608 +      {  if (mpl->token == T_CROSS)
233.2609 +         {  if (x->type != A_ELEMSET)
233.2610 +               error_preceding(mpl, "cross");
233.2611 +            get_token(mpl /* cross */);
233.2612 +            y = expression_6(mpl);
233.2613 +            if (y->type != A_ELEMSET)
233.2614 +               error_following(mpl, "cross");
233.2615 +            x = make_binary(mpl, O_CROSS, x, y, A_ELEMSET,
233.2616 +               x->dim + y->dim);
233.2617 +         }
233.2618 +         else
233.2619 +            break;
233.2620 +      }
233.2621 +      return x;
233.2622 +}
233.2623 +
233.2624 +/*----------------------------------------------------------------------
233.2625 +-- expression_8 - parse expression of level 8.
233.2626 +--
233.2627 +-- This routine parses expression of level 8 using the syntax:
233.2628 +--
233.2629 +-- <expression 8> ::= <expression 7>
233.2630 +-- <expression 8> ::= <expression 8> inter <expression 7> */
233.2631 +
233.2632 +CODE *expression_8(MPL *mpl)
233.2633 +{     CODE *x, *y;
233.2634 +      x = expression_7(mpl);
233.2635 +      for (;;)
233.2636 +      {  if (mpl->token == T_INTER)
233.2637 +         {  if (x->type != A_ELEMSET)
233.2638 +               error_preceding(mpl, "inter");
233.2639 +            get_token(mpl /* inter */);
233.2640 +            y = expression_7(mpl);
233.2641 +            if (y->type != A_ELEMSET)
233.2642 +               error_following(mpl, "inter");
233.2643 +            if (x->dim != y->dim)
233.2644 +               error_dimension(mpl, "inter", x->dim, y->dim);
233.2645 +            x = make_binary(mpl, O_INTER, x, y, A_ELEMSET, x->dim);
233.2646 +         }
233.2647 +         else
233.2648 +            break;
233.2649 +      }
233.2650 +      return x;
233.2651 +}
233.2652 +
233.2653 +/*----------------------------------------------------------------------
233.2654 +-- expression_9 - parse expression of level 9.
233.2655 +--
233.2656 +-- This routine parses expression of level 9 using the syntax:
233.2657 +--
233.2658 +-- <expression 9> ::= <expression 8>
233.2659 +-- <expression 9> ::= <expression 9> union <expression 8>
233.2660 +-- <expression 9> ::= <expression 9> diff <expression 8>
233.2661 +-- <expression 9> ::= <expression 9> symdiff <expression 8> */
233.2662 +
233.2663 +CODE *expression_9(MPL *mpl)
233.2664 +{     CODE *x, *y;
233.2665 +      x = expression_8(mpl);
233.2666 +      for (;;)
233.2667 +      {  if (mpl->token == T_UNION)
233.2668 +         {  if (x->type != A_ELEMSET)
233.2669 +               error_preceding(mpl, "union");
233.2670 +            get_token(mpl /* union */);
233.2671 +            y = expression_8(mpl);
233.2672 +            if (y->type != A_ELEMSET)
233.2673 +               error_following(mpl, "union");
233.2674 +            if (x->dim != y->dim)
233.2675 +               error_dimension(mpl, "union", x->dim, y->dim);
233.2676 +            x = make_binary(mpl, O_UNION, x, y, A_ELEMSET, x->dim);
233.2677 +         }
233.2678 +         else if (mpl->token == T_DIFF)
233.2679 +         {  if (x->type != A_ELEMSET)
233.2680 +               error_preceding(mpl, "diff");
233.2681 +            get_token(mpl /* diff */);
233.2682 +            y = expression_8(mpl);
233.2683 +            if (y->type != A_ELEMSET)
233.2684 +               error_following(mpl, "diff");
233.2685 +            if (x->dim != y->dim)
233.2686 +               error_dimension(mpl, "diff", x->dim, y->dim);
233.2687 +            x = make_binary(mpl, O_DIFF, x, y, A_ELEMSET, x->dim);
233.2688 +         }
233.2689 +         else if (mpl->token == T_SYMDIFF)
233.2690 +         {  if (x->type != A_ELEMSET)
233.2691 +               error_preceding(mpl, "symdiff");
233.2692 +            get_token(mpl /* symdiff */);
233.2693 +            y = expression_8(mpl);
233.2694 +            if (y->type != A_ELEMSET)
233.2695 +               error_following(mpl, "symdiff");
233.2696 +            if (x->dim != y->dim)
233.2697 +               error_dimension(mpl, "symdiff", x->dim, y->dim);
233.2698 +            x = make_binary(mpl, O_SYMDIFF, x, y, A_ELEMSET, x->dim);
233.2699 +         }
233.2700 +         else
233.2701 +            break;
233.2702 +      }
233.2703 +      return x;
233.2704 +}
233.2705 +
233.2706 +/*----------------------------------------------------------------------
233.2707 +-- expression_10 - parse expression of level 10.
233.2708 +--
233.2709 +-- This routine parses expression of level 10 using the syntax:
233.2710 +--
233.2711 +-- <expression 10> ::= <expression 9>
233.2712 +-- <expression 10> ::= <expression 9> <rho> <expression 9>
233.2713 +-- <rho> ::= < | <= | = | == | >= | > | <> | != | in | not in | ! in |
233.2714 +--           within | not within | ! within */
233.2715 +
233.2716 +CODE *expression_10(MPL *mpl)
233.2717 +{     CODE *x, *y;
233.2718 +      int op = -1;
233.2719 +      char opstr[16];
233.2720 +      x = expression_9(mpl);
233.2721 +      strcpy(opstr, "");
233.2722 +      switch (mpl->token)
233.2723 +      {  case T_LT:
233.2724 +            op = O_LT; break;
233.2725 +         case T_LE:
233.2726 +            op = O_LE; break;
233.2727 +         case T_EQ:
233.2728 +            op = O_EQ; break;
233.2729 +         case T_GE:
233.2730 +            op = O_GE; break;
233.2731 +         case T_GT:
233.2732 +            op = O_GT; break;
233.2733 +         case T_NE:
233.2734 +            op = O_NE; break;
233.2735 +         case T_IN:
233.2736 +            op = O_IN; break;
233.2737 +         case T_WITHIN:
233.2738 +            op = O_WITHIN; break;
233.2739 +         case T_NOT:
233.2740 +            strcpy(opstr, mpl->image);
233.2741 +            get_token(mpl /* not | ! */);
233.2742 +            if (mpl->token == T_IN)
233.2743 +               op = O_NOTIN;
233.2744 +            else if (mpl->token == T_WITHIN)
233.2745 +               op = O_NOTWITHIN;
233.2746 +            else
233.2747 +               error(mpl, "invalid use of %s", opstr);
233.2748 +            strcat(opstr, " ");
233.2749 +            break;
233.2750 +         default:
233.2751 +            goto done;
233.2752 +      }
233.2753 +      strcat(opstr, mpl->image);
233.2754 +      xassert(strlen(opstr) < sizeof(opstr));
233.2755 +      switch (op)
233.2756 +      {  case O_EQ:
233.2757 +         case O_NE:
233.2758 +#if 1 /* 02/VIII-2008 */
233.2759 +         case O_LT:
233.2760 +         case O_LE:
233.2761 +         case O_GT:
233.2762 +         case O_GE:
233.2763 +#endif
233.2764 +            if (!(x->type == A_NUMERIC || x->type == A_SYMBOLIC))
233.2765 +               error_preceding(mpl, opstr);
233.2766 +            get_token(mpl /* <rho> */);
233.2767 +            y = expression_9(mpl);
233.2768 +            if (!(y->type == A_NUMERIC || y->type == A_SYMBOLIC))
233.2769 +               error_following(mpl, opstr);
233.2770 +            if (x->type == A_NUMERIC && y->type == A_SYMBOLIC)
233.2771 +               x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
233.2772 +            if (x->type == A_SYMBOLIC && y->type == A_NUMERIC)
233.2773 +               y = make_unary(mpl, O_CVTSYM, y, A_SYMBOLIC, 0);
233.2774 +            x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
233.2775 +            break;
233.2776 +#if 0 /* 02/VIII-2008 */
233.2777 +         case O_LT:
233.2778 +         case O_LE:
233.2779 +         case O_GT:
233.2780 +         case O_GE:
233.2781 +            if (x->type == A_SYMBOLIC)
233.2782 +               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2783 +            if (x->type != A_NUMERIC)
233.2784 +               error_preceding(mpl, opstr);
233.2785 +            get_token(mpl /* <rho> */);
233.2786 +            y = expression_9(mpl);
233.2787 +            if (y->type == A_SYMBOLIC)
233.2788 +               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2789 +            if (y->type != A_NUMERIC)
233.2790 +               error_following(mpl, opstr);
233.2791 +            x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
233.2792 +            break;
233.2793 +#endif
233.2794 +         case O_IN:
233.2795 +         case O_NOTIN:
233.2796 +            if (x->type == A_NUMERIC)
233.2797 +               x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
233.2798 +            if (x->type == A_SYMBOLIC)
233.2799 +               x = make_unary(mpl, O_CVTTUP, x, A_TUPLE, 1);
233.2800 +            if (x->type != A_TUPLE)
233.2801 +               error_preceding(mpl, opstr);
233.2802 +            get_token(mpl /* <rho> */);
233.2803 +            y = expression_9(mpl);
233.2804 +            if (y->type != A_ELEMSET)
233.2805 +               error_following(mpl, opstr);
233.2806 +            if (x->dim != y->dim)
233.2807 +               error_dimension(mpl, opstr, x->dim, y->dim);
233.2808 +            x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
233.2809 +            break;
233.2810 +         case O_WITHIN:
233.2811 +         case O_NOTWITHIN:
233.2812 +            if (x->type != A_ELEMSET)
233.2813 +               error_preceding(mpl, opstr);
233.2814 +            get_token(mpl /* <rho> */);
233.2815 +            y = expression_9(mpl);
233.2816 +            if (y->type != A_ELEMSET)
233.2817 +               error_following(mpl, opstr);
233.2818 +            if (x->dim != y->dim)
233.2819 +               error_dimension(mpl, opstr, x->dim, y->dim);
233.2820 +            x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
233.2821 +            break;
233.2822 +         default:
233.2823 +            xassert(op != op);
233.2824 +      }
233.2825 +done: return x;
233.2826 +}
233.2827 +
233.2828 +/*----------------------------------------------------------------------
233.2829 +-- expression_11 - parse expression of level 11.
233.2830 +--
233.2831 +-- This routine parses expression of level 11 using the syntax:
233.2832 +--
233.2833 +-- <expression 11> ::= <expression 10>
233.2834 +-- <expression 11> ::= not <expression 10>
233.2835 +-- <expression 11> ::= ! <expression 10> */
233.2836 +
233.2837 +CODE *expression_11(MPL *mpl)
233.2838 +{     CODE *x;
233.2839 +      char opstr[8];
233.2840 +      if (mpl->token == T_NOT)
233.2841 +      {  strcpy(opstr, mpl->image);
233.2842 +         xassert(strlen(opstr) < sizeof(opstr));
233.2843 +         get_token(mpl /* not | ! */);
233.2844 +         x = expression_10(mpl);
233.2845 +         if (x->type == A_SYMBOLIC)
233.2846 +            x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2847 +         if (x->type == A_NUMERIC)
233.2848 +            x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
233.2849 +         if (x->type != A_LOGICAL)
233.2850 +            error_following(mpl, opstr);
233.2851 +         x = make_unary(mpl, O_NOT, x, A_LOGICAL, 0);
233.2852 +      }
233.2853 +      else
233.2854 +         x = expression_10(mpl);
233.2855 +      return x;
233.2856 +}
233.2857 +
233.2858 +/*----------------------------------------------------------------------
233.2859 +-- expression_12 - parse expression of level 12.
233.2860 +--
233.2861 +-- This routine parses expression of level 12 using the syntax:
233.2862 +--
233.2863 +-- <expression 12> ::= <expression 11>
233.2864 +-- <expression 12> ::= <expression 12> and <expression 11>
233.2865 +-- <expression 12> ::= <expression 12> && <expression 11> */
233.2866 +
233.2867 +CODE *expression_12(MPL *mpl)
233.2868 +{     CODE *x, *y;
233.2869 +      char opstr[8];
233.2870 +      x = expression_11(mpl);
233.2871 +      for (;;)
233.2872 +      {  if (mpl->token == T_AND)
233.2873 +         {  strcpy(opstr, mpl->image);
233.2874 +            xassert(strlen(opstr) < sizeof(opstr));
233.2875 +            if (x->type == A_SYMBOLIC)
233.2876 +               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2877 +            if (x->type == A_NUMERIC)
233.2878 +               x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
233.2879 +            if (x->type != A_LOGICAL)
233.2880 +               error_preceding(mpl, opstr);
233.2881 +            get_token(mpl /* and | && */);
233.2882 +            y = expression_11(mpl);
233.2883 +            if (y->type == A_SYMBOLIC)
233.2884 +               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2885 +            if (y->type == A_NUMERIC)
233.2886 +               y = make_unary(mpl, O_CVTLOG, y, A_LOGICAL, 0);
233.2887 +            if (y->type != A_LOGICAL)
233.2888 +               error_following(mpl, opstr);
233.2889 +            x = make_binary(mpl, O_AND, x, y, A_LOGICAL, 0);
233.2890 +         }
233.2891 +         else
233.2892 +            break;
233.2893 +      }
233.2894 +      return x;
233.2895 +}
233.2896 +
233.2897 +/*----------------------------------------------------------------------
233.2898 +-- expression_13 - parse expression of level 13.
233.2899 +--
233.2900 +-- This routine parses expression of level 13 using the syntax:
233.2901 +--
233.2902 +-- <expression 13> ::= <expression 12>
233.2903 +-- <expression 13> ::= <expression 13> or <expression 12>
233.2904 +-- <expression 13> ::= <expression 13> || <expression 12> */
233.2905 +
233.2906 +CODE *expression_13(MPL *mpl)
233.2907 +{     CODE *x, *y;
233.2908 +      char opstr[8];
233.2909 +      x = expression_12(mpl);
233.2910 +      for (;;)
233.2911 +      {  if (mpl->token == T_OR)
233.2912 +         {  strcpy(opstr, mpl->image);
233.2913 +            xassert(strlen(opstr) < sizeof(opstr));
233.2914 +            if (x->type == A_SYMBOLIC)
233.2915 +               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2916 +            if (x->type == A_NUMERIC)
233.2917 +               x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
233.2918 +            if (x->type != A_LOGICAL)
233.2919 +               error_preceding(mpl, opstr);
233.2920 +            get_token(mpl /* or | || */);
233.2921 +            y = expression_12(mpl);
233.2922 +            if (y->type == A_SYMBOLIC)
233.2923 +               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2924 +            if (y->type == A_NUMERIC)
233.2925 +               y = make_unary(mpl, O_CVTLOG, y, A_LOGICAL, 0);
233.2926 +            if (y->type != A_LOGICAL)
233.2927 +               error_following(mpl, opstr);
233.2928 +            x = make_binary(mpl, O_OR, x, y, A_LOGICAL, 0);
233.2929 +         }
233.2930 +         else
233.2931 +            break;
233.2932 +      }
233.2933 +      return x;
233.2934 +}
233.2935 +
233.2936 +/*----------------------------------------------------------------------
233.2937 +-- set_statement - parse set statement.
233.2938 +--
233.2939 +-- This routine parses set statement using the syntax:
233.2940 +--
233.2941 +-- <set statement> ::= set <symbolic name> <alias> <domain>
233.2942 +--                     <attributes> ;
233.2943 +-- <alias> ::= <empty>
233.2944 +-- <alias> ::= <string literal>
233.2945 +-- <domain> ::= <empty>
233.2946 +-- <domain> ::= <indexing expression>
233.2947 +-- <attributes> ::= <empty>
233.2948 +-- <attributes> ::= <attributes> , dimen <numeric literal>
233.2949 +-- <attributes> ::= <attributes> , within <expression 9>
233.2950 +-- <attributes> ::= <attributes> , := <expression 9>
233.2951 +-- <attributes> ::= <attributes> , default <expression 9>
233.2952 +--
233.2953 +-- Commae in <attributes> are optional and may be omitted anywhere. */
233.2954 +
233.2955 +SET *set_statement(MPL *mpl)
233.2956 +{     SET *set;
233.2957 +      int dimen_used = 0;
233.2958 +      xassert(is_keyword(mpl, "set"));
233.2959 +      get_token(mpl /* set */);
233.2960 +      /* symbolic name must follow the keyword 'set' */
233.2961 +      if (mpl->token == T_NAME)
233.2962 +         ;
233.2963 +      else if (is_reserved(mpl))
233.2964 +         error(mpl, "invalid use of reserved keyword %s", mpl->image);
233.2965 +      else
233.2966 +         error(mpl, "symbolic name missing where expected");
233.2967 +      /* there must be no other object with the same name */
233.2968 +      if (avl_find_node(mpl->tree, mpl->image) != NULL)
233.2969 +         error(mpl, "%s multiply declared", mpl->image);
233.2970 +      /* create model set */
233.2971 +      set = alloc(SET);
233.2972 +      set->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.2973 +      strcpy(set->name, mpl->image);
233.2974 +      set->alias = NULL;
233.2975 +      set->dim = 0;
233.2976 +      set->domain = NULL;
233.2977 +      set->dimen = 0;
233.2978 +      set->within = NULL;
233.2979 +      set->assign = NULL;
233.2980 +      set->option = NULL;
233.2981 +      set->gadget = NULL;
233.2982 +      set->data = 0;
233.2983 +      set->array = NULL;
233.2984 +      get_token(mpl /* <symbolic name> */);
233.2985 +      /* parse optional alias */
233.2986 +      if (mpl->token == T_STRING)
233.2987 +      {  set->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.2988 +         strcpy(set->alias, mpl->image);
233.2989 +         get_token(mpl /* <string literal> */);
233.2990 +      }
233.2991 +      /* parse optional indexing expression */
233.2992 +      if (mpl->token == T_LBRACE)
233.2993 +      {  set->domain = indexing_expression(mpl);
233.2994 +         set->dim = domain_arity(mpl, set->domain);
233.2995 +      }
233.2996 +      /* include the set name in the symbolic names table */
233.2997 +      {  AVLNODE *node;
233.2998 +         node = avl_insert_node(mpl->tree, set->name);
233.2999 +         avl_set_node_type(node, A_SET);
233.3000 +         avl_set_node_link(node, (void *)set);
233.3001 +      }
233.3002 +      /* parse the list of optional attributes */
233.3003 +      for (;;)
233.3004 +      {  if (mpl->token == T_COMMA)
233.3005 +            get_token(mpl /* , */);
233.3006 +         else if (mpl->token == T_SEMICOLON)
233.3007 +            break;
233.3008 +         if (is_keyword(mpl, "dimen"))
233.3009 +         {  /* dimension of set members */
233.3010 +            int dimen;
233.3011 +            get_token(mpl /* dimen */);
233.3012 +            if (!(mpl->token == T_NUMBER &&
233.3013 +                  1.0 <= mpl->value && mpl->value <= 20.0 &&
233.3014 +                  floor(mpl->value) == mpl->value))
233.3015 +               error(mpl, "dimension must be integer between 1 and 20");
233.3016 +            dimen = (int)(mpl->value + 0.5);
233.3017 +            if (dimen_used)
233.3018 +               error(mpl, "at most one dimension attribute allowed");
233.3019 +            if (set->dimen > 0)
233.3020 +               error(mpl, "dimension %d conflicts with dimension %d alr"
233.3021 +                  "eady determined", dimen, set->dimen);
233.3022 +            set->dimen = dimen;
233.3023 +            dimen_used = 1;
233.3024 +            get_token(mpl /* <numeric literal> */);
233.3025 +         }
233.3026 +         else if (mpl->token == T_WITHIN || mpl->token == T_IN)
233.3027 +         {  /* restricting superset */
233.3028 +            WITHIN *within, *temp;
233.3029 +            if (mpl->token == T_IN && !mpl->as_within)
233.3030 +            {  warning(mpl, "keyword in understood as within");
233.3031 +               mpl->as_within = 1;
233.3032 +            }
233.3033 +            get_token(mpl /* within */);
233.3034 +            /* create new restricting superset list entry and append it
233.3035 +               to the within-list */
233.3036 +            within = alloc(WITHIN);
233.3037 +            within->code = NULL;
233.3038 +            within->next = NULL;
233.3039 +            if (set->within == NULL)
233.3040 +               set->within = within;
233.3041 +            else
233.3042 +            {  for (temp = set->within; temp->next != NULL; temp =
233.3043 +                  temp->next);
233.3044 +               temp->next = within;
233.3045 +            }
233.3046 +            /* parse an expression that follows 'within' */
233.3047 +            within->code = expression_9(mpl);
233.3048 +            if (within->code->type != A_ELEMSET)
233.3049 +               error(mpl, "expression following within has invalid type"
233.3050 +                  );
233.3051 +            xassert(within->code->dim > 0);
233.3052 +            /* check/set dimension of set members */
233.3053 +            if (set->dimen == 0) set->dimen = within->code->dim;
233.3054 +            if (set->dimen != within->code->dim)
233.3055 +               error(mpl, "set expression following within must have di"
233.3056 +                  "mension %d rather than %d",
233.3057 +                  set->dimen, within->code->dim);
233.3058 +         }
233.3059 +         else if (mpl->token == T_ASSIGN)
233.3060 +         {  /* assignment expression */
233.3061 +            if (!(set->assign == NULL && set->option == NULL &&
233.3062 +                  set->gadget == NULL))
233.3063 +err:           error(mpl, "at most one := or default/data allowed");
233.3064 +            get_token(mpl /* := */);
233.3065 +            /* parse an expression that follows ':=' */
233.3066 +            set->assign = expression_9(mpl);
233.3067 +            if (set->assign->type != A_ELEMSET)
233.3068 +               error(mpl, "expression following := has invalid type");
233.3069 +            xassert(set->assign->dim > 0);
233.3070 +            /* check/set dimension of set members */
233.3071 +            if (set->dimen == 0) set->dimen = set->assign->dim;
233.3072 +            if (set->dimen != set->assign->dim)
233.3073 +               error(mpl, "set expression following := must have dimens"
233.3074 +                  "ion %d rather than %d",
233.3075 +                  set->dimen, set->assign->dim);
233.3076 +         }
233.3077 +         else if (is_keyword(mpl, "default"))
233.3078 +         {  /* expression for default value */
233.3079 +            if (!(set->assign == NULL && set->option == NULL)) goto err;
233.3080 +            get_token(mpl /* := */);
233.3081 +            /* parse an expression that follows 'default' */
233.3082 +            set->option = expression_9(mpl);
233.3083 +            if (set->option->type != A_ELEMSET)
233.3084 +               error(mpl, "expression following default has invalid typ"
233.3085 +                  "e");
233.3086 +            xassert(set->option->dim > 0);
233.3087 +            /* check/set dimension of set members */
233.3088 +            if (set->dimen == 0) set->dimen = set->option->dim;
233.3089 +            if (set->dimen != set->option->dim)
233.3090 +               error(mpl, "set expression following default must have d"
233.3091 +                  "imension %d rather than %d",
233.3092 +                  set->dimen, set->option->dim);
233.3093 +         }
233.3094 +#if 1 /* 12/XII-2008 */
233.3095 +         else if (is_keyword(mpl, "data"))
233.3096 +         {  /* gadget to initialize the set by data from plain set */
233.3097 +            GADGET *gadget;
233.3098 +            AVLNODE *node;
233.3099 +            int i, k, fff[20];
233.3100 +            if (!(set->assign == NULL && set->gadget == NULL)) goto err;
233.3101 +            get_token(mpl /* data */);
233.3102 +            set->gadget = gadget = alloc(GADGET);
233.3103 +            /* set name must follow the keyword 'data' */
233.3104 +            if (mpl->token == T_NAME)
233.3105 +               ;
233.3106 +            else if (is_reserved(mpl))
233.3107 +               error(mpl, "invalid use of reserved keyword %s",
233.3108 +                  mpl->image);
233.3109 +            else
233.3110 +               error(mpl, "set name missing where expected");
233.3111 +            /* find the set in the symbolic name table */
233.3112 +            node = avl_find_node(mpl->tree, mpl->image);
233.3113 +            if (node == NULL)
233.3114 +               error(mpl, "%s not defined", mpl->image);
233.3115 +            if (avl_get_node_type(node) != A_SET)
233.3116 +err1:          error(mpl, "%s not a plain set", mpl->image);
233.3117 +            gadget->set = avl_get_node_link(node);
233.3118 +            if (gadget->set->dim != 0) goto err1;
233.3119 +            if (gadget->set == set)
233.3120 +               error(mpl, "set cannot be initialized by itself");
233.3121 +            /* check and set dimensions */
233.3122 +            if (set->dim >= gadget->set->dimen)
233.3123 +err2:          error(mpl, "dimension of %s too small", mpl->image);
233.3124 +            if (set->dimen == 0)
233.3125 +               set->dimen = gadget->set->dimen - set->dim;
233.3126 +            if (set->dim + set->dimen > gadget->set->dimen)
233.3127 +               goto err2;
233.3128 +            else if (set->dim + set->dimen < gadget->set->dimen)
233.3129 +               error(mpl, "dimension of %s too big", mpl->image);
233.3130 +            get_token(mpl /* set name */);
233.3131 +            /* left parenthesis must follow the set name */
233.3132 +            if (mpl->token == T_LEFT)
233.3133 +               get_token(mpl /* ( */);
233.3134 +            else
233.3135 +               error(mpl, "left parenthesis missing where expected");
233.3136 +            /* parse permutation of component numbers */
233.3137 +            for (k = 0; k < gadget->set->dimen; k++) fff[k] = 0;
233.3138 +            k = 0;
233.3139 +            for (;;)
233.3140 +            {  if (mpl->token != T_NUMBER)
233.3141 +                  error(mpl, "component number missing where expected");
233.3142 +               if (str2int(mpl->image, &i) != 0)
233.3143 +err3:             error(mpl, "component number must be integer between "
233.3144 +                     "1 and %d", gadget->set->dimen);
233.3145 +               if (!(1 <= i && i <= gadget->set->dimen)) goto err3;
233.3146 +               if (fff[i-1] != 0)
233.3147 +                  error(mpl, "component %d multiply specified", i);
233.3148 +               gadget->ind[k++] = i, fff[i-1] = 1;
233.3149 +               xassert(k <= gadget->set->dimen);
233.3150 +               get_token(mpl /* number */);
233.3151 +               if (mpl->token == T_COMMA)
233.3152 +                  get_token(mpl /* , */);
233.3153 +               else if (mpl->token == T_RIGHT)
233.3154 +                  break;
233.3155 +               else
233.3156 +                  error(mpl, "syntax error in data attribute");
233.3157 +            }
233.3158 +            if (k < gadget->set->dimen)
233.3159 +               error(mpl, "there are must be %d components rather than "
233.3160 +                  "%d", gadget->set->dimen, k);
233.3161 +            get_token(mpl /* ) */);
233.3162 +         }
233.3163 +#endif
233.3164 +         else
233.3165 +            error(mpl, "syntax error in set statement");
233.3166 +      }
233.3167 +      /* close the domain scope */
233.3168 +      if (set->domain != NULL) close_scope(mpl, set->domain);
233.3169 +      /* if dimension of set members is still unknown, set it to 1 */
233.3170 +      if (set->dimen == 0) set->dimen = 1;
233.3171 +      /* the set statement has been completely parsed */
233.3172 +      xassert(mpl->token == T_SEMICOLON);
233.3173 +      get_token(mpl /* ; */);
233.3174 +      return set;
233.3175 +}
233.3176 +
233.3177 +/*----------------------------------------------------------------------
233.3178 +-- parameter_statement - parse parameter statement.
233.3179 +--
233.3180 +-- This routine parses parameter statement using the syntax:
233.3181 +--
233.3182 +-- <parameter statement> ::= param <symbolic name> <alias> <domain>
233.3183 +--                           <attributes> ;
233.3184 +-- <alias> ::= <empty>
233.3185 +-- <alias> ::= <string literal>
233.3186 +-- <domain> ::= <empty>
233.3187 +-- <domain> ::= <indexing expression>
233.3188 +-- <attributes> ::= <empty>
233.3189 +-- <attributes> ::= <attributes> , integer
233.3190 +-- <attributes> ::= <attributes> , binary
233.3191 +-- <attributes> ::= <attributes> , symbolic
233.3192 +-- <attributes> ::= <attributes> , <rho> <expression 5>
233.3193 +-- <attributes> ::= <attributes> , in <expression 9>
233.3194 +-- <attributes> ::= <attributes> , := <expression 5>
233.3195 +-- <attributes> ::= <attributes> , default <expression 5>
233.3196 +-- <rho> ::= < | <= | = | == | >= | > | <> | !=
233.3197 +--
233.3198 +-- Commae in <attributes> are optional and may be omitted anywhere. */
233.3199 +
233.3200 +PARAMETER *parameter_statement(MPL *mpl)
233.3201 +{     PARAMETER *par;
233.3202 +      int integer_used = 0, binary_used = 0, symbolic_used = 0;
233.3203 +      xassert(is_keyword(mpl, "param"));
233.3204 +      get_token(mpl /* param */);
233.3205 +      /* symbolic name must follow the keyword 'param' */
233.3206 +      if (mpl->token == T_NAME)
233.3207 +         ;
233.3208 +      else if (is_reserved(mpl))
233.3209 +         error(mpl, "invalid use of reserved keyword %s", mpl->image);
233.3210 +      else
233.3211 +         error(mpl, "symbolic name missing where expected");
233.3212 +      /* there must be no other object with the same name */
233.3213 +      if (avl_find_node(mpl->tree, mpl->image) != NULL)
233.3214 +         error(mpl, "%s multiply declared", mpl->image);
233.3215 +      /* create model parameter */
233.3216 +      par = alloc(PARAMETER);
233.3217 +      par->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.3218 +      strcpy(par->name, mpl->image);
233.3219 +      par->alias = NULL;
233.3220 +      par->dim = 0;
233.3221 +      par->domain = NULL;
233.3222 +      par->type = A_NUMERIC;
233.3223 +      par->cond = NULL;
233.3224 +      par->in = NULL;
233.3225 +      par->assign = NULL;
233.3226 +      par->option = NULL;
233.3227 +      par->data = 0;
233.3228 +      par->defval = NULL;
233.3229 +      par->array = NULL;
233.3230 +      get_token(mpl /* <symbolic name> */);
233.3231 +      /* parse optional alias */
233.3232 +      if (mpl->token == T_STRING)
233.3233 +      {  par->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.3234 +         strcpy(par->alias, mpl->image);
233.3235 +         get_token(mpl /* <string literal> */);
233.3236 +      }
233.3237 +      /* parse optional indexing expression */
233.3238 +      if (mpl->token == T_LBRACE)
233.3239 +      {  par->domain = indexing_expression(mpl);
233.3240 +         par->dim = domain_arity(mpl, par->domain);
233.3241 +      }
233.3242 +      /* include the parameter name in the symbolic names table */
233.3243 +      {  AVLNODE *node;
233.3244 +         node = avl_insert_node(mpl->tree, par->name);
233.3245 +         avl_set_node_type(node, A_PARAMETER);
233.3246 +         avl_set_node_link(node, (void *)par);
233.3247 +      }
233.3248 +      /* parse the list of optional attributes */
233.3249 +      for (;;)
233.3250 +      {  if (mpl->token == T_COMMA)
233.3251 +            get_token(mpl /* , */);
233.3252 +         else if (mpl->token == T_SEMICOLON)
233.3253 +            break;
233.3254 +         if (is_keyword(mpl, "integer"))
233.3255 +         {  if (integer_used)
233.3256 +               error(mpl, "at most one integer allowed");
233.3257 +            if (par->type == A_SYMBOLIC)
233.3258 +               error(mpl, "symbolic parameter cannot be integer");
233.3259 +            if (par->type != A_BINARY) par->type = A_INTEGER;
233.3260 +            integer_used = 1;
233.3261 +            get_token(mpl /* integer */);
233.3262 +         }
233.3263 +         else if (is_keyword(mpl, "binary"))
233.3264 +bin:     {  if (binary_used)
233.3265 +               error(mpl, "at most one binary allowed");
233.3266 +            if (par->type == A_SYMBOLIC)
233.3267 +               error(mpl, "symbolic parameter cannot be binary");
233.3268 +            par->type = A_BINARY;
233.3269 +            binary_used = 1;
233.3270 +            get_token(mpl /* binary */);
233.3271 +         }
233.3272 +         else if (is_keyword(mpl, "logical"))
233.3273 +         {  if (!mpl->as_binary)
233.3274 +            {  warning(mpl, "keyword logical understood as binary");
233.3275 +               mpl->as_binary = 1;
233.3276 +            }
233.3277 +            goto bin;
233.3278 +         }
233.3279 +         else if (is_keyword(mpl, "symbolic"))
233.3280 +         {  if (symbolic_used)
233.3281 +               error(mpl, "at most one symbolic allowed");
233.3282 +            if (par->type != A_NUMERIC)
233.3283 +               error(mpl, "integer or binary parameter cannot be symbol"
233.3284 +                  "ic");
233.3285 +            /* the parameter may be referenced from expressions given
233.3286 +               in the same parameter declaration, so its type must be
233.3287 +               completed before parsing that expressions */
233.3288 +            if (!(par->cond == NULL && par->in == NULL &&
233.3289 +                  par->assign == NULL && par->option == NULL))
233.3290 +               error(mpl, "keyword symbolic must precede any other para"
233.3291 +                  "meter attributes");
233.3292 +            par->type = A_SYMBOLIC;
233.3293 +            symbolic_used = 1;
233.3294 +            get_token(mpl /* symbolic */);
233.3295 +         }
233.3296 +         else if (mpl->token == T_LT || mpl->token == T_LE ||
233.3297 +                  mpl->token == T_EQ || mpl->token == T_GE ||
233.3298 +                  mpl->token == T_GT || mpl->token == T_NE)
233.3299 +         {  /* restricting condition */
233.3300 +            CONDITION *cond, *temp;
233.3301 +            char opstr[8];
233.3302 +            /* create new restricting condition list entry and append
233.3303 +               it to the conditions list */
233.3304 +            cond = alloc(CONDITION);
233.3305 +            switch (mpl->token)
233.3306 +            {  case T_LT:
233.3307 +                  cond->rho = O_LT, strcpy(opstr, mpl->image); break;
233.3308 +               case T_LE:
233.3309 +                  cond->rho = O_LE, strcpy(opstr, mpl->image); break;
233.3310 +               case T_EQ:
233.3311 +                  cond->rho = O_EQ, strcpy(opstr, mpl->image); break;
233.3312 +               case T_GE:
233.3313 +                  cond->rho = O_GE, strcpy(opstr, mpl->image); break;
233.3314 +               case T_GT:
233.3315 +                  cond->rho = O_GT, strcpy(opstr, mpl->image); break;
233.3316 +               case T_NE:
233.3317 +                  cond->rho = O_NE, strcpy(opstr, mpl->image); break;
233.3318 +               default:
233.3319 +                  xassert(mpl->token != mpl->token);
233.3320 +            }
233.3321 +            xassert(strlen(opstr) < sizeof(opstr));
233.3322 +            cond->code = NULL;
233.3323 +            cond->next = NULL;
233.3324 +            if (par->cond == NULL)
233.3325 +               par->cond = cond;
233.3326 +            else
233.3327 +            {  for (temp = par->cond; temp->next != NULL; temp =
233.3328 +                  temp->next);
233.3329 +               temp->next = cond;
233.3330 +            }
233.3331 +#if 0 /* 13/VIII-2008 */
233.3332 +            if (par->type == A_SYMBOLIC &&
233.3333 +               !(cond->rho == O_EQ || cond->rho == O_NE))
233.3334 +               error(mpl, "inequality restriction not allowed");
233.3335 +#endif
233.3336 +            get_token(mpl /* rho */);
233.3337 +            /* parse an expression that follows relational operator */
233.3338 +            cond->code = expression_5(mpl);
233.3339 +            if (!(cond->code->type == A_NUMERIC ||
233.3340 +                  cond->code->type == A_SYMBOLIC))
233.3341 +               error(mpl, "expression following %s has invalid type",
233.3342 +                  opstr);
233.3343 +            xassert(cond->code->dim == 0);
233.3344 +            /* convert to the parameter type, if necessary */
233.3345 +            if (par->type != A_SYMBOLIC && cond->code->type ==
233.3346 +               A_SYMBOLIC)
233.3347 +               cond->code = make_unary(mpl, O_CVTNUM, cond->code,
233.3348 +                  A_NUMERIC, 0);
233.3349 +            if (par->type == A_SYMBOLIC && cond->code->type !=
233.3350 +               A_SYMBOLIC)
233.3351 +               cond->code = make_unary(mpl, O_CVTSYM, cond->code,
233.3352 +                  A_SYMBOLIC, 0);
233.3353 +         }
233.3354 +         else if (mpl->token == T_IN || mpl->token == T_WITHIN)
233.3355 +         {  /* restricting superset */
233.3356 +            WITHIN *in, *temp;
233.3357 +            if (mpl->token == T_WITHIN && !mpl->as_in)
233.3358 +            {  warning(mpl, "keyword within understood as in");
233.3359 +               mpl->as_in = 1;
233.3360 +            }
233.3361 +            get_token(mpl /* in */);
233.3362 +            /* create new restricting superset list entry and append it
233.3363 +               to the in-list */
233.3364 +            in = alloc(WITHIN);
233.3365 +            in->code = NULL;
233.3366 +            in->next = NULL;
233.3367 +            if (par->in == NULL)
233.3368 +               par->in = in;
233.3369 +            else
233.3370 +            {  for (temp = par->in; temp->next != NULL; temp =
233.3371 +                  temp->next);
233.3372 +               temp->next = in;
233.3373 +            }
233.3374 +            /* parse an expression that follows 'in' */
233.3375 +            in->code = expression_9(mpl);
233.3376 +            if (in->code->type != A_ELEMSET)
233.3377 +               error(mpl, "expression following in has invalid type");
233.3378 +            xassert(in->code->dim > 0);
233.3379 +            if (in->code->dim != 1)
233.3380 +               error(mpl, "set expression following in must have dimens"
233.3381 +                  "ion 1 rather than %d", in->code->dim);
233.3382 +         }
233.3383 +         else if (mpl->token == T_ASSIGN)
233.3384 +         {  /* assignment expression */
233.3385 +            if (!(par->assign == NULL && par->option == NULL))
233.3386 +err:           error(mpl, "at most one := or default allowed");
233.3387 +            get_token(mpl /* := */);
233.3388 +            /* parse an expression that follows ':=' */
233.3389 +            par->assign = expression_5(mpl);
233.3390 +            /* the expression must be of numeric/symbolic type */
233.3391 +            if (!(par->assign->type == A_NUMERIC ||
233.3392 +                  par->assign->type == A_SYMBOLIC))
233.3393 +               error(mpl, "expression following := has invalid type");
233.3394 +            xassert(par->assign->dim == 0);
233.3395 +            /* convert to the parameter type, if necessary */
233.3396 +            if (par->type != A_SYMBOLIC && par->assign->type ==
233.3397 +               A_SYMBOLIC)
233.3398 +               par->assign = make_unary(mpl, O_CVTNUM, par->assign,
233.3399 +                  A_NUMERIC, 0);
233.3400 +            if (par->type == A_SYMBOLIC && par->assign->type !=
233.3401 +               A_SYMBOLIC)
233.3402 +               par->assign = make_unary(mpl, O_CVTSYM, par->assign,
233.3403 +                  A_SYMBOLIC, 0);
233.3404 +         }
233.3405 +         else if (is_keyword(mpl, "default"))
233.3406 +         {  /* expression for default value */
233.3407 +            if (!(par->assign == NULL && par->option == NULL)) goto err;
233.3408 +            get_token(mpl /* default */);
233.3409 +            /* parse an expression that follows 'default' */
233.3410 +            par->option = expression_5(mpl);
233.3411 +            if (!(par->option->type == A_NUMERIC ||
233.3412 +                  par->option->type == A_SYMBOLIC))
233.3413 +               error(mpl, "expression following default has invalid typ"
233.3414 +                  "e");
233.3415 +            xassert(par->option->dim == 0);
233.3416 +            /* convert to the parameter type, if necessary */
233.3417 +            if (par->type != A_SYMBOLIC && par->option->type ==
233.3418 +               A_SYMBOLIC)
233.3419 +               par->option = make_unary(mpl, O_CVTNUM, par->option,
233.3420 +                  A_NUMERIC, 0);
233.3421 +            if (par->type == A_SYMBOLIC && par->option->type !=
233.3422 +               A_SYMBOLIC)
233.3423 +               par->option = make_unary(mpl, O_CVTSYM, par->option,
233.3424 +                  A_SYMBOLIC, 0);
233.3425 +         }
233.3426 +         else
233.3427 +            error(mpl, "syntax error in parameter statement");
233.3428 +      }
233.3429 +      /* close the domain scope */
233.3430 +      if (par->domain != NULL) close_scope(mpl, par->domain);
233.3431 +      /* the parameter statement has been completely parsed */
233.3432 +      xassert(mpl->token == T_SEMICOLON);
233.3433 +      get_token(mpl /* ; */);
233.3434 +      return par;
233.3435 +}
233.3436 +
233.3437 +/*----------------------------------------------------------------------
233.3438 +-- variable_statement - parse variable statement.
233.3439 +--
233.3440 +-- This routine parses variable statement using the syntax:
233.3441 +--
233.3442 +-- <variable statement> ::= var <symbolic name> <alias> <domain>
233.3443 +--                          <attributes> ;
233.3444 +-- <alias> ::= <empty>
233.3445 +-- <alias> ::= <string literal>
233.3446 +-- <domain> ::= <empty>
233.3447 +-- <domain> ::= <indexing expression>
233.3448 +-- <attributes> ::= <empty>
233.3449 +-- <attributes> ::= <attributes> , integer
233.3450 +-- <attributes> ::= <attributes> , binary
233.3451 +-- <attributes> ::= <attributes> , <rho> <expression 5>
233.3452 +-- <rho> ::= >= | <= | = | ==
233.3453 +--
233.3454 +-- Commae in <attributes> are optional and may be omitted anywhere. */
233.3455 +
233.3456 +VARIABLE *variable_statement(MPL *mpl)
233.3457 +{     VARIABLE *var;
233.3458 +      int integer_used = 0, binary_used = 0;
233.3459 +      xassert(is_keyword(mpl, "var"));
233.3460 +      if (mpl->flag_s)
233.3461 +         error(mpl, "variable statement must precede solve statement");
233.3462 +      get_token(mpl /* var */);
233.3463 +      /* symbolic name must follow the keyword 'var' */
233.3464 +      if (mpl->token == T_NAME)
233.3465 +         ;
233.3466 +      else if (is_reserved(mpl))
233.3467 +         error(mpl, "invalid use of reserved keyword %s", mpl->image);
233.3468 +      else
233.3469 +         error(mpl, "symbolic name missing where expected");
233.3470 +      /* there must be no other object with the same name */
233.3471 +      if (avl_find_node(mpl->tree, mpl->image) != NULL)
233.3472 +         error(mpl, "%s multiply declared", mpl->image);
233.3473 +      /* create model variable */
233.3474 +      var = alloc(VARIABLE);
233.3475 +      var->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.3476 +      strcpy(var->name, mpl->image);
233.3477 +      var->alias = NULL;
233.3478 +      var->dim = 0;
233.3479 +      var->domain = NULL;
233.3480 +      var->type = A_NUMERIC;
233.3481 +      var->lbnd = NULL;
233.3482 +      var->ubnd = NULL;
233.3483 +      var->array = NULL;
233.3484 +      get_token(mpl /* <symbolic name> */);
233.3485 +      /* parse optional alias */
233.3486 +      if (mpl->token == T_STRING)
233.3487 +      {  var->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.3488 +         strcpy(var->alias, mpl->image);
233.3489 +         get_token(mpl /* <string literal> */);
233.3490 +      }
233.3491 +      /* parse optional indexing expression */
233.3492 +      if (mpl->token == T_LBRACE)
233.3493 +      {  var->domain = indexing_expression(mpl);
233.3494 +         var->dim = domain_arity(mpl, var->domain);
233.3495 +      }
233.3496 +      /* include the variable name in the symbolic names table */
233.3497 +      {  AVLNODE *node;
233.3498 +         node = avl_insert_node(mpl->tree, var->name);
233.3499 +         avl_set_node_type(node, A_VARIABLE);
233.3500 +         avl_set_node_link(node, (void *)var);
233.3501 +      }
233.3502 +      /* parse the list of optional attributes */
233.3503 +      for (;;)
233.3504 +      {  if (mpl->token == T_COMMA)
233.3505 +            get_token(mpl /* , */);
233.3506 +         else if (mpl->token == T_SEMICOLON)
233.3507 +            break;
233.3508 +         if (is_keyword(mpl, "integer"))
233.3509 +         {  if (integer_used)
233.3510 +               error(mpl, "at most one integer allowed");
233.3511 +            if (var->type != A_BINARY) var->type = A_INTEGER;
233.3512 +            integer_used = 1;
233.3513 +            get_token(mpl /* integer */);
233.3514 +         }
233.3515 +         else if (is_keyword(mpl, "binary"))
233.3516 +bin:     {  if (binary_used)
233.3517 +               error(mpl, "at most one binary allowed");
233.3518 +            var->type = A_BINARY;
233.3519 +            binary_used = 1;
233.3520 +            get_token(mpl /* binary */);
233.3521 +         }
233.3522 +         else if (is_keyword(mpl, "logical"))
233.3523 +         {  if (!mpl->as_binary)
233.3524 +            {  warning(mpl, "keyword logical understood as binary");
233.3525 +               mpl->as_binary = 1;
233.3526 +            }
233.3527 +            goto bin;
233.3528 +         }
233.3529 +         else if (is_keyword(mpl, "symbolic"))
233.3530 +            error(mpl, "variable cannot be symbolic");
233.3531 +         else if (mpl->token == T_GE)
233.3532 +         {  /* lower bound */
233.3533 +            if (var->lbnd != NULL)
233.3534 +            {  if (var->lbnd == var->ubnd)
233.3535 +                  error(mpl, "both fixed value and lower bound not allo"
233.3536 +                     "wed");
233.3537 +               else
233.3538 +                  error(mpl, "at most one lower bound allowed");
233.3539 +            }
233.3540 +            get_token(mpl /* >= */);
233.3541 +            /* parse an expression that specifies the lower bound */
233.3542 +            var->lbnd = expression_5(mpl);
233.3543 +            if (var->lbnd->type == A_SYMBOLIC)
233.3544 +               var->lbnd = make_unary(mpl, O_CVTNUM, var->lbnd,
233.3545 +                  A_NUMERIC, 0);
233.3546 +            if (var->lbnd->type != A_NUMERIC)
233.3547 +               error(mpl, "expression following >= has invalid type");
233.3548 +            xassert(var->lbnd->dim == 0);
233.3549 +         }
233.3550 +         else if (mpl->token == T_LE)
233.3551 +         {  /* upper bound */
233.3552 +            if (var->ubnd != NULL)
233.3553 +            {  if (var->ubnd == var->lbnd)
233.3554 +                  error(mpl, "both fixed value and upper bound not allo"
233.3555 +                     "wed");
233.3556 +               else
233.3557 +                  error(mpl, "at most one upper bound allowed");
233.3558 +            }
233.3559 +            get_token(mpl /* <= */);
233.3560 +            /* parse an expression that specifies the upper bound */
233.3561 +            var->ubnd = expression_5(mpl);
233.3562 +            if (var->ubnd->type == A_SYMBOLIC)
233.3563 +               var->ubnd = make_unary(mpl, O_CVTNUM, var->ubnd,
233.3564 +                  A_NUMERIC, 0);
233.3565 +            if (var->ubnd->type != A_NUMERIC)
233.3566 +               error(mpl, "expression following <= has invalid type");
233.3567 +            xassert(var->ubnd->dim == 0);
233.3568 +         }
233.3569 +         else if (mpl->token == T_EQ)
233.3570 +         {  /* fixed value */
233.3571 +            char opstr[8];
233.3572 +            if (!(var->lbnd == NULL && var->ubnd == NULL))
233.3573 +            {  if (var->lbnd == var->ubnd)
233.3574 +                  error(mpl, "at most one fixed value allowed");
233.3575 +               else if (var->lbnd != NULL)
233.3576 +                  error(mpl, "both lower bound and fixed value not allo"
233.3577 +                     "wed");
233.3578 +               else
233.3579 +                  error(mpl, "both upper bound and fixed value not allo"
233.3580 +                     "wed");
233.3581 +            }
233.3582 +            strcpy(opstr, mpl->image);
233.3583 +            xassert(strlen(opstr) < sizeof(opstr));
233.3584 +            get_token(mpl /* = | == */);
233.3585 +            /* parse an expression that specifies the fixed value */
233.3586 +            var->lbnd = expression_5(mpl);
233.3587 +            if (var->lbnd->type == A_SYMBOLIC)
233.3588 +               var->lbnd = make_unary(mpl, O_CVTNUM, var->lbnd,
233.3589 +                  A_NUMERIC, 0);
233.3590 +            if (var->lbnd->type != A_NUMERIC)
233.3591 +               error(mpl, "expression following %s has invalid type",
233.3592 +                  opstr);
233.3593 +            xassert(var->lbnd->dim == 0);
233.3594 +            /* indicate that the variable is fixed, not bounded */
233.3595 +            var->ubnd = var->lbnd;
233.3596 +         }
233.3597 +         else if (mpl->token == T_LT || mpl->token == T_GT ||
233.3598 +                  mpl->token == T_NE)
233.3599 +            error(mpl, "strict bound not allowed");
233.3600 +         else
233.3601 +            error(mpl, "syntax error in variable statement");
233.3602 +      }
233.3603 +      /* close the domain scope */
233.3604 +      if (var->domain != NULL) close_scope(mpl, var->domain);
233.3605 +      /* the variable statement has been completely parsed */
233.3606 +      xassert(mpl->token == T_SEMICOLON);
233.3607 +      get_token(mpl /* ; */);
233.3608 +      return var;
233.3609 +}
233.3610 +
233.3611 +/*----------------------------------------------------------------------
233.3612 +-- constraint_statement - parse constraint statement.
233.3613 +--
233.3614 +-- This routine parses constraint statement using the syntax:
233.3615 +--
233.3616 +-- <constraint statement> ::= <subject to> <symbolic name> <alias>
233.3617 +--                            <domain> : <constraint> ;
233.3618 +-- <subject to> ::= <empty>
233.3619 +-- <subject to> ::= subject to
233.3620 +-- <subject to> ::= subj to
233.3621 +-- <subject to> ::= s.t.
233.3622 +-- <alias> ::= <empty>
233.3623 +-- <alias> ::= <string literal>
233.3624 +-- <domain> ::= <empty>
233.3625 +-- <domain> ::= <indexing expression>
233.3626 +-- <constraint> ::= <formula> , >= <formula>
233.3627 +-- <constraint> ::= <formula> , <= <formula>
233.3628 +-- <constraint> ::= <formula> , = <formula>
233.3629 +-- <constraint> ::= <formula> , <= <formula> , <= <formula>
233.3630 +-- <constraint> ::= <formula> , >= <formula> , >= <formula>
233.3631 +-- <formula> ::= <expression 5>
233.3632 +--
233.3633 +-- Commae in <constraint> are optional and may be omitted anywhere. */
233.3634 +
233.3635 +CONSTRAINT *constraint_statement(MPL *mpl)
233.3636 +{     CONSTRAINT *con;
233.3637 +      CODE *first, *second, *third;
233.3638 +      int rho;
233.3639 +      char opstr[8];
233.3640 +      if (mpl->flag_s)
233.3641 +         error(mpl, "constraint statement must precede solve statement")
233.3642 +            ;
233.3643 +      if (is_keyword(mpl, "subject"))
233.3644 +      {  get_token(mpl /* subject */);
233.3645 +         if (!is_keyword(mpl, "to"))
233.3646 +            error(mpl, "keyword subject to incomplete");
233.3647 +         get_token(mpl /* to */);
233.3648 +      }
233.3649 +      else if (is_keyword(mpl, "subj"))
233.3650 +      {  get_token(mpl /* subj */);
233.3651 +         if (!is_keyword(mpl, "to"))
233.3652 +            error(mpl, "keyword subj to incomplete");
233.3653 +         get_token(mpl /* to */);
233.3654 +      }
233.3655 +      else if (mpl->token == T_SPTP)
233.3656 +         get_token(mpl /* s.t. */);
233.3657 +      /* the current token must be symbolic name of constraint */
233.3658 +      if (mpl->token == T_NAME)
233.3659 +         ;
233.3660 +      else if (is_reserved(mpl))
233.3661 +         error(mpl, "invalid use of reserved keyword %s", mpl->image);
233.3662 +      else
233.3663 +         error(mpl, "symbolic name missing where expected");
233.3664 +      /* there must be no other object with the same name */
233.3665 +      if (avl_find_node(mpl->tree, mpl->image) != NULL)
233.3666 +         error(mpl, "%s multiply declared", mpl->image);
233.3667 +      /* create model constraint */
233.3668 +      con = alloc(CONSTRAINT);
233.3669 +      con->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.3670 +      strcpy(con->name, mpl->image);
233.3671 +      con->alias = NULL;
233.3672 +      con->dim = 0;
233.3673 +      con->domain = NULL;
233.3674 +      con->type = A_CONSTRAINT;
233.3675 +      con->code = NULL;
233.3676 +      con->lbnd = NULL;
233.3677 +      con->ubnd = NULL;
233.3678 +      con->array = NULL;
233.3679 +      get_token(mpl /* <symbolic name> */);
233.3680 +      /* parse optional alias */
233.3681 +      if (mpl->token == T_STRING)
233.3682 +      {  con->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.3683 +         strcpy(con->alias, mpl->image);
233.3684 +         get_token(mpl /* <string literal> */);
233.3685 +      }
233.3686 +      /* parse optional indexing expression */
233.3687 +      if (mpl->token == T_LBRACE)
233.3688 +      {  con->domain = indexing_expression(mpl);
233.3689 +         con->dim = domain_arity(mpl, con->domain);
233.3690 +      }
233.3691 +      /* include the constraint name in the symbolic names table */
233.3692 +      {  AVLNODE *node;
233.3693 +         node = avl_insert_node(mpl->tree, con->name);
233.3694 +         avl_set_node_type(node, A_CONSTRAINT);
233.3695 +         avl_set_node_link(node, (void *)con);
233.3696 +      }
233.3697 +      /* the colon must precede the first expression */
233.3698 +      if (mpl->token != T_COLON)
233.3699 +         error(mpl, "colon missing where expected");
233.3700 +      get_token(mpl /* : */);
233.3701 +      /* parse the first expression */
233.3702 +      first = expression_5(mpl);
233.3703 +      if (first->type == A_SYMBOLIC)
233.3704 +         first = make_unary(mpl, O_CVTNUM, first, A_NUMERIC, 0);
233.3705 +      if (!(first->type == A_NUMERIC || first->type == A_FORMULA))
233.3706 +         error(mpl, "expression following colon has invalid type");
233.3707 +      xassert(first->dim == 0);
233.3708 +      /* relational operator must follow the first expression */
233.3709 +      if (mpl->token == T_COMMA) get_token(mpl /* , */);
233.3710 +      switch (mpl->token)
233.3711 +      {  case T_LE:
233.3712 +         case T_GE:
233.3713 +         case T_EQ:
233.3714 +            break;
233.3715 +         case T_LT:
233.3716 +         case T_GT:
233.3717 +         case T_NE:
233.3718 +            error(mpl, "strict inequality not allowed");
233.3719 +         case T_SEMICOLON:
233.3720 +            error(mpl, "constraint must be equality or inequality");
233.3721 +         default:
233.3722 +            goto err;
233.3723 +      }
233.3724 +      rho = mpl->token;
233.3725 +      strcpy(opstr, mpl->image);
233.3726 +      xassert(strlen(opstr) < sizeof(opstr));
233.3727 +      get_token(mpl /* rho */);
233.3728 +      /* parse the second expression */
233.3729 +      second = expression_5(mpl);
233.3730 +      if (second->type == A_SYMBOLIC)
233.3731 +         second = make_unary(mpl, O_CVTNUM, second, A_NUMERIC, 0);
233.3732 +      if (!(second->type == A_NUMERIC || second->type == A_FORMULA))
233.3733 +         error(mpl, "expression following %s has invalid type", opstr);
233.3734 +      xassert(second->dim == 0);
233.3735 +      /* check a token that follow the second expression */
233.3736 +      if (mpl->token == T_COMMA)
233.3737 +      {  get_token(mpl /* , */);
233.3738 +         if (mpl->token == T_SEMICOLON) goto err;
233.3739 +      }
233.3740 +      if (mpl->token == T_LT || mpl->token == T_LE ||
233.3741 +          mpl->token == T_EQ || mpl->token == T_GE ||
233.3742 +          mpl->token == T_GT || mpl->token == T_NE)
233.3743 +      {  /* it is another relational operator, therefore the constraint
233.3744 +            is double inequality */
233.3745 +         if (rho == T_EQ || mpl->token != rho)
233.3746 +            error(mpl, "double inequality must be ... <= ... <= ... or "
233.3747 +               "... >= ... >= ...");
233.3748 +         /* the first expression cannot be linear form */
233.3749 +         if (first->type == A_FORMULA)
233.3750 +            error(mpl, "leftmost expression in double inequality cannot"
233.3751 +               " be linear form");
233.3752 +         get_token(mpl /* rho */);
233.3753 +         /* parse the third expression */
233.3754 +         third = expression_5(mpl);
233.3755 +         if (third->type == A_SYMBOLIC)
233.3756 +            third = make_unary(mpl, O_CVTNUM, second, A_NUMERIC, 0);
233.3757 +         if (!(third->type == A_NUMERIC || third->type == A_FORMULA))
233.3758 +            error(mpl, "rightmost expression in double inequality const"
233.3759 +               "raint has invalid type");
233.3760 +         xassert(third->dim == 0);
233.3761 +         /* the third expression also cannot be linear form */
233.3762 +         if (third->type == A_FORMULA)
233.3763 +            error(mpl, "rightmost expression in double inequality canno"
233.3764 +               "t be linear form");
233.3765 +      }
233.3766 +      else
233.3767 +      {  /* the constraint is equality or single inequality */
233.3768 +         third = NULL;
233.3769 +      }
233.3770 +      /* close the domain scope */
233.3771 +      if (con->domain != NULL) close_scope(mpl, con->domain);
233.3772 +      /* convert all expressions to linear form, if necessary */
233.3773 +      if (first->type != A_FORMULA)
233.3774 +         first = make_unary(mpl, O_CVTLFM, first, A_FORMULA, 0);
233.3775 +      if (second->type != A_FORMULA)
233.3776 +         second = make_unary(mpl, O_CVTLFM, second, A_FORMULA, 0);
233.3777 +      if (third != NULL)
233.3778 +         third = make_unary(mpl, O_CVTLFM, third, A_FORMULA, 0);
233.3779 +      /* arrange expressions in the constraint */
233.3780 +      if (third == NULL)
233.3781 +      {  /* the constraint is equality or single inequality */
233.3782 +         switch (rho)
233.3783 +         {  case T_LE:
233.3784 +               /* first <= second */
233.3785 +               con->code = first;
233.3786 +               con->lbnd = NULL;
233.3787 +               con->ubnd = second;
233.3788 +               break;
233.3789 +            case T_GE:
233.3790 +               /* first >= second */
233.3791 +               con->code = first;
233.3792 +               con->lbnd = second;
233.3793 +               con->ubnd = NULL;
233.3794 +               break;
233.3795 +            case T_EQ:
233.3796 +               /* first = second */
233.3797 +               con->code = first;
233.3798 +               con->lbnd = second;
233.3799 +               con->ubnd = second;
233.3800 +               break;
233.3801 +            default:
233.3802 +               xassert(rho != rho);
233.3803 +         }
233.3804 +      }
233.3805 +      else
233.3806 +      {  /* the constraint is double inequality */
233.3807 +         switch (rho)
233.3808 +         {  case T_LE:
233.3809 +               /* first <= second <= third */
233.3810 +               con->code = second;
233.3811 +               con->lbnd = first;
233.3812 +               con->ubnd = third;
233.3813 +               break;
233.3814 +            case T_GE:
233.3815 +               /* first >= second >= third */
233.3816 +               con->code = second;
233.3817 +               con->lbnd = third;
233.3818 +               con->ubnd = first;
233.3819 +               break;
233.3820 +            default:
233.3821 +               xassert(rho != rho);
233.3822 +         }
233.3823 +      }
233.3824 +      /* the constraint statement has been completely parsed */
233.3825 +      if (mpl->token != T_SEMICOLON)
233.3826 +err:     error(mpl, "syntax error in constraint statement");
233.3827 +      get_token(mpl /* ; */);
233.3828 +      return con;
233.3829 +}
233.3830 +
233.3831 +/*----------------------------------------------------------------------
233.3832 +-- objective_statement - parse objective statement.
233.3833 +--
233.3834 +-- This routine parses objective statement using the syntax:
233.3835 +--
233.3836 +-- <objective statement> ::= <verb> <symbolic name> <alias> <domain> :
233.3837 +--                           <formula> ;
233.3838 +-- <verb> ::= minimize
233.3839 +-- <verb> ::= maximize
233.3840 +-- <alias> ::= <empty>
233.3841 +-- <alias> ::= <string literal>
233.3842 +-- <domain> ::= <empty>
233.3843 +-- <domain> ::= <indexing expression>
233.3844 +-- <formula> ::= <expression 5> */
233.3845 +
233.3846 +CONSTRAINT *objective_statement(MPL *mpl)
233.3847 +{     CONSTRAINT *obj;
233.3848 +      int type;
233.3849 +      if (is_keyword(mpl, "minimize"))
233.3850 +         type = A_MINIMIZE;
233.3851 +      else if (is_keyword(mpl, "maximize"))
233.3852 +         type = A_MAXIMIZE;
233.3853 +      else
233.3854 +         xassert(mpl != mpl);
233.3855 +      if (mpl->flag_s)
233.3856 +         error(mpl, "objective statement must precede solve statement");
233.3857 +      get_token(mpl /* minimize | maximize */);
233.3858 +      /* symbolic name must follow the verb 'minimize' or 'maximize' */
233.3859 +      if (mpl->token == T_NAME)
233.3860 +         ;
233.3861 +      else if (is_reserved(mpl))
233.3862 +         error(mpl, "invalid use of reserved keyword %s", mpl->image);
233.3863 +      else
233.3864 +         error(mpl, "symbolic name missing where expected");
233.3865 +      /* there must be no other object with the same name */
233.3866 +      if (avl_find_node(mpl->tree, mpl->image) != NULL)
233.3867 +         error(mpl, "%s multiply declared", mpl->image);
233.3868 +      /* create model objective */
233.3869 +      obj = alloc(CONSTRAINT);
233.3870 +      obj->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.3871 +      strcpy(obj->name, mpl->image);
233.3872 +      obj->alias = NULL;
233.3873 +      obj->dim = 0;
233.3874 +      obj->domain = NULL;
233.3875 +      obj->type = type;
233.3876 +      obj->code = NULL;
233.3877 +      obj->lbnd = NULL;
233.3878 +      obj->ubnd = NULL;
233.3879 +      obj->array = NULL;
233.3880 +      get_token(mpl /* <symbolic name> */);
233.3881 +      /* parse optional alias */
233.3882 +      if (mpl->token == T_STRING)
233.3883 +      {  obj->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.3884 +         strcpy(obj->alias, mpl->image);
233.3885 +         get_token(mpl /* <string literal> */);
233.3886 +      }
233.3887 +      /* parse optional indexing expression */
233.3888 +      if (mpl->token == T_LBRACE)
233.3889 +      {  obj->domain = indexing_expression(mpl);
233.3890 +         obj->dim = domain_arity(mpl, obj->domain);
233.3891 +      }
233.3892 +      /* include the constraint name in the symbolic names table */
233.3893 +      {  AVLNODE *node;
233.3894 +         node = avl_insert_node(mpl->tree, obj->name);
233.3895 +         avl_set_node_type(node, A_CONSTRAINT);
233.3896 +         avl_set_node_link(node, (void *)obj);
233.3897 +      }
233.3898 +      /* the colon must precede the objective expression */
233.3899 +      if (mpl->token != T_COLON)
233.3900 +         error(mpl, "colon missing where expected");
233.3901 +      get_token(mpl /* : */);
233.3902 +      /* parse the objective expression */
233.3903 +      obj->code = expression_5(mpl);
233.3904 +      if (obj->code->type == A_SYMBOLIC)
233.3905 +         obj->code = make_unary(mpl, O_CVTNUM, obj->code, A_NUMERIC, 0);
233.3906 +      if (obj->code->type == A_NUMERIC)
233.3907 +         obj->code = make_unary(mpl, O_CVTLFM, obj->code, A_FORMULA, 0);
233.3908 +      if (obj->code->type != A_FORMULA)
233.3909 +         error(mpl, "expression following colon has invalid type");
233.3910 +      xassert(obj->code->dim == 0);
233.3911 +      /* close the domain scope */
233.3912 +      if (obj->domain != NULL) close_scope(mpl, obj->domain);
233.3913 +      /* the objective statement has been completely parsed */
233.3914 +      if (mpl->token != T_SEMICOLON)
233.3915 +         error(mpl, "syntax error in objective statement");
233.3916 +      get_token(mpl /* ; */);
233.3917 +      return obj;
233.3918 +}
233.3919 +
233.3920 +#if 1 /* 11/II-2008 */
233.3921 +/***********************************************************************
233.3922 +*  table_statement - parse table statement
233.3923 +*
233.3924 +*  This routine parses table statement using the syntax:
233.3925 +*
233.3926 +*  <table statement> ::= <input table statement>
233.3927 +*  <table statement> ::= <output table statement>
233.3928 +*
233.3929 +*  <input table statement> ::=
233.3930 +*        table <table name> <alias> IN <argument list> :
233.3931 +*        <input set> [ <field list> ] , <input list> ;
233.3932 +*  <alias> ::= <empty>
233.3933 +*  <alias> ::= <string literal>
233.3934 +*  <argument list> ::= <expression 5>
233.3935 +*  <argument list> ::= <argument list> <expression 5>
233.3936 +*  <argument list> ::= <argument list> , <expression 5>
233.3937 +*  <input set> ::= <empty>
233.3938 +*  <input set> ::= <set name> <-
233.3939 +*  <field list> ::= <field name>
233.3940 +*  <field list> ::= <field list> , <field name>
233.3941 +*  <input list> ::= <input item>
233.3942 +*  <input list> ::= <input list> , <input item>
233.3943 +*  <input item> ::= <parameter name>
233.3944 +*  <input item> ::= <parameter name> ~ <field name>
233.3945 +*
233.3946 +*  <output table statement> ::=
233.3947 +*        table <table name> <alias> <domain> OUT <argument list> :
233.3948 +*        <output list> ;
233.3949 +*  <domain> ::= <indexing expression>
233.3950 +*  <output list> ::= <output item>
233.3951 +*  <output list> ::= <output list> , <output item>
233.3952 +*  <output item> ::= <expression 5>
233.3953 +*  <output item> ::= <expression 5> ~ <field name> */
233.3954 +
233.3955 +TABLE *table_statement(MPL *mpl)
233.3956 +{     TABLE *tab;
233.3957 +      TABARG *last_arg, *arg;
233.3958 +      TABFLD *last_fld, *fld;
233.3959 +      TABIN *last_in, *in;
233.3960 +      TABOUT *last_out, *out;
233.3961 +      AVLNODE *node;
233.3962 +      int nflds;
233.3963 +      char name[MAX_LENGTH+1];
233.3964 +      xassert(is_keyword(mpl, "table"));
233.3965 +      get_token(mpl /* solve */);
233.3966 +      /* symbolic name must follow the keyword table */
233.3967 +      if (mpl->token == T_NAME)
233.3968 +         ;
233.3969 +      else if (is_reserved(mpl))
233.3970 +         error(mpl, "invalid use of reserved keyword %s", mpl->image);
233.3971 +      else
233.3972 +         error(mpl, "symbolic name missing where expected");
233.3973 +      /* there must be no other object with the same name */
233.3974 +      if (avl_find_node(mpl->tree, mpl->image) != NULL)
233.3975 +         error(mpl, "%s multiply declared", mpl->image);
233.3976 +      /* create data table */
233.3977 +      tab = alloc(TABLE);
233.3978 +      tab->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.3979 +      strcpy(tab->name, mpl->image);
233.3980 +      get_token(mpl /* <symbolic name> */);
233.3981 +      /* parse optional alias */
233.3982 +      if (mpl->token == T_STRING)
233.3983 +      {  tab->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.3984 +         strcpy(tab->alias, mpl->image);
233.3985 +         get_token(mpl /* <string literal> */);
233.3986 +      }
233.3987 +      else
233.3988 +         tab->alias = NULL;
233.3989 +      /* parse optional indexing expression */
233.3990 +      if (mpl->token == T_LBRACE)
233.3991 +      {  /* this is output table */
233.3992 +         tab->type = A_OUTPUT;
233.3993 +         tab->u.out.domain = indexing_expression(mpl);
233.3994 +         if (!is_keyword(mpl, "OUT"))
233.3995 +            error(mpl, "keyword OUT missing where expected");
233.3996 +         get_token(mpl /* OUT */);
233.3997 +      }
233.3998 +      else
233.3999 +      {  /* this is input table */
233.4000 +         tab->type = A_INPUT;
233.4001 +         if (!is_keyword(mpl, "IN"))
233.4002 +            error(mpl, "keyword IN missing where expected");
233.4003 +         get_token(mpl /* IN */);
233.4004 +      }
233.4005 +      /* parse argument list */
233.4006 +      tab->arg = last_arg = NULL;
233.4007 +      for (;;)
233.4008 +      {  /* create argument list entry */
233.4009 +         arg = alloc(TABARG);
233.4010 +         /* parse argument expression */
233.4011 +         if (mpl->token == T_COMMA || mpl->token == T_COLON ||
233.4012 +             mpl->token == T_SEMICOLON)
233.4013 +            error(mpl, "argument expression missing where expected");
233.4014 +         arg->code = expression_5(mpl);
233.4015 +         /* convert the result to symbolic type, if necessary */
233.4016 +         if (arg->code->type == A_NUMERIC)
233.4017 +            arg->code =
233.4018 +               make_unary(mpl, O_CVTSYM, arg->code, A_SYMBOLIC, 0);
233.4019 +         /* check that now the result is of symbolic type */
233.4020 +         if (arg->code->type != A_SYMBOLIC)
233.4021 +            error(mpl, "argument expression has invalid type");
233.4022 +         /* add the entry to the end of the list */
233.4023 +         arg->next = NULL;
233.4024 +         if (last_arg == NULL)
233.4025 +            tab->arg = arg;
233.4026 +         else
233.4027 +            last_arg->next = arg;
233.4028 +         last_arg = arg;
233.4029 +         /* argument expression has been parsed */
233.4030 +         if (mpl->token == T_COMMA)
233.4031 +            get_token(mpl /* , */);
233.4032 +         else if (mpl->token == T_COLON || mpl->token == T_SEMICOLON)
233.4033 +            break;
233.4034 +      }
233.4035 +      xassert(tab->arg != NULL);
233.4036 +      /* argument list must end with colon */
233.4037 +      if (mpl->token == T_COLON)
233.4038 +         get_token(mpl /* : */);
233.4039 +      else
233.4040 +         error(mpl, "colon missing where expected");
233.4041 +      /* parse specific part of the table statement */
233.4042 +      switch (tab->type)
233.4043 +      {  case A_INPUT:  goto input_table;
233.4044 +         case A_OUTPUT: goto output_table;
233.4045 +         default:       xassert(tab != tab);
233.4046 +      }
233.4047 +input_table:
233.4048 +      /* parse optional set name */
233.4049 +      if (mpl->token == T_NAME)
233.4050 +      {  node = avl_find_node(mpl->tree, mpl->image);
233.4051 +         if (node == NULL)
233.4052 +            error(mpl, "%s not defined", mpl->image);
233.4053 +         if (avl_get_node_type(node) != A_SET)
233.4054 +            error(mpl, "%s not a set", mpl->image);
233.4055 +         tab->u.in.set = (SET *)avl_get_node_link(node);
233.4056 +         if (tab->u.in.set->assign != NULL)
233.4057 +            error(mpl, "%s needs no data", mpl->image);
233.4058 +         if (tab->u.in.set->dim != 0)
233.4059 +            error(mpl, "%s must be a simple set", mpl->image);
233.4060 +         get_token(mpl /* <symbolic name> */);
233.4061 +         if (mpl->token == T_INPUT)
233.4062 +            get_token(mpl /* <- */);
233.4063 +         else
233.4064 +            error(mpl, "delimiter <- missing where expected");
233.4065 +      }
233.4066 +      else if (is_reserved(mpl))
233.4067 +         error(mpl, "invalid use of reserved keyword %s", mpl->image);
233.4068 +      else
233.4069 +         tab->u.in.set = NULL;
233.4070 +      /* parse field list */
233.4071 +      tab->u.in.fld = last_fld = NULL;
233.4072 +      nflds = 0;
233.4073 +      if (mpl->token == T_LBRACKET)
233.4074 +         get_token(mpl /* [ */);
233.4075 +      else
233.4076 +         error(mpl, "field list missing where expected");
233.4077 +      for (;;)
233.4078 +      {  /* create field list entry */
233.4079 +         fld = alloc(TABFLD);
233.4080 +         /* parse field name */
233.4081 +         if (mpl->token == T_NAME)
233.4082 +            ;
233.4083 +         else if (is_reserved(mpl))
233.4084 +            error(mpl,
233.4085 +               "invalid use of reserved keyword %s", mpl->image);
233.4086 +         else
233.4087 +            error(mpl, "field name missing where expected");
233.4088 +         fld->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.4089 +         strcpy(fld->name, mpl->image);
233.4090 +         get_token(mpl /* <symbolic name> */);
233.4091 +         /* add the entry to the end of the list */
233.4092 +         fld->next = NULL;
233.4093 +         if (last_fld == NULL)
233.4094 +            tab->u.in.fld = fld;
233.4095 +         else
233.4096 +            last_fld->next = fld;
233.4097 +         last_fld = fld;
233.4098 +         nflds++;
233.4099 +         /* field name has been parsed */
233.4100 +         if (mpl->token == T_COMMA)
233.4101 +            get_token(mpl /* , */);
233.4102 +         else if (mpl->token == T_RBRACKET)
233.4103 +            break;
233.4104 +         else
233.4105 +            error(mpl, "syntax error in field list");
233.4106 +      }
233.4107 +      /* check that the set dimen is equal to the number of fields */
233.4108 +      if (tab->u.in.set != NULL && tab->u.in.set->dimen != nflds)
233.4109 +         error(mpl, "there must be %d field%s rather than %d",
233.4110 +            tab->u.in.set->dimen, tab->u.in.set->dimen == 1 ? "" : "s",
233.4111 +            nflds);
233.4112 +      get_token(mpl /* ] */);
233.4113 +      /* parse optional input list */
233.4114 +      tab->u.in.list = last_in = NULL;
233.4115 +      while (mpl->token == T_COMMA)
233.4116 +      {  get_token(mpl /* , */);
233.4117 +         /* create input list entry */
233.4118 +         in = alloc(TABIN);
233.4119 +         /* parse parameter name */
233.4120 +         if (mpl->token == T_NAME)
233.4121 +            ;
233.4122 +         else if (is_reserved(mpl))
233.4123 +            error(mpl,
233.4124 +               "invalid use of reserved keyword %s", mpl->image);
233.4125 +         else
233.4126 +            error(mpl, "parameter name missing where expected");
233.4127 +         node = avl_find_node(mpl->tree, mpl->image);
233.4128 +         if (node == NULL)
233.4129 +            error(mpl, "%s not defined", mpl->image);
233.4130 +         if (avl_get_node_type(node) != A_PARAMETER)
233.4131 +            error(mpl, "%s not a parameter", mpl->image);
233.4132 +         in->par = (PARAMETER *)avl_get_node_link(node);
233.4133 +         if (in->par->dim != nflds)
233.4134 +            error(mpl, "%s must have %d subscript%s rather than %d",
233.4135 +               mpl->image, nflds, nflds == 1 ? "" : "s", in->par->dim);
233.4136 +         if (in->par->assign != NULL)
233.4137 +            error(mpl, "%s needs no data", mpl->image);
233.4138 +         get_token(mpl /* <symbolic name> */);
233.4139 +         /* parse optional field name */
233.4140 +         if (mpl->token == T_TILDE)
233.4141 +         {  get_token(mpl /* ~ */);
233.4142 +            /* parse field name */
233.4143 +            if (mpl->token == T_NAME)
233.4144 +               ;
233.4145 +            else if (is_reserved(mpl))
233.4146 +               error(mpl,
233.4147 +                  "invalid use of reserved keyword %s", mpl->image);
233.4148 +            else
233.4149 +               error(mpl, "field name missing where expected");
233.4150 +            xassert(strlen(mpl->image) < sizeof(name));
233.4151 +            strcpy(name, mpl->image);
233.4152 +            get_token(mpl /* <symbolic name> */);
233.4153 +         }
233.4154 +         else
233.4155 +         {  /* field name is the same as the parameter name */
233.4156 +            xassert(strlen(in->par->name) < sizeof(name));
233.4157 +            strcpy(name, in->par->name);
233.4158 +         }
233.4159 +         /* assign field name */
233.4160 +         in->name = dmp_get_atomv(mpl->pool, strlen(name)+1);
233.4161 +         strcpy(in->name, name);
233.4162 +         /* add the entry to the end of the list */
233.4163 +         in->next = NULL;
233.4164 +         if (last_in == NULL)
233.4165 +            tab->u.in.list = in;
233.4166 +         else
233.4167 +            last_in->next = in;
233.4168 +         last_in = in;
233.4169 +      }
233.4170 +      goto end_of_table;
233.4171 +output_table:
233.4172 +      /* parse output list */
233.4173 +      tab->u.out.list = last_out = NULL;
233.4174 +      for (;;)
233.4175 +      {  /* create output list entry */
233.4176 +         out = alloc(TABOUT);
233.4177 +         /* parse expression */
233.4178 +         if (mpl->token == T_COMMA || mpl->token == T_SEMICOLON)
233.4179 +            error(mpl, "expression missing where expected");
233.4180 +         if (mpl->token == T_NAME)
233.4181 +         {  xassert(strlen(mpl->image) < sizeof(name));
233.4182 +            strcpy(name, mpl->image);
233.4183 +         }
233.4184 +         else
233.4185 +            name[0] = '\0';
233.4186 +         out->code = expression_5(mpl);
233.4187 +         /* parse optional field name */
233.4188 +         if (mpl->token == T_TILDE)
233.4189 +         {  get_token(mpl /* ~ */);
233.4190 +            /* parse field name */
233.4191 +            if (mpl->token == T_NAME)
233.4192 +               ;
233.4193 +            else if (is_reserved(mpl))
233.4194 +               error(mpl,
233.4195 +                  "invalid use of reserved keyword %s", mpl->image);
233.4196 +            else
233.4197 +               error(mpl, "field name missing where expected");
233.4198 +            xassert(strlen(mpl->image) < sizeof(name));
233.4199 +            strcpy(name, mpl->image);
233.4200 +            get_token(mpl /* <symbolic name> */);
233.4201 +         }
233.4202 +         /* assign field name */
233.4203 +         if (name[0] == '\0')
233.4204 +            error(mpl, "field name required");
233.4205 +         out->name = dmp_get_atomv(mpl->pool, strlen(name)+1);
233.4206 +         strcpy(out->name, name);
233.4207 +         /* add the entry to the end of the list */
233.4208 +         out->next = NULL;
233.4209 +         if (last_out == NULL)
233.4210 +            tab->u.out.list = out;
233.4211 +         else
233.4212 +            last_out->next = out;
233.4213 +         last_out = out;
233.4214 +         /* output item has been parsed */
233.4215 +         if (mpl->token == T_COMMA)
233.4216 +            get_token(mpl /* , */);
233.4217 +         else if (mpl->token == T_SEMICOLON)
233.4218 +            break;
233.4219 +         else
233.4220 +            error(mpl, "syntax error in output list");
233.4221 +      }
233.4222 +      /* close the domain scope */
233.4223 +      close_scope(mpl,tab->u.out.domain);
233.4224 +end_of_table:
233.4225 +      /* the table statement must end with semicolon */
233.4226 +      if (mpl->token != T_SEMICOLON)
233.4227 +         error(mpl, "syntax error in table statement");
233.4228 +      get_token(mpl /* ; */);
233.4229 +      return tab;
233.4230 +}
233.4231 +#endif
233.4232 +
233.4233 +/*----------------------------------------------------------------------
233.4234 +-- solve_statement - parse solve statement.
233.4235 +--
233.4236 +-- This routine parses solve statement using the syntax:
233.4237 +--
233.4238 +-- <solve statement> ::= solve ;
233.4239 +--
233.4240 +-- The solve statement can be used at most once. */
233.4241 +
233.4242 +void *solve_statement(MPL *mpl)
233.4243 +{     xassert(is_keyword(mpl, "solve"));
233.4244 +      if (mpl->flag_s)
233.4245 +         error(mpl, "at most one solve statement allowed");
233.4246 +      mpl->flag_s = 1;
233.4247 +      get_token(mpl /* solve */);
233.4248 +      /* semicolon must follow solve statement */
233.4249 +      if (mpl->token != T_SEMICOLON)
233.4250 +         error(mpl, "syntax error in solve statement");
233.4251 +      get_token(mpl /* ; */);
233.4252 +      return NULL;
233.4253 +}
233.4254 +
233.4255 +/*----------------------------------------------------------------------
233.4256 +-- check_statement - parse check statement.
233.4257 +--
233.4258 +-- This routine parses check statement using the syntax:
233.4259 +--
233.4260 +-- <check statement> ::= check <domain> : <expression 13> ;
233.4261 +-- <domain> ::= <empty>
233.4262 +-- <domain> ::= <indexing expression>
233.4263 +--
233.4264 +-- If <domain> is omitted, colon following it may also be omitted. */
233.4265 +
233.4266 +CHECK *check_statement(MPL *mpl)
233.4267 +{     CHECK *chk;
233.4268 +      xassert(is_keyword(mpl, "check"));
233.4269 +      /* create check descriptor */
233.4270 +      chk = alloc(CHECK);
233.4271 +      chk->domain = NULL;
233.4272 +      chk->code = NULL;
233.4273 +      get_token(mpl /* check */);
233.4274 +      /* parse optional indexing expression */
233.4275 +      if (mpl->token == T_LBRACE)
233.4276 +      {  chk->domain = indexing_expression(mpl);
233.4277 +#if 0
233.4278 +         if (mpl->token != T_COLON)
233.4279 +            error(mpl, "colon missing where expected");
233.4280 +#endif
233.4281 +      }
233.4282 +      /* skip optional colon */
233.4283 +      if (mpl->token == T_COLON) get_token(mpl /* : */);
233.4284 +      /* parse logical expression */
233.4285 +      chk->code = expression_13(mpl);
233.4286 +      if (chk->code->type != A_LOGICAL)
233.4287 +         error(mpl, "expression has invalid type");
233.4288 +      xassert(chk->code->dim == 0);
233.4289 +      /* close the domain scope */
233.4290 +      if (chk->domain != NULL) close_scope(mpl, chk->domain);
233.4291 +      /* the check statement has been completely parsed */
233.4292 +      if (mpl->token != T_SEMICOLON)
233.4293 +         error(mpl, "syntax error in check statement");
233.4294 +      get_token(mpl /* ; */);
233.4295 +      return chk;
233.4296 +}
233.4297 +
233.4298 +#if 1 /* 15/V-2010 */
233.4299 +/*----------------------------------------------------------------------
233.4300 +-- display_statement - parse display statement.
233.4301 +--
233.4302 +-- This routine parses display statement using the syntax:
233.4303 +--
233.4304 +-- <display statement> ::= display <domain> : <display list> ;
233.4305 +-- <display statement> ::= display <domain> <display list> ;
233.4306 +-- <domain> ::= <empty>
233.4307 +-- <domain> ::= <indexing expression>
233.4308 +-- <display list> ::= <display entry>
233.4309 +-- <display list> ::= <display list> , <display entry>
233.4310 +-- <display entry> ::= <dummy index>
233.4311 +-- <display entry> ::= <set name>
233.4312 +-- <display entry> ::= <set name> [ <subscript list> ]
233.4313 +-- <display entry> ::= <parameter name>
233.4314 +-- <display entry> ::= <parameter name> [ <subscript list> ]
233.4315 +-- <display entry> ::= <variable name>
233.4316 +-- <display entry> ::= <variable name> [ <subscript list> ]
233.4317 +-- <display entry> ::= <constraint name>
233.4318 +-- <display entry> ::= <constraint name> [ <subscript list> ]
233.4319 +-- <display entry> ::= <expression 13> */
233.4320 +
233.4321 +DISPLAY *display_statement(MPL *mpl)
233.4322 +{     DISPLAY *dpy;
233.4323 +      DISPLAY1 *entry, *last_entry;
233.4324 +      xassert(is_keyword(mpl, "display"));
233.4325 +      /* create display descriptor */
233.4326 +      dpy = alloc(DISPLAY);
233.4327 +      dpy->domain = NULL;
233.4328 +      dpy->list = last_entry = NULL;
233.4329 +      get_token(mpl /* display */);
233.4330 +      /* parse optional indexing expression */
233.4331 +      if (mpl->token == T_LBRACE)
233.4332 +         dpy->domain = indexing_expression(mpl);
233.4333 +      /* skip optional colon */
233.4334 +      if (mpl->token == T_COLON) get_token(mpl /* : */);
233.4335 +      /* parse display list */
233.4336 +      for (;;)
233.4337 +      {  /* create new display entry */
233.4338 +         entry = alloc(DISPLAY1);
233.4339 +         entry->type = 0;
233.4340 +         entry->next = NULL;
233.4341 +         /* and append it to the display list */
233.4342 +         if (dpy->list == NULL)
233.4343 +            dpy->list = entry;
233.4344 +         else
233.4345 +            last_entry->next = entry;
233.4346 +         last_entry = entry;
233.4347 +         /* parse display entry */
233.4348 +         if (mpl->token == T_NAME)
233.4349 +         {  AVLNODE *node;
233.4350 +            int next_token;
233.4351 +            get_token(mpl /* <symbolic name> */);
233.4352 +            next_token = mpl->token;
233.4353 +            unget_token(mpl);
233.4354 +            if (!(next_token == T_COMMA || next_token == T_SEMICOLON))
233.4355 +            {  /* symbolic name begins expression */
233.4356 +               goto expr;
233.4357 +            }
233.4358 +            /* display entry is dummy index or model object */
233.4359 +            node = avl_find_node(mpl->tree, mpl->image);
233.4360 +            if (node == NULL)
233.4361 +               error(mpl, "%s not defined", mpl->image);
233.4362 +            entry->type = avl_get_node_type(node);
233.4363 +            switch (avl_get_node_type(node))
233.4364 +            {  case A_INDEX:
233.4365 +                  entry->u.slot =
233.4366 +                     (DOMAIN_SLOT *)avl_get_node_link(node);
233.4367 +                  break;
233.4368 +               case A_SET:
233.4369 +                  entry->u.set = (SET *)avl_get_node_link(node);
233.4370 +                  break;
233.4371 +               case A_PARAMETER:
233.4372 +                  entry->u.par = (PARAMETER *)avl_get_node_link(node);
233.4373 +                  break;
233.4374 +               case A_VARIABLE:
233.4375 +                  entry->u.var = (VARIABLE *)avl_get_node_link(node);
233.4376 +                  if (!mpl->flag_s)
233.4377 +                     error(mpl, "invalid reference to variable %s above"
233.4378 +                        " solve statement", entry->u.var->name);
233.4379 +                  break;
233.4380 +               case A_CONSTRAINT:
233.4381 +                  entry->u.con = (CONSTRAINT *)avl_get_node_link(node);
233.4382 +                  if (!mpl->flag_s)
233.4383 +                     error(mpl, "invalid reference to %s %s above solve"
233.4384 +                        " statement",
233.4385 +                        entry->u.con->type == A_CONSTRAINT ?
233.4386 +                        "constraint" : "objective", entry->u.con->name);
233.4387 +                  break;
233.4388 +               default:
233.4389 +                  xassert(node != node);
233.4390 +            }
233.4391 +            get_token(mpl /* <symbolic name> */);
233.4392 +         }
233.4393 +         else
233.4394 +expr:    {  /* display entry is expression */
233.4395 +            entry->type = A_EXPRESSION;
233.4396 +            entry->u.code = expression_13(mpl);
233.4397 +         }
233.4398 +         /* check a token that follows the entry parsed */
233.4399 +         if (mpl->token == T_COMMA)
233.4400 +            get_token(mpl /* , */);
233.4401 +         else
233.4402 +            break;
233.4403 +      }
233.4404 +      /* close the domain scope */
233.4405 +      if (dpy->domain != NULL) close_scope(mpl, dpy->domain);
233.4406 +      /* the display statement has been completely parsed */
233.4407 +      if (mpl->token != T_SEMICOLON)
233.4408 +         error(mpl, "syntax error in display statement");
233.4409 +      get_token(mpl /* ; */);
233.4410 +      return dpy;
233.4411 +}
233.4412 +#endif
233.4413 +
233.4414 +/*----------------------------------------------------------------------
233.4415 +-- printf_statement - parse printf statement.
233.4416 +--
233.4417 +-- This routine parses print statement using the syntax:
233.4418 +--
233.4419 +-- <printf statement> ::= <printf clause> ;
233.4420 +-- <printf statement> ::= <printf clause> > <file name> ;
233.4421 +-- <printf statement> ::= <printf clause> >> <file name> ;
233.4422 +-- <printf clause> ::= printf <domain> : <format> <printf list>
233.4423 +-- <printf clause> ::= printf <domain> <format> <printf list>
233.4424 +-- <domain> ::= <empty>
233.4425 +-- <domain> ::= <indexing expression>
233.4426 +-- <format> ::= <expression 5>
233.4427 +-- <printf list> ::= <empty>
233.4428 +-- <printf list> ::= <printf list> , <printf entry>
233.4429 +-- <printf entry> ::= <expression 9>
233.4430 +-- <file name> ::= <expression 5> */
233.4431 +
233.4432 +PRINTF *printf_statement(MPL *mpl)
233.4433 +{     PRINTF *prt;
233.4434 +      PRINTF1 *entry, *last_entry;
233.4435 +      xassert(is_keyword(mpl, "printf"));
233.4436 +      /* create printf descriptor */
233.4437 +      prt = alloc(PRINTF);
233.4438 +      prt->domain = NULL;
233.4439 +      prt->fmt = NULL;
233.4440 +      prt->list = last_entry = NULL;
233.4441 +      get_token(mpl /* printf */);
233.4442 +      /* parse optional indexing expression */
233.4443 +      if (mpl->token == T_LBRACE)
233.4444 +      {  prt->domain = indexing_expression(mpl);
233.4445 +#if 0
233.4446 +         if (mpl->token != T_COLON)
233.4447 +            error(mpl, "colon missing where expected");
233.4448 +#endif
233.4449 +      }
233.4450 +      /* skip optional colon */
233.4451 +      if (mpl->token == T_COLON) get_token(mpl /* : */);
233.4452 +      /* parse expression for format string */
233.4453 +      prt->fmt = expression_5(mpl);
233.4454 +      /* convert it to symbolic type, if necessary */
233.4455 +      if (prt->fmt->type == A_NUMERIC)
233.4456 +         prt->fmt = make_unary(mpl, O_CVTSYM, prt->fmt, A_SYMBOLIC, 0);
233.4457 +      /* check that now the expression is of symbolic type */
233.4458 +      if (prt->fmt->type != A_SYMBOLIC)
233.4459 +         error(mpl, "format expression has invalid type");
233.4460 +      /* parse printf list */
233.4461 +      while (mpl->token == T_COMMA)
233.4462 +      {  get_token(mpl /* , */);
233.4463 +         /* create new printf entry */
233.4464 +         entry = alloc(PRINTF1);
233.4465 +         entry->code = NULL;
233.4466 +         entry->next = NULL;
233.4467 +         /* and append it to the printf list */
233.4468 +         if (prt->list == NULL)
233.4469 +            prt->list = entry;
233.4470 +         else
233.4471 +            last_entry->next = entry;
233.4472 +         last_entry = entry;
233.4473 +         /* parse printf entry */
233.4474 +         entry->code = expression_9(mpl);
233.4475 +         if (!(entry->code->type == A_NUMERIC ||
233.4476 +               entry->code->type == A_SYMBOLIC ||
233.4477 +               entry->code->type == A_LOGICAL))
233.4478 +            error(mpl, "only numeric, symbolic, or logical expression a"
233.4479 +               "llowed");
233.4480 +      }
233.4481 +      /* close the domain scope */
233.4482 +      if (prt->domain != NULL) close_scope(mpl, prt->domain);
233.4483 +#if 1 /* 14/VII-2006 */
233.4484 +      /* parse optional redirection */
233.4485 +      prt->fname = NULL, prt->app = 0;
233.4486 +      if (mpl->token == T_GT || mpl->token == T_APPEND)
233.4487 +      {  prt->app = (mpl->token == T_APPEND);
233.4488 +         get_token(mpl /* > or >> */);
233.4489 +         /* parse expression for file name string */
233.4490 +         prt->fname = expression_5(mpl);
233.4491 +         /* convert it to symbolic type, if necessary */
233.4492 +         if (prt->fname->type == A_NUMERIC)
233.4493 +            prt->fname = make_unary(mpl, O_CVTSYM, prt->fname,
233.4494 +               A_SYMBOLIC, 0);
233.4495 +         /* check that now the expression is of symbolic type */
233.4496 +         if (prt->fname->type != A_SYMBOLIC)
233.4497 +            error(mpl, "file name expression has invalid type");
233.4498 +      }
233.4499 +#endif
233.4500 +      /* the printf statement has been completely parsed */
233.4501 +      if (mpl->token != T_SEMICOLON)
233.4502 +         error(mpl, "syntax error in printf statement");
233.4503 +      get_token(mpl /* ; */);
233.4504 +      return prt;
233.4505 +}
233.4506 +
233.4507 +/*----------------------------------------------------------------------
233.4508 +-- for_statement - parse for statement.
233.4509 +--
233.4510 +-- This routine parses for statement using the syntax:
233.4511 +--
233.4512 +-- <for statement> ::= for <domain> <statement>
233.4513 +-- <for statement> ::= for <domain> { <statement list> }
233.4514 +-- <domain> ::= <indexing expression>
233.4515 +-- <statement list> ::= <empty>
233.4516 +-- <statement list> ::= <statement list> <statement>
233.4517 +-- <statement> ::= <check statement>
233.4518 +-- <statement> ::= <display statement>
233.4519 +-- <statement> ::= <printf statement>
233.4520 +-- <statement> ::= <for statement> */
233.4521 +
233.4522 +FOR *for_statement(MPL *mpl)
233.4523 +{     FOR *fur;
233.4524 +      STATEMENT *stmt, *last_stmt;
233.4525 +      xassert(is_keyword(mpl, "for"));
233.4526 +      /* create for descriptor */
233.4527 +      fur = alloc(FOR);
233.4528 +      fur->domain = NULL;
233.4529 +      fur->list = last_stmt = NULL;
233.4530 +      get_token(mpl /* for */);
233.4531 +      /* parse indexing expression */
233.4532 +      if (mpl->token != T_LBRACE)
233.4533 +         error(mpl, "indexing expression missing where expected");
233.4534 +      fur->domain = indexing_expression(mpl);
233.4535 +      /* skip optional colon */
233.4536 +      if (mpl->token == T_COLON) get_token(mpl /* : */);
233.4537 +      /* parse for statement body */
233.4538 +      if (mpl->token != T_LBRACE)
233.4539 +      {  /* parse simple statement */
233.4540 +         fur->list = simple_statement(mpl, 1);
233.4541 +      }
233.4542 +      else
233.4543 +      {  /* parse compound statement */
233.4544 +         get_token(mpl /* { */);
233.4545 +         while (mpl->token != T_RBRACE)
233.4546 +         {  /* parse statement */
233.4547 +            stmt = simple_statement(mpl, 1);
233.4548 +            /* and append it to the end of the statement list */
233.4549 +            if (last_stmt == NULL)
233.4550 +               fur->list = stmt;
233.4551 +            else
233.4552 +               last_stmt->next = stmt;
233.4553 +            last_stmt = stmt;
233.4554 +         }
233.4555 +         get_token(mpl /* } */);
233.4556 +      }
233.4557 +      /* close the domain scope */
233.4558 +      xassert(fur->domain != NULL);
233.4559 +      close_scope(mpl, fur->domain);
233.4560 +      /* the for statement has been completely parsed */
233.4561 +      return fur;
233.4562 +}
233.4563 +
233.4564 +/*----------------------------------------------------------------------
233.4565 +-- end_statement - parse end statement.
233.4566 +--
233.4567 +-- This routine parses end statement using the syntax:
233.4568 +--
233.4569 +-- <end statement> ::= end ; <eof> */
233.4570 +
233.4571 +void end_statement(MPL *mpl)
233.4572 +{     if (!mpl->flag_d && is_keyword(mpl, "end") ||
233.4573 +           mpl->flag_d && is_literal(mpl, "end"))
233.4574 +      {  get_token(mpl /* end */);
233.4575 +         if (mpl->token == T_SEMICOLON)
233.4576 +            get_token(mpl /* ; */);
233.4577 +         else
233.4578 +            warning(mpl, "no semicolon following end statement; missing"
233.4579 +               " semicolon inserted");
233.4580 +      }
233.4581 +      else
233.4582 +         warning(mpl, "unexpected end of file; missing end statement in"
233.4583 +            "serted");
233.4584 +      if (mpl->token != T_EOF)
233.4585 +         warning(mpl, "some text detected beyond end statement; text ig"
233.4586 +            "nored");
233.4587 +      return;
233.4588 +}
233.4589 +
233.4590 +/*----------------------------------------------------------------------
233.4591 +-- simple_statement - parse simple statement.
233.4592 +--
233.4593 +-- This routine parses simple statement using the syntax:
233.4594 +--
233.4595 +-- <statement> ::= <set statement>
233.4596 +-- <statement> ::= <parameter statement>
233.4597 +-- <statement> ::= <variable statement>
233.4598 +-- <statement> ::= <constraint statement>
233.4599 +-- <statement> ::= <objective statement>
233.4600 +-- <statement> ::= <solve statement>
233.4601 +-- <statement> ::= <check statement>
233.4602 +-- <statement> ::= <display statement>
233.4603 +-- <statement> ::= <printf statement>
233.4604 +-- <statement> ::= <for statement>
233.4605 +--
233.4606 +-- If the flag spec is set, some statements cannot be used. */
233.4607 +
233.4608 +STATEMENT *simple_statement(MPL *mpl, int spec)
233.4609 +{     STATEMENT *stmt;
233.4610 +      stmt = alloc(STATEMENT);
233.4611 +      stmt->line = mpl->line;
233.4612 +      stmt->next = NULL;
233.4613 +      if (is_keyword(mpl, "set"))
233.4614 +      {  if (spec)
233.4615 +            error(mpl, "set statement not allowed here");
233.4616 +         stmt->type = A_SET;
233.4617 +         stmt->u.set = set_statement(mpl);
233.4618 +      }
233.4619 +      else if (is_keyword(mpl, "param"))
233.4620 +      {  if (spec)
233.4621 +            error(mpl, "parameter statement not allowed here");
233.4622 +         stmt->type = A_PARAMETER;
233.4623 +         stmt->u.par = parameter_statement(mpl);
233.4624 +      }
233.4625 +      else if (is_keyword(mpl, "var"))
233.4626 +      {  if (spec)
233.4627 +            error(mpl, "variable statement not allowed here");
233.4628 +         stmt->type = A_VARIABLE;
233.4629 +         stmt->u.var = variable_statement(mpl);
233.4630 +      }
233.4631 +      else if (is_keyword(mpl, "subject") ||
233.4632 +               is_keyword(mpl, "subj") ||
233.4633 +               mpl->token == T_SPTP)
233.4634 +      {  if (spec)
233.4635 +            error(mpl, "constraint statement not allowed here");
233.4636 +         stmt->type = A_CONSTRAINT;
233.4637 +         stmt->u.con = constraint_statement(mpl);
233.4638 +      }
233.4639 +      else if (is_keyword(mpl, "minimize") ||
233.4640 +               is_keyword(mpl, "maximize"))
233.4641 +      {  if (spec)
233.4642 +            error(mpl, "objective statement not allowed here");
233.4643 +         stmt->type = A_CONSTRAINT;
233.4644 +         stmt->u.con = objective_statement(mpl);
233.4645 +      }
233.4646 +#if 1 /* 11/II-2008 */
233.4647 +      else if (is_keyword(mpl, "table"))
233.4648 +      {  if (spec)
233.4649 +            error(mpl, "table statement not allowed here");
233.4650 +         stmt->type = A_TABLE;
233.4651 +         stmt->u.tab = table_statement(mpl);
233.4652 +      }
233.4653 +#endif
233.4654 +      else if (is_keyword(mpl, "solve"))
233.4655 +      {  if (spec)
233.4656 +            error(mpl, "solve statement not allowed here");
233.4657 +         stmt->type = A_SOLVE;
233.4658 +         stmt->u.slv = solve_statement(mpl);
233.4659 +      }
233.4660 +      else if (is_keyword(mpl, "check"))
233.4661 +      {  stmt->type = A_CHECK;
233.4662 +         stmt->u.chk = check_statement(mpl);
233.4663 +      }
233.4664 +      else if (is_keyword(mpl, "display"))
233.4665 +      {  stmt->type = A_DISPLAY;
233.4666 +         stmt->u.dpy = display_statement(mpl);
233.4667 +      }
233.4668 +      else if (is_keyword(mpl, "printf"))
233.4669 +      {  stmt->type = A_PRINTF;
233.4670 +         stmt->u.prt = printf_statement(mpl);
233.4671 +      }
233.4672 +      else if (is_keyword(mpl, "for"))
233.4673 +      {  stmt->type = A_FOR;
233.4674 +         stmt->u.fur = for_statement(mpl);
233.4675 +      }
233.4676 +      else if (mpl->token == T_NAME)
233.4677 +      {  if (spec)
233.4678 +            error(mpl, "constraint statement not allowed here");
233.4679 +         stmt->type = A_CONSTRAINT;
233.4680 +         stmt->u.con = constraint_statement(mpl);
233.4681 +      }
233.4682 +      else if (is_reserved(mpl))
233.4683 +         error(mpl, "invalid use of reserved keyword %s", mpl->image);
233.4684 +      else
233.4685 +         error(mpl, "syntax error in model section");
233.4686 +      return stmt;
233.4687 +}
233.4688 +
233.4689 +/*----------------------------------------------------------------------
233.4690 +-- model_section - parse model section.
233.4691 +--
233.4692 +-- This routine parses model section using the syntax:
233.4693 +--
233.4694 +-- <model section> ::= <empty>
233.4695 +-- <model section> ::= <model section> <statement>
233.4696 +--
233.4697 +-- Parsing model section is terminated by either the keyword 'data', or
233.4698 +-- the keyword 'end', or the end of file. */
233.4699 +
233.4700 +void model_section(MPL *mpl)
233.4701 +{     STATEMENT *stmt, *last_stmt;
233.4702 +      xassert(mpl->model == NULL);
233.4703 +      last_stmt = NULL;
233.4704 +      while (!(mpl->token == T_EOF || is_keyword(mpl, "data") ||
233.4705 +               is_keyword(mpl, "end")))
233.4706 +      {  /* parse statement */
233.4707 +         stmt = simple_statement(mpl, 0);
233.4708 +         /* and append it to the end of the statement list */
233.4709 +         if (last_stmt == NULL)
233.4710 +            mpl->model = stmt;
233.4711 +         else
233.4712 +            last_stmt->next = stmt;
233.4713 +         last_stmt = stmt;
233.4714 +      }
233.4715 +      return;
233.4716 +}
233.4717 +
233.4718 +/* eof */
   234.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   234.2 +++ b/src/glpmpl02.c	Mon Dec 06 13:09:21 2010 +0100
   234.3 @@ -0,0 +1,1205 @@
   234.4 +/* glpmpl02.c */
   234.5 +
   234.6 +/***********************************************************************
   234.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   234.8 +*
   234.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  234.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  234.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  234.12 +*  E-mail: <mao@gnu.org>.
  234.13 +*
  234.14 +*  GLPK is free software: you can redistribute it and/or modify it
  234.15 +*  under the terms of the GNU General Public License as published by
  234.16 +*  the Free Software Foundation, either version 3 of the License, or
  234.17 +*  (at your option) any later version.
  234.18 +*
  234.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  234.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  234.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  234.22 +*  License for more details.
  234.23 +*
  234.24 +*  You should have received a copy of the GNU General Public License
  234.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  234.26 +***********************************************************************/
  234.27 +
  234.28 +#define _GLPSTD_STDIO
  234.29 +#include "glpenv.h"
  234.30 +#include "glpmpl.h"
  234.31 +
  234.32 +/**********************************************************************/
  234.33 +/* * *                  PROCESSING DATA SECTION                   * * */
  234.34 +/**********************************************************************/
  234.35 +
  234.36 +/*----------------------------------------------------------------------
  234.37 +-- create_slice - create slice.
  234.38 +--
  234.39 +-- This routine creates a slice, which initially has no components. */
  234.40 +
  234.41 +SLICE *create_slice(MPL *mpl)
  234.42 +{     SLICE *slice;
  234.43 +      xassert(mpl == mpl);
  234.44 +      slice = NULL;
  234.45 +      return slice;
  234.46 +}
  234.47 +
  234.48 +/*----------------------------------------------------------------------
  234.49 +-- expand_slice - append new component to slice.
  234.50 +--
  234.51 +-- This routine expands slice appending to it either a given symbol or
  234.52 +-- null component, which becomes the last component of the slice. */
  234.53 +
  234.54 +SLICE *expand_slice
  234.55 +(     MPL *mpl,
  234.56 +      SLICE *slice,           /* destroyed */
  234.57 +      SYMBOL *sym             /* destroyed */
  234.58 +)
  234.59 +{     SLICE *tail, *temp;
  234.60 +      /* create a new component */
  234.61 +      tail = dmp_get_atom(mpl->tuples, sizeof(SLICE));
  234.62 +      tail->sym = sym;
  234.63 +      tail->next = NULL;
  234.64 +      /* and append it to the component list */
  234.65 +      if (slice == NULL)
  234.66 +         slice = tail;
  234.67 +      else
  234.68 +      {  for (temp = slice; temp->next != NULL; temp = temp->next);
  234.69 +         temp->next = tail;
  234.70 +      }
  234.71 +      return slice;
  234.72 +}
  234.73 +
  234.74 +/*----------------------------------------------------------------------
  234.75 +-- slice_dimen - determine dimension of slice.
  234.76 +--
  234.77 +-- This routine returns dimension of slice, which is number of all its
  234.78 +-- components including null ones. */
  234.79 +
  234.80 +int slice_dimen
  234.81 +(     MPL *mpl,
  234.82 +      SLICE *slice            /* not changed */
  234.83 +)
  234.84 +{     SLICE *temp;
  234.85 +      int dim;
  234.86 +      xassert(mpl == mpl);
  234.87 +      dim = 0;
  234.88 +      for (temp = slice; temp != NULL; temp = temp->next) dim++;
  234.89 +      return dim;
  234.90 +}
  234.91 +
  234.92 +/*----------------------------------------------------------------------
  234.93 +-- slice_arity - determine arity of slice.
  234.94 +--
  234.95 +-- This routine returns arity of slice, i.e. number of null components
  234.96 +-- (indicated by asterisks) in the slice. */
  234.97 +
  234.98 +int slice_arity
  234.99 +(     MPL *mpl,
 234.100 +      SLICE *slice            /* not changed */
 234.101 +)
 234.102 +{     SLICE *temp;
 234.103 +      int arity;
 234.104 +      xassert(mpl == mpl);
 234.105 +      arity = 0;
 234.106 +      for (temp = slice; temp != NULL; temp = temp->next)
 234.107 +         if (temp->sym == NULL) arity++;
 234.108 +      return arity;
 234.109 +}
 234.110 +
 234.111 +/*----------------------------------------------------------------------
 234.112 +-- fake_slice - create fake slice of all asterisks.
 234.113 +--
 234.114 +-- This routine creates a fake slice of given dimension, which contains
 234.115 +-- asterisks in all components. Zero dimension is allowed. */
 234.116 +
 234.117 +SLICE *fake_slice(MPL *mpl, int dim)
 234.118 +{     SLICE *slice;
 234.119 +      slice = create_slice(mpl);
 234.120 +      while (dim-- > 0) slice = expand_slice(mpl, slice, NULL);
 234.121 +      return slice;
 234.122 +}
 234.123 +
 234.124 +/*----------------------------------------------------------------------
 234.125 +-- delete_slice - delete slice.
 234.126 +--
 234.127 +-- This routine deletes specified slice. */
 234.128 +
 234.129 +void delete_slice
 234.130 +(     MPL *mpl,
 234.131 +      SLICE *slice            /* destroyed */
 234.132 +)
 234.133 +{     SLICE *temp;
 234.134 +      while (slice != NULL)
 234.135 +      {  temp = slice;
 234.136 +         slice = temp->next;
 234.137 +         if (temp->sym != NULL) delete_symbol(mpl, temp->sym);
 234.138 +xassert(sizeof(SLICE) == sizeof(TUPLE));
 234.139 +         dmp_free_atom(mpl->tuples, temp, sizeof(TUPLE));
 234.140 +      }
 234.141 +      return;
 234.142 +}
 234.143 +
 234.144 +/*----------------------------------------------------------------------
 234.145 +-- is_number - check if current token is number.
 234.146 +--
 234.147 +-- If the current token is a number, this routine returns non-zero.
 234.148 +-- Otherwise zero is returned. */
 234.149 +
 234.150 +int is_number(MPL *mpl)
 234.151 +{     return
 234.152 +         mpl->token == T_NUMBER;
 234.153 +}
 234.154 +
 234.155 +/*----------------------------------------------------------------------
 234.156 +-- is_symbol - check if current token is symbol.
 234.157 +--
 234.158 +-- If the current token is suitable to be a symbol, the routine returns
 234.159 +-- non-zero. Otherwise zero is returned. */
 234.160 +
 234.161 +int is_symbol(MPL *mpl)
 234.162 +{     return
 234.163 +         mpl->token == T_NUMBER ||
 234.164 +         mpl->token == T_SYMBOL ||
 234.165 +         mpl->token == T_STRING;
 234.166 +}
 234.167 +
 234.168 +/*----------------------------------------------------------------------
 234.169 +-- is_literal - check if current token is given symbolic literal.
 234.170 +--
 234.171 +-- If the current token is given symbolic literal, this routine returns
 234.172 +-- non-zero. Otherwise zero is returned.
 234.173 +--
 234.174 +-- This routine is used on processing the data section in the same way
 234.175 +-- as the routine is_keyword on processing the model section. */
 234.176 +
 234.177 +int is_literal(MPL *mpl, char *literal)
 234.178 +{     return
 234.179 +         is_symbol(mpl) && strcmp(mpl->image, literal) == 0;
 234.180 +}
 234.181 +
 234.182 +/*----------------------------------------------------------------------
 234.183 +-- read_number - read number.
 234.184 +--
 234.185 +-- This routine reads the current token, which must be a number, and
 234.186 +-- returns its numeric value. */
 234.187 +
 234.188 +double read_number(MPL *mpl)
 234.189 +{     double num;
 234.190 +      xassert(is_number(mpl));
 234.191 +      num = mpl->value;
 234.192 +      get_token(mpl /* <number> */);
 234.193 +      return num;
 234.194 +}
 234.195 +
 234.196 +/*----------------------------------------------------------------------
 234.197 +-- read_symbol - read symbol.
 234.198 +--
 234.199 +-- This routine reads the current token, which must be a symbol, and
 234.200 +-- returns its symbolic value. */
 234.201 +
 234.202 +SYMBOL *read_symbol(MPL *mpl)
 234.203 +{     SYMBOL *sym;
 234.204 +      xassert(is_symbol(mpl));
 234.205 +      if (is_number(mpl))
 234.206 +         sym = create_symbol_num(mpl, mpl->value);
 234.207 +      else
 234.208 +         sym = create_symbol_str(mpl, create_string(mpl, mpl->image));
 234.209 +      get_token(mpl /* <symbol> */);
 234.210 +      return sym;
 234.211 +}
 234.212 +
 234.213 +/*----------------------------------------------------------------------
 234.214 +-- read_slice - read slice.
 234.215 +--
 234.216 +-- This routine reads slice using the syntax:
 234.217 +--
 234.218 +-- <slice> ::= [ <symbol list> ]
 234.219 +-- <slice> ::= ( <symbol list> )
 234.220 +-- <symbol list> ::= <symbol or star>
 234.221 +-- <symbol list> ::= <symbol list> , <symbol or star>
 234.222 +-- <symbol or star> ::= <symbol>
 234.223 +-- <symbol or star> ::= *
 234.224 +--
 234.225 +-- The bracketed form of slice is used for members of multi-dimensional
 234.226 +-- objects while the parenthesized form is used for elemental sets. */
 234.227 +
 234.228 +SLICE *read_slice
 234.229 +(     MPL *mpl,
 234.230 +      char *name,             /* not changed */
 234.231 +      int dim
 234.232 +)
 234.233 +{     SLICE *slice;
 234.234 +      int close;
 234.235 +      xassert(name != NULL);
 234.236 +      switch (mpl->token)
 234.237 +      {  case T_LBRACKET:
 234.238 +            close = T_RBRACKET;
 234.239 +            break;
 234.240 +         case T_LEFT:
 234.241 +            xassert(dim > 0);
 234.242 +            close = T_RIGHT;
 234.243 +            break;
 234.244 +         default:
 234.245 +            xassert(mpl != mpl);
 234.246 +      }
 234.247 +      if (dim == 0)
 234.248 +         error(mpl, "%s cannot be subscripted", name);
 234.249 +      get_token(mpl /* ( | [ */);
 234.250 +      /* read slice components */
 234.251 +      slice = create_slice(mpl);
 234.252 +      for (;;)
 234.253 +      {  /* the current token must be a symbol or asterisk */
 234.254 +         if (is_symbol(mpl))
 234.255 +            slice = expand_slice(mpl, slice, read_symbol(mpl));
 234.256 +         else if (mpl->token == T_ASTERISK)
 234.257 +         {  slice = expand_slice(mpl, slice, NULL);
 234.258 +            get_token(mpl /* * */);
 234.259 +         }
 234.260 +         else
 234.261 +            error(mpl, "number, symbol, or asterisk missing where expec"
 234.262 +               "ted");
 234.263 +         /* check a token that follows the symbol */
 234.264 +         if (mpl->token == T_COMMA)
 234.265 +            get_token(mpl /* , */);
 234.266 +         else if (mpl->token == close)
 234.267 +            break;
 234.268 +         else
 234.269 +            error(mpl, "syntax error in slice");
 234.270 +      }
 234.271 +      /* number of slice components must be the same as the appropriate
 234.272 +         dimension */
 234.273 +      if (slice_dimen(mpl, slice) != dim)
 234.274 +      {  switch (close)
 234.275 +         {  case T_RBRACKET:
 234.276 +               error(mpl, "%s must have %d subscript%s, not %d", name,
 234.277 +                  dim, dim == 1 ? "" : "s", slice_dimen(mpl, slice));
 234.278 +               break;
 234.279 +            case T_RIGHT:
 234.280 +               error(mpl, "%s has dimension %d, not %d", name, dim,
 234.281 +                  slice_dimen(mpl, slice));
 234.282 +               break;
 234.283 +            default:
 234.284 +               xassert(close != close);
 234.285 +         }
 234.286 +      }
 234.287 +      get_token(mpl /* ) | ] */);
 234.288 +      return slice;
 234.289 +}
 234.290 +
 234.291 +/*----------------------------------------------------------------------
 234.292 +-- select_set - select set to saturate it with elemental sets.
 234.293 +--
 234.294 +-- This routine selects set to saturate it with elemental sets provided
 234.295 +-- in the data section. */
 234.296 +
 234.297 +SET *select_set
 234.298 +(     MPL *mpl,
 234.299 +      char *name              /* not changed */
 234.300 +)
 234.301 +{     SET *set;
 234.302 +      AVLNODE *node;
 234.303 +      xassert(name != NULL);
 234.304 +      node = avl_find_node(mpl->tree, name);
 234.305 +      if (node == NULL || avl_get_node_type(node) != A_SET)
 234.306 +         error(mpl, "%s not a set", name);
 234.307 +      set = (SET *)avl_get_node_link(node);
 234.308 +      if (set->assign != NULL || set->gadget != NULL)
 234.309 +         error(mpl, "%s needs no data", name);
 234.310 +      set->data = 1;
 234.311 +      return set;
 234.312 +}
 234.313 +
 234.314 +/*----------------------------------------------------------------------
 234.315 +-- simple_format - read set data block in simple format.
 234.316 +--
 234.317 +-- This routine reads set data block using the syntax:
 234.318 +--
 234.319 +-- <simple format> ::= <symbol> , <symbol> , ... , <symbol>
 234.320 +--
 234.321 +-- where <symbols> are used to construct a complete n-tuple, which is
 234.322 +-- included in elemental set assigned to the set member. Commae between
 234.323 +-- symbols are optional and may be omitted anywhere.
 234.324 +--
 234.325 +-- Number of components in the slice must be the same as dimension of
 234.326 +-- n-tuples in elemental sets assigned to the set members. To construct
 234.327 +-- complete n-tuple the routine replaces null positions in the slice by
 234.328 +-- corresponding <symbols>.
 234.329 +--
 234.330 +-- If the slice contains at least one null position, the current token
 234.331 +-- must be symbol. Otherwise, the routine reads no symbols to construct
 234.332 +-- the n-tuple, so the current token is not checked. */
 234.333 +
 234.334 +void simple_format
 234.335 +(     MPL *mpl,
 234.336 +      SET *set,               /* not changed */
 234.337 +      MEMBER *memb,           /* modified */
 234.338 +      SLICE *slice            /* not changed */
 234.339 +)
 234.340 +{     TUPLE *tuple;
 234.341 +      SLICE *temp;
 234.342 +      SYMBOL *sym, *with = NULL;
 234.343 +      xassert(set != NULL);
 234.344 +      xassert(memb != NULL);
 234.345 +      xassert(slice != NULL);
 234.346 +      xassert(set->dimen == slice_dimen(mpl, slice));
 234.347 +      xassert(memb->value.set->dim == set->dimen);
 234.348 +      if (slice_arity(mpl, slice) > 0) xassert(is_symbol(mpl));
 234.349 +      /* read symbols and construct complete n-tuple */
 234.350 +      tuple = create_tuple(mpl);
 234.351 +      for (temp = slice; temp != NULL; temp = temp->next)
 234.352 +      {  if (temp->sym == NULL)
 234.353 +         {  /* substitution is needed; read symbol */
 234.354 +            if (!is_symbol(mpl))
 234.355 +            {  int lack = slice_arity(mpl, temp);
 234.356 +               /* with cannot be null due to assertion above */
 234.357 +               xassert(with != NULL);
 234.358 +               if (lack == 1)
 234.359 +                  error(mpl, "one item missing in data group beginning "
 234.360 +                     "with %s", format_symbol(mpl, with));
 234.361 +               else
 234.362 +                  error(mpl, "%d items missing in data group beginning "
 234.363 +                     "with %s", lack, format_symbol(mpl, with));
 234.364 +            }
 234.365 +            sym = read_symbol(mpl);
 234.366 +            if (with == NULL) with = sym;
 234.367 +         }
 234.368 +         else
 234.369 +         {  /* copy symbol from the slice */
 234.370 +            sym = copy_symbol(mpl, temp->sym);
 234.371 +         }
 234.372 +         /* append the symbol to the n-tuple */
 234.373 +         tuple = expand_tuple(mpl, tuple, sym);
 234.374 +         /* skip optional comma *between* <symbols> */
 234.375 +         if (temp->next != NULL && mpl->token == T_COMMA)
 234.376 +            get_token(mpl /* , */);
 234.377 +      }
 234.378 +      /* add constructed n-tuple to elemental set */
 234.379 +      check_then_add(mpl, memb->value.set, tuple);
 234.380 +      return;
 234.381 +}
 234.382 +
 234.383 +/*----------------------------------------------------------------------
 234.384 +-- matrix_format - read set data block in matrix format.
 234.385 +--
 234.386 +-- This routine reads set data block using the syntax:
 234.387 +--
 234.388 +-- <matrix format> ::= <column> <column> ... <column> :=
 234.389 +--               <row>   +/-      +/-    ...   +/-
 234.390 +--               <row>   +/-      +/-    ...   +/-
 234.391 +--                 .  .  .  .  .  .  .  .  .  .  .
 234.392 +--               <row>   +/-      +/-    ...   +/-
 234.393 +--
 234.394 +-- where <rows> are symbols that denote rows of the matrix, <columns>
 234.395 +-- are symbols that denote columns of the matrix, "+" and "-" indicate
 234.396 +-- whether corresponding n-tuple needs to be included in the elemental
 234.397 +-- set or not, respectively.
 234.398 +--
 234.399 +-- Number of the slice components must be the same as dimension of the
 234.400 +-- elemental set. The slice must have two null positions. To construct
 234.401 +-- complete n-tuple for particular element of the matrix the routine
 234.402 +-- replaces first null position of the slice by the corresponding <row>
 234.403 +-- (or <column>, if the flag tr is on) and second null position by the
 234.404 +-- corresponding <column> (or by <row>, if the flag tr is on). */
 234.405 +
 234.406 +void matrix_format
 234.407 +(     MPL *mpl,
 234.408 +      SET *set,               /* not changed */
 234.409 +      MEMBER *memb,           /* modified */
 234.410 +      SLICE *slice,           /* not changed */
 234.411 +      int tr
 234.412 +)
 234.413 +{     SLICE *list, *col, *temp;
 234.414 +      TUPLE *tuple;
 234.415 +      SYMBOL *row;
 234.416 +      xassert(set != NULL);
 234.417 +      xassert(memb != NULL);
 234.418 +      xassert(slice != NULL);
 234.419 +      xassert(set->dimen == slice_dimen(mpl, slice));
 234.420 +      xassert(memb->value.set->dim == set->dimen);
 234.421 +      xassert(slice_arity(mpl, slice) == 2);
 234.422 +      /* read the matrix heading that contains column symbols (there
 234.423 +         may be no columns at all) */
 234.424 +      list = create_slice(mpl);
 234.425 +      while (mpl->token != T_ASSIGN)
 234.426 +      {  /* read column symbol and append it to the column list */
 234.427 +         if (!is_symbol(mpl))
 234.428 +            error(mpl, "number, symbol, or := missing where expected");
 234.429 +         list = expand_slice(mpl, list, read_symbol(mpl));
 234.430 +      }
 234.431 +      get_token(mpl /* := */);
 234.432 +      /* read zero or more rows that contain matrix data */
 234.433 +      while (is_symbol(mpl))
 234.434 +      {  /* read row symbol (if the matrix has no columns, row symbols
 234.435 +            are just ignored) */
 234.436 +         row = read_symbol(mpl);
 234.437 +         /* read the matrix row accordingly to the column list */
 234.438 +         for (col = list; col != NULL; col = col->next)
 234.439 +         {  int which = 0;
 234.440 +            /* check indicator */
 234.441 +            if (is_literal(mpl, "+"))
 234.442 +               ;
 234.443 +            else if (is_literal(mpl, "-"))
 234.444 +            {  get_token(mpl /* - */);
 234.445 +               continue;
 234.446 +            }
 234.447 +            else
 234.448 +            {  int lack = slice_dimen(mpl, col);
 234.449 +               if (lack == 1)
 234.450 +                  error(mpl, "one item missing in data group beginning "
 234.451 +                     "with %s", format_symbol(mpl, row));
 234.452 +               else
 234.453 +                  error(mpl, "%d items missing in data group beginning "
 234.454 +                     "with %s", lack, format_symbol(mpl, row));
 234.455 +            }
 234.456 +            /* construct complete n-tuple */
 234.457 +            tuple = create_tuple(mpl);
 234.458 +            for (temp = slice; temp != NULL; temp = temp->next)
 234.459 +            {  if (temp->sym == NULL)
 234.460 +               {  /* substitution is needed */
 234.461 +                  switch (++which)
 234.462 +                  {  case 1:
 234.463 +                        /* substitute in the first null position */
 234.464 +                        tuple = expand_tuple(mpl, tuple,
 234.465 +                           copy_symbol(mpl, tr ? col->sym : row));
 234.466 +                        break;
 234.467 +                     case 2:
 234.468 +                        /* substitute in the second null position */
 234.469 +                        tuple = expand_tuple(mpl, tuple,
 234.470 +                           copy_symbol(mpl, tr ? row : col->sym));
 234.471 +                        break;
 234.472 +                     default:
 234.473 +                        xassert(which != which);
 234.474 +                  }
 234.475 +               }
 234.476 +               else
 234.477 +               {  /* copy symbol from the slice */
 234.478 +                  tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
 234.479 +                     temp->sym));
 234.480 +               }
 234.481 +            }
 234.482 +            xassert(which == 2);
 234.483 +            /* add constructed n-tuple to elemental set */
 234.484 +            check_then_add(mpl, memb->value.set, tuple);
 234.485 +            get_token(mpl /* + */);
 234.486 +         }
 234.487 +         /* delete the row symbol */
 234.488 +         delete_symbol(mpl, row);
 234.489 +      }
 234.490 +      /* delete the column list */
 234.491 +      delete_slice(mpl, list);
 234.492 +      return;
 234.493 +}
 234.494 +
 234.495 +/*----------------------------------------------------------------------
 234.496 +-- set_data - read set data.
 234.497 +--
 234.498 +-- This routine reads set data using the syntax:
 234.499 +--
 234.500 +-- <set data> ::= set <set name> <assignments> ;
 234.501 +-- <set data> ::= set <set name> [ <symbol list> ] <assignments> ;
 234.502 +-- <set name> ::= <symbolic name>
 234.503 +-- <assignments> ::= <empty>
 234.504 +-- <assignments> ::= <assignments> , :=
 234.505 +-- <assignments> ::= <assignments> , ( <symbol list> )
 234.506 +-- <assignments> ::= <assignments> , <simple format>
 234.507 +-- <assignments> ::= <assignments> , : <matrix format>
 234.508 +-- <assignments> ::= <assignments> , (tr) <matrix format>
 234.509 +-- <assignments> ::= <assignments> , (tr) : <matrix format>
 234.510 +--
 234.511 +-- Commae in <assignments> are optional and may be omitted anywhere. */
 234.512 +
 234.513 +void set_data(MPL *mpl)
 234.514 +{     SET *set;
 234.515 +      TUPLE *tuple;
 234.516 +      MEMBER *memb;
 234.517 +      SLICE *slice;
 234.518 +      int tr = 0;
 234.519 +      xassert(is_literal(mpl, "set"));
 234.520 +      get_token(mpl /* set */);
 234.521 +      /* symbolic name of set must follows the keyword 'set' */
 234.522 +      if (!is_symbol(mpl))
 234.523 +         error(mpl, "set name missing where expected");
 234.524 +      /* select the set to saturate it with data */
 234.525 +      set = select_set(mpl, mpl->image);
 234.526 +      get_token(mpl /* <symbolic name> */);
 234.527 +      /* read optional subscript list, which identifies member of the
 234.528 +         set to be read */
 234.529 +      tuple = create_tuple(mpl);
 234.530 +      if (mpl->token == T_LBRACKET)
 234.531 +      {  /* subscript list is specified */
 234.532 +         if (set->dim == 0)
 234.533 +            error(mpl, "%s cannot be subscripted", set->name);
 234.534 +         get_token(mpl /* [ */);
 234.535 +         /* read symbols and construct subscript list */
 234.536 +         for (;;)
 234.537 +         {  if (!is_symbol(mpl))
 234.538 +               error(mpl, "number or symbol missing where expected");
 234.539 +            tuple = expand_tuple(mpl, tuple, read_symbol(mpl));
 234.540 +            if (mpl->token == T_COMMA)
 234.541 +               get_token(mpl /* , */);
 234.542 +            else if (mpl->token == T_RBRACKET)
 234.543 +               break;
 234.544 +            else
 234.545 +               error(mpl, "syntax error in subscript list");
 234.546 +         }
 234.547 +         if (set->dim != tuple_dimen(mpl, tuple))
 234.548 +            error(mpl, "%s must have %d subscript%s rather than %d",
 234.549 +               set->name, set->dim, set->dim == 1 ? "" : "s",
 234.550 +               tuple_dimen(mpl, tuple));
 234.551 +         get_token(mpl /* ] */);
 234.552 +      }
 234.553 +      else
 234.554 +      {  /* subscript list is not specified */
 234.555 +         if (set->dim != 0)
 234.556 +            error(mpl, "%s must be subscripted", set->name);
 234.557 +      }
 234.558 +      /* there must be no member with the same subscript list */
 234.559 +      if (find_member(mpl, set->array, tuple) != NULL)
 234.560 +         error(mpl, "%s%s already defined",
 234.561 +            set->name, format_tuple(mpl, '[', tuple));
 234.562 +      /* add new member to the set and assign it empty elemental set */
 234.563 +      memb = add_member(mpl, set->array, tuple);
 234.564 +      memb->value.set = create_elemset(mpl, set->dimen);
 234.565 +      /* create an initial fake slice of all asterisks */
 234.566 +      slice = fake_slice(mpl, set->dimen);
 234.567 +      /* read zero or more data assignments */
 234.568 +      for (;;)
 234.569 +      {  /* skip optional comma */
 234.570 +         if (mpl->token == T_COMMA) get_token(mpl /* , */);
 234.571 +         /* process assignment element */
 234.572 +         if (mpl->token == T_ASSIGN)
 234.573 +         {  /* assignment ligature is non-significant element */
 234.574 +            get_token(mpl /* := */);
 234.575 +         }
 234.576 +         else if (mpl->token == T_LEFT)
 234.577 +         {  /* left parenthesis begins either new slice or "transpose"
 234.578 +               indicator */
 234.579 +            int is_tr;
 234.580 +            get_token(mpl /* ( */);
 234.581 +            is_tr = is_literal(mpl, "tr");
 234.582 +            unget_token(mpl /* ( */);
 234.583 +            if (is_tr) goto left;
 234.584 +            /* delete the current slice and read new one */
 234.585 +            delete_slice(mpl, slice);
 234.586 +            slice = read_slice(mpl, set->name, set->dimen);
 234.587 +            /* each new slice resets the "transpose" indicator */
 234.588 +            tr = 0;
 234.589 +            /* if the new slice is 0-ary, formally there is one 0-tuple
 234.590 +               (in the simple format) that follows it */
 234.591 +            if (slice_arity(mpl, slice) == 0)
 234.592 +               simple_format(mpl, set, memb, slice);
 234.593 +         }
 234.594 +         else if (is_symbol(mpl))
 234.595 +         {  /* number or symbol begins data in the simple format */
 234.596 +            simple_format(mpl, set, memb, slice);
 234.597 +         }
 234.598 +         else if (mpl->token == T_COLON)
 234.599 +         {  /* colon begins data in the matrix format */
 234.600 +            if (slice_arity(mpl, slice) != 2)
 234.601 +err1:          error(mpl, "slice currently used must specify 2 asterisk"
 234.602 +                  "s, not %d", slice_arity(mpl, slice));
 234.603 +            get_token(mpl /* : */);
 234.604 +            /* read elemental set data in the matrix format */
 234.605 +            matrix_format(mpl, set, memb, slice, tr);
 234.606 +         }
 234.607 +         else if (mpl->token == T_LEFT)
 234.608 +left:    {  /* left parenthesis begins the "transpose" indicator, which
 234.609 +               is followed by data in the matrix format */
 234.610 +            get_token(mpl /* ( */);
 234.611 +            if (!is_literal(mpl, "tr"))
 234.612 +err2:          error(mpl, "transpose indicator (tr) incomplete");
 234.613 +            if (slice_arity(mpl, slice) != 2) goto err1;
 234.614 +            get_token(mpl /* tr */);
 234.615 +            if (mpl->token != T_RIGHT) goto err2;
 234.616 +            get_token(mpl /* ) */);
 234.617 +            /* in this case the colon is optional */
 234.618 +            if (mpl->token == T_COLON) get_token(mpl /* : */);
 234.619 +            /* set the "transpose" indicator */
 234.620 +            tr = 1;
 234.621 +            /* read elemental set data in the matrix format */
 234.622 +            matrix_format(mpl, set, memb, slice, tr);
 234.623 +         }
 234.624 +         else if (mpl->token == T_SEMICOLON)
 234.625 +         {  /* semicolon terminates the data block */
 234.626 +            get_token(mpl /* ; */);
 234.627 +            break;
 234.628 +         }
 234.629 +         else
 234.630 +            error(mpl, "syntax error in set data block");
 234.631 +      }
 234.632 +      /* delete the current slice */
 234.633 +      delete_slice(mpl, slice);
 234.634 +      return;
 234.635 +}
 234.636 +
 234.637 +/*----------------------------------------------------------------------
 234.638 +-- select_parameter - select parameter to saturate it with data.
 234.639 +--
 234.640 +-- This routine selects parameter to saturate it with data provided in
 234.641 +-- the data section. */
 234.642 +
 234.643 +PARAMETER *select_parameter
 234.644 +(     MPL *mpl,
 234.645 +      char *name              /* not changed */
 234.646 +)
 234.647 +{     PARAMETER *par;
 234.648 +      AVLNODE *node;
 234.649 +      xassert(name != NULL);
 234.650 +      node = avl_find_node(mpl->tree, name);
 234.651 +      if (node == NULL || avl_get_node_type(node) != A_PARAMETER)
 234.652 +         error(mpl, "%s not a parameter", name);
 234.653 +      par = (PARAMETER *)avl_get_node_link(node);
 234.654 +      if (par->assign != NULL)
 234.655 +         error(mpl, "%s needs no data", name);
 234.656 +      if (par->data)
 234.657 +         error(mpl, "%s already provided with data", name);
 234.658 +      par->data = 1;
 234.659 +      return par;
 234.660 +}
 234.661 +
 234.662 +/*----------------------------------------------------------------------
 234.663 +-- set_default - set default parameter value.
 234.664 +--
 234.665 +-- This routine sets default value for specified parameter. */
 234.666 +
 234.667 +void set_default
 234.668 +(     MPL *mpl,
 234.669 +      PARAMETER *par,         /* not changed */
 234.670 +      SYMBOL *altval          /* destroyed */
 234.671 +)
 234.672 +{     xassert(par != NULL);
 234.673 +      xassert(altval != NULL);
 234.674 +      if (par->option != NULL)
 234.675 +         error(mpl, "default value for %s already specified in model se"
 234.676 +            "ction", par->name);
 234.677 +      xassert(par->defval == NULL);
 234.678 +      par->defval = altval;
 234.679 +      return;
 234.680 +}
 234.681 +
 234.682 +/*----------------------------------------------------------------------
 234.683 +-- read_value - read value and assign it to parameter member.
 234.684 +--
 234.685 +-- This routine reads numeric or symbolic value from the input stream
 234.686 +-- and assigns to new parameter member specified by its n-tuple, which
 234.687 +-- (the member) is created and added to the parameter array. */
 234.688 +
 234.689 +MEMBER *read_value
 234.690 +(     MPL *mpl,
 234.691 +      PARAMETER *par,         /* not changed */
 234.692 +      TUPLE *tuple            /* destroyed */
 234.693 +)
 234.694 +{     MEMBER *memb;
 234.695 +      xassert(par != NULL);
 234.696 +      xassert(is_symbol(mpl));
 234.697 +      /* there must be no member with the same n-tuple */
 234.698 +      if (find_member(mpl, par->array, tuple) != NULL)
 234.699 +         error(mpl, "%s%s already defined",
 234.700 +            par->name, format_tuple(mpl, '[', tuple));
 234.701 +      /* create new parameter member with given n-tuple */
 234.702 +      memb = add_member(mpl, par->array, tuple);
 234.703 +      /* read value and assigns it to the new parameter member */
 234.704 +      switch (par->type)
 234.705 +      {  case A_NUMERIC:
 234.706 +         case A_INTEGER:
 234.707 +         case A_BINARY:
 234.708 +            if (!is_number(mpl))
 234.709 +               error(mpl, "%s requires numeric data", par->name);
 234.710 +            memb->value.num = read_number(mpl);
 234.711 +            break;
 234.712 +         case A_SYMBOLIC:
 234.713 +            memb->value.sym = read_symbol(mpl);
 234.714 +            break;
 234.715 +         default:
 234.716 +            xassert(par != par);
 234.717 +      }
 234.718 +      return memb;
 234.719 +}
 234.720 +
 234.721 +/*----------------------------------------------------------------------
 234.722 +-- plain_format - read parameter data block in plain format.
 234.723 +--
 234.724 +-- This routine reads parameter data block using the syntax:
 234.725 +--
 234.726 +-- <plain format> ::= <symbol> , <symbol> , ... , <symbol> , <value>
 234.727 +--
 234.728 +-- where <symbols> are used to determine a complete subscript list for
 234.729 +-- parameter member, <value> is a numeric or symbolic value assigned to
 234.730 +-- the parameter member. Commae between data items are optional and may
 234.731 +-- be omitted anywhere.
 234.732 +--
 234.733 +-- Number of components in the slice must be the same as dimension of
 234.734 +-- the parameter. To construct the complete subscript list the routine
 234.735 +-- replaces null positions in the slice by corresponding <symbols>. */
 234.736 +
 234.737 +void plain_format
 234.738 +(     MPL *mpl,
 234.739 +      PARAMETER *par,         /* not changed */
 234.740 +      SLICE *slice            /* not changed */
 234.741 +)
 234.742 +{     TUPLE *tuple;
 234.743 +      SLICE *temp;
 234.744 +      SYMBOL *sym, *with = NULL;
 234.745 +      xassert(par != NULL);
 234.746 +      xassert(par->dim == slice_dimen(mpl, slice));
 234.747 +      xassert(is_symbol(mpl));
 234.748 +      /* read symbols and construct complete subscript list */
 234.749 +      tuple = create_tuple(mpl);
 234.750 +      for (temp = slice; temp != NULL; temp = temp->next)
 234.751 +      {  if (temp->sym == NULL)
 234.752 +         {  /* substitution is needed; read symbol */
 234.753 +            if (!is_symbol(mpl))
 234.754 +            {  int lack = slice_arity(mpl, temp) + 1;
 234.755 +               xassert(with != NULL);
 234.756 +               xassert(lack > 1);
 234.757 +               error(mpl, "%d items missing in data group beginning wit"
 234.758 +                  "h %s", lack, format_symbol(mpl, with));
 234.759 +            }
 234.760 +            sym = read_symbol(mpl);
 234.761 +            if (with == NULL) with = sym;
 234.762 +         }
 234.763 +         else
 234.764 +         {  /* copy symbol from the slice */
 234.765 +            sym = copy_symbol(mpl, temp->sym);
 234.766 +         }
 234.767 +         /* append the symbol to the subscript list */
 234.768 +         tuple = expand_tuple(mpl, tuple, sym);
 234.769 +         /* skip optional comma */
 234.770 +         if (mpl->token == T_COMMA) get_token(mpl /* , */);
 234.771 +      }
 234.772 +      /* read value and assign it to new parameter member */
 234.773 +      if (!is_symbol(mpl))
 234.774 +      {  xassert(with != NULL);
 234.775 +         error(mpl, "one item missing in data group beginning with %s",
 234.776 +            format_symbol(mpl, with));
 234.777 +      }
 234.778 +      read_value(mpl, par, tuple);
 234.779 +      return;
 234.780 +}
 234.781 +
 234.782 +/*----------------------------------------------------------------------
 234.783 +-- tabular_format - read parameter data block in tabular format.
 234.784 +--
 234.785 +-- This routine reads parameter data block using the syntax:
 234.786 +--
 234.787 +-- <tabular format> ::= <column> <column> ... <column> :=
 234.788 +--                <row> <value>  <value>  ... <value>
 234.789 +--                <row> <value>  <value>  ... <value>
 234.790 +--                  .  .  .  .  .  .  .  .  .  .  .
 234.791 +--                <row> <value>  <value>  ... <value>
 234.792 +--
 234.793 +-- where <rows> are symbols that denote rows of the table, <columns>
 234.794 +-- are symbols that denote columns of the table, <values> are numeric
 234.795 +-- or symbolic values assigned to the corresponding parameter members.
 234.796 +-- If <value> is specified as single point, no value is provided.
 234.797 +--
 234.798 +-- Number of components in the slice must be the same as dimension of
 234.799 +-- the parameter. The slice must have two null positions. To construct
 234.800 +-- complete subscript list for particular <value> the routine replaces
 234.801 +-- the first null position of the slice by the corresponding <row> (or
 234.802 +-- <column>, if the flag tr is on) and the second null position by the
 234.803 +-- corresponding <column> (or by <row>, if the flag tr is on). */
 234.804 +
 234.805 +void tabular_format
 234.806 +(     MPL *mpl,
 234.807 +      PARAMETER *par,         /* not changed */
 234.808 +      SLICE *slice,           /* not changed */
 234.809 +      int tr
 234.810 +)
 234.811 +{     SLICE *list, *col, *temp;
 234.812 +      TUPLE *tuple;
 234.813 +      SYMBOL *row;
 234.814 +      xassert(par != NULL);
 234.815 +      xassert(par->dim == slice_dimen(mpl, slice));
 234.816 +      xassert(slice_arity(mpl, slice) == 2);
 234.817 +      /* read the table heading that contains column symbols (the table
 234.818 +         may have no columns) */
 234.819 +      list = create_slice(mpl);
 234.820 +      while (mpl->token != T_ASSIGN)
 234.821 +      {  /* read column symbol and append it to the column list */
 234.822 +         if (!is_symbol(mpl))
 234.823 +            error(mpl, "number, symbol, or := missing where expected");
 234.824 +         list = expand_slice(mpl, list, read_symbol(mpl));
 234.825 +      }
 234.826 +      get_token(mpl /* := */);
 234.827 +      /* read zero or more rows that contain tabular data */
 234.828 +      while (is_symbol(mpl))
 234.829 +      {  /* read row symbol (if the table has no columns, these symbols
 234.830 +            are just ignored) */
 234.831 +         row = read_symbol(mpl);
 234.832 +         /* read values accordingly to the column list */
 234.833 +         for (col = list; col != NULL; col = col->next)
 234.834 +         {  int which = 0;
 234.835 +            /* if the token is single point, no value is provided */
 234.836 +            if (is_literal(mpl, "."))
 234.837 +            {  get_token(mpl /* . */);
 234.838 +               continue;
 234.839 +            }
 234.840 +            /* construct complete subscript list */
 234.841 +            tuple = create_tuple(mpl);
 234.842 +            for (temp = slice; temp != NULL; temp = temp->next)
 234.843 +            {  if (temp->sym == NULL)
 234.844 +               {  /* substitution is needed */
 234.845 +                  switch (++which)
 234.846 +                  {  case 1:
 234.847 +                        /* substitute in the first null position */
 234.848 +                        tuple = expand_tuple(mpl, tuple,
 234.849 +                           copy_symbol(mpl, tr ? col->sym : row));
 234.850 +                        break;
 234.851 +                     case 2:
 234.852 +                        /* substitute in the second null position */
 234.853 +                        tuple = expand_tuple(mpl, tuple,
 234.854 +                           copy_symbol(mpl, tr ? row : col->sym));
 234.855 +                        break;
 234.856 +                     default:
 234.857 +                        xassert(which != which);
 234.858 +                  }
 234.859 +               }
 234.860 +               else
 234.861 +               {  /* copy symbol from the slice */
 234.862 +                  tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
 234.863 +                     temp->sym));
 234.864 +               }
 234.865 +            }
 234.866 +            xassert(which == 2);
 234.867 +            /* read value and assign it to new parameter member */
 234.868 +            if (!is_symbol(mpl))
 234.869 +            {  int lack = slice_dimen(mpl, col);
 234.870 +               if (lack == 1)
 234.871 +                  error(mpl, "one item missing in data group beginning "
 234.872 +                     "with %s", format_symbol(mpl, row));
 234.873 +               else
 234.874 +                  error(mpl, "%d items missing in data group beginning "
 234.875 +                     "with %s", lack, format_symbol(mpl, row));
 234.876 +            }
 234.877 +            read_value(mpl, par, tuple);
 234.878 +         }
 234.879 +         /* delete the row symbol */
 234.880 +         delete_symbol(mpl, row);
 234.881 +      }
 234.882 +      /* delete the column list */
 234.883 +      delete_slice(mpl, list);
 234.884 +      return;
 234.885 +}
 234.886 +
 234.887 +/*----------------------------------------------------------------------
 234.888 +-- tabbing_format - read parameter data block in tabbing format.
 234.889 +--
 234.890 +-- This routine reads parameter data block using the syntax:
 234.891 +--
 234.892 +-- <tabbing format> ::=  <prefix> <name>  , ... , <name>  , := ,
 234.893 +--    <symbol> , ... , <symbol> , <value> , ... , <value> ,
 234.894 +--    <symbol> , ... , <symbol> , <value> , ... , <value> ,
 234.895 +--     .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
 234.896 +--    <symbol> , ... , <symbol> , <value> , ... , <value>
 234.897 +-- <prefix> ::= <empty>
 234.898 +-- <prefix> ::= <set name> :
 234.899 +--
 234.900 +-- where <names> are names of parameters (all the parameters must be
 234.901 +-- subscripted and have identical dimensions), <symbols> are symbols
 234.902 +-- used to define subscripts of parameter members, <values> are numeric
 234.903 +-- or symbolic values assigned to the corresponding parameter members.
 234.904 +-- Optional <prefix> may specify a simple set, in which case n-tuples
 234.905 +-- built of <symbols> for each row of the data table (i.e. subscripts
 234.906 +-- of parameter members) are added to the specified set. Commae between
 234.907 +-- data items are optional and may be omitted anywhere.
 234.908 +--
 234.909 +-- If the parameter altval is not NULL, it specifies a default value
 234.910 +-- provided for all the parameters specified in the data block.  */
 234.911 +
 234.912 +void tabbing_format
 234.913 +(     MPL *mpl,
 234.914 +      SYMBOL *altval          /* not changed */
 234.915 +)
 234.916 +{     SET *set = NULL;
 234.917 +      PARAMETER *par;
 234.918 +      SLICE *list, *col;
 234.919 +      TUPLE *tuple;
 234.920 +      int next_token, j, dim = 0;
 234.921 +      char *last_name = NULL;
 234.922 +      /* read the optional <prefix> */
 234.923 +      if (is_symbol(mpl))
 234.924 +      {  get_token(mpl /* <symbol> */);
 234.925 +         next_token = mpl->token;
 234.926 +         unget_token(mpl /* <symbol> */);
 234.927 +         if (next_token == T_COLON)
 234.928 +         {  /* select the set to saturate it with data */
 234.929 +            set = select_set(mpl, mpl->image);
 234.930 +            /* the set must be simple (i.e. not set of sets) */
 234.931 +            if (set->dim != 0)
 234.932 +               error(mpl, "%s must be a simple set", set->name);
 234.933 +            /* and must not be defined yet */
 234.934 +            if (set->array->head != NULL)
 234.935 +               error(mpl, "%s already defined", set->name);
 234.936 +            /* add new (the only) member to the set and assign it empty
 234.937 +               elemental set */
 234.938 +            add_member(mpl, set->array, NULL)->value.set =
 234.939 +               create_elemset(mpl, set->dimen);
 234.940 +            last_name = set->name, dim = set->dimen;
 234.941 +            get_token(mpl /* <symbol> */);
 234.942 +            xassert(mpl->token == T_COLON);
 234.943 +            get_token(mpl /* : */);
 234.944 +         }
 234.945 +      }
 234.946 +      /* read the table heading that contains parameter names */
 234.947 +      list = create_slice(mpl);
 234.948 +      while (mpl->token != T_ASSIGN)
 234.949 +      {  /* there must be symbolic name of parameter */
 234.950 +         if (!is_symbol(mpl))
 234.951 +            error(mpl, "parameter name or := missing where expected");
 234.952 +         /* select the parameter to saturate it with data */
 234.953 +         par = select_parameter(mpl, mpl->image);
 234.954 +         /* the parameter must be subscripted */
 234.955 +         if (par->dim == 0)
 234.956 +            error(mpl, "%s not a subscripted parameter", mpl->image);
 234.957 +         /* the set (if specified) and all the parameters in the data
 234.958 +            block must have identical dimension */
 234.959 +         if (dim != 0 && par->dim != dim)
 234.960 +         {  xassert(last_name != NULL);
 234.961 +            error(mpl, "%s has dimension %d while %s has dimension %d",
 234.962 +               last_name, dim, par->name, par->dim);
 234.963 +         }
 234.964 +         /* set default value for the parameter (if specified) */
 234.965 +         if (altval != NULL)
 234.966 +            set_default(mpl, par, copy_symbol(mpl, altval));
 234.967 +         /* append the parameter to the column list */
 234.968 +         list = expand_slice(mpl, list, (SYMBOL *)par);
 234.969 +         last_name = par->name, dim = par->dim;
 234.970 +         get_token(mpl /* <symbol> */);
 234.971 +         /* skip optional comma */
 234.972 +         if (mpl->token == T_COMMA) get_token(mpl /* , */);
 234.973 +      }
 234.974 +      if (slice_dimen(mpl, list) == 0)
 234.975 +         error(mpl, "at least one parameter name required");
 234.976 +      get_token(mpl /* := */);
 234.977 +      /* skip optional comma */
 234.978 +      if (mpl->token == T_COMMA) get_token(mpl /* , */);
 234.979 +      /* read rows that contain tabbing data */
 234.980 +      while (is_symbol(mpl))
 234.981 +      {  /* read subscript list */
 234.982 +         tuple = create_tuple(mpl);
 234.983 +         for (j = 1; j <= dim; j++)
 234.984 +         {  /* read j-th subscript */
 234.985 +            if (!is_symbol(mpl))
 234.986 +            {  int lack = slice_dimen(mpl, list) + dim - j + 1;
 234.987 +               xassert(tuple != NULL);
 234.988 +               xassert(lack > 1);
 234.989 +               error(mpl, "%d items missing in data group beginning wit"
 234.990 +                  "h %s", lack, format_symbol(mpl, tuple->sym));
 234.991 +            }
 234.992 +            /* read and append j-th subscript to the n-tuple */
 234.993 +            tuple = expand_tuple(mpl, tuple, read_symbol(mpl));
 234.994 +            /* skip optional comma *between* <symbols> */
 234.995 +            if (j < dim && mpl->token == T_COMMA)
 234.996 +               get_token(mpl /* , */);
 234.997 +         }
 234.998 +         /* if the set is specified, add to it new n-tuple, which is a
 234.999 +            copy of the subscript list just read */
234.1000 +         if (set != NULL)
234.1001 +            check_then_add(mpl, set->array->head->value.set,
234.1002 +               copy_tuple(mpl, tuple));
234.1003 +         /* skip optional comma between <symbol> and <value> */
234.1004 +         if (mpl->token == T_COMMA) get_token(mpl /* , */);
234.1005 +         /* read values accordingly to the column list */
234.1006 +         for (col = list; col != NULL; col = col->next)
234.1007 +         {  /* if the token is single point, no value is provided */
234.1008 +            if (is_literal(mpl, "."))
234.1009 +            {  get_token(mpl /* . */);
234.1010 +               continue;
234.1011 +            }
234.1012 +            /* read value and assign it to new parameter member */
234.1013 +            if (!is_symbol(mpl))
234.1014 +            {  int lack = slice_dimen(mpl, col);
234.1015 +               xassert(tuple != NULL);
234.1016 +               if (lack == 1)
234.1017 +                  error(mpl, "one item missing in data group beginning "
234.1018 +                     "with %s", format_symbol(mpl, tuple->sym));
234.1019 +               else
234.1020 +                  error(mpl, "%d items missing in data group beginning "
234.1021 +                     "with %s", lack, format_symbol(mpl, tuple->sym));
234.1022 +            }
234.1023 +            read_value(mpl, (PARAMETER *)col->sym, copy_tuple(mpl,
234.1024 +               tuple));
234.1025 +            /* skip optional comma preceding the next value */
234.1026 +            if (col->next != NULL && mpl->token == T_COMMA)
234.1027 +               get_token(mpl /* , */);
234.1028 +         }
234.1029 +         /* delete the original subscript list */
234.1030 +         delete_tuple(mpl, tuple);
234.1031 +         /* skip optional comma (only if there is next data group) */
234.1032 +         if (mpl->token == T_COMMA)
234.1033 +         {  get_token(mpl /* , */);
234.1034 +            if (!is_symbol(mpl)) unget_token(mpl /* , */);
234.1035 +         }
234.1036 +      }
234.1037 +      /* delete the column list (it contains parameters, not symbols,
234.1038 +         so nullify it before) */
234.1039 +      for (col = list; col != NULL; col = col->next) col->sym = NULL;
234.1040 +      delete_slice(mpl, list);
234.1041 +      return;
234.1042 +}
234.1043 +
234.1044 +/*----------------------------------------------------------------------
234.1045 +-- parameter_data - read parameter data.
234.1046 +--
234.1047 +-- This routine reads parameter data using the syntax:
234.1048 +--
234.1049 +-- <parameter data> ::= param <default value> : <tabbing format> ;
234.1050 +-- <parameter data> ::= param <parameter name> <default value>
234.1051 +--                      <assignments> ;
234.1052 +-- <parameter name> ::= <symbolic name>
234.1053 +-- <default value> ::= <empty>
234.1054 +-- <default value> ::= default <symbol>
234.1055 +-- <assignments> ::= <empty>
234.1056 +-- <assignments> ::= <assignments> , :=
234.1057 +-- <assignments> ::= <assignments> , [ <symbol list> ]
234.1058 +-- <assignments> ::= <assignments> , <plain format>
234.1059 +-- <assignemnts> ::= <assignments> , : <tabular format>
234.1060 +-- <assignments> ::= <assignments> , (tr) <tabular format>
234.1061 +-- <assignments> ::= <assignments> , (tr) : <tabular format>
234.1062 +--
234.1063 +-- Commae in <assignments> are optional and may be omitted anywhere. */
234.1064 +
234.1065 +void parameter_data(MPL *mpl)
234.1066 +{     PARAMETER *par;
234.1067 +      SYMBOL *altval = NULL;
234.1068 +      SLICE *slice;
234.1069 +      int tr = 0;
234.1070 +      xassert(is_literal(mpl, "param"));
234.1071 +      get_token(mpl /* param */);
234.1072 +      /* read optional default value */
234.1073 +      if (is_literal(mpl, "default"))
234.1074 +      {  get_token(mpl /* default */);
234.1075 +         if (!is_symbol(mpl))
234.1076 +            error(mpl, "default value missing where expected");
234.1077 +         altval = read_symbol(mpl);
234.1078 +         /* if the default value follows the keyword 'param', the next
234.1079 +            token must be only the colon */
234.1080 +         if (mpl->token != T_COLON)
234.1081 +            error(mpl, "colon missing where expected");
234.1082 +      }
234.1083 +      /* being used after the keyword 'param' or the optional default
234.1084 +         value the colon begins data in the tabbing format */
234.1085 +      if (mpl->token == T_COLON)
234.1086 +      {  get_token(mpl /* : */);
234.1087 +         /* skip optional comma */
234.1088 +         if (mpl->token == T_COMMA) get_token(mpl /* , */);
234.1089 +         /* read parameter data in the tabbing format */
234.1090 +         tabbing_format(mpl, altval);
234.1091 +         /* on reading data in the tabbing format the default value is
234.1092 +            always copied, so delete the original symbol */
234.1093 +         if (altval != NULL) delete_symbol(mpl, altval);
234.1094 +         /* the next token must be only semicolon */
234.1095 +         if (mpl->token != T_SEMICOLON)
234.1096 +            error(mpl, "symbol, number, or semicolon missing where expe"
234.1097 +               "cted");
234.1098 +         get_token(mpl /* ; */);
234.1099 +         goto done;
234.1100 +      }
234.1101 +      /* in other cases there must be symbolic name of parameter, which
234.1102 +         follows the keyword 'param' */
234.1103 +      if (!is_symbol(mpl))
234.1104 +         error(mpl, "parameter name missing where expected");
234.1105 +      /* select the parameter to saturate it with data */
234.1106 +      par = select_parameter(mpl, mpl->image);
234.1107 +      get_token(mpl /* <symbol> */);
234.1108 +      /* read optional default value */
234.1109 +      if (is_literal(mpl, "default"))
234.1110 +      {  get_token(mpl /* default */);
234.1111 +         if (!is_symbol(mpl))
234.1112 +            error(mpl, "default value missing where expected");
234.1113 +         altval = read_symbol(mpl);
234.1114 +         /* set default value for the parameter */
234.1115 +         set_default(mpl, par, altval);
234.1116 +      }
234.1117 +      /* create initial fake slice of all asterisks */
234.1118 +      slice = fake_slice(mpl, par->dim);
234.1119 +      /* read zero or more data assignments */
234.1120 +      for (;;)
234.1121 +      {  /* skip optional comma */
234.1122 +         if (mpl->token == T_COMMA) get_token(mpl /* , */);
234.1123 +         /* process current assignment */
234.1124 +         if (mpl->token == T_ASSIGN)
234.1125 +         {  /* assignment ligature is non-significant element */
234.1126 +            get_token(mpl /* := */);
234.1127 +         }
234.1128 +         else if (mpl->token == T_LBRACKET)
234.1129 +         {  /* left bracket begins new slice; delete the current slice
234.1130 +               and read new one */
234.1131 +            delete_slice(mpl, slice);
234.1132 +            slice = read_slice(mpl, par->name, par->dim);
234.1133 +            /* each new slice resets the "transpose" indicator */
234.1134 +            tr = 0;
234.1135 +         }
234.1136 +         else if (is_symbol(mpl))
234.1137 +         {  /* number or symbol begins data in the plain format */
234.1138 +            plain_format(mpl, par, slice);
234.1139 +         }
234.1140 +         else if (mpl->token == T_COLON)
234.1141 +         {  /* colon begins data in the tabular format */
234.1142 +            if (par->dim == 0)
234.1143 +err1:          error(mpl, "%s not a subscripted parameter",
234.1144 +                  par->name);
234.1145 +            if (slice_arity(mpl, slice) != 2)
234.1146 +err2:          error(mpl, "slice currently used must specify 2 asterisk"
234.1147 +                  "s, not %d", slice_arity(mpl, slice));
234.1148 +            get_token(mpl /* : */);
234.1149 +            /* read parameter data in the tabular format */
234.1150 +            tabular_format(mpl, par, slice, tr);
234.1151 +         }
234.1152 +         else if (mpl->token == T_LEFT)
234.1153 +         {  /* left parenthesis begins the "transpose" indicator, which
234.1154 +               is followed by data in the tabular format */
234.1155 +            get_token(mpl /* ( */);
234.1156 +            if (!is_literal(mpl, "tr"))
234.1157 +err3:          error(mpl, "transpose indicator (tr) incomplete");
234.1158 +            if (par->dim == 0) goto err1;
234.1159 +            if (slice_arity(mpl, slice) != 2) goto err2;
234.1160 +            get_token(mpl /* tr */);
234.1161 +            if (mpl->token != T_RIGHT) goto err3;
234.1162 +            get_token(mpl /* ) */);
234.1163 +            /* in this case the colon is optional */
234.1164 +            if (mpl->token == T_COLON) get_token(mpl /* : */);
234.1165 +            /* set the "transpose" indicator */
234.1166 +            tr = 1;
234.1167 +            /* read parameter data in the tabular format */
234.1168 +            tabular_format(mpl, par, slice, tr);
234.1169 +         }
234.1170 +         else if (mpl->token == T_SEMICOLON)
234.1171 +         {  /* semicolon terminates the data block */
234.1172 +            get_token(mpl /* ; */);
234.1173 +            break;
234.1174 +         }
234.1175 +         else
234.1176 +            error(mpl, "syntax error in parameter data block");
234.1177 +      }
234.1178 +      /* delete the current slice */
234.1179 +      delete_slice(mpl, slice);
234.1180 +done: return;
234.1181 +}
234.1182 +
234.1183 +/*----------------------------------------------------------------------
234.1184 +-- data_section - read data section.
234.1185 +--
234.1186 +-- This routine reads data section using the syntax:
234.1187 +--
234.1188 +-- <data section> ::= <empty>
234.1189 +-- <data section> ::= <data section> <data block> ;
234.1190 +-- <data block> ::= <set data>
234.1191 +-- <data block> ::= <parameter data>
234.1192 +--
234.1193 +-- Reading data section is terminated by either the keyword 'end' or
234.1194 +-- the end of file. */
234.1195 +
234.1196 +void data_section(MPL *mpl)
234.1197 +{     while (!(mpl->token == T_EOF || is_literal(mpl, "end")))
234.1198 +      {  if (is_literal(mpl, "set"))
234.1199 +            set_data(mpl);
234.1200 +         else if (is_literal(mpl, "param"))
234.1201 +            parameter_data(mpl);
234.1202 +         else
234.1203 +            error(mpl, "syntax error in data section");
234.1204 +      }
234.1205 +      return;
234.1206 +}
234.1207 +
234.1208 +/* eof */
   235.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   235.2 +++ b/src/glpmpl03.c	Mon Dec 06 13:09:21 2010 +0100
   235.3 @@ -0,0 +1,6078 @@
   235.4 +/* glpmpl03.c */
   235.5 +
   235.6 +/***********************************************************************
   235.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   235.8 +*
   235.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  235.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  235.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  235.12 +*  E-mail: <mao@gnu.org>.
  235.13 +*
  235.14 +*  GLPK is free software: you can redistribute it and/or modify it
  235.15 +*  under the terms of the GNU General Public License as published by
  235.16 +*  the Free Software Foundation, either version 3 of the License, or
  235.17 +*  (at your option) any later version.
  235.18 +*
  235.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  235.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  235.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  235.22 +*  License for more details.
  235.23 +*
  235.24 +*  You should have received a copy of the GNU General Public License
  235.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  235.26 +***********************************************************************/
  235.27 +
  235.28 +#define _GLPSTD_ERRNO
  235.29 +#define _GLPSTD_STDIO
  235.30 +#include "glpenv.h"
  235.31 +#include "glpmpl.h"
  235.32 +
  235.33 +/**********************************************************************/
  235.34 +/* * *                   FLOATING-POINT NUMBERS                   * * */
  235.35 +/**********************************************************************/
  235.36 +
  235.37 +/*----------------------------------------------------------------------
  235.38 +-- fp_add - floating-point addition.
  235.39 +--
  235.40 +-- This routine computes the sum x + y. */
  235.41 +
  235.42 +double fp_add(MPL *mpl, double x, double y)
  235.43 +{     if (x > 0.0 && y > 0.0 && x > + 0.999 * DBL_MAX - y ||
  235.44 +          x < 0.0 && y < 0.0 && x < - 0.999 * DBL_MAX - y)
  235.45 +         error(mpl, "%.*g + %.*g; floating-point overflow",
  235.46 +            DBL_DIG, x, DBL_DIG, y);
  235.47 +      return x + y;
  235.48 +}
  235.49 +
  235.50 +/*----------------------------------------------------------------------
  235.51 +-- fp_sub - floating-point subtraction.
  235.52 +--
  235.53 +-- This routine computes the difference x - y. */
  235.54 +
  235.55 +double fp_sub(MPL *mpl, double x, double y)
  235.56 +{     if (x > 0.0 && y < 0.0 && x > + 0.999 * DBL_MAX + y ||
  235.57 +          x < 0.0 && y > 0.0 && x < - 0.999 * DBL_MAX + y)
  235.58 +         error(mpl, "%.*g - %.*g; floating-point overflow",
  235.59 +            DBL_DIG, x, DBL_DIG, y);
  235.60 +      return x - y;
  235.61 +}
  235.62 +
  235.63 +/*----------------------------------------------------------------------
  235.64 +-- fp_less - floating-point non-negative subtraction.
  235.65 +--
  235.66 +-- This routine computes the non-negative difference max(0, x - y). */
  235.67 +
  235.68 +double fp_less(MPL *mpl, double x, double y)
  235.69 +{     if (x < y) return 0.0;
  235.70 +      if (x > 0.0 && y < 0.0 && x > + 0.999 * DBL_MAX + y)
  235.71 +         error(mpl, "%.*g less %.*g; floating-point overflow",
  235.72 +            DBL_DIG, x, DBL_DIG, y);
  235.73 +      return x - y;
  235.74 +}
  235.75 +
  235.76 +/*----------------------------------------------------------------------
  235.77 +-- fp_mul - floating-point multiplication.
  235.78 +--
  235.79 +-- This routine computes the product x * y. */
  235.80 +
  235.81 +double fp_mul(MPL *mpl, double x, double y)
  235.82 +{     if (fabs(y) > 1.0 && fabs(x) > (0.999 * DBL_MAX) / fabs(y))
  235.83 +         error(mpl, "%.*g * %.*g; floating-point overflow",
  235.84 +            DBL_DIG, x, DBL_DIG, y);
  235.85 +      return x * y;
  235.86 +}
  235.87 +
  235.88 +/*----------------------------------------------------------------------
  235.89 +-- fp_div - floating-point division.
  235.90 +--
  235.91 +-- This routine computes the quotient x / y. */
  235.92 +
  235.93 +double fp_div(MPL *mpl, double x, double y)
  235.94 +{     if (fabs(y) < DBL_MIN)
  235.95 +         error(mpl, "%.*g / %.*g; floating-point zero divide",
  235.96 +            DBL_DIG, x, DBL_DIG, y);
  235.97 +      if (fabs(y) < 1.0 && fabs(x) > (0.999 * DBL_MAX) * fabs(y))
  235.98 +         error(mpl, "%.*g / %.*g; floating-point overflow",
  235.99 +            DBL_DIG, x, DBL_DIG, y);
 235.100 +      return x / y;
 235.101 +}
 235.102 +
 235.103 +/*----------------------------------------------------------------------
 235.104 +-- fp_idiv - floating-point quotient of exact division.
 235.105 +--
 235.106 +-- This routine computes the quotient of exact division x div y. */
 235.107 +
 235.108 +double fp_idiv(MPL *mpl, double x, double y)
 235.109 +{     if (fabs(y) < DBL_MIN)
 235.110 +         error(mpl, "%.*g div %.*g; floating-point zero divide",
 235.111 +            DBL_DIG, x, DBL_DIG, y);
 235.112 +      if (fabs(y) < 1.0 && fabs(x) > (0.999 * DBL_MAX) * fabs(y))
 235.113 +         error(mpl, "%.*g div %.*g; floating-point overflow",
 235.114 +            DBL_DIG, x, DBL_DIG, y);
 235.115 +      x /= y;
 235.116 +      return x > 0.0 ? floor(x) : x < 0.0 ? ceil(x) : 0.0;
 235.117 +}
 235.118 +
 235.119 +/*----------------------------------------------------------------------
 235.120 +-- fp_mod - floating-point remainder of exact division.
 235.121 +--
 235.122 +-- This routine computes the remainder of exact division x mod y.
 235.123 +--
 235.124 +-- NOTE: By definition x mod y = x - y * floor(x / y). */
 235.125 +
 235.126 +double fp_mod(MPL *mpl, double x, double y)
 235.127 +{     double r;
 235.128 +      xassert(mpl == mpl);
 235.129 +      if (x == 0.0)
 235.130 +         r = 0.0;
 235.131 +      else if (y == 0.0)
 235.132 +         r = x;
 235.133 +      else
 235.134 +      {  r = fmod(fabs(x), fabs(y));
 235.135 +         if (r != 0.0)
 235.136 +         {  if (x < 0.0) r = - r;
 235.137 +            if (x > 0.0 && y < 0.0 || x < 0.0 && y > 0.0) r += y;
 235.138 +         }
 235.139 +      }
 235.140 +      return r;
 235.141 +}
 235.142 +
 235.143 +/*----------------------------------------------------------------------
 235.144 +-- fp_power - floating-point exponentiation (raise to power).
 235.145 +--
 235.146 +-- This routine computes the exponentiation x ** y. */
 235.147 +
 235.148 +double fp_power(MPL *mpl, double x, double y)
 235.149 +{     double r;
 235.150 +      if (x == 0.0 && y <= 0.0 || x < 0.0 && y != floor(y))
 235.151 +         error(mpl, "%.*g ** %.*g; result undefined",
 235.152 +            DBL_DIG, x, DBL_DIG, y);
 235.153 +      if (x == 0.0) goto eval;
 235.154 +      if (fabs(x) > 1.0 && y > +1.0 &&
 235.155 +            +log(fabs(x)) > (0.999 * log(DBL_MAX)) / y ||
 235.156 +          fabs(x) < 1.0 && y < -1.0 &&
 235.157 +            +log(fabs(x)) < (0.999 * log(DBL_MAX)) / y)
 235.158 +         error(mpl, "%.*g ** %.*g; floating-point overflow",
 235.159 +            DBL_DIG, x, DBL_DIG, y);
 235.160 +      if (fabs(x) > 1.0 && y < -1.0 &&
 235.161 +            -log(fabs(x)) < (0.999 * log(DBL_MAX)) / y ||
 235.162 +          fabs(x) < 1.0 && y > +1.0 &&
 235.163 +            -log(fabs(x)) > (0.999 * log(DBL_MAX)) / y)
 235.164 +         r = 0.0;
 235.165 +      else
 235.166 +eval:    r = pow(x, y);
 235.167 +      return r;
 235.168 +}
 235.169 +
 235.170 +/*----------------------------------------------------------------------
 235.171 +-- fp_exp - floating-point base-e exponential.
 235.172 +--
 235.173 +-- This routine computes the base-e exponential e ** x. */
 235.174 +
 235.175 +double fp_exp(MPL *mpl, double x)
 235.176 +{     if (x > 0.999 * log(DBL_MAX))
 235.177 +         error(mpl, "exp(%.*g); floating-point overflow", DBL_DIG, x);
 235.178 +      return exp(x);
 235.179 +}
 235.180 +
 235.181 +/*----------------------------------------------------------------------
 235.182 +-- fp_log - floating-point natural logarithm.
 235.183 +--
 235.184 +-- This routine computes the natural logarithm log x. */
 235.185 +
 235.186 +double fp_log(MPL *mpl, double x)
 235.187 +{     if (x <= 0.0)
 235.188 +         error(mpl, "log(%.*g); non-positive argument", DBL_DIG, x);
 235.189 +      return log(x);
 235.190 +}
 235.191 +
 235.192 +/*----------------------------------------------------------------------
 235.193 +-- fp_log10 - floating-point common (decimal) logarithm.
 235.194 +--
 235.195 +-- This routine computes the common (decimal) logarithm lg x. */
 235.196 +
 235.197 +double fp_log10(MPL *mpl, double x)
 235.198 +{     if (x <= 0.0)
 235.199 +         error(mpl, "log10(%.*g); non-positive argument", DBL_DIG, x);
 235.200 +      return log10(x);
 235.201 +}
 235.202 +
 235.203 +/*----------------------------------------------------------------------
 235.204 +-- fp_sqrt - floating-point square root.
 235.205 +--
 235.206 +-- This routine computes the square root x ** 0.5. */
 235.207 +
 235.208 +double fp_sqrt(MPL *mpl, double x)
 235.209 +{     if (x < 0.0)
 235.210 +         error(mpl, "sqrt(%.*g); negative argument", DBL_DIG, x);
 235.211 +      return sqrt(x);
 235.212 +}
 235.213 +
 235.214 +/*----------------------------------------------------------------------
 235.215 +-- fp_sin - floating-point trigonometric sine.
 235.216 +--
 235.217 +-- This routine computes the trigonometric sine sin(x). */
 235.218 +
 235.219 +double fp_sin(MPL *mpl, double x)
 235.220 +{     if (!(-1e6 <= x && x <= +1e6))
 235.221 +         error(mpl, "sin(%.*g); argument too large", DBL_DIG, x);
 235.222 +      return sin(x);
 235.223 +}
 235.224 +
 235.225 +/*----------------------------------------------------------------------
 235.226 +-- fp_cos - floating-point trigonometric cosine.
 235.227 +--
 235.228 +-- This routine computes the trigonometric cosine cos(x). */
 235.229 +
 235.230 +double fp_cos(MPL *mpl, double x)
 235.231 +{     if (!(-1e6 <= x && x <= +1e6))
 235.232 +         error(mpl, "cos(%.*g); argument too large", DBL_DIG, x);
 235.233 +      return cos(x);
 235.234 +}
 235.235 +
 235.236 +/*----------------------------------------------------------------------
 235.237 +-- fp_atan - floating-point trigonometric arctangent.
 235.238 +--
 235.239 +-- This routine computes the trigonometric arctangent atan(x). */
 235.240 +
 235.241 +double fp_atan(MPL *mpl, double x)
 235.242 +{     xassert(mpl == mpl);
 235.243 +      return atan(x);
 235.244 +}
 235.245 +
 235.246 +/*----------------------------------------------------------------------
 235.247 +-- fp_atan2 - floating-point trigonometric arctangent.
 235.248 +--
 235.249 +-- This routine computes the trigonometric arctangent atan(y / x). */
 235.250 +
 235.251 +double fp_atan2(MPL *mpl, double y, double x)
 235.252 +{     xassert(mpl == mpl);
 235.253 +      return atan2(y, x);
 235.254 +}
 235.255 +
 235.256 +/*----------------------------------------------------------------------
 235.257 +-- fp_round - round floating-point value to n fractional digits.
 235.258 +--
 235.259 +-- This routine rounds given floating-point value x to n fractional
 235.260 +-- digits with the formula:
 235.261 +--
 235.262 +--    round(x, n) = floor(x * 10^n + 0.5) / 10^n.
 235.263 +--
 235.264 +-- The parameter n is assumed to be integer. */
 235.265 +
 235.266 +double fp_round(MPL *mpl, double x, double n)
 235.267 +{     double ten_to_n;
 235.268 +      if (n != floor(n))
 235.269 +         error(mpl, "round(%.*g, %.*g); non-integer second argument",
 235.270 +            DBL_DIG, x, DBL_DIG, n);
 235.271 +      if (n <= DBL_DIG + 2)
 235.272 +      {  ten_to_n = pow(10.0, n);
 235.273 +         if (fabs(x) < (0.999 * DBL_MAX) / ten_to_n)
 235.274 +         {  x = floor(x * ten_to_n + 0.5);
 235.275 +            if (x != 0.0) x /= ten_to_n;
 235.276 +         }
 235.277 +      }
 235.278 +      return x;
 235.279 +}
 235.280 +
 235.281 +/*----------------------------------------------------------------------
 235.282 +-- fp_trunc - truncate floating-point value to n fractional digits.
 235.283 +--
 235.284 +-- This routine truncates given floating-point value x to n fractional
 235.285 +-- digits with the formula:
 235.286 +--
 235.287 +--                  ( floor(x * 10^n) / 10^n,  if x >= 0
 235.288 +--    trunc(x, n) = <
 235.289 +--                  ( ceil(x * 10^n) / 10^n,   if x < 0
 235.290 +--
 235.291 +-- The parameter n is assumed to be integer. */
 235.292 +
 235.293 +double fp_trunc(MPL *mpl, double x, double n)
 235.294 +{     double ten_to_n;
 235.295 +      if (n != floor(n))
 235.296 +         error(mpl, "trunc(%.*g, %.*g); non-integer second argument",
 235.297 +            DBL_DIG, x, DBL_DIG, n);
 235.298 +      if (n <= DBL_DIG + 2)
 235.299 +      {  ten_to_n = pow(10.0, n);
 235.300 +         if (fabs(x) < (0.999 * DBL_MAX) / ten_to_n)
 235.301 +         {  x = (x >= 0.0 ? floor(x * ten_to_n) : ceil(x * ten_to_n));
 235.302 +            if (x != 0.0) x /= ten_to_n;
 235.303 +         }
 235.304 +      }
 235.305 +      return x;
 235.306 +}
 235.307 +
 235.308 +/**********************************************************************/
 235.309 +/* * *              PSEUDO-RANDOM NUMBER GENERATORS               * * */
 235.310 +/**********************************************************************/
 235.311 +
 235.312 +/*----------------------------------------------------------------------
 235.313 +-- fp_irand224 - pseudo-random integer in the range [0, 2^24).
 235.314 +--
 235.315 +-- This routine returns a next pseudo-random integer (converted to
 235.316 +-- floating-point) which is uniformly distributed between 0 and 2^24-1,
 235.317 +-- inclusive. */
 235.318 +
 235.319 +#define two_to_the_24 0x1000000
 235.320 +
 235.321 +double fp_irand224(MPL *mpl)
 235.322 +{     return
 235.323 +         (double)rng_unif_rand(mpl->rand, two_to_the_24);
 235.324 +}
 235.325 +
 235.326 +/*----------------------------------------------------------------------
 235.327 +-- fp_uniform01 - pseudo-random number in the range [0, 1).
 235.328 +--
 235.329 +-- This routine returns a next pseudo-random number which is uniformly
 235.330 +-- distributed in the range [0, 1). */
 235.331 +
 235.332 +#define two_to_the_31 ((unsigned int)0x80000000)
 235.333 +
 235.334 +double fp_uniform01(MPL *mpl)
 235.335 +{     return
 235.336 +         (double)rng_next_rand(mpl->rand) / (double)two_to_the_31;
 235.337 +}
 235.338 +
 235.339 +/*----------------------------------------------------------------------
 235.340 +-- fp_uniform - pseudo-random number in the range [a, b).
 235.341 +--
 235.342 +-- This routine returns a next pseudo-random number which is uniformly
 235.343 +-- distributed in the range [a, b). */
 235.344 +
 235.345 +double fp_uniform(MPL *mpl, double a, double b)
 235.346 +{     double x;
 235.347 +      if (a >= b)
 235.348 +         error(mpl, "Uniform(%.*g, %.*g); invalid range",
 235.349 +            DBL_DIG, a, DBL_DIG, b);
 235.350 +      x = fp_uniform01(mpl);
 235.351 +#if 0
 235.352 +      x = a * (1.0 - x) + b * x;
 235.353 +#else
 235.354 +      x = fp_add(mpl, a * (1.0 - x), b * x);
 235.355 +#endif
 235.356 +      return x;
 235.357 +}
 235.358 +
 235.359 +/*----------------------------------------------------------------------
 235.360 +-- fp_normal01 - Gaussian random variate with mu = 0 and sigma = 1.
 235.361 +--
 235.362 +-- This routine returns a Gaussian random variate with zero mean and
 235.363 +-- unit standard deviation. The polar (Box-Mueller) method is used.
 235.364 +--
 235.365 +-- This code is a modified version of the routine gsl_ran_gaussian from
 235.366 +-- the GNU Scientific Library Version 1.0. */
 235.367 +
 235.368 +double fp_normal01(MPL *mpl)
 235.369 +{     double x, y, r2;
 235.370 +      do
 235.371 +      {  /* choose x, y in uniform square (-1,-1) to (+1,+1) */
 235.372 +         x = -1.0 + 2.0 * fp_uniform01(mpl);
 235.373 +         y = -1.0 + 2.0 * fp_uniform01(mpl);
 235.374 +         /* see if it is in the unit circle */
 235.375 +         r2 = x * x + y * y;
 235.376 +      } while (r2 > 1.0 || r2 == 0.0);
 235.377 +      /* Box-Muller transform */
 235.378 +      return y * sqrt(-2.0 * log (r2) / r2);
 235.379 +}
 235.380 +
 235.381 +/*----------------------------------------------------------------------
 235.382 +-- fp_normal - Gaussian random variate with specified mu and sigma.
 235.383 +--
 235.384 +-- This routine returns a Gaussian random variate with mean mu and
 235.385 +-- standard deviation sigma. */
 235.386 +
 235.387 +double fp_normal(MPL *mpl, double mu, double sigma)
 235.388 +{     double x;
 235.389 +#if 0
 235.390 +      x = mu + sigma * fp_normal01(mpl);
 235.391 +#else
 235.392 +      x = fp_add(mpl, mu, fp_mul(mpl, sigma, fp_normal01(mpl)));
 235.393 +#endif
 235.394 +      return x;
 235.395 +}
 235.396 +
 235.397 +/**********************************************************************/
 235.398 +/* * *                SEGMENTED CHARACTER STRINGS                 * * */
 235.399 +/**********************************************************************/
 235.400 +
 235.401 +/*----------------------------------------------------------------------
 235.402 +-- create_string - create character string.
 235.403 +--
 235.404 +-- This routine creates a segmented character string, which is exactly
 235.405 +-- equivalent to specified character string. */
 235.406 +
 235.407 +STRING *create_string
 235.408 +(     MPL *mpl,
 235.409 +      char buf[MAX_LENGTH+1]  /* not changed */
 235.410 +)
 235.411 +#if 0
 235.412 +{     STRING *head, *tail;
 235.413 +      int i, j;
 235.414 +      xassert(buf != NULL);
 235.415 +      xassert(strlen(buf) <= MAX_LENGTH);
 235.416 +      head = tail = dmp_get_atom(mpl->strings, sizeof(STRING));
 235.417 +      for (i = j = 0; ; i++)
 235.418 +      {  if ((tail->seg[j++] = buf[i]) == '\0') break;
 235.419 +         if (j == STRSEG_SIZE)
 235.420 +tail = (tail->next = dmp_get_atom(mpl->strings, sizeof(STRING))), j = 0;
 235.421 +      }
 235.422 +      tail->next = NULL;
 235.423 +      return head;
 235.424 +}
 235.425 +#else
 235.426 +{     STRING *str;
 235.427 +      xassert(strlen(buf) <= MAX_LENGTH);
 235.428 +      str = dmp_get_atom(mpl->strings, strlen(buf)+1);
 235.429 +      strcpy(str, buf);
 235.430 +      return str;
 235.431 +}
 235.432 +#endif
 235.433 +
 235.434 +/*----------------------------------------------------------------------
 235.435 +-- copy_string - make copy of character string.
 235.436 +--
 235.437 +-- This routine returns an exact copy of segmented character string. */
 235.438 +
 235.439 +STRING *copy_string
 235.440 +(     MPL *mpl,
 235.441 +      STRING *str             /* not changed */
 235.442 +)
 235.443 +#if 0
 235.444 +{     STRING *head, *tail;
 235.445 +      xassert(str != NULL);
 235.446 +      head = tail = dmp_get_atom(mpl->strings, sizeof(STRING));
 235.447 +      for (; str != NULL; str = str->next)
 235.448 +      {  memcpy(tail->seg, str->seg, STRSEG_SIZE);
 235.449 +         if (str->next != NULL)
 235.450 +tail = (tail->next = dmp_get_atom(mpl->strings, sizeof(STRING)));
 235.451 +      }
 235.452 +      tail->next = NULL;
 235.453 +      return head;
 235.454 +}
 235.455 +#else
 235.456 +{     xassert(mpl == mpl);
 235.457 +      return create_string(mpl, str);
 235.458 +}
 235.459 +#endif
 235.460 +
 235.461 +/*----------------------------------------------------------------------
 235.462 +-- compare_strings - compare one character string with another.
 235.463 +--
 235.464 +-- This routine compares one segmented character strings with another
 235.465 +-- and returns the result of comparison as follows:
 235.466 +--
 235.467 +-- = 0 - both strings are identical;
 235.468 +-- < 0 - the first string precedes the second one;
 235.469 +-- > 0 - the first string follows the second one. */
 235.470 +
 235.471 +int compare_strings
 235.472 +(     MPL *mpl,
 235.473 +      STRING *str1,           /* not changed */
 235.474 +      STRING *str2            /* not changed */
 235.475 +)
 235.476 +#if 0
 235.477 +{     int j, c1, c2;
 235.478 +      xassert(mpl == mpl);
 235.479 +      for (;; str1 = str1->next, str2 = str2->next)
 235.480 +      {  xassert(str1 != NULL);
 235.481 +         xassert(str2 != NULL);
 235.482 +         for (j = 0; j < STRSEG_SIZE; j++)
 235.483 +         {  c1 = (unsigned char)str1->seg[j];
 235.484 +            c2 = (unsigned char)str2->seg[j];
 235.485 +            if (c1 < c2) return -1;
 235.486 +            if (c1 > c2) return +1;
 235.487 +            if (c1 == '\0') goto done;
 235.488 +         }
 235.489 +      }
 235.490 +done: return 0;
 235.491 +}
 235.492 +#else
 235.493 +{     xassert(mpl == mpl);
 235.494 +      return strcmp(str1, str2);
 235.495 +}
 235.496 +#endif
 235.497 +
 235.498 +/*----------------------------------------------------------------------
 235.499 +-- fetch_string - extract content of character string.
 235.500 +--
 235.501 +-- This routine returns a character string, which is exactly equivalent
 235.502 +-- to specified segmented character string. */
 235.503 +
 235.504 +char *fetch_string
 235.505 +(     MPL *mpl,
 235.506 +      STRING *str,            /* not changed */
 235.507 +      char buf[MAX_LENGTH+1]  /* modified */
 235.508 +)
 235.509 +#if 0
 235.510 +{     int i, j;
 235.511 +      xassert(mpl == mpl);
 235.512 +      xassert(buf != NULL);
 235.513 +      for (i = 0; ; str = str->next)
 235.514 +      {  xassert(str != NULL);
 235.515 +         for (j = 0; j < STRSEG_SIZE; j++)
 235.516 +            if ((buf[i++] = str->seg[j]) == '\0') goto done;
 235.517 +      }
 235.518 +done: xassert(strlen(buf) <= MAX_LENGTH);
 235.519 +      return buf;
 235.520 +}
 235.521 +#else
 235.522 +{     xassert(mpl == mpl);
 235.523 +      return strcpy(buf, str);
 235.524 +}
 235.525 +#endif
 235.526 +
 235.527 +/*----------------------------------------------------------------------
 235.528 +-- delete_string - delete character string.
 235.529 +--
 235.530 +-- This routine deletes specified segmented character string. */
 235.531 +
 235.532 +void delete_string
 235.533 +(     MPL *mpl,
 235.534 +      STRING *str             /* destroyed */
 235.535 +)
 235.536 +#if 0
 235.537 +{     STRING *temp;
 235.538 +      xassert(str != NULL);
 235.539 +      while (str != NULL)
 235.540 +      {  temp = str;
 235.541 +         str = str->next;
 235.542 +         dmp_free_atom(mpl->strings, temp, sizeof(STRING));
 235.543 +      }
 235.544 +      return;
 235.545 +}
 235.546 +#else
 235.547 +{     dmp_free_atom(mpl->strings, str, strlen(str)+1);
 235.548 +      return;
 235.549 +}
 235.550 +#endif
 235.551 +
 235.552 +/**********************************************************************/
 235.553 +/* * *                          SYMBOLS                           * * */
 235.554 +/**********************************************************************/
 235.555 +
 235.556 +/*----------------------------------------------------------------------
 235.557 +-- create_symbol_num - create symbol of numeric type.
 235.558 +--
 235.559 +-- This routine creates a symbol, which has a numeric value specified
 235.560 +-- as floating-point number. */
 235.561 +
 235.562 +SYMBOL *create_symbol_num(MPL *mpl, double num)
 235.563 +{     SYMBOL *sym;
 235.564 +      sym = dmp_get_atom(mpl->symbols, sizeof(SYMBOL));
 235.565 +      sym->num = num;
 235.566 +      sym->str = NULL;
 235.567 +      return sym;
 235.568 +}
 235.569 +
 235.570 +/*----------------------------------------------------------------------
 235.571 +-- create_symbol_str - create symbol of abstract type.
 235.572 +--
 235.573 +-- This routine creates a symbol, which has an abstract value specified
 235.574 +-- as segmented character string. */
 235.575 +
 235.576 +SYMBOL *create_symbol_str
 235.577 +(     MPL *mpl,
 235.578 +      STRING *str             /* destroyed */
 235.579 +)
 235.580 +{     SYMBOL *sym;
 235.581 +      xassert(str != NULL);
 235.582 +      sym = dmp_get_atom(mpl->symbols, sizeof(SYMBOL));
 235.583 +      sym->num = 0.0;
 235.584 +      sym->str = str;
 235.585 +      return sym;
 235.586 +}
 235.587 +
 235.588 +/*----------------------------------------------------------------------
 235.589 +-- copy_symbol - make copy of symbol.
 235.590 +--
 235.591 +-- This routine returns an exact copy of symbol. */
 235.592 +
 235.593 +SYMBOL *copy_symbol
 235.594 +(     MPL *mpl,
 235.595 +      SYMBOL *sym             /* not changed */
 235.596 +)
 235.597 +{     SYMBOL *copy;
 235.598 +      xassert(sym != NULL);
 235.599 +      copy = dmp_get_atom(mpl->symbols, sizeof(SYMBOL));
 235.600 +      if (sym->str == NULL)
 235.601 +      {  copy->num = sym->num;
 235.602 +         copy->str = NULL;
 235.603 +      }
 235.604 +      else
 235.605 +      {  copy->num = 0.0;
 235.606 +         copy->str = copy_string(mpl, sym->str);
 235.607 +      }
 235.608 +      return copy;
 235.609 +}
 235.610 +
 235.611 +/*----------------------------------------------------------------------
 235.612 +-- compare_symbols - compare one symbol with another.
 235.613 +--
 235.614 +-- This routine compares one symbol with another and returns the result
 235.615 +-- of comparison as follows:
 235.616 +--
 235.617 +-- = 0 - both symbols are identical;
 235.618 +-- < 0 - the first symbol precedes the second one;
 235.619 +-- > 0 - the first symbol follows the second one.
 235.620 +--
 235.621 +-- Note that the linear order, in which symbols follow each other, is
 235.622 +-- implementation-dependent. It may be not an alphabetical order. */
 235.623 +
 235.624 +int compare_symbols
 235.625 +(     MPL *mpl,
 235.626 +      SYMBOL *sym1,           /* not changed */
 235.627 +      SYMBOL *sym2            /* not changed */
 235.628 +)
 235.629 +{     xassert(sym1 != NULL);
 235.630 +      xassert(sym2 != NULL);
 235.631 +      /* let all numeric quantities precede all symbolic quantities */
 235.632 +      if (sym1->str == NULL && sym2->str == NULL)
 235.633 +      {  if (sym1->num < sym2->num) return -1;
 235.634 +         if (sym1->num > sym2->num) return +1;
 235.635 +         return 0;
 235.636 +      }
 235.637 +      if (sym1->str == NULL) return -1;
 235.638 +      if (sym2->str == NULL) return +1;
 235.639 +      return compare_strings(mpl, sym1->str, sym2->str);
 235.640 +}
 235.641 +
 235.642 +/*----------------------------------------------------------------------
 235.643 +-- delete_symbol - delete symbol.
 235.644 +--
 235.645 +-- This routine deletes specified symbol. */
 235.646 +
 235.647 +void delete_symbol
 235.648 +(     MPL *mpl,
 235.649 +      SYMBOL *sym             /* destroyed */
 235.650 +)
 235.651 +{     xassert(sym != NULL);
 235.652 +      if (sym->str != NULL) delete_string(mpl, sym->str);
 235.653 +      dmp_free_atom(mpl->symbols, sym, sizeof(SYMBOL));
 235.654 +      return;
 235.655 +}
 235.656 +
 235.657 +/*----------------------------------------------------------------------
 235.658 +-- format_symbol - format symbol for displaying or printing.
 235.659 +--
 235.660 +-- This routine converts specified symbol to a charater string, which
 235.661 +-- is suitable for displaying or printing.
 235.662 +--
 235.663 +-- The resultant string is never longer than 255 characters. If it gets
 235.664 +-- longer, it is truncated from the right and appended by dots. */
 235.665 +
 235.666 +char *format_symbol
 235.667 +(     MPL *mpl,
 235.668 +      SYMBOL *sym             /* not changed */
 235.669 +)
 235.670 +{     char *buf = mpl->sym_buf;
 235.671 +      xassert(sym != NULL);
 235.672 +      if (sym->str == NULL)
 235.673 +         sprintf(buf, "%.*g", DBL_DIG, sym->num);
 235.674 +      else
 235.675 +      {  char str[MAX_LENGTH+1];
 235.676 +         int quoted, j, len;
 235.677 +         fetch_string(mpl, sym->str, str);
 235.678 +         if (!(isalpha((unsigned char)str[0]) || str[0] == '_'))
 235.679 +            quoted = 1;
 235.680 +         else
 235.681 +         {  quoted = 0;
 235.682 +            for (j = 1; str[j] != '\0'; j++)
 235.683 +            {  if (!(isalnum((unsigned char)str[j]) ||
 235.684 +                     strchr("+-._", (unsigned char)str[j]) != NULL))
 235.685 +               {  quoted = 1;
 235.686 +                  break;
 235.687 +               }
 235.688 +            }
 235.689 +         }
 235.690 +#        define safe_append(c) \
 235.691 +            (void)(len < 255 ? (buf[len++] = (char)(c)) : 0)
 235.692 +         buf[0] = '\0', len = 0;
 235.693 +         if (quoted) safe_append('\'');
 235.694 +         for (j = 0; str[j] != '\0'; j++)
 235.695 +         {  if (quoted && str[j] == '\'') safe_append('\'');
 235.696 +            safe_append(str[j]);
 235.697 +         }
 235.698 +         if (quoted) safe_append('\'');
 235.699 +#        undef safe_append
 235.700 +         buf[len] = '\0';
 235.701 +         if (len == 255) strcpy(buf+252, "...");
 235.702 +      }
 235.703 +      xassert(strlen(buf) <= 255);
 235.704 +      return buf;
 235.705 +}
 235.706 +
 235.707 +/*----------------------------------------------------------------------
 235.708 +-- concat_symbols - concatenate one symbol with another.
 235.709 +--
 235.710 +-- This routine concatenates values of two given symbols and assigns
 235.711 +-- the resultant character string to a new symbol, which is returned on
 235.712 +-- exit. Both original symbols are destroyed. */
 235.713 +
 235.714 +SYMBOL *concat_symbols
 235.715 +(     MPL *mpl,
 235.716 +      SYMBOL *sym1,           /* destroyed */
 235.717 +      SYMBOL *sym2            /* destroyed */
 235.718 +)
 235.719 +{     char str1[MAX_LENGTH+1], str2[MAX_LENGTH+1];
 235.720 +      xassert(MAX_LENGTH >= DBL_DIG + DBL_DIG);
 235.721 +      if (sym1->str == NULL)
 235.722 +         sprintf(str1, "%.*g", DBL_DIG, sym1->num);
 235.723 +      else
 235.724 +         fetch_string(mpl, sym1->str, str1);
 235.725 +      if (sym2->str == NULL)
 235.726 +         sprintf(str2, "%.*g", DBL_DIG, sym2->num);
 235.727 +      else
 235.728 +         fetch_string(mpl, sym2->str, str2);
 235.729 +      if (strlen(str1) + strlen(str2) > MAX_LENGTH)
 235.730 +      {  char buf[255+1];
 235.731 +         strcpy(buf, format_symbol(mpl, sym1));
 235.732 +         xassert(strlen(buf) < sizeof(buf));
 235.733 +         error(mpl, "%s & %s; resultant symbol exceeds %d characters",
 235.734 +            buf, format_symbol(mpl, sym2), MAX_LENGTH);
 235.735 +      }
 235.736 +      delete_symbol(mpl, sym1);
 235.737 +      delete_symbol(mpl, sym2);
 235.738 +      return create_symbol_str(mpl, create_string(mpl, strcat(str1,
 235.739 +         str2)));
 235.740 +}
 235.741 +
 235.742 +/**********************************************************************/
 235.743 +/* * *                          N-TUPLES                          * * */
 235.744 +/**********************************************************************/
 235.745 +
 235.746 +/*----------------------------------------------------------------------
 235.747 +-- create_tuple - create n-tuple.
 235.748 +--
 235.749 +-- This routine creates a n-tuple, which initially has no components,
 235.750 +-- i.e. which is 0-tuple. */
 235.751 +
 235.752 +TUPLE *create_tuple(MPL *mpl)
 235.753 +{     TUPLE *tuple;
 235.754 +      xassert(mpl == mpl);
 235.755 +      tuple = NULL;
 235.756 +      return tuple;
 235.757 +}
 235.758 +
 235.759 +/*----------------------------------------------------------------------
 235.760 +-- expand_tuple - append symbol to n-tuple.
 235.761 +--
 235.762 +-- This routine expands n-tuple appending to it a given symbol, which
 235.763 +-- becomes its new last component. */
 235.764 +
 235.765 +TUPLE *expand_tuple
 235.766 +(     MPL *mpl,
 235.767 +      TUPLE *tuple,           /* destroyed */
 235.768 +      SYMBOL *sym             /* destroyed */
 235.769 +)
 235.770 +{     TUPLE *tail, *temp;
 235.771 +      xassert(sym != NULL);
 235.772 +      /* create a new component */
 235.773 +      tail = dmp_get_atom(mpl->tuples, sizeof(TUPLE));
 235.774 +      tail->sym = sym;
 235.775 +      tail->next = NULL;
 235.776 +      /* and append it to the component list */
 235.777 +      if (tuple == NULL)
 235.778 +         tuple = tail;
 235.779 +      else
 235.780 +      {  for (temp = tuple; temp->next != NULL; temp = temp->next);
 235.781 +         temp->next = tail;
 235.782 +      }
 235.783 +      return tuple;
 235.784 +}
 235.785 +
 235.786 +/*----------------------------------------------------------------------
 235.787 +-- tuple_dimen - determine dimension of n-tuple.
 235.788 +--
 235.789 +-- This routine returns dimension of n-tuple, i.e. number of components
 235.790 +-- in the n-tuple. */
 235.791 +
 235.792 +int tuple_dimen
 235.793 +(     MPL *mpl,
 235.794 +      TUPLE *tuple            /* not changed */
 235.795 +)
 235.796 +{     TUPLE *temp;
 235.797 +      int dim = 0;
 235.798 +      xassert(mpl == mpl);
 235.799 +      for (temp = tuple; temp != NULL; temp = temp->next) dim++;
 235.800 +      return dim;
 235.801 +}
 235.802 +
 235.803 +/*----------------------------------------------------------------------
 235.804 +-- copy_tuple - make copy of n-tuple.
 235.805 +--
 235.806 +-- This routine returns an exact copy of n-tuple. */
 235.807 +
 235.808 +TUPLE *copy_tuple
 235.809 +(     MPL *mpl,
 235.810 +      TUPLE *tuple            /* not changed */
 235.811 +)
 235.812 +{     TUPLE *head, *tail;
 235.813 +      if (tuple == NULL)
 235.814 +         head = NULL;
 235.815 +      else
 235.816 +      {  head = tail = dmp_get_atom(mpl->tuples, sizeof(TUPLE));
 235.817 +         for (; tuple != NULL; tuple = tuple->next)
 235.818 +         {  xassert(tuple->sym != NULL);
 235.819 +            tail->sym = copy_symbol(mpl, tuple->sym);
 235.820 +            if (tuple->next != NULL)
 235.821 +tail = (tail->next = dmp_get_atom(mpl->tuples, sizeof(TUPLE)));
 235.822 +         }
 235.823 +         tail->next = NULL;
 235.824 +      }
 235.825 +      return head;
 235.826 +}
 235.827 +
 235.828 +/*----------------------------------------------------------------------
 235.829 +-- compare_tuples - compare one n-tuple with another.
 235.830 +--
 235.831 +-- This routine compares two given n-tuples, which must have the same
 235.832 +-- dimension (not checked for the sake of efficiency), and returns one
 235.833 +-- of the following codes:
 235.834 +--
 235.835 +-- = 0 - both n-tuples are identical;
 235.836 +-- < 0 - the first n-tuple precedes the second one;
 235.837 +-- > 0 - the first n-tuple follows the second one.
 235.838 +--
 235.839 +-- Note that the linear order, in which n-tuples follow each other, is
 235.840 +-- implementation-dependent. It may be not an alphabetical order. */
 235.841 +
 235.842 +int compare_tuples
 235.843 +(     MPL *mpl,
 235.844 +      TUPLE *tuple1,          /* not changed */
 235.845 +      TUPLE *tuple2           /* not changed */
 235.846 +)
 235.847 +{     TUPLE *item1, *item2;
 235.848 +      int ret;
 235.849 +      xassert(mpl == mpl);
 235.850 +      for (item1 = tuple1, item2 = tuple2; item1 != NULL;
 235.851 +           item1 = item1->next, item2 = item2->next)
 235.852 +      {  xassert(item2 != NULL);
 235.853 +         xassert(item1->sym != NULL);
 235.854 +         xassert(item2->sym != NULL);
 235.855 +         ret = compare_symbols(mpl, item1->sym, item2->sym);
 235.856 +         if (ret != 0) return ret;
 235.857 +      }
 235.858 +      xassert(item2 == NULL);
 235.859 +      return 0;
 235.860 +}
 235.861 +
 235.862 +/*----------------------------------------------------------------------
 235.863 +-- build_subtuple - build subtuple of given n-tuple.
 235.864 +--
 235.865 +-- This routine builds subtuple, which consists of first dim components
 235.866 +-- of given n-tuple. */
 235.867 +
 235.868 +TUPLE *build_subtuple
 235.869 +(     MPL *mpl,
 235.870 +      TUPLE *tuple,           /* not changed */
 235.871 +      int dim
 235.872 +)
 235.873 +{     TUPLE *head, *temp;
 235.874 +      int j;
 235.875 +      head = create_tuple(mpl);
 235.876 +      for (j = 1, temp = tuple; j <= dim; j++, temp = temp->next)
 235.877 +      {  xassert(temp != NULL);
 235.878 +         head = expand_tuple(mpl, head, copy_symbol(mpl, temp->sym));
 235.879 +      }
 235.880 +      return head;
 235.881 +}
 235.882 +
 235.883 +/*----------------------------------------------------------------------
 235.884 +-- delete_tuple - delete n-tuple.
 235.885 +--
 235.886 +-- This routine deletes specified n-tuple. */
 235.887 +
 235.888 +void delete_tuple
 235.889 +(     MPL *mpl,
 235.890 +      TUPLE *tuple            /* destroyed */
 235.891 +)
 235.892 +{     TUPLE *temp;
 235.893 +      while (tuple != NULL)
 235.894 +      {  temp = tuple;
 235.895 +         tuple = temp->next;
 235.896 +         xassert(temp->sym != NULL);
 235.897 +         delete_symbol(mpl, temp->sym);
 235.898 +         dmp_free_atom(mpl->tuples, temp, sizeof(TUPLE));
 235.899 +      }
 235.900 +      return;
 235.901 +}
 235.902 +
 235.903 +/*----------------------------------------------------------------------
 235.904 +-- format_tuple - format n-tuple for displaying or printing.
 235.905 +--
 235.906 +-- This routine converts specified n-tuple to a character string, which
 235.907 +-- is suitable for displaying or printing.
 235.908 +--
 235.909 +-- The resultant string is never longer than 255 characters. If it gets
 235.910 +-- longer, it is truncated from the right and appended by dots. */
 235.911 +
 235.912 +char *format_tuple
 235.913 +(     MPL *mpl,
 235.914 +      int c,
 235.915 +      TUPLE *tuple            /* not changed */
 235.916 +)
 235.917 +{     TUPLE *temp;
 235.918 +      int dim, j, len;
 235.919 +      char *buf = mpl->tup_buf, str[255+1], *save;
 235.920 +#     define safe_append(c) \
 235.921 +         (void)(len < 255 ? (buf[len++] = (char)(c)) : 0)
 235.922 +      buf[0] = '\0', len = 0;
 235.923 +      dim = tuple_dimen(mpl, tuple);
 235.924 +      if (c == '[' && dim > 0) safe_append('[');
 235.925 +      if (c == '(' && dim > 1) safe_append('(');
 235.926 +      for (temp = tuple; temp != NULL; temp = temp->next)
 235.927 +      {  if (temp != tuple) safe_append(',');
 235.928 +         xassert(temp->sym != NULL);
 235.929 +         save = mpl->sym_buf;
 235.930 +         mpl->sym_buf = str;
 235.931 +         format_symbol(mpl, temp->sym);
 235.932 +         mpl->sym_buf = save;
 235.933 +         xassert(strlen(str) < sizeof(str));
 235.934 +         for (j = 0; str[j] != '\0'; j++) safe_append(str[j]);
 235.935 +      }
 235.936 +      if (c == '[' && dim > 0) safe_append(']');
 235.937 +      if (c == '(' && dim > 1) safe_append(')');
 235.938 +#     undef safe_append
 235.939 +      buf[len] = '\0';
 235.940 +      if (len == 255) strcpy(buf+252, "...");
 235.941 +      xassert(strlen(buf) <= 255);
 235.942 +      return buf;
 235.943 +}
 235.944 +
 235.945 +/**********************************************************************/
 235.946 +/* * *                       ELEMENTAL SETS                       * * */
 235.947 +/**********************************************************************/
 235.948 +
 235.949 +/*----------------------------------------------------------------------
 235.950 +-- create_elemset - create elemental set.
 235.951 +--
 235.952 +-- This routine creates an elemental set, whose members are n-tuples of
 235.953 +-- specified dimension. Being created the set is initially empty. */
 235.954 +
 235.955 +ELEMSET *create_elemset(MPL *mpl, int dim)
 235.956 +{     ELEMSET *set;
 235.957 +      xassert(dim > 0);
 235.958 +      set = create_array(mpl, A_NONE, dim);
 235.959 +      return set;
 235.960 +}
 235.961 +
 235.962 +/*----------------------------------------------------------------------
 235.963 +-- find_tuple - check if elemental set contains given n-tuple.
 235.964 +--
 235.965 +-- This routine finds given n-tuple in specified elemental set in order
 235.966 +-- to check if the set contains that n-tuple. If the n-tuple is found,
 235.967 +-- the routine returns pointer to corresponding array member. Otherwise
 235.968 +-- null pointer is returned. */
 235.969 +
 235.970 +MEMBER *find_tuple
 235.971 +(     MPL *mpl,
 235.972 +      ELEMSET *set,           /* not changed */
 235.973 +      TUPLE *tuple            /* not changed */
 235.974 +)
 235.975 +{     xassert(set != NULL);
 235.976 +      xassert(set->type == A_NONE);
 235.977 +      xassert(set->dim == tuple_dimen(mpl, tuple));
 235.978 +      return find_member(mpl, set, tuple);
 235.979 +}
 235.980 +
 235.981 +/*----------------------------------------------------------------------
 235.982 +-- add_tuple - add new n-tuple to elemental set.
 235.983 +--
 235.984 +-- This routine adds given n-tuple to specified elemental set.
 235.985 +--
 235.986 +-- For the sake of efficiency this routine doesn't check whether the
 235.987 +-- set already contains the same n-tuple or not. Therefore the calling
 235.988 +-- program should use the routine find_tuple (if necessary) in order to
 235.989 +-- make sure that the given n-tuple is not contained in the set, since
 235.990 +-- duplicate n-tuples within the same set are not allowed. */
 235.991 +
 235.992 +MEMBER *add_tuple
 235.993 +(     MPL *mpl,
 235.994 +      ELEMSET *set,           /* modified */
 235.995 +      TUPLE *tuple            /* destroyed */
 235.996 +)
 235.997 +{     MEMBER *memb;
 235.998 +      xassert(set != NULL);
 235.999 +      xassert(set->type == A_NONE);
235.1000 +      xassert(set->dim == tuple_dimen(mpl, tuple));
235.1001 +      memb = add_member(mpl, set, tuple);
235.1002 +      memb->value.none = NULL;
235.1003 +      return memb;
235.1004 +}
235.1005 +
235.1006 +/*----------------------------------------------------------------------
235.1007 +-- check_then_add - check and add new n-tuple to elemental set.
235.1008 +--
235.1009 +-- This routine is equivalent to the routine add_tuple except that it
235.1010 +-- does check for duplicate n-tuples. */
235.1011 +
235.1012 +MEMBER *check_then_add
235.1013 +(     MPL *mpl,
235.1014 +      ELEMSET *set,           /* modified */
235.1015 +      TUPLE *tuple            /* destroyed */
235.1016 +)
235.1017 +{     if (find_tuple(mpl, set, tuple) != NULL)
235.1018 +         error(mpl, "duplicate tuple %s detected", format_tuple(mpl,
235.1019 +            '(', tuple));
235.1020 +      return add_tuple(mpl, set, tuple);
235.1021 +}
235.1022 +
235.1023 +/*----------------------------------------------------------------------
235.1024 +-- copy_elemset - make copy of elemental set.
235.1025 +--
235.1026 +-- This routine makes an exact copy of elemental set. */
235.1027 +
235.1028 +ELEMSET *copy_elemset
235.1029 +(     MPL *mpl,
235.1030 +      ELEMSET *set            /* not changed */
235.1031 +)
235.1032 +{     ELEMSET *copy;
235.1033 +      MEMBER *memb;
235.1034 +      xassert(set != NULL);
235.1035 +      xassert(set->type == A_NONE);
235.1036 +      xassert(set->dim > 0);
235.1037 +      copy = create_elemset(mpl, set->dim);
235.1038 +      for (memb = set->head; memb != NULL; memb = memb->next)
235.1039 +         add_tuple(mpl, copy, copy_tuple(mpl, memb->tuple));
235.1040 +      return copy;
235.1041 +}
235.1042 +
235.1043 +/*----------------------------------------------------------------------
235.1044 +-- delete_elemset - delete elemental set.
235.1045 +--
235.1046 +-- This routine deletes specified elemental set. */
235.1047 +
235.1048 +void delete_elemset
235.1049 +(     MPL *mpl,
235.1050 +      ELEMSET *set            /* destroyed */
235.1051 +)
235.1052 +{     xassert(set != NULL);
235.1053 +      xassert(set->type == A_NONE);
235.1054 +      delete_array(mpl, set);
235.1055 +      return;
235.1056 +}
235.1057 +
235.1058 +/*----------------------------------------------------------------------
235.1059 +-- arelset_size - compute size of "arithmetic" elemental set.
235.1060 +--
235.1061 +-- This routine computes the size of "arithmetic" elemental set, which
235.1062 +-- is specified in the form of arithmetic progression:
235.1063 +--
235.1064 +--    { t0 .. tf by dt }.
235.1065 +--
235.1066 +-- The size is computed using the formula:
235.1067 +--
235.1068 +--    n = max(0, floor((tf - t0) / dt) + 1). */
235.1069 +
235.1070 +int arelset_size(MPL *mpl, double t0, double tf, double dt)
235.1071 +{     double temp;
235.1072 +      if (dt == 0.0)
235.1073 +         error(mpl, "%.*g .. %.*g by %.*g; zero stride not allowed",
235.1074 +            DBL_DIG, t0, DBL_DIG, tf, DBL_DIG, dt);
235.1075 +      if (tf > 0.0 && t0 < 0.0 && tf > + 0.999 * DBL_MAX + t0)
235.1076 +         temp = +DBL_MAX;
235.1077 +      else if (tf < 0.0 && t0 > 0.0 && tf < - 0.999 * DBL_MAX + t0)
235.1078 +         temp = -DBL_MAX;
235.1079 +      else
235.1080 +         temp = tf - t0;
235.1081 +      if (fabs(dt) < 1.0 && fabs(temp) > (0.999 * DBL_MAX) * fabs(dt))
235.1082 +      {  if (temp > 0.0 && dt > 0.0 || temp < 0.0 && dt < 0.0)
235.1083 +            temp = +DBL_MAX;
235.1084 +         else
235.1085 +            temp = 0.0;
235.1086 +      }
235.1087 +      else
235.1088 +      {  temp = floor(temp / dt) + 1.0;
235.1089 +         if (temp < 0.0) temp = 0.0;
235.1090 +      }
235.1091 +      xassert(temp >= 0.0);
235.1092 +      if (temp > (double)(INT_MAX - 1))
235.1093 +         error(mpl, "%.*g .. %.*g by %.*g; set too large",
235.1094 +            DBL_DIG, t0, DBL_DIG, tf, DBL_DIG, dt);
235.1095 +      return (int)(temp + 0.5);
235.1096 +}
235.1097 +
235.1098 +/*----------------------------------------------------------------------
235.1099 +-- arelset_member - compute member of "arithmetic" elemental set.
235.1100 +--
235.1101 +-- This routine returns a numeric value of symbol, which is equivalent
235.1102 +-- to j-th member of given "arithmetic" elemental set specified in the
235.1103 +-- form of arithmetic progression:
235.1104 +--
235.1105 +--    { t0 .. tf by dt }.
235.1106 +--
235.1107 +-- The symbol value is computed with the formula:
235.1108 +--
235.1109 +--    j-th member = t0 + (j - 1) * dt,
235.1110 +--
235.1111 +-- The number j must satisfy to the restriction 1 <= j <= n, where n is
235.1112 +-- the set size computed by the routine arelset_size. */
235.1113 +
235.1114 +double arelset_member(MPL *mpl, double t0, double tf, double dt, int j)
235.1115 +{     xassert(1 <= j && j <= arelset_size(mpl, t0, tf, dt));
235.1116 +      return t0 + (double)(j - 1) * dt;
235.1117 +}
235.1118 +
235.1119 +/*----------------------------------------------------------------------
235.1120 +-- create_arelset - create "arithmetic" elemental set.
235.1121 +--
235.1122 +-- This routine creates "arithmetic" elemental set, which is specified
235.1123 +-- in the form of arithmetic progression:
235.1124 +--
235.1125 +--    { t0 .. tf by dt }.
235.1126 +--
235.1127 +-- Components of this set are 1-tuples. */
235.1128 +
235.1129 +ELEMSET *create_arelset(MPL *mpl, double t0, double tf, double dt)
235.1130 +{     ELEMSET *set;
235.1131 +      int j, n;
235.1132 +      set = create_elemset(mpl, 1);
235.1133 +      n = arelset_size(mpl, t0, tf, dt);
235.1134 +      for (j = 1; j <= n; j++)
235.1135 +      {  add_tuple
235.1136 +         (  mpl,
235.1137 +            set,
235.1138 +            expand_tuple
235.1139 +            (  mpl,
235.1140 +               create_tuple(mpl),
235.1141 +               create_symbol_num
235.1142 +               (  mpl,
235.1143 +                  arelset_member(mpl, t0, tf, dt, j)
235.1144 +               )
235.1145 +            )
235.1146 +         );
235.1147 +      }
235.1148 +      return set;
235.1149 +}
235.1150 +
235.1151 +/*----------------------------------------------------------------------
235.1152 +-- set_union - union of two elemental sets.
235.1153 +--
235.1154 +-- This routine computes the union:
235.1155 +--
235.1156 +--    X U Y = { j | (j in X) or (j in Y) },
235.1157 +--
235.1158 +-- where X and Y are given elemental sets (destroyed on exit). */
235.1159 +
235.1160 +ELEMSET *set_union
235.1161 +(     MPL *mpl,
235.1162 +      ELEMSET *X,             /* destroyed */
235.1163 +      ELEMSET *Y              /* destroyed */
235.1164 +)
235.1165 +{     MEMBER *memb;
235.1166 +      xassert(X != NULL);
235.1167 +      xassert(X->type == A_NONE);
235.1168 +      xassert(X->dim > 0);
235.1169 +      xassert(Y != NULL);
235.1170 +      xassert(Y->type == A_NONE);
235.1171 +      xassert(Y->dim > 0);
235.1172 +      xassert(X->dim == Y->dim);
235.1173 +      for (memb = Y->head; memb != NULL; memb = memb->next)
235.1174 +      {  if (find_tuple(mpl, X, memb->tuple) == NULL)
235.1175 +            add_tuple(mpl, X, copy_tuple(mpl, memb->tuple));
235.1176 +      }
235.1177 +      delete_elemset(mpl, Y);
235.1178 +      return X;
235.1179 +}
235.1180 +
235.1181 +/*----------------------------------------------------------------------
235.1182 +-- set_diff - difference between two elemental sets.
235.1183 +--
235.1184 +-- This routine computes the difference:
235.1185 +--
235.1186 +--    X \ Y = { j | (j in X) and (j not in Y) },
235.1187 +--
235.1188 +-- where X and Y are given elemental sets (destroyed on exit). */
235.1189 +
235.1190 +ELEMSET *set_diff
235.1191 +(     MPL *mpl,
235.1192 +      ELEMSET *X,             /* destroyed */
235.1193 +      ELEMSET *Y              /* destroyed */
235.1194 +)
235.1195 +{     ELEMSET *Z;
235.1196 +      MEMBER *memb;
235.1197 +      xassert(X != NULL);
235.1198 +      xassert(X->type == A_NONE);
235.1199 +      xassert(X->dim > 0);
235.1200 +      xassert(Y != NULL);
235.1201 +      xassert(Y->type == A_NONE);
235.1202 +      xassert(Y->dim > 0);
235.1203 +      xassert(X->dim == Y->dim);
235.1204 +      Z = create_elemset(mpl, X->dim);
235.1205 +      for (memb = X->head; memb != NULL; memb = memb->next)
235.1206 +      {  if (find_tuple(mpl, Y, memb->tuple) == NULL)
235.1207 +            add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
235.1208 +      }
235.1209 +      delete_elemset(mpl, X);
235.1210 +      delete_elemset(mpl, Y);
235.1211 +      return Z;
235.1212 +}
235.1213 +
235.1214 +/*----------------------------------------------------------------------
235.1215 +-- set_symdiff - symmetric difference between two elemental sets.
235.1216 +--
235.1217 +-- This routine computes the symmetric difference:
235.1218 +--
235.1219 +--    X (+) Y = (X \ Y) U (Y \ X),
235.1220 +--
235.1221 +-- where X and Y are given elemental sets (destroyed on exit). */
235.1222 +
235.1223 +ELEMSET *set_symdiff
235.1224 +(     MPL *mpl,
235.1225 +      ELEMSET *X,             /* destroyed */
235.1226 +      ELEMSET *Y              /* destroyed */
235.1227 +)
235.1228 +{     ELEMSET *Z;
235.1229 +      MEMBER *memb;
235.1230 +      xassert(X != NULL);
235.1231 +      xassert(X->type == A_NONE);
235.1232 +      xassert(X->dim > 0);
235.1233 +      xassert(Y != NULL);
235.1234 +      xassert(Y->type == A_NONE);
235.1235 +      xassert(Y->dim > 0);
235.1236 +      xassert(X->dim == Y->dim);
235.1237 +      /* Z := X \ Y */
235.1238 +      Z = create_elemset(mpl, X->dim);
235.1239 +      for (memb = X->head; memb != NULL; memb = memb->next)
235.1240 +      {  if (find_tuple(mpl, Y, memb->tuple) == NULL)
235.1241 +            add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
235.1242 +      }
235.1243 +      /* Z := Z U (Y \ X) */
235.1244 +      for (memb = Y->head; memb != NULL; memb = memb->next)
235.1245 +      {  if (find_tuple(mpl, X, memb->tuple) == NULL)
235.1246 +            add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
235.1247 +      }
235.1248 +      delete_elemset(mpl, X);
235.1249 +      delete_elemset(mpl, Y);
235.1250 +      return Z;
235.1251 +}
235.1252 +
235.1253 +/*----------------------------------------------------------------------
235.1254 +-- set_inter - intersection of two elemental sets.
235.1255 +--
235.1256 +-- This routine computes the intersection:
235.1257 +--
235.1258 +--    X ^ Y = { j | (j in X) and (j in Y) },
235.1259 +--
235.1260 +-- where X and Y are given elemental sets (destroyed on exit). */
235.1261 +
235.1262 +ELEMSET *set_inter
235.1263 +(     MPL *mpl,
235.1264 +      ELEMSET *X,             /* destroyed */
235.1265 +      ELEMSET *Y              /* destroyed */
235.1266 +)
235.1267 +{     ELEMSET *Z;
235.1268 +      MEMBER *memb;
235.1269 +      xassert(X != NULL);
235.1270 +      xassert(X->type == A_NONE);
235.1271 +      xassert(X->dim > 0);
235.1272 +      xassert(Y != NULL);
235.1273 +      xassert(Y->type == A_NONE);
235.1274 +      xassert(Y->dim > 0);
235.1275 +      xassert(X->dim == Y->dim);
235.1276 +      Z = create_elemset(mpl, X->dim);
235.1277 +      for (memb = X->head; memb != NULL; memb = memb->next)
235.1278 +      {  if (find_tuple(mpl, Y, memb->tuple) != NULL)
235.1279 +            add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
235.1280 +      }
235.1281 +      delete_elemset(mpl, X);
235.1282 +      delete_elemset(mpl, Y);
235.1283 +      return Z;
235.1284 +}
235.1285 +
235.1286 +/*----------------------------------------------------------------------
235.1287 +-- set_cross - cross (Cartesian) product of two elemental sets.
235.1288 +--
235.1289 +-- This routine computes the cross (Cartesian) product:
235.1290 +--
235.1291 +--    X x Y = { (i,j) | (i in X) and (j in Y) },
235.1292 +--
235.1293 +-- where X and Y are given elemental sets (destroyed on exit). */
235.1294 +
235.1295 +ELEMSET *set_cross
235.1296 +(     MPL *mpl,
235.1297 +      ELEMSET *X,             /* destroyed */
235.1298 +      ELEMSET *Y              /* destroyed */
235.1299 +)
235.1300 +{     ELEMSET *Z;
235.1301 +      MEMBER *memx, *memy;
235.1302 +      TUPLE *tuple, *temp;
235.1303 +      xassert(X != NULL);
235.1304 +      xassert(X->type == A_NONE);
235.1305 +      xassert(X->dim > 0);
235.1306 +      xassert(Y != NULL);
235.1307 +      xassert(Y->type == A_NONE);
235.1308 +      xassert(Y->dim > 0);
235.1309 +      Z = create_elemset(mpl, X->dim + Y->dim);
235.1310 +      for (memx = X->head; memx != NULL; memx = memx->next)
235.1311 +      {  for (memy = Y->head; memy != NULL; memy = memy->next)
235.1312 +         {  tuple = copy_tuple(mpl, memx->tuple);
235.1313 +            for (temp = memy->tuple; temp != NULL; temp = temp->next)
235.1314 +               tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
235.1315 +                  temp->sym));
235.1316 +            add_tuple(mpl, Z, tuple);
235.1317 +         }
235.1318 +      }
235.1319 +      delete_elemset(mpl, X);
235.1320 +      delete_elemset(mpl, Y);
235.1321 +      return Z;
235.1322 +}
235.1323 +
235.1324 +/**********************************************************************/
235.1325 +/* * *                    ELEMENTAL VARIABLES                     * * */
235.1326 +/**********************************************************************/
235.1327 +
235.1328 +/* (there are no specific routines for elemental variables) */
235.1329 +
235.1330 +/**********************************************************************/
235.1331 +/* * *                        LINEAR FORMS                        * * */
235.1332 +/**********************************************************************/
235.1333 +
235.1334 +/*----------------------------------------------------------------------
235.1335 +-- constant_term - create constant term.
235.1336 +--
235.1337 +-- This routine creates the linear form, which is a constant term. */
235.1338 +
235.1339 +FORMULA *constant_term(MPL *mpl, double coef)
235.1340 +{     FORMULA *form;
235.1341 +      if (coef == 0.0)
235.1342 +         form = NULL;
235.1343 +      else
235.1344 +      {  form = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
235.1345 +         form->coef = coef;
235.1346 +         form->var = NULL;
235.1347 +         form->next = NULL;
235.1348 +      }
235.1349 +      return form;
235.1350 +}
235.1351 +
235.1352 +/*----------------------------------------------------------------------
235.1353 +-- single_variable - create single variable.
235.1354 +--
235.1355 +-- This routine creates the linear form, which is a single elemental
235.1356 +-- variable. */
235.1357 +
235.1358 +FORMULA *single_variable
235.1359 +(     MPL *mpl,
235.1360 +      ELEMVAR *var            /* referenced */
235.1361 +)
235.1362 +{     FORMULA *form;
235.1363 +      xassert(var != NULL);
235.1364 +      form = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
235.1365 +      form->coef = 1.0;
235.1366 +      form->var = var;
235.1367 +      form->next = NULL;
235.1368 +      return form;
235.1369 +}
235.1370 +
235.1371 +/*----------------------------------------------------------------------
235.1372 +-- copy_formula - make copy of linear form.
235.1373 +--
235.1374 +-- This routine returns an exact copy of linear form. */
235.1375 +
235.1376 +FORMULA *copy_formula
235.1377 +(     MPL *mpl,
235.1378 +      FORMULA *form           /* not changed */
235.1379 +)
235.1380 +{     FORMULA *head, *tail;
235.1381 +      if (form == NULL)
235.1382 +         head = NULL;
235.1383 +      else
235.1384 +      {  head = tail = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
235.1385 +         for (; form != NULL; form = form->next)
235.1386 +         {  tail->coef = form->coef;
235.1387 +            tail->var = form->var;
235.1388 +            if (form->next != NULL)
235.1389 +tail = (tail->next = dmp_get_atom(mpl->formulae, sizeof(FORMULA)));
235.1390 +         }
235.1391 +         tail->next = NULL;
235.1392 +      }
235.1393 +      return head;
235.1394 +}
235.1395 +
235.1396 +/*----------------------------------------------------------------------
235.1397 +-- delete_formula - delete linear form.
235.1398 +--
235.1399 +-- This routine deletes specified linear form. */
235.1400 +
235.1401 +void delete_formula
235.1402 +(     MPL *mpl,
235.1403 +      FORMULA *form           /* destroyed */
235.1404 +)
235.1405 +{     FORMULA *temp;
235.1406 +      while (form != NULL)
235.1407 +      {  temp = form;
235.1408 +         form = form->next;
235.1409 +         dmp_free_atom(mpl->formulae, temp, sizeof(FORMULA));
235.1410 +      }
235.1411 +      return;
235.1412 +}
235.1413 +
235.1414 +/*----------------------------------------------------------------------
235.1415 +-- linear_comb - linear combination of two linear forms.
235.1416 +--
235.1417 +-- This routine computes the linear combination:
235.1418 +--
235.1419 +--    a * fx + b * fy,
235.1420 +--
235.1421 +-- where a and b are numeric coefficients, fx and fy are linear forms
235.1422 +-- (destroyed on exit). */
235.1423 +
235.1424 +FORMULA *linear_comb
235.1425 +(     MPL *mpl,
235.1426 +      double a, FORMULA *fx,  /* destroyed */
235.1427 +      double b, FORMULA *fy   /* destroyed */
235.1428 +)
235.1429 +{     FORMULA *form = NULL, *term, *temp;
235.1430 +      double c0 = 0.0;
235.1431 +      for (term = fx; term != NULL; term = term->next)
235.1432 +      {  if (term->var == NULL)
235.1433 +            c0 = fp_add(mpl, c0, fp_mul(mpl, a, term->coef));
235.1434 +         else
235.1435 +            term->var->temp =
235.1436 +               fp_add(mpl, term->var->temp, fp_mul(mpl, a, term->coef));
235.1437 +      }
235.1438 +      for (term = fy; term != NULL; term = term->next)
235.1439 +      {  if (term->var == NULL)
235.1440 +            c0 = fp_add(mpl, c0, fp_mul(mpl, b, term->coef));
235.1441 +         else
235.1442 +            term->var->temp =
235.1443 +               fp_add(mpl, term->var->temp, fp_mul(mpl, b, term->coef));
235.1444 +      }
235.1445 +      for (term = fx; term != NULL; term = term->next)
235.1446 +      {  if (term->var != NULL && term->var->temp != 0.0)
235.1447 +         {  temp = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
235.1448 +            temp->coef = term->var->temp, temp->var = term->var;
235.1449 +            temp->next = form, form = temp;
235.1450 +            term->var->temp = 0.0;
235.1451 +         }
235.1452 +      }
235.1453 +      for (term = fy; term != NULL; term = term->next)
235.1454 +      {  if (term->var != NULL && term->var->temp != 0.0)
235.1455 +         {  temp = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
235.1456 +            temp->coef = term->var->temp, temp->var = term->var;
235.1457 +            temp->next = form, form = temp;
235.1458 +            term->var->temp = 0.0;
235.1459 +         }
235.1460 +      }
235.1461 +      if (c0 != 0.0)
235.1462 +      {  temp = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
235.1463 +         temp->coef = c0, temp->var = NULL;
235.1464 +         temp->next = form, form = temp;
235.1465 +      }
235.1466 +      delete_formula(mpl, fx);
235.1467 +      delete_formula(mpl, fy);
235.1468 +      return form;
235.1469 +}
235.1470 +
235.1471 +/*----------------------------------------------------------------------
235.1472 +-- remove_constant - remove constant term from linear form.
235.1473 +--
235.1474 +-- This routine removes constant term from linear form and stores its
235.1475 +-- value to given location. */
235.1476 +
235.1477 +FORMULA *remove_constant
235.1478 +(     MPL *mpl,
235.1479 +      FORMULA *form,          /* destroyed */
235.1480 +      double *coef            /* modified */
235.1481 +)
235.1482 +{     FORMULA *head = NULL, *temp;
235.1483 +      *coef = 0.0;
235.1484 +      while (form != NULL)
235.1485 +      {  temp = form;
235.1486 +         form = form->next;
235.1487 +         if (temp->var == NULL)
235.1488 +         {  /* constant term */
235.1489 +            *coef = fp_add(mpl, *coef, temp->coef);
235.1490 +            dmp_free_atom(mpl->formulae, temp, sizeof(FORMULA));
235.1491 +         }
235.1492 +         else
235.1493 +         {  /* linear term */
235.1494 +            temp->next = head;
235.1495 +            head = temp;
235.1496 +         }
235.1497 +      }
235.1498 +      return head;
235.1499 +}
235.1500 +
235.1501 +/*----------------------------------------------------------------------
235.1502 +-- reduce_terms - reduce identical terms in linear form.
235.1503 +--
235.1504 +-- This routine reduces identical terms in specified linear form. */
235.1505 +
235.1506 +FORMULA *reduce_terms
235.1507 +(     MPL *mpl,
235.1508 +      FORMULA *form           /* destroyed */
235.1509 +)
235.1510 +{     FORMULA *term, *next_term;
235.1511 +      double c0 = 0.0;
235.1512 +      for (term = form; term != NULL; term = term->next)
235.1513 +      {  if (term->var == NULL)
235.1514 +            c0 = fp_add(mpl, c0, term->coef);
235.1515 +         else
235.1516 +            term->var->temp = fp_add(mpl, term->var->temp, term->coef);
235.1517 +      }
235.1518 +      next_term = form, form = NULL;
235.1519 +      for (term = next_term; term != NULL; term = next_term)
235.1520 +      {  next_term = term->next;
235.1521 +         if (term->var == NULL && c0 != 0.0)
235.1522 +         {  term->coef = c0, c0 = 0.0;
235.1523 +            term->next = form, form = term;
235.1524 +         }
235.1525 +         else if (term->var != NULL && term->var->temp != 0.0)
235.1526 +         {  term->coef = term->var->temp, term->var->temp = 0.0;
235.1527 +            term->next = form, form = term;
235.1528 +         }
235.1529 +         else
235.1530 +            dmp_free_atom(mpl->formulae, term, sizeof(FORMULA));
235.1531 +      }
235.1532 +      return form;
235.1533 +}
235.1534 +
235.1535 +/**********************************************************************/
235.1536 +/* * *                   ELEMENTAL CONSTRAINTS                    * * */
235.1537 +/**********************************************************************/
235.1538 +
235.1539 +/* (there are no specific routines for elemental constraints) */
235.1540 +
235.1541 +/**********************************************************************/
235.1542 +/* * *                       GENERIC VALUES                       * * */
235.1543 +/**********************************************************************/
235.1544 +
235.1545 +/*----------------------------------------------------------------------
235.1546 +-- delete_value - delete generic value.
235.1547 +--
235.1548 +-- This routine deletes specified generic value.
235.1549 +--
235.1550 +-- NOTE: The generic value to be deleted must be valid. */
235.1551 +
235.1552 +void delete_value
235.1553 +(     MPL *mpl,
235.1554 +      int type,
235.1555 +      VALUE *value            /* content destroyed */
235.1556 +)
235.1557 +{     xassert(value != NULL);
235.1558 +      switch (type)
235.1559 +      {  case A_NONE:
235.1560 +            value->none = NULL;
235.1561 +            break;
235.1562 +         case A_NUMERIC:
235.1563 +            value->num = 0.0;
235.1564 +            break;
235.1565 +         case A_SYMBOLIC:
235.1566 +            delete_symbol(mpl, value->sym), value->sym = NULL;
235.1567 +            break;
235.1568 +         case A_LOGICAL:
235.1569 +            value->bit = 0;
235.1570 +            break;
235.1571 +         case A_TUPLE:
235.1572 +            delete_tuple(mpl, value->tuple), value->tuple = NULL;
235.1573 +            break;
235.1574 +         case A_ELEMSET:
235.1575 +            delete_elemset(mpl, value->set), value->set = NULL;
235.1576 +            break;
235.1577 +         case A_ELEMVAR:
235.1578 +            value->var = NULL;
235.1579 +            break;
235.1580 +         case A_FORMULA:
235.1581 +            delete_formula(mpl, value->form), value->form = NULL;
235.1582 +            break;
235.1583 +         case A_ELEMCON:
235.1584 +            value->con = NULL;
235.1585 +            break;
235.1586 +         default:
235.1587 +            xassert(type != type);
235.1588 +      }
235.1589 +      return;
235.1590 +}
235.1591 +
235.1592 +/**********************************************************************/
235.1593 +/* * *                SYMBOLICALLY INDEXED ARRAYS                 * * */
235.1594 +/**********************************************************************/
235.1595 +
235.1596 +/*----------------------------------------------------------------------
235.1597 +-- create_array - create array.
235.1598 +--
235.1599 +-- This routine creates an array of specified type and dimension. Being
235.1600 +-- created the array is initially empty.
235.1601 +--
235.1602 +-- The type indicator determines generic values, which can be assigned
235.1603 +-- to the array members:
235.1604 +--
235.1605 +-- A_NONE     - none (members have no assigned values)
235.1606 +-- A_NUMERIC  - floating-point numbers
235.1607 +-- A_SYMBOLIC - symbols
235.1608 +-- A_ELEMSET  - elemental sets
235.1609 +-- A_ELEMVAR  - elemental variables
235.1610 +-- A_ELEMCON  - elemental constraints
235.1611 +--
235.1612 +-- The dimension may be 0, in which case the array consists of the only
235.1613 +-- member (such arrays represent 0-dimensional objects). */
235.1614 +
235.1615 +ARRAY *create_array(MPL *mpl, int type, int dim)
235.1616 +{     ARRAY *array;
235.1617 +      xassert(type == A_NONE || type == A_NUMERIC ||
235.1618 +             type == A_SYMBOLIC || type == A_ELEMSET ||
235.1619 +             type == A_ELEMVAR || type == A_ELEMCON);
235.1620 +      xassert(dim >= 0);
235.1621 +      array = dmp_get_atom(mpl->arrays, sizeof(ARRAY));
235.1622 +      array->type = type;
235.1623 +      array->dim = dim;
235.1624 +      array->size = 0;
235.1625 +      array->head = NULL;
235.1626 +      array->tail = NULL;
235.1627 +      array->tree = NULL;
235.1628 +      array->prev = NULL;
235.1629 +      array->next = mpl->a_list;
235.1630 +      /* include the array in the global array list */
235.1631 +      if (array->next != NULL) array->next->prev = array;
235.1632 +      mpl->a_list = array;
235.1633 +      return array;
235.1634 +}
235.1635 +
235.1636 +/*----------------------------------------------------------------------
235.1637 +-- find_member - find array member with given n-tuple.
235.1638 +--
235.1639 +-- This routine finds an array member, which has given n-tuple. If the
235.1640 +-- array is short, the linear search is used. Otherwise the routine
235.1641 +-- autimatically creates the search tree (i.e. the array index) to find
235.1642 +-- members for logarithmic time. */
235.1643 +
235.1644 +static int compare_member_tuples(void *info, const void *key1,
235.1645 +      const void *key2)
235.1646 +{     /* this is an auxiliary routine used to compare keys, which are
235.1647 +         n-tuples assigned to array members */
235.1648 +      return compare_tuples((MPL *)info, (TUPLE *)key1, (TUPLE *)key2);
235.1649 +}
235.1650 +
235.1651 +MEMBER *find_member
235.1652 +(     MPL *mpl,
235.1653 +      ARRAY *array,           /* not changed */
235.1654 +      TUPLE *tuple            /* not changed */
235.1655 +)
235.1656 +{     MEMBER *memb;
235.1657 +      xassert(array != NULL);
235.1658 +      /* the n-tuple must have the same dimension as the array */
235.1659 +      xassert(tuple_dimen(mpl, tuple) == array->dim);
235.1660 +      /* if the array is large enough, create the search tree and index
235.1661 +         all existing members of the array */
235.1662 +      if (array->size > 30 && array->tree == NULL)
235.1663 +      {  array->tree = avl_create_tree(compare_member_tuples, mpl);
235.1664 +         for (memb = array->head; memb != NULL; memb = memb->next)
235.1665 +avl_set_node_link(avl_insert_node(array->tree, memb->tuple),
235.1666 +               (void *)memb);
235.1667 +      }
235.1668 +      /* find a member, which has the given tuple */
235.1669 +      if (array->tree == NULL)
235.1670 +      {  /* the search tree doesn't exist; use the linear search */
235.1671 +         for (memb = array->head; memb != NULL; memb = memb->next)
235.1672 +            if (compare_tuples(mpl, memb->tuple, tuple) == 0) break;
235.1673 +      }
235.1674 +      else
235.1675 +      {  /* the search tree exists; use the binary search */
235.1676 +         AVLNODE *node;
235.1677 +         node = avl_find_node(array->tree, tuple);
235.1678 +memb = (MEMBER *)(node == NULL ? NULL : avl_get_node_link(node));
235.1679 +      }
235.1680 +      return memb;
235.1681 +}
235.1682 +
235.1683 +/*----------------------------------------------------------------------
235.1684 +-- add_member - add new member to array.
235.1685 +--
235.1686 +-- This routine creates a new member with given n-tuple and adds it to
235.1687 +-- specified array.
235.1688 +--
235.1689 +-- For the sake of efficiency this routine doesn't check whether the
235.1690 +-- array already contains a member with the given n-tuple or not. Thus,
235.1691 +-- if necessary, the calling program should use the routine find_member
235.1692 +-- in order to be sure that the array contains no member with the same
235.1693 +-- n-tuple, because members with duplicate n-tuples are not allowed.
235.1694 +--
235.1695 +-- This routine assigns no generic value to the new member, because the
235.1696 +-- calling program must do that. */
235.1697 +
235.1698 +MEMBER *add_member
235.1699 +(     MPL *mpl,
235.1700 +      ARRAY *array,           /* modified */
235.1701 +      TUPLE *tuple            /* destroyed */
235.1702 +)
235.1703 +{     MEMBER *memb;
235.1704 +      xassert(array != NULL);
235.1705 +      /* the n-tuple must have the same dimension as the array */
235.1706 +      xassert(tuple_dimen(mpl, tuple) == array->dim);
235.1707 +      /* create new member */
235.1708 +      memb = dmp_get_atom(mpl->members, sizeof(MEMBER));
235.1709 +      memb->tuple = tuple;
235.1710 +      memb->next = NULL;
235.1711 +      memset(&memb->value, '?', sizeof(VALUE));
235.1712 +      /* and append it to the member list */
235.1713 +      array->size++;
235.1714 +      if (array->head == NULL)
235.1715 +         array->head = memb;
235.1716 +      else
235.1717 +         array->tail->next = memb;
235.1718 +      array->tail = memb;
235.1719 +      /* if the search tree exists, index the new member */
235.1720 +      if (array->tree != NULL)
235.1721 +avl_set_node_link(avl_insert_node(array->tree, memb->tuple),
235.1722 +            (void *)memb);
235.1723 +      return memb;
235.1724 +}
235.1725 +
235.1726 +/*----------------------------------------------------------------------
235.1727 +-- delete_array - delete array.
235.1728 +--
235.1729 +-- This routine deletes specified array.
235.1730 +--
235.1731 +-- Generic values assigned to the array members are not deleted by this
235.1732 +-- routine. The calling program itself must delete all assigned generic
235.1733 +-- values before deleting the array. */
235.1734 +
235.1735 +void delete_array
235.1736 +(     MPL *mpl,
235.1737 +      ARRAY *array            /* destroyed */
235.1738 +)
235.1739 +{     MEMBER *memb;
235.1740 +      xassert(array != NULL);
235.1741 +      /* delete all existing array members */
235.1742 +      while (array->head != NULL)
235.1743 +      {  memb = array->head;
235.1744 +         array->head = memb->next;
235.1745 +         delete_tuple(mpl, memb->tuple);
235.1746 +         dmp_free_atom(mpl->members, memb, sizeof(MEMBER));
235.1747 +      }
235.1748 +      /* if the search tree exists, also delete it */
235.1749 +      if (array->tree != NULL) avl_delete_tree(array->tree);
235.1750 +      /* remove the array from the global array list */
235.1751 +      if (array->prev == NULL)
235.1752 +         mpl->a_list = array->next;
235.1753 +      else
235.1754 +         array->prev->next = array->next;
235.1755 +      if (array->next == NULL)
235.1756 +         ;
235.1757 +      else
235.1758 +         array->next->prev = array->prev;
235.1759 +      /* delete the array descriptor */
235.1760 +      dmp_free_atom(mpl->arrays, array, sizeof(ARRAY));
235.1761 +      return;
235.1762 +}
235.1763 +
235.1764 +/**********************************************************************/
235.1765 +/* * *                 DOMAINS AND DUMMY INDICES                  * * */
235.1766 +/**********************************************************************/
235.1767 +
235.1768 +/*----------------------------------------------------------------------
235.1769 +-- assign_dummy_index - assign new value to dummy index.
235.1770 +--
235.1771 +-- This routine assigns new value to specified dummy index and, that is
235.1772 +-- important, invalidates all temporary resultant values, which depends
235.1773 +-- on that dummy index. */
235.1774 +
235.1775 +void assign_dummy_index
235.1776 +(     MPL *mpl,
235.1777 +      DOMAIN_SLOT *slot,      /* modified */
235.1778 +      SYMBOL *value           /* not changed */
235.1779 +)
235.1780 +{     CODE *leaf, *code;
235.1781 +      xassert(slot != NULL);
235.1782 +      xassert(value != NULL);
235.1783 +      /* delete the current value assigned to the dummy index */
235.1784 +      if (slot->value != NULL)
235.1785 +      {  /* if the current value and the new one are identical, actual
235.1786 +            assignment is not needed */
235.1787 +         if (compare_symbols(mpl, slot->value, value) == 0) goto done;
235.1788 +         /* delete a symbol, which is the current value */
235.1789 +         delete_symbol(mpl, slot->value), slot->value = NULL;
235.1790 +      }
235.1791 +      /* now walk through all the pseudo-codes with op = O_INDEX, which
235.1792 +         refer to the dummy index to be changed (these pseudo-codes are
235.1793 +         leaves in the forest of *all* expressions in the database) */
235.1794 +      for (leaf = slot->list; leaf != NULL; leaf = leaf->arg.index.
235.1795 +         next)
235.1796 +      {  xassert(leaf->op == O_INDEX);
235.1797 +         /* invalidate all resultant values, which depend on the dummy
235.1798 +            index, walking from the current leaf toward the root of the
235.1799 +            corresponding expression tree */
235.1800 +         for (code = leaf; code != NULL; code = code->up)
235.1801 +         {  if (code->valid)
235.1802 +            {  /* invalidate and delete resultant value */
235.1803 +               code->valid = 0;
235.1804 +               delete_value(mpl, code->type, &code->value);
235.1805 +            }
235.1806 +         }
235.1807 +      }
235.1808 +      /* assign new value to the dummy index */
235.1809 +      slot->value = copy_symbol(mpl, value);
235.1810 +done: return;
235.1811 +}
235.1812 +
235.1813 +/*----------------------------------------------------------------------
235.1814 +-- update_dummy_indices - update current values of dummy indices.
235.1815 +--
235.1816 +-- This routine assigns components of "backup" n-tuple to dummy indices
235.1817 +-- of specified domain block. If no "backup" n-tuple is defined for the
235.1818 +-- domain block, values of the dummy indices remain untouched. */
235.1819 +
235.1820 +void update_dummy_indices
235.1821 +(     MPL *mpl,
235.1822 +      DOMAIN_BLOCK *block     /* not changed */
235.1823 +)
235.1824 +{     DOMAIN_SLOT *slot;
235.1825 +      TUPLE *temp;
235.1826 +      if (block->backup != NULL)
235.1827 +      {  for (slot = block->list, temp = block->backup; slot != NULL;
235.1828 +            slot = slot->next, temp = temp->next)
235.1829 +         {  xassert(temp != NULL);
235.1830 +            xassert(temp->sym != NULL);
235.1831 +            assign_dummy_index(mpl, slot, temp->sym);
235.1832 +         }
235.1833 +      }
235.1834 +      return;
235.1835 +}
235.1836 +
235.1837 +/*----------------------------------------------------------------------
235.1838 +-- enter_domain_block - enter domain block.
235.1839 +--
235.1840 +-- Let specified domain block have the form:
235.1841 +--
235.1842 +--    { ..., (j1, j2, ..., jn) in J, ... }
235.1843 +--
235.1844 +-- where j1, j2, ..., jn are dummy indices, J is a basic set.
235.1845 +--
235.1846 +-- This routine does the following:
235.1847 +--
235.1848 +-- 1. Checks if the given n-tuple is a member of the basic set J. Note
235.1849 +--    that J being *out of the scope* of the domain block cannot depend
235.1850 +--    on the dummy indices in the same and inner domain blocks, so it
235.1851 +--    can be computed before the dummy indices are assigned new values.
235.1852 +--    If this check fails, the routine returns with non-zero code.
235.1853 +--
235.1854 +-- 2. Saves current values of the dummy indices j1, j2, ..., jn.
235.1855 +--
235.1856 +-- 3. Assigns new values, which are components of the given n-tuple, to
235.1857 +--    the dummy indices j1, j2, ..., jn. If dimension of the n-tuple is
235.1858 +--    larger than n, its extra components n+1, n+2, ... are not used.
235.1859 +--
235.1860 +-- 4. Calls the formal routine func which either enters the next domain
235.1861 +--    block or evaluates some code within the domain scope.
235.1862 +--
235.1863 +-- 5. Restores former values of the dummy indices j1, j2, ..., jn.
235.1864 +--
235.1865 +-- Since current values assigned to the dummy indices on entry to this
235.1866 +-- routine are restored on exit, the formal routine func is allowed to
235.1867 +-- call this routine recursively. */
235.1868 +
235.1869 +int enter_domain_block
235.1870 +(     MPL *mpl,
235.1871 +      DOMAIN_BLOCK *block,    /* not changed */
235.1872 +      TUPLE *tuple,           /* not changed */
235.1873 +      void *info, void (*func)(MPL *mpl, void *info)
235.1874 +)
235.1875 +{     TUPLE *backup;
235.1876 +      int ret = 0;
235.1877 +      /* check if the given n-tuple is a member of the basic set */
235.1878 +      xassert(block->code != NULL);
235.1879 +      if (!is_member(mpl, block->code, tuple))
235.1880 +      {  ret = 1;
235.1881 +         goto done;
235.1882 +      }
235.1883 +      /* save reference to "backup" n-tuple, which was used to assign
235.1884 +         current values of the dummy indices (it is sufficient to save
235.1885 +         reference, not value, because that n-tuple is defined in some
235.1886 +         outer level of recursion and therefore cannot be changed on
235.1887 +         this and deeper recursive calls) */
235.1888 +      backup = block->backup;
235.1889 +      /* set up new "backup" n-tuple, which defines new values of the
235.1890 +         dummy indices */
235.1891 +      block->backup = tuple;
235.1892 +      /* assign new values to the dummy indices */
235.1893 +      update_dummy_indices(mpl, block);
235.1894 +      /* call the formal routine that does the rest part of the job */
235.1895 +      func(mpl, info);
235.1896 +      /* restore reference to the former "backup" n-tuple */
235.1897 +      block->backup = backup;
235.1898 +      /* restore former values of the dummy indices; note that if the
235.1899 +         domain block just escaped has no other active instances which
235.1900 +         may exist due to recursion (it is indicated by a null pointer
235.1901 +         to the former n-tuple), former values of the dummy indices are
235.1902 +         undefined; therefore in this case the routine keeps currently
235.1903 +         assigned values of the dummy indices that involves keeping all
235.1904 +         dependent temporary results and thereby, if this domain block
235.1905 +         is not used recursively, allows improving efficiency */
235.1906 +      update_dummy_indices(mpl, block);
235.1907 +done: return ret;
235.1908 +}
235.1909 +
235.1910 +/*----------------------------------------------------------------------
235.1911 +-- eval_within_domain - perform evaluation within domain scope.
235.1912 +--
235.1913 +-- This routine assigns new values (symbols) to all dummy indices of
235.1914 +-- specified domain and calls the formal routine func, which is used to
235.1915 +-- evaluate some code in the domain scope. Each free dummy index in the
235.1916 +-- domain is assigned a value specified in the corresponding component
235.1917 +-- of given n-tuple. Non-free dummy indices are assigned values, which
235.1918 +-- are computed by this routine.
235.1919 +--
235.1920 +-- Number of components in the given n-tuple must be the same as number
235.1921 +-- of free indices in the domain.
235.1922 +--
235.1923 +-- If the given n-tuple is not a member of the domain set, the routine
235.1924 +-- func is not called, and non-zero code is returned.
235.1925 +--
235.1926 +-- For the sake of convenience it is allowed to specify domain as NULL
235.1927 +-- (then n-tuple also must be 0-tuple, i.e. empty), in which case this
235.1928 +-- routine just calls the routine func and returns zero.
235.1929 +--
235.1930 +-- This routine allows recursive calls from the routine func providing
235.1931 +-- correct values of dummy indices for each instance.
235.1932 +--
235.1933 +-- NOTE: The n-tuple passed to this routine must not be changed by any
235.1934 +--       other routines called from the formal routine func until this
235.1935 +--       routine has returned. */
235.1936 +
235.1937 +struct eval_domain_info
235.1938 +{     /* working info used by the routine eval_within_domain */
235.1939 +      DOMAIN *domain;
235.1940 +      /* domain, which has to be entered */
235.1941 +      DOMAIN_BLOCK *block;
235.1942 +      /* domain block, which is currently processed */
235.1943 +      TUPLE *tuple;
235.1944 +      /* tail of original n-tuple, whose components have to be assigned
235.1945 +         to free dummy indices in the current domain block */
235.1946 +      void *info;
235.1947 +      /* transit pointer passed to the formal routine func */
235.1948 +      void (*func)(MPL *mpl, void *info);
235.1949 +      /* routine, which has to be executed in the domain scope */
235.1950 +      int failure;
235.1951 +      /* this flag indicates that given n-tuple is not a member of the
235.1952 +         domain set */
235.1953 +};
235.1954 +
235.1955 +static void eval_domain_func(MPL *mpl, void *_my_info)
235.1956 +{     /* this routine recursively enters into the domain scope and then
235.1957 +         calls the routine func */
235.1958 +      struct eval_domain_info *my_info = _my_info;
235.1959 +      if (my_info->block != NULL)
235.1960 +      {  /* the current domain block to be entered exists */
235.1961 +         DOMAIN_BLOCK *block;
235.1962 +         DOMAIN_SLOT *slot;
235.1963 +         TUPLE *tuple = NULL, *temp = NULL;
235.1964 +         /* save pointer to the current domain block */
235.1965 +         block = my_info->block;
235.1966 +         /* and get ready to enter the next block (if it exists) */
235.1967 +         my_info->block = block->next;
235.1968 +         /* construct temporary n-tuple, whose components correspond to
235.1969 +            dummy indices (slots) of the current domain; components of
235.1970 +            the temporary n-tuple that correspond to free dummy indices
235.1971 +            are assigned references (not values!) to symbols specified
235.1972 +            in the corresponding components of the given n-tuple, while
235.1973 +            other components that correspond to non-free dummy indices
235.1974 +            are assigned symbolic values computed here */
235.1975 +         for (slot = block->list; slot != NULL; slot = slot->next)
235.1976 +         {  /* create component that corresponds to the current slot */
235.1977 +            if (tuple == NULL)
235.1978 +               tuple = temp = dmp_get_atom(mpl->tuples, sizeof(TUPLE));
235.1979 +            else
235.1980 +temp = (temp->next = dmp_get_atom(mpl->tuples, sizeof(TUPLE)));
235.1981 +            if (slot->code == NULL)
235.1982 +            {  /* dummy index is free; take reference to symbol, which
235.1983 +                  is specified in the corresponding component of given
235.1984 +                  n-tuple */
235.1985 +               xassert(my_info->tuple != NULL);
235.1986 +               temp->sym = my_info->tuple->sym;
235.1987 +               xassert(temp->sym != NULL);
235.1988 +               my_info->tuple = my_info->tuple->next;
235.1989 +            }
235.1990 +            else
235.1991 +            {  /* dummy index is non-free; compute symbolic value to be
235.1992 +                  temporarily assigned to the dummy index */
235.1993 +               temp->sym = eval_symbolic(mpl, slot->code);
235.1994 +            }
235.1995 +         }
235.1996 +         temp->next = NULL;
235.1997 +         /* enter the current domain block */
235.1998 +         if (enter_domain_block(mpl, block, tuple, my_info,
235.1999 +               eval_domain_func)) my_info->failure = 1;
235.2000 +         /* delete temporary n-tuple as well as symbols that correspond
235.2001 +            to non-free dummy indices (they were computed here) */
235.2002 +         for (slot = block->list; slot != NULL; slot = slot->next)
235.2003 +         {  xassert(tuple != NULL);
235.2004 +            temp = tuple;
235.2005 +            tuple = tuple->next;
235.2006 +            if (slot->code != NULL)
235.2007 +            {  /* dummy index is non-free; delete symbolic value */
235.2008 +               delete_symbol(mpl, temp->sym);
235.2009 +            }
235.2010 +            /* delete component that corresponds to the current slot */
235.2011 +            dmp_free_atom(mpl->tuples, temp, sizeof(TUPLE));
235.2012 +         }
235.2013 +      }
235.2014 +      else
235.2015 +      {  /* there are no more domain blocks, i.e. we have reached the
235.2016 +            domain scope */
235.2017 +         xassert(my_info->tuple == NULL);
235.2018 +         /* check optional predicate specified for the domain */
235.2019 +         if (my_info->domain->code != NULL && !eval_logical(mpl,
235.2020 +            my_info->domain->code))
235.2021 +         {  /* the predicate is false */
235.2022 +            my_info->failure = 2;
235.2023 +         }
235.2024 +         else
235.2025 +         {  /* the predicate is true; do the job */
235.2026 +            my_info->func(mpl, my_info->info);
235.2027 +         }
235.2028 +      }
235.2029 +      return;
235.2030 +}
235.2031 +
235.2032 +int eval_within_domain
235.2033 +(     MPL *mpl,
235.2034 +      DOMAIN *domain,         /* not changed */
235.2035 +      TUPLE *tuple,           /* not changed */
235.2036 +      void *info, void (*func)(MPL *mpl, void *info)
235.2037 +)
235.2038 +{     /* this routine performs evaluation within domain scope */
235.2039 +      struct eval_domain_info _my_info, *my_info = &_my_info;
235.2040 +      if (domain == NULL)
235.2041 +      {  xassert(tuple == NULL);
235.2042 +         func(mpl, info);
235.2043 +         my_info->failure = 0;
235.2044 +      }
235.2045 +      else
235.2046 +      {  xassert(tuple != NULL);
235.2047 +         my_info->domain = domain;
235.2048 +         my_info->block = domain->list;
235.2049 +         my_info->tuple = tuple;
235.2050 +         my_info->info = info;
235.2051 +         my_info->func = func;
235.2052 +         my_info->failure = 0;
235.2053 +         /* enter the very first domain block */
235.2054 +         eval_domain_func(mpl, my_info);
235.2055 +      }
235.2056 +      return my_info->failure;
235.2057 +}
235.2058 +
235.2059 +/*----------------------------------------------------------------------
235.2060 +-- loop_within_domain - perform iterations within domain scope.
235.2061 +--
235.2062 +-- This routine iteratively assigns new values (symbols) to the dummy
235.2063 +-- indices of specified domain by enumerating all n-tuples, which are
235.2064 +-- members of the domain set, and for every n-tuple it calls the formal
235.2065 +-- routine func to evaluate some code within the domain scope.
235.2066 +--
235.2067 +-- If the routine func returns non-zero, enumeration within the domain
235.2068 +-- is prematurely terminated.
235.2069 +--
235.2070 +-- For the sake of convenience it is allowed to specify domain as NULL,
235.2071 +-- in which case this routine just calls the routine func only once and
235.2072 +-- returns zero.
235.2073 +--
235.2074 +-- This routine allows recursive calls from the routine func providing
235.2075 +-- correct values of dummy indices for each instance. */
235.2076 +
235.2077 +struct loop_domain_info
235.2078 +{     /* working info used by the routine loop_within_domain */
235.2079 +      DOMAIN *domain;
235.2080 +      /* domain, which has to be entered */
235.2081 +      DOMAIN_BLOCK *block;
235.2082 +      /* domain block, which is currently processed */
235.2083 +      int looping;
235.2084 +      /* clearing this flag leads to terminating enumeration */
235.2085 +      void *info;
235.2086 +      /* transit pointer passed to the formal routine func */
235.2087 +      int (*func)(MPL *mpl, void *info);
235.2088 +      /* routine, which needs to be executed in the domain scope */
235.2089 +};
235.2090 +
235.2091 +static void loop_domain_func(MPL *mpl, void *_my_info)
235.2092 +{     /* this routine enumerates all n-tuples in the basic set of the
235.2093 +         current domain block, enters recursively into the domain scope
235.2094 +         for every n-tuple, and then calls the routine func */
235.2095 +      struct loop_domain_info *my_info = _my_info;
235.2096 +      if (my_info->block != NULL)
235.2097 +      {  /* the current domain block to be entered exists */
235.2098 +         DOMAIN_BLOCK *block;
235.2099 +         DOMAIN_SLOT *slot;
235.2100 +         TUPLE *bound;
235.2101 +         /* save pointer to the current domain block */
235.2102 +         block = my_info->block;
235.2103 +         /* and get ready to enter the next block (if it exists) */
235.2104 +         my_info->block = block->next;
235.2105 +         /* compute symbolic values, at which non-free dummy indices of
235.2106 +            the current domain block are bound; since that values don't
235.2107 +            depend on free dummy indices of the current block, they can
235.2108 +            be computed once out of the enumeration loop */
235.2109 +         bound = create_tuple(mpl);
235.2110 +         for (slot = block->list; slot != NULL; slot = slot->next)
235.2111 +         {  if (slot->code != NULL)
235.2112 +               bound = expand_tuple(mpl, bound, eval_symbolic(mpl,
235.2113 +                  slot->code));
235.2114 +         }
235.2115 +         /* start enumeration */
235.2116 +         xassert(block->code != NULL);
235.2117 +         if (block->code->op == O_DOTS)
235.2118 +         {  /* the basic set is "arithmetic", in which case it doesn't
235.2119 +               need to be computed explicitly */
235.2120 +            TUPLE *tuple;
235.2121 +            int n, j;
235.2122 +            double t0, tf, dt;
235.2123 +            /* compute "parameters" of the basic set */
235.2124 +            t0 = eval_numeric(mpl, block->code->arg.arg.x);
235.2125 +            tf = eval_numeric(mpl, block->code->arg.arg.y);
235.2126 +            if (block->code->arg.arg.z == NULL)
235.2127 +               dt = 1.0;
235.2128 +            else
235.2129 +               dt = eval_numeric(mpl, block->code->arg.arg.z);
235.2130 +            /* determine cardinality of the basic set */
235.2131 +            n = arelset_size(mpl, t0, tf, dt);
235.2132 +            /* create dummy 1-tuple for members of the basic set */
235.2133 +            tuple = expand_tuple(mpl, create_tuple(mpl),
235.2134 +               create_symbol_num(mpl, 0.0));
235.2135 +            /* in case of "arithmetic" set there is exactly one dummy
235.2136 +               index, which cannot be non-free */
235.2137 +            xassert(bound == NULL);
235.2138 +            /* walk through 1-tuples of the basic set */
235.2139 +            for (j = 1; j <= n && my_info->looping; j++)
235.2140 +            {  /* construct dummy 1-tuple for the current member */
235.2141 +               tuple->sym->num = arelset_member(mpl, t0, tf, dt, j);
235.2142 +               /* enter the current domain block */
235.2143 +               enter_domain_block(mpl, block, tuple, my_info,
235.2144 +                  loop_domain_func);
235.2145 +            }
235.2146 +            /* delete dummy 1-tuple */
235.2147 +            delete_tuple(mpl, tuple);
235.2148 +         }
235.2149 +         else
235.2150 +         {  /* the basic set is of general kind, in which case it needs
235.2151 +               to be explicitly computed */
235.2152 +            ELEMSET *set;
235.2153 +            MEMBER *memb;
235.2154 +            TUPLE *temp1, *temp2;
235.2155 +            /* compute the basic set */
235.2156 +            set = eval_elemset(mpl, block->code);
235.2157 +            /* walk through all n-tuples of the basic set */
235.2158 +            for (memb = set->head; memb != NULL && my_info->looping;
235.2159 +               memb = memb->next)
235.2160 +            {  /* all components of the current n-tuple that correspond
235.2161 +                  to non-free dummy indices must be feasible; otherwise
235.2162 +                  the n-tuple is not in the basic set */
235.2163 +               temp1 = memb->tuple;
235.2164 +               temp2 = bound;
235.2165 +               for (slot = block->list; slot != NULL; slot = slot->next)
235.2166 +               {  xassert(temp1 != NULL);
235.2167 +                  if (slot->code != NULL)
235.2168 +                  {  /* non-free dummy index */
235.2169 +                     xassert(temp2 != NULL);
235.2170 +                     if (compare_symbols(mpl, temp1->sym, temp2->sym)
235.2171 +                        != 0)
235.2172 +                     {  /* the n-tuple is not in the basic set */
235.2173 +                        goto skip;
235.2174 +                     }
235.2175 +                     temp2 = temp2->next;
235.2176 +                  }
235.2177 +                  temp1 = temp1->next;
235.2178 +               }
235.2179 +               xassert(temp1 == NULL);
235.2180 +               xassert(temp2 == NULL);
235.2181 +               /* enter the current domain block */
235.2182 +               enter_domain_block(mpl, block, memb->tuple, my_info,
235.2183 +                  loop_domain_func);
235.2184 +skip:          ;
235.2185 +            }
235.2186 +            /* delete the basic set */
235.2187 +            delete_elemset(mpl, set);
235.2188 +         }
235.2189 +         /* delete symbolic values binding non-free dummy indices */
235.2190 +         delete_tuple(mpl, bound);
235.2191 +         /* restore pointer to the current domain block */
235.2192 +         my_info->block = block;
235.2193 +      }
235.2194 +      else
235.2195 +      {  /* there are no more domain blocks, i.e. we have reached the
235.2196 +            domain scope */
235.2197 +         /* check optional predicate specified for the domain */
235.2198 +         if (my_info->domain->code != NULL && !eval_logical(mpl,
235.2199 +            my_info->domain->code))
235.2200 +         {  /* the predicate is false */
235.2201 +            /* nop */;
235.2202 +         }
235.2203 +         else
235.2204 +         {  /* the predicate is true; do the job */
235.2205 +            my_info->looping = !my_info->func(mpl, my_info->info);
235.2206 +         }
235.2207 +      }
235.2208 +      return;
235.2209 +}
235.2210 +
235.2211 +void loop_within_domain
235.2212 +(     MPL *mpl,
235.2213 +      DOMAIN *domain,         /* not changed */
235.2214 +      void *info, int (*func)(MPL *mpl, void *info)
235.2215 +)
235.2216 +{     /* this routine performs iterations within domain scope */
235.2217 +      struct loop_domain_info _my_info, *my_info = &_my_info;
235.2218 +      if (domain == NULL)
235.2219 +         func(mpl, info);
235.2220 +      else
235.2221 +      {  my_info->domain = domain;
235.2222 +         my_info->block = domain->list;
235.2223 +         my_info->looping = 1;
235.2224 +         my_info->info = info;
235.2225 +         my_info->func = func;
235.2226 +         /* enter the very first domain block */
235.2227 +         loop_domain_func(mpl, my_info);
235.2228 +      }
235.2229 +      return;
235.2230 +}
235.2231 +
235.2232 +/*----------------------------------------------------------------------
235.2233 +-- out_of_domain - raise domain exception.
235.2234 +--
235.2235 +-- This routine is called when a reference is made to a member of some
235.2236 +-- model object, but its n-tuple is out of the object domain. */
235.2237 +
235.2238 +void out_of_domain
235.2239 +(     MPL *mpl,
235.2240 +      char *name,             /* not changed */
235.2241 +      TUPLE *tuple            /* not changed */
235.2242 +)
235.2243 +{     xassert(name != NULL);
235.2244 +      xassert(tuple != NULL);
235.2245 +      error(mpl, "%s%s out of domain", name, format_tuple(mpl, '[',
235.2246 +         tuple));
235.2247 +      /* no return */
235.2248 +}
235.2249 +
235.2250 +/*----------------------------------------------------------------------
235.2251 +-- get_domain_tuple - obtain current n-tuple from domain.
235.2252 +--
235.2253 +-- This routine constructs n-tuple, whose components are current values
235.2254 +-- assigned to *free* dummy indices of specified domain.
235.2255 +--
235.2256 +-- For the sake of convenience it is allowed to specify domain as NULL,
235.2257 +-- in which case this routine returns 0-tuple.
235.2258 +--
235.2259 +-- NOTE: This routine must not be called out of domain scope. */
235.2260 +
235.2261 +TUPLE *get_domain_tuple
235.2262 +(     MPL *mpl,
235.2263 +      DOMAIN *domain          /* not changed */
235.2264 +)
235.2265 +{     DOMAIN_BLOCK *block;
235.2266 +      DOMAIN_SLOT *slot;
235.2267 +      TUPLE *tuple;
235.2268 +      tuple = create_tuple(mpl);
235.2269 +      if (domain != NULL)
235.2270 +      {  for (block = domain->list; block != NULL; block = block->next)
235.2271 +         {  for (slot = block->list; slot != NULL; slot = slot->next)
235.2272 +            {  if (slot->code == NULL)
235.2273 +               {  xassert(slot->value != NULL);
235.2274 +                  tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
235.2275 +                     slot->value));
235.2276 +               }
235.2277 +            }
235.2278 +         }
235.2279 +      }
235.2280 +      return tuple;
235.2281 +}
235.2282 +
235.2283 +/*----------------------------------------------------------------------
235.2284 +-- clean_domain - clean domain.
235.2285 +--
235.2286 +-- This routine cleans specified domain that assumes deleting all stuff
235.2287 +-- dynamically allocated during the generation phase. */
235.2288 +
235.2289 +void clean_domain(MPL *mpl, DOMAIN *domain)
235.2290 +{     DOMAIN_BLOCK *block;
235.2291 +      DOMAIN_SLOT *slot;
235.2292 +      /* if no domain is specified, do nothing */
235.2293 +      if (domain == NULL) goto done;
235.2294 +      /* clean all domain blocks */
235.2295 +      for (block = domain->list; block != NULL; block = block->next)
235.2296 +      {  /* clean all domain slots */
235.2297 +         for (slot = block->list; slot != NULL; slot = slot->next)
235.2298 +         {  /* clean pseudo-code for computing bound value */
235.2299 +            clean_code(mpl, slot->code);
235.2300 +            /* delete symbolic value assigned to dummy index */
235.2301 +            if (slot->value != NULL)
235.2302 +               delete_symbol(mpl, slot->value), slot->value = NULL;
235.2303 +         }
235.2304 +         /* clean pseudo-code for computing basic set */
235.2305 +         clean_code(mpl, block->code);
235.2306 +      }
235.2307 +      /* clean pseudo-code for computing domain predicate */
235.2308 +      clean_code(mpl, domain->code);
235.2309 +done: return;
235.2310 +}
235.2311 +
235.2312 +/**********************************************************************/
235.2313 +/* * *                         MODEL SETS                         * * */
235.2314 +/**********************************************************************/
235.2315 +
235.2316 +/*----------------------------------------------------------------------
235.2317 +-- check_elem_set - check elemental set assigned to set member.
235.2318 +--
235.2319 +-- This routine checks if given elemental set being assigned to member
235.2320 +-- of specified model set satisfies to all restrictions.
235.2321 +--
235.2322 +-- NOTE: This routine must not be called out of domain scope. */
235.2323 +
235.2324 +void check_elem_set
235.2325 +(     MPL *mpl,
235.2326 +      SET *set,               /* not changed */
235.2327 +      TUPLE *tuple,           /* not changed */
235.2328 +      ELEMSET *refer          /* not changed */
235.2329 +)
235.2330 +{     WITHIN *within;
235.2331 +      MEMBER *memb;
235.2332 +      int eqno;
235.2333 +      /* elemental set must be within all specified supersets */
235.2334 +      for (within = set->within, eqno = 1; within != NULL; within =
235.2335 +         within->next, eqno++)
235.2336 +      {  xassert(within->code != NULL);
235.2337 +         for (memb = refer->head; memb != NULL; memb = memb->next)
235.2338 +         {  if (!is_member(mpl, within->code, memb->tuple))
235.2339 +            {  char buf[255+1];
235.2340 +               strcpy(buf, format_tuple(mpl, '(', memb->tuple));
235.2341 +               xassert(strlen(buf) < sizeof(buf));
235.2342 +               error(mpl, "%s%s contains %s which not within specified "
235.2343 +                  "set; see (%d)", set->name, format_tuple(mpl, '[',
235.2344 +                     tuple), buf, eqno);
235.2345 +            }
235.2346 +         }
235.2347 +      }
235.2348 +      return;
235.2349 +}
235.2350 +
235.2351 +/*----------------------------------------------------------------------
235.2352 +-- take_member_set - obtain elemental set assigned to set member.
235.2353 +--
235.2354 +-- This routine obtains a reference to elemental set assigned to given
235.2355 +-- member of specified model set and returns it on exit.
235.2356 +--
235.2357 +-- NOTE: This routine must not be called out of domain scope. */
235.2358 +
235.2359 +ELEMSET *take_member_set      /* returns reference, not value */
235.2360 +(     MPL *mpl,
235.2361 +      SET *set,               /* not changed */
235.2362 +      TUPLE *tuple            /* not changed */
235.2363 +)
235.2364 +{     MEMBER *memb;
235.2365 +      ELEMSET *refer;
235.2366 +      /* find member in the set array */
235.2367 +      memb = find_member(mpl, set->array, tuple);
235.2368 +      if (memb != NULL)
235.2369 +      {  /* member exists, so just take the reference */
235.2370 +         refer = memb->value.set;
235.2371 +      }
235.2372 +      else if (set->assign != NULL)
235.2373 +      {  /* compute value using assignment expression */
235.2374 +         refer = eval_elemset(mpl, set->assign);
235.2375 +add:     /* check that the elemental set satisfies to all restrictions,
235.2376 +            assign it to new member, and add the member to the array */
235.2377 +         check_elem_set(mpl, set, tuple, refer);
235.2378 +         memb = add_member(mpl, set->array, copy_tuple(mpl, tuple));
235.2379 +         memb->value.set = refer;
235.2380 +      }
235.2381 +      else if (set->option != NULL)
235.2382 +      {  /* compute default elemental set */
235.2383 +         refer = eval_elemset(mpl, set->option);
235.2384 +         goto add;
235.2385 +      }
235.2386 +      else
235.2387 +      {  /* no value (elemental set) is provided */
235.2388 +         error(mpl, "no value for %s%s", set->name, format_tuple(mpl,
235.2389 +            '[', tuple));
235.2390 +      }
235.2391 +      return refer;
235.2392 +}
235.2393 +
235.2394 +/*----------------------------------------------------------------------
235.2395 +-- eval_member_set - evaluate elemental set assigned to set member.
235.2396 +--
235.2397 +-- This routine evaluates a reference to elemental set assigned to given
235.2398 +-- member of specified model set and returns it on exit. */
235.2399 +
235.2400 +struct eval_set_info
235.2401 +{     /* working info used by the routine eval_member_set */
235.2402 +      SET *set;
235.2403 +      /* model set */
235.2404 +      TUPLE *tuple;
235.2405 +      /* n-tuple, which defines set member */
235.2406 +      MEMBER *memb;
235.2407 +      /* normally this pointer is NULL; the routine uses this pointer
235.2408 +         to check data provided in the data section, in which case it
235.2409 +         points to a member currently checked; this check is performed
235.2410 +         automatically only once when a reference to any member occurs
235.2411 +         for the first time */
235.2412 +      ELEMSET *refer;
235.2413 +      /* evaluated reference to elemental set */
235.2414 +};
235.2415 +
235.2416 +static void eval_set_func(MPL *mpl, void *_info)
235.2417 +{     /* this is auxiliary routine to work within domain scope */
235.2418 +      struct eval_set_info *info = _info;
235.2419 +      if (info->memb != NULL)
235.2420 +      {  /* checking call; check elemental set being assigned */
235.2421 +         check_elem_set(mpl, info->set, info->memb->tuple,
235.2422 +            info->memb->value.set);
235.2423 +      }
235.2424 +      else
235.2425 +      {  /* normal call; evaluate member, which has given n-tuple */
235.2426 +         info->refer = take_member_set(mpl, info->set, info->tuple);
235.2427 +      }
235.2428 +      return;
235.2429 +}
235.2430 +
235.2431 +#if 1 /* 12/XII-2008 */
235.2432 +static void saturate_set(MPL *mpl, SET *set)
235.2433 +{     GADGET *gadget = set->gadget;
235.2434 +      ELEMSET *data;
235.2435 +      MEMBER *elem, *memb;
235.2436 +      TUPLE *tuple, *work[20];
235.2437 +      int i;
235.2438 +      xprintf("Generating %s...\n", set->name);
235.2439 +      eval_whole_set(mpl, gadget->set);
235.2440 +      /* gadget set must have exactly one member */
235.2441 +      xassert(gadget->set->array != NULL);
235.2442 +      xassert(gadget->set->array->head != NULL);
235.2443 +      xassert(gadget->set->array->head == gadget->set->array->tail);
235.2444 +      data = gadget->set->array->head->value.set;
235.2445 +      xassert(data->type == A_NONE);
235.2446 +      xassert(data->dim == gadget->set->dimen);
235.2447 +      /* walk thru all elements of the plain set */
235.2448 +      for (elem = data->head; elem != NULL; elem = elem->next)
235.2449 +      {  /* create a copy of n-tuple */
235.2450 +         tuple = copy_tuple(mpl, elem->tuple);
235.2451 +         /* rearrange component of the n-tuple */
235.2452 +         for (i = 0; i < gadget->set->dimen; i++)
235.2453 +            work[i] = NULL;
235.2454 +         for (i = 0; tuple != NULL; tuple = tuple->next)
235.2455 +            work[gadget->ind[i++]-1] = tuple;
235.2456 +         xassert(i == gadget->set->dimen);
235.2457 +         for (i = 0; i < gadget->set->dimen; i++)
235.2458 +         {  xassert(work[i] != NULL);
235.2459 +            work[i]->next = work[i+1];
235.2460 +         }
235.2461 +         /* construct subscript list from first set->dim components */
235.2462 +         if (set->dim == 0)
235.2463 +            tuple = NULL;
235.2464 +         else
235.2465 +            tuple = work[0], work[set->dim-1]->next = NULL;
235.2466 +         /* find corresponding member of the set to be initialized */
235.2467 +         memb = find_member(mpl, set->array, tuple);
235.2468 +         if (memb == NULL)
235.2469 +         {  /* not found; add new member to the set and assign it empty
235.2470 +               elemental set */
235.2471 +            memb = add_member(mpl, set->array, tuple);
235.2472 +            memb->value.set = create_elemset(mpl, set->dimen);
235.2473 +         }
235.2474 +         else
235.2475 +         {  /* found; free subscript list */
235.2476 +            delete_tuple(mpl, tuple);
235.2477 +         }
235.2478 +         /* construct new n-tuple from rest set->dimen components */
235.2479 +         tuple = work[set->dim];
235.2480 +         xassert(set->dim + set->dimen == gadget->set->dimen);
235.2481 +         work[gadget->set->dimen-1]->next = NULL;
235.2482 +         /* and add it to the elemental set assigned to the member
235.2483 +            (no check for duplicates is needed) */
235.2484 +         add_tuple(mpl, memb->value.set, tuple);
235.2485 +      }
235.2486 +      /* the set has been saturated with data */
235.2487 +      set->data = 1;
235.2488 +      return;
235.2489 +}
235.2490 +#endif
235.2491 +
235.2492 +ELEMSET *eval_member_set      /* returns reference, not value */
235.2493 +(     MPL *mpl,
235.2494 +      SET *set,               /* not changed */
235.2495 +      TUPLE *tuple            /* not changed */
235.2496 +)
235.2497 +{     /* this routine evaluates set member */
235.2498 +      struct eval_set_info _info, *info = &_info;
235.2499 +      xassert(set->dim == tuple_dimen(mpl, tuple));
235.2500 +      info->set = set;
235.2501 +      info->tuple = tuple;
235.2502 +#if 1 /* 12/XII-2008 */
235.2503 +      if (set->gadget != NULL && set->data == 0)
235.2504 +      {  /* initialize the set with data from a plain set */
235.2505 +         saturate_set(mpl, set);
235.2506 +      }
235.2507 +#endif
235.2508 +      if (set->data == 1)
235.2509 +      {  /* check data, which are provided in the data section, but not
235.2510 +            checked yet */
235.2511 +         /* save pointer to the last array member; note that during the
235.2512 +            check new members may be added beyond the last member due to
235.2513 +            references to the same parameter from default expression as
235.2514 +            well as from expressions that define restricting supersets;
235.2515 +            however, values assigned to the new members will be checked
235.2516 +            by other routine, so we don't need to check them here */
235.2517 +         MEMBER *tail = set->array->tail;
235.2518 +         /* change the data status to prevent infinite recursive loop
235.2519 +            due to references to the same set during the check */
235.2520 +         set->data = 2;
235.2521 +         /* check elemental sets assigned to array members in the data
235.2522 +            section until the marked member has been reached */
235.2523 +         for (info->memb = set->array->head; info->memb != NULL;
235.2524 +            info->memb = info->memb->next)
235.2525 +         {  if (eval_within_domain(mpl, set->domain, info->memb->tuple,
235.2526 +               info, eval_set_func))
235.2527 +               out_of_domain(mpl, set->name, info->memb->tuple);
235.2528 +            if (info->memb == tail) break;
235.2529 +         }
235.2530 +         /* the check has been finished */
235.2531 +      }
235.2532 +      /* evaluate member, which has given n-tuple */
235.2533 +      info->memb = NULL;
235.2534 +      if (eval_within_domain(mpl, info->set->domain, info->tuple, info,
235.2535 +         eval_set_func))
235.2536 +      out_of_domain(mpl, set->name, info->tuple);
235.2537 +      /* bring evaluated reference to the calling program */
235.2538 +      return info->refer;
235.2539 +}
235.2540 +
235.2541 +/*----------------------------------------------------------------------
235.2542 +-- eval_whole_set - evaluate model set over entire domain.
235.2543 +--
235.2544 +-- This routine evaluates all members of specified model set over entire
235.2545 +-- domain. */
235.2546 +
235.2547 +static int whole_set_func(MPL *mpl, void *info)
235.2548 +{     /* this is auxiliary routine to work within domain scope */
235.2549 +      SET *set = (SET *)info;
235.2550 +      TUPLE *tuple = get_domain_tuple(mpl, set->domain);
235.2551 +      eval_member_set(mpl, set, tuple);
235.2552 +      delete_tuple(mpl, tuple);
235.2553 +      return 0;
235.2554 +}
235.2555 +
235.2556 +void eval_whole_set(MPL *mpl, SET *set)
235.2557 +{     loop_within_domain(mpl, set->domain, set, whole_set_func);
235.2558 +      return;
235.2559 +}
235.2560 +
235.2561 +/*----------------------------------------------------------------------
235.2562 +-- clean set - clean model set.
235.2563 +--
235.2564 +-- This routine cleans specified model set that assumes deleting all
235.2565 +-- stuff dynamically allocated during the generation phase. */
235.2566 +
235.2567 +void clean_set(MPL *mpl, SET *set)
235.2568 +{     WITHIN *within;
235.2569 +      MEMBER *memb;
235.2570 +      /* clean subscript domain */
235.2571 +      clean_domain(mpl, set->domain);
235.2572 +      /* clean pseudo-code for computing supersets */
235.2573 +      for (within = set->within; within != NULL; within = within->next)
235.2574 +         clean_code(mpl, within->code);
235.2575 +      /* clean pseudo-code for computing assigned value */
235.2576 +      clean_code(mpl, set->assign);
235.2577 +      /* clean pseudo-code for computing default value */
235.2578 +      clean_code(mpl, set->option);
235.2579 +      /* reset data status flag */
235.2580 +      set->data = 0;
235.2581 +      /* delete content array */
235.2582 +      for (memb = set->array->head; memb != NULL; memb = memb->next)
235.2583 +         delete_value(mpl, set->array->type, &memb->value);
235.2584 +      delete_array(mpl, set->array), set->array = NULL;
235.2585 +      return;
235.2586 +}
235.2587 +
235.2588 +/**********************************************************************/
235.2589 +/* * *                      MODEL PARAMETERS                      * * */
235.2590 +/**********************************************************************/
235.2591 +
235.2592 +/*----------------------------------------------------------------------
235.2593 +-- check_value_num - check numeric value assigned to parameter member.
235.2594 +--
235.2595 +-- This routine checks if numeric value being assigned to some member
235.2596 +-- of specified numeric model parameter satisfies to all restrictions.
235.2597 +--
235.2598 +-- NOTE: This routine must not be called out of domain scope. */
235.2599 +
235.2600 +void check_value_num
235.2601 +(     MPL *mpl,
235.2602 +      PARAMETER *par,         /* not changed */
235.2603 +      TUPLE *tuple,           /* not changed */
235.2604 +      double value
235.2605 +)
235.2606 +{     CONDITION *cond;
235.2607 +      WITHIN *in;
235.2608 +      int eqno;
235.2609 +      /* the value must satisfy to the parameter type */
235.2610 +      switch (par->type)
235.2611 +      {  case A_NUMERIC:
235.2612 +            break;
235.2613 +         case A_INTEGER:
235.2614 +            if (value != floor(value))
235.2615 +               error(mpl, "%s%s = %.*g not integer", par->name,
235.2616 +                  format_tuple(mpl, '[', tuple), DBL_DIG, value);
235.2617 +            break;
235.2618 +         case A_BINARY:
235.2619 +            if (!(value == 0.0 || value == 1.0))
235.2620 +               error(mpl, "%s%s = %.*g not binary", par->name,
235.2621 +                  format_tuple(mpl, '[', tuple), DBL_DIG, value);
235.2622 +            break;
235.2623 +         default:
235.2624 +            xassert(par != par);
235.2625 +      }
235.2626 +      /* the value must satisfy to all specified conditions */
235.2627 +      for (cond = par->cond, eqno = 1; cond != NULL; cond = cond->next,
235.2628 +         eqno++)
235.2629 +      {  double bound;
235.2630 +         char *rho;
235.2631 +         xassert(cond->code != NULL);
235.2632 +         bound = eval_numeric(mpl, cond->code);
235.2633 +         switch (cond->rho)
235.2634 +         {  case O_LT:
235.2635 +               if (!(value < bound))
235.2636 +               {  rho = "<";
235.2637 +err:              error(mpl, "%s%s = %.*g not %s %.*g; see (%d)",
235.2638 +                     par->name, format_tuple(mpl, '[', tuple), DBL_DIG,
235.2639 +                     value, rho, DBL_DIG, bound, eqno);
235.2640 +               }
235.2641 +               break;
235.2642 +            case O_LE:
235.2643 +               if (!(value <= bound)) { rho = "<="; goto err; }
235.2644 +               break;
235.2645 +            case O_EQ:
235.2646 +               if (!(value == bound)) { rho = "="; goto err; }
235.2647 +               break;
235.2648 +            case O_GE:
235.2649 +               if (!(value >= bound)) { rho = ">="; goto err; }
235.2650 +               break;
235.2651 +            case O_GT:
235.2652 +               if (!(value > bound)) { rho = ">"; goto err; }
235.2653 +               break;
235.2654 +            case O_NE:
235.2655 +               if (!(value != bound)) { rho = "<>"; goto err; }
235.2656 +               break;
235.2657 +            default:
235.2658 +               xassert(cond != cond);
235.2659 +         }
235.2660 +      }
235.2661 +      /* the value must be in all specified supersets */
235.2662 +      for (in = par->in, eqno = 1; in != NULL; in = in->next, eqno++)
235.2663 +      {  TUPLE *dummy;
235.2664 +         xassert(in->code != NULL);
235.2665 +         xassert(in->code->dim == 1);
235.2666 +         dummy = expand_tuple(mpl, create_tuple(mpl),
235.2667 +            create_symbol_num(mpl, value));
235.2668 +         if (!is_member(mpl, in->code, dummy))
235.2669 +            error(mpl, "%s%s = %.*g not in specified set; see (%d)",
235.2670 +               par->name, format_tuple(mpl, '[', tuple), DBL_DIG,
235.2671 +               value, eqno);
235.2672 +         delete_tuple(mpl, dummy);
235.2673 +      }
235.2674 +      return;
235.2675 +}
235.2676 +
235.2677 +/*----------------------------------------------------------------------
235.2678 +-- take_member_num - obtain num. value assigned to parameter member.
235.2679 +--
235.2680 +-- This routine obtains a numeric value assigned to member of specified
235.2681 +-- numeric model parameter and returns it on exit.
235.2682 +--
235.2683 +-- NOTE: This routine must not be called out of domain scope. */
235.2684 +
235.2685 +double take_member_num
235.2686 +(     MPL *mpl,
235.2687 +      PARAMETER *par,         /* not changed */
235.2688 +      TUPLE *tuple            /* not changed */
235.2689 +)
235.2690 +{     MEMBER *memb;
235.2691 +      double value;
235.2692 +      /* find member in the parameter array */
235.2693 +      memb = find_member(mpl, par->array, tuple);
235.2694 +      if (memb != NULL)
235.2695 +      {  /* member exists, so just take its value */
235.2696 +         value = memb->value.num;
235.2697 +      }
235.2698 +      else if (par->assign != NULL)
235.2699 +      {  /* compute value using assignment expression */
235.2700 +         value = eval_numeric(mpl, par->assign);
235.2701 +add:     /* check that the value satisfies to all restrictions, assign
235.2702 +            it to new member, and add the member to the array */
235.2703 +         check_value_num(mpl, par, tuple, value);
235.2704 +         memb = add_member(mpl, par->array, copy_tuple(mpl, tuple));
235.2705 +         memb->value.num = value;
235.2706 +      }
235.2707 +      else if (par->option != NULL)
235.2708 +      {  /* compute default value */
235.2709 +         value = eval_numeric(mpl, par->option);
235.2710 +         goto add;
235.2711 +      }
235.2712 +      else if (par->defval != NULL)
235.2713 +      {  /* take default value provided in the data section */
235.2714 +         if (par->defval->str != NULL)
235.2715 +            error(mpl, "cannot convert %s to floating-point number",
235.2716 +               format_symbol(mpl, par->defval));
235.2717 +         value = par->defval->num;
235.2718 +         goto add;
235.2719 +      }
235.2720 +      else
235.2721 +      {  /* no value is provided */
235.2722 +         error(mpl, "no value for %s%s", par->name, format_tuple(mpl,
235.2723 +            '[', tuple));
235.2724 +      }
235.2725 +      return value;
235.2726 +}
235.2727 +
235.2728 +/*----------------------------------------------------------------------
235.2729 +-- eval_member_num - evaluate num. value assigned to parameter member.
235.2730 +--
235.2731 +-- This routine evaluates a numeric value assigned to given member of
235.2732 +-- specified numeric model parameter and returns it on exit. */
235.2733 +
235.2734 +struct eval_num_info
235.2735 +{     /* working info used by the routine eval_member_num */
235.2736 +      PARAMETER *par;
235.2737 +      /* model parameter  */
235.2738 +      TUPLE *tuple;
235.2739 +      /* n-tuple, which defines parameter member */
235.2740 +      MEMBER *memb;
235.2741 +      /* normally this pointer is NULL; the routine uses this pointer
235.2742 +         to check data provided in the data section, in which case it
235.2743 +         points to a member currently checked; this check is performed
235.2744 +         automatically only once when a reference to any member occurs
235.2745 +         for the first time */
235.2746 +      double value;
235.2747 +      /* evaluated numeric value */
235.2748 +};
235.2749 +
235.2750 +static void eval_num_func(MPL *mpl, void *_info)
235.2751 +{     /* this is auxiliary routine to work within domain scope */
235.2752 +      struct eval_num_info *info = _info;
235.2753 +      if (info->memb != NULL)
235.2754 +      {  /* checking call; check numeric value being assigned */
235.2755 +         check_value_num(mpl, info->par, info->memb->tuple,
235.2756 +            info->memb->value.num);
235.2757 +      }
235.2758 +      else
235.2759 +      {  /* normal call; evaluate member, which has given n-tuple */
235.2760 +         info->value = take_member_num(mpl, info->par, info->tuple);
235.2761 +      }
235.2762 +      return;
235.2763 +}
235.2764 +
235.2765 +double eval_member_num
235.2766 +(     MPL *mpl,
235.2767 +      PARAMETER *par,         /* not changed */
235.2768 +      TUPLE *tuple            /* not changed */
235.2769 +)
235.2770 +{     /* this routine evaluates numeric parameter member */
235.2771 +      struct eval_num_info _info, *info = &_info;
235.2772 +      xassert(par->type == A_NUMERIC || par->type == A_INTEGER ||
235.2773 +             par->type == A_BINARY);
235.2774 +      xassert(par->dim == tuple_dimen(mpl, tuple));
235.2775 +      info->par = par;
235.2776 +      info->tuple = tuple;
235.2777 +      if (par->data == 1)
235.2778 +      {  /* check data, which are provided in the data section, but not
235.2779 +            checked yet */
235.2780 +         /* save pointer to the last array member; note that during the
235.2781 +            check new members may be added beyond the last member due to
235.2782 +            references to the same parameter from default expression as
235.2783 +            well as from expressions that define restricting conditions;
235.2784 +            however, values assigned to the new members will be checked
235.2785 +            by other routine, so we don't need to check them here */
235.2786 +         MEMBER *tail = par->array->tail;
235.2787 +         /* change the data status to prevent infinite recursive loop
235.2788 +            due to references to the same parameter during the check */
235.2789 +         par->data = 2;
235.2790 +         /* check values assigned to array members in the data section
235.2791 +            until the marked member has been reached */
235.2792 +         for (info->memb = par->array->head; info->memb != NULL;
235.2793 +            info->memb = info->memb->next)
235.2794 +         {  if (eval_within_domain(mpl, par->domain, info->memb->tuple,
235.2795 +               info, eval_num_func))
235.2796 +               out_of_domain(mpl, par->name, info->memb->tuple);
235.2797 +            if (info->memb == tail) break;
235.2798 +         }
235.2799 +         /* the check has been finished */
235.2800 +      }
235.2801 +      /* evaluate member, which has given n-tuple */
235.2802 +      info->memb = NULL;
235.2803 +      if (eval_within_domain(mpl, info->par->domain, info->tuple, info,
235.2804 +         eval_num_func))
235.2805 +         out_of_domain(mpl, par->name, info->tuple);
235.2806 +      /* bring evaluated value to the calling program */
235.2807 +      return info->value;
235.2808 +}
235.2809 +
235.2810 +/*----------------------------------------------------------------------
235.2811 +-- check_value_sym - check symbolic value assigned to parameter member.
235.2812 +--
235.2813 +-- This routine checks if symbolic value being assigned to some member
235.2814 +-- of specified symbolic model parameter satisfies to all restrictions.
235.2815 +--
235.2816 +-- NOTE: This routine must not be called out of domain scope. */
235.2817 +
235.2818 +void check_value_sym
235.2819 +(     MPL *mpl,
235.2820 +      PARAMETER *par,         /* not changed */
235.2821 +      TUPLE *tuple,           /* not changed */
235.2822 +      SYMBOL *value           /* not changed */
235.2823 +)
235.2824 +{     CONDITION *cond;
235.2825 +      WITHIN *in;
235.2826 +      int eqno;
235.2827 +      /* the value must satisfy to all specified conditions */
235.2828 +      for (cond = par->cond, eqno = 1; cond != NULL; cond = cond->next,
235.2829 +         eqno++)
235.2830 +      {  SYMBOL *bound;
235.2831 +         char buf[255+1];
235.2832 +         xassert(cond->code != NULL);
235.2833 +         bound = eval_symbolic(mpl, cond->code);
235.2834 +         switch (cond->rho)
235.2835 +         {
235.2836 +#if 1 /* 13/VIII-2008 */
235.2837 +            case O_LT:
235.2838 +               if (!(compare_symbols(mpl, value, bound) < 0))
235.2839 +               {  strcpy(buf, format_symbol(mpl, bound));
235.2840 +                  xassert(strlen(buf) < sizeof(buf));
235.2841 +                  error(mpl, "%s%s = %s not < %s",
235.2842 +                     par->name, format_tuple(mpl, '[', tuple),
235.2843 +                     format_symbol(mpl, value), buf, eqno);
235.2844 +               }
235.2845 +               break;
235.2846 +            case O_LE:
235.2847 +               if (!(compare_symbols(mpl, value, bound) <= 0))
235.2848 +               {  strcpy(buf, format_symbol(mpl, bound));
235.2849 +                  xassert(strlen(buf) < sizeof(buf));
235.2850 +                  error(mpl, "%s%s = %s not <= %s",
235.2851 +                     par->name, format_tuple(mpl, '[', tuple),
235.2852 +                     format_symbol(mpl, value), buf, eqno);
235.2853 +               }
235.2854 +               break;
235.2855 +#endif
235.2856 +            case O_EQ:
235.2857 +               if (!(compare_symbols(mpl, value, bound) == 0))
235.2858 +               {  strcpy(buf, format_symbol(mpl, bound));
235.2859 +                  xassert(strlen(buf) < sizeof(buf));
235.2860 +                  error(mpl, "%s%s = %s not = %s",
235.2861 +                     par->name, format_tuple(mpl, '[', tuple),
235.2862 +                     format_symbol(mpl, value), buf, eqno);
235.2863 +               }
235.2864 +               break;
235.2865 +#if 1 /* 13/VIII-2008 */
235.2866 +            case O_GE:
235.2867 +               if (!(compare_symbols(mpl, value, bound) >= 0))
235.2868 +               {  strcpy(buf, format_symbol(mpl, bound));
235.2869 +                  xassert(strlen(buf) < sizeof(buf));
235.2870 +                  error(mpl, "%s%s = %s not >= %s",
235.2871 +                     par->name, format_tuple(mpl, '[', tuple),
235.2872 +                     format_symbol(mpl, value), buf, eqno);
235.2873 +               }
235.2874 +               break;
235.2875 +            case O_GT:
235.2876 +               if (!(compare_symbols(mpl, value, bound) > 0))
235.2877 +               {  strcpy(buf, format_symbol(mpl, bound));
235.2878 +                  xassert(strlen(buf) < sizeof(buf));
235.2879 +                  error(mpl, "%s%s = %s not > %s",
235.2880 +                     par->name, format_tuple(mpl, '[', tuple),
235.2881 +                     format_symbol(mpl, value), buf, eqno);
235.2882 +               }
235.2883 +               break;
235.2884 +#endif
235.2885 +            case O_NE:
235.2886 +               if (!(compare_symbols(mpl, value, bound) != 0))
235.2887 +               {  strcpy(buf, format_symbol(mpl, bound));
235.2888 +                  xassert(strlen(buf) < sizeof(buf));
235.2889 +                  error(mpl, "%s%s = %s not <> %s",
235.2890 +                     par->name, format_tuple(mpl, '[', tuple),
235.2891 +                     format_symbol(mpl, value), buf, eqno);
235.2892 +               }
235.2893 +               break;
235.2894 +            default:
235.2895 +               xassert(cond != cond);
235.2896 +         }
235.2897 +         delete_symbol(mpl, bound);
235.2898 +      }
235.2899 +      /* the value must be in all specified supersets */
235.2900 +      for (in = par->in, eqno = 1; in != NULL; in = in->next, eqno++)
235.2901 +      {  TUPLE *dummy;
235.2902 +         xassert(in->code != NULL);
235.2903 +         xassert(in->code->dim == 1);
235.2904 +         dummy = expand_tuple(mpl, create_tuple(mpl), copy_symbol(mpl,
235.2905 +            value));
235.2906 +         if (!is_member(mpl, in->code, dummy))
235.2907 +            error(mpl, "%s%s = %s not in specified set; see (%d)",
235.2908 +               par->name, format_tuple(mpl, '[', tuple),
235.2909 +               format_symbol(mpl, value), eqno);
235.2910 +         delete_tuple(mpl, dummy);
235.2911 +      }
235.2912 +      return;
235.2913 +}
235.2914 +
235.2915 +/*----------------------------------------------------------------------
235.2916 +-- take_member_sym - obtain symb. value assigned to parameter member.
235.2917 +--
235.2918 +-- This routine obtains a symbolic value assigned to member of specified
235.2919 +-- symbolic model parameter and returns it on exit.
235.2920 +--
235.2921 +-- NOTE: This routine must not be called out of domain scope. */
235.2922 +
235.2923 +SYMBOL *take_member_sym       /* returns value, not reference */
235.2924 +(     MPL *mpl,
235.2925 +      PARAMETER *par,         /* not changed */
235.2926 +      TUPLE *tuple            /* not changed */
235.2927 +)
235.2928 +{     MEMBER *memb;
235.2929 +      SYMBOL *value;
235.2930 +      /* find member in the parameter array */
235.2931 +      memb = find_member(mpl, par->array, tuple);
235.2932 +      if (memb != NULL)
235.2933 +      {  /* member exists, so just take its value */
235.2934 +         value = copy_symbol(mpl, memb->value.sym);
235.2935 +      }
235.2936 +      else if (par->assign != NULL)
235.2937 +      {  /* compute value using assignment expression */
235.2938 +         value = eval_symbolic(mpl, par->assign);
235.2939 +add:     /* check that the value satisfies to all restrictions, assign
235.2940 +            it to new member, and add the member to the array */
235.2941 +         check_value_sym(mpl, par, tuple, value);
235.2942 +         memb = add_member(mpl, par->array, copy_tuple(mpl, tuple));
235.2943 +         memb->value.sym = copy_symbol(mpl, value);
235.2944 +      }
235.2945 +      else if (par->option != NULL)
235.2946 +      {  /* compute default value */
235.2947 +         value = eval_symbolic(mpl, par->option);
235.2948 +         goto add;
235.2949 +      }
235.2950 +      else if (par->defval != NULL)
235.2951 +      {  /* take default value provided in the data section */
235.2952 +         value = copy_symbol(mpl, par->defval);
235.2953 +         goto add;
235.2954 +      }
235.2955 +      else
235.2956 +      {  /* no value is provided */
235.2957 +         error(mpl, "no value for %s%s", par->name, format_tuple(mpl,
235.2958 +            '[', tuple));
235.2959 +      }
235.2960 +      return value;
235.2961 +}
235.2962 +
235.2963 +/*----------------------------------------------------------------------
235.2964 +-- eval_member_sym - evaluate symb. value assigned to parameter member.
235.2965 +--
235.2966 +-- This routine evaluates a symbolic value assigned to given member of
235.2967 +-- specified symbolic model parameter and returns it on exit. */
235.2968 +
235.2969 +struct eval_sym_info
235.2970 +{     /* working info used by the routine eval_member_sym */
235.2971 +      PARAMETER *par;
235.2972 +      /* model parameter */
235.2973 +      TUPLE *tuple;
235.2974 +      /* n-tuple, which defines parameter member */
235.2975 +      MEMBER *memb;
235.2976 +      /* normally this pointer is NULL; the routine uses this pointer
235.2977 +         to check data provided in the data section, in which case it
235.2978 +         points to a member currently checked; this check is performed
235.2979 +         automatically only once when a reference to any member occurs
235.2980 +         for the first time */
235.2981 +      SYMBOL *value;
235.2982 +      /* evaluated symbolic value */
235.2983 +};
235.2984 +
235.2985 +static void eval_sym_func(MPL *mpl, void *_info)
235.2986 +{     /* this is auxiliary routine to work within domain scope */
235.2987 +      struct eval_sym_info *info = _info;
235.2988 +      if (info->memb != NULL)
235.2989 +      {  /* checking call; check symbolic value being assigned */
235.2990 +         check_value_sym(mpl, info->par, info->memb->tuple,
235.2991 +            info->memb->value.sym);
235.2992 +      }
235.2993 +      else
235.2994 +      {  /* normal call; evaluate member, which has given n-tuple */
235.2995 +         info->value = take_member_sym(mpl, info->par, info->tuple);
235.2996 +      }
235.2997 +      return;
235.2998 +}
235.2999 +
235.3000 +SYMBOL *eval_member_sym       /* returns value, not reference */
235.3001 +(     MPL *mpl,
235.3002 +      PARAMETER *par,         /* not changed */
235.3003 +      TUPLE *tuple            /* not changed */
235.3004 +)
235.3005 +{     /* this routine evaluates symbolic parameter member */
235.3006 +      struct eval_sym_info _info, *info = &_info;
235.3007 +      xassert(par->type == A_SYMBOLIC);
235.3008 +      xassert(par->dim == tuple_dimen(mpl, tuple));
235.3009 +      info->par = par;
235.3010 +      info->tuple = tuple;
235.3011 +      if (par->data == 1)
235.3012 +      {  /* check data, which are provided in the data section, but not
235.3013 +            checked yet */
235.3014 +         /* save pointer to the last array member; note that during the
235.3015 +            check new members may be added beyond the last member due to
235.3016 +            references to the same parameter from default expression as
235.3017 +            well as from expressions that define restricting conditions;
235.3018 +            however, values assigned to the new members will be checked
235.3019 +            by other routine, so we don't need to check them here */
235.3020 +         MEMBER *tail = par->array->tail;
235.3021 +         /* change the data status to prevent infinite recursive loop
235.3022 +            due to references to the same parameter during the check */
235.3023 +         par->data = 2;
235.3024 +         /* check values assigned to array members in the data section
235.3025 +            until the marked member has been reached */
235.3026 +         for (info->memb = par->array->head; info->memb != NULL;
235.3027 +            info->memb = info->memb->next)
235.3028 +         {  if (eval_within_domain(mpl, par->domain, info->memb->tuple,
235.3029 +               info, eval_sym_func))
235.3030 +               out_of_domain(mpl, par->name, info->memb->tuple);
235.3031 +            if (info->memb == tail) break;
235.3032 +         }
235.3033 +         /* the check has been finished */
235.3034 +      }
235.3035 +      /* evaluate member, which has given n-tuple */
235.3036 +      info->memb = NULL;
235.3037 +      if (eval_within_domain(mpl, info->par->domain, info->tuple, info,
235.3038 +         eval_sym_func))
235.3039 +         out_of_domain(mpl, par->name, info->tuple);
235.3040 +      /* bring evaluated value to the calling program */
235.3041 +      return info->value;
235.3042 +}
235.3043 +
235.3044 +/*----------------------------------------------------------------------
235.3045 +-- eval_whole_par - evaluate model parameter over entire domain.
235.3046 +--
235.3047 +-- This routine evaluates all members of specified model parameter over
235.3048 +-- entire domain. */
235.3049 +
235.3050 +static int whole_par_func(MPL *mpl, void *info)
235.3051 +{     /* this is auxiliary routine to work within domain scope */
235.3052 +      PARAMETER *par = (PARAMETER *)info;
235.3053 +      TUPLE *tuple = get_domain_tuple(mpl, par->domain);
235.3054 +      switch (par->type)
235.3055 +      {  case A_NUMERIC:
235.3056 +         case A_INTEGER:
235.3057 +         case A_BINARY:
235.3058 +            eval_member_num(mpl, par, tuple);
235.3059 +            break;
235.3060 +         case A_SYMBOLIC:
235.3061 +            delete_symbol(mpl, eval_member_sym(mpl, par, tuple));
235.3062 +            break;
235.3063 +         default:
235.3064 +            xassert(par != par);
235.3065 +      }
235.3066 +      delete_tuple(mpl, tuple);
235.3067 +      return 0;
235.3068 +}
235.3069 +
235.3070 +void eval_whole_par(MPL *mpl, PARAMETER *par)
235.3071 +{     loop_within_domain(mpl, par->domain, par, whole_par_func);
235.3072 +      return;
235.3073 +}
235.3074 +
235.3075 +/*----------------------------------------------------------------------
235.3076 +-- clean_parameter - clean model parameter.
235.3077 +--
235.3078 +-- This routine cleans specified model parameter that assumes deleting
235.3079 +-- all stuff dynamically allocated during the generation phase. */
235.3080 +
235.3081 +void clean_parameter(MPL *mpl, PARAMETER *par)
235.3082 +{     CONDITION *cond;
235.3083 +      WITHIN *in;
235.3084 +      MEMBER *memb;
235.3085 +      /* clean subscript domain */
235.3086 +      clean_domain(mpl, par->domain);
235.3087 +      /* clean pseudo-code for computing restricting conditions */
235.3088 +      for (cond = par->cond; cond != NULL; cond = cond->next)
235.3089 +         clean_code(mpl, cond->code);
235.3090 +      /* clean pseudo-code for computing restricting supersets */
235.3091 +      for (in = par->in; in != NULL; in = in->next)
235.3092 +         clean_code(mpl, in->code);
235.3093 +      /* clean pseudo-code for computing assigned value */
235.3094 +      clean_code(mpl, par->assign);
235.3095 +      /* clean pseudo-code for computing default value */
235.3096 +      clean_code(mpl, par->option);
235.3097 +      /* reset data status flag */
235.3098 +      par->data = 0;
235.3099 +      /* delete default symbolic value */
235.3100 +      if (par->defval != NULL)
235.3101 +         delete_symbol(mpl, par->defval), par->defval = NULL;
235.3102 +      /* delete content array */
235.3103 +      for (memb = par->array->head; memb != NULL; memb = memb->next)
235.3104 +         delete_value(mpl, par->array->type, &memb->value);
235.3105 +      delete_array(mpl, par->array), par->array = NULL;
235.3106 +      return;
235.3107 +}
235.3108 +
235.3109 +/**********************************************************************/
235.3110 +/* * *                      MODEL VARIABLES                       * * */
235.3111 +/**********************************************************************/
235.3112 +
235.3113 +/*----------------------------------------------------------------------
235.3114 +-- take_member_var - obtain reference to elemental variable.
235.3115 +--
235.3116 +-- This routine obtains a reference to elemental variable assigned to
235.3117 +-- given member of specified model variable and returns it on exit. If
235.3118 +-- necessary, new elemental variable is created.
235.3119 +--
235.3120 +-- NOTE: This routine must not be called out of domain scope. */
235.3121 +
235.3122 +ELEMVAR *take_member_var      /* returns reference */
235.3123 +(     MPL *mpl,
235.3124 +      VARIABLE *var,          /* not changed */
235.3125 +      TUPLE *tuple            /* not changed */
235.3126 +)
235.3127 +{     MEMBER *memb;
235.3128 +      ELEMVAR *refer;
235.3129 +      /* find member in the variable array */
235.3130 +      memb = find_member(mpl, var->array, tuple);
235.3131 +      if (memb != NULL)
235.3132 +      {  /* member exists, so just take the reference */
235.3133 +         refer = memb->value.var;
235.3134 +      }
235.3135 +      else
235.3136 +      {  /* member is referenced for the first time and therefore does
235.3137 +            not exist; create new elemental variable, assign it to new
235.3138 +            member, and add the member to the variable array */
235.3139 +         memb = add_member(mpl, var->array, copy_tuple(mpl, tuple));
235.3140 +         refer = (memb->value.var =
235.3141 +            dmp_get_atom(mpl->elemvars, sizeof(ELEMVAR)));
235.3142 +         refer->j = 0;
235.3143 +         refer->var = var;
235.3144 +         refer->memb = memb;
235.3145 +         /* compute lower bound */
235.3146 +         if (var->lbnd == NULL)
235.3147 +            refer->lbnd = 0.0;
235.3148 +         else
235.3149 +            refer->lbnd = eval_numeric(mpl, var->lbnd);
235.3150 +         /* compute upper bound */
235.3151 +         if (var->ubnd == NULL)
235.3152 +            refer->ubnd = 0.0;
235.3153 +         else if (var->ubnd == var->lbnd)
235.3154 +            refer->ubnd = refer->lbnd;
235.3155 +         else
235.3156 +            refer->ubnd = eval_numeric(mpl, var->ubnd);
235.3157 +         /* nullify working quantity */
235.3158 +         refer->temp = 0.0;
235.3159 +#if 1 /* 15/V-2010 */
235.3160 +         /* solution has not been obtained by the solver yet */
235.3161 +         refer->stat = 0;
235.3162 +         refer->prim = refer->dual = 0.0;
235.3163 +#endif
235.3164 +      }
235.3165 +      return refer;
235.3166 +}
235.3167 +
235.3168 +/*----------------------------------------------------------------------
235.3169 +-- eval_member_var - evaluate reference to elemental variable.
235.3170 +--
235.3171 +-- This routine evaluates a reference to elemental variable assigned to
235.3172 +-- member of specified model variable and returns it on exit. */
235.3173 +
235.3174 +struct eval_var_info
235.3175 +{     /* working info used by the routine eval_member_var */
235.3176 +      VARIABLE *var;
235.3177 +      /* model variable */
235.3178 +      TUPLE *tuple;
235.3179 +      /* n-tuple, which defines variable member */
235.3180 +      ELEMVAR *refer;
235.3181 +      /* evaluated reference to elemental variable */
235.3182 +};
235.3183 +
235.3184 +static void eval_var_func(MPL *mpl, void *_info)
235.3185 +{     /* this is auxiliary routine to work within domain scope */
235.3186 +      struct eval_var_info *info = _info;
235.3187 +      info->refer = take_member_var(mpl, info->var, info->tuple);
235.3188 +      return;
235.3189 +}
235.3190 +
235.3191 +ELEMVAR *eval_member_var      /* returns reference */
235.3192 +(     MPL *mpl,
235.3193 +      VARIABLE *var,          /* not changed */
235.3194 +      TUPLE *tuple            /* not changed */
235.3195 +)
235.3196 +{     /* this routine evaluates variable member */
235.3197 +      struct eval_var_info _info, *info = &_info;
235.3198 +      xassert(var->dim == tuple_dimen(mpl, tuple));
235.3199 +      info->var = var;
235.3200 +      info->tuple = tuple;
235.3201 +      /* evaluate member, which has given n-tuple */
235.3202 +      if (eval_within_domain(mpl, info->var->domain, info->tuple, info,
235.3203 +         eval_var_func))
235.3204 +         out_of_domain(mpl, var->name, info->tuple);
235.3205 +      /* bring evaluated reference to the calling program */
235.3206 +      return info->refer;
235.3207 +}
235.3208 +
235.3209 +/*----------------------------------------------------------------------
235.3210 +-- eval_whole_var - evaluate model variable over entire domain.
235.3211 +--
235.3212 +-- This routine evaluates all members of specified model variable over
235.3213 +-- entire domain. */
235.3214 +
235.3215 +static int whole_var_func(MPL *mpl, void *info)
235.3216 +{     /* this is auxiliary routine to work within domain scope */
235.3217 +      VARIABLE *var = (VARIABLE *)info;
235.3218 +      TUPLE *tuple = get_domain_tuple(mpl, var->domain);
235.3219 +      eval_member_var(mpl, var, tuple);
235.3220 +      delete_tuple(mpl, tuple);
235.3221 +      return 0;
235.3222 +}
235.3223 +
235.3224 +void eval_whole_var(MPL *mpl, VARIABLE *var)
235.3225 +{     loop_within_domain(mpl, var->domain, var, whole_var_func);
235.3226 +      return;
235.3227 +}
235.3228 +
235.3229 +/*----------------------------------------------------------------------
235.3230 +-- clean_variable - clean model variable.
235.3231 +--
235.3232 +-- This routine cleans specified model variable that assumes deleting
235.3233 +-- all stuff dynamically allocated during the generation phase. */
235.3234 +
235.3235 +void clean_variable(MPL *mpl, VARIABLE *var)
235.3236 +{     MEMBER *memb;
235.3237 +      /* clean subscript domain */
235.3238 +      clean_domain(mpl, var->domain);
235.3239 +      /* clean code for computing lower bound */
235.3240 +      clean_code(mpl, var->lbnd);
235.3241 +      /* clean code for computing upper bound */
235.3242 +      if (var->ubnd != var->lbnd) clean_code(mpl, var->ubnd);
235.3243 +      /* delete content array */
235.3244 +      for (memb = var->array->head; memb != NULL; memb = memb->next)
235.3245 +         dmp_free_atom(mpl->elemvars, memb->value.var, sizeof(ELEMVAR));
235.3246 +      delete_array(mpl, var->array), var->array = NULL;
235.3247 +      return;
235.3248 +}
235.3249 +
235.3250 +/**********************************************************************/
235.3251 +/* * *              MODEL CONSTRAINTS AND OBJECTIVES              * * */
235.3252 +/**********************************************************************/
235.3253 +
235.3254 +/*----------------------------------------------------------------------
235.3255 +-- take_member_con - obtain reference to elemental constraint.
235.3256 +--
235.3257 +-- This routine obtains a reference to elemental constraint assigned
235.3258 +-- to given member of specified model constraint and returns it on exit.
235.3259 +-- If necessary, new elemental constraint is created.
235.3260 +--
235.3261 +-- NOTE: This routine must not be called out of domain scope. */
235.3262 +
235.3263 +ELEMCON *take_member_con      /* returns reference */
235.3264 +(     MPL *mpl,
235.3265 +      CONSTRAINT *con,        /* not changed */
235.3266 +      TUPLE *tuple            /* not changed */
235.3267 +)
235.3268 +{     MEMBER *memb;
235.3269 +      ELEMCON *refer;
235.3270 +      /* find member in the constraint array */
235.3271 +      memb = find_member(mpl, con->array, tuple);
235.3272 +      if (memb != NULL)
235.3273 +      {  /* member exists, so just take the reference */
235.3274 +         refer = memb->value.con;
235.3275 +      }
235.3276 +      else
235.3277 +      {  /* member is referenced for the first time and therefore does
235.3278 +            not exist; create new elemental constraint, assign it to new
235.3279 +            member, and add the member to the constraint array */
235.3280 +         memb = add_member(mpl, con->array, copy_tuple(mpl, tuple));
235.3281 +         refer = (memb->value.con =
235.3282 +            dmp_get_atom(mpl->elemcons, sizeof(ELEMCON)));
235.3283 +         refer->i = 0;
235.3284 +         refer->con = con;
235.3285 +         refer->memb = memb;
235.3286 +         /* compute linear form */
235.3287 +         xassert(con->code != NULL);
235.3288 +         refer->form = eval_formula(mpl, con->code);
235.3289 +         /* compute lower and upper bounds */
235.3290 +         if (con->lbnd == NULL && con->ubnd == NULL)
235.3291 +         {  /* objective has no bounds */
235.3292 +            double temp;
235.3293 +            xassert(con->type == A_MINIMIZE || con->type == A_MAXIMIZE);
235.3294 +            /* carry the constant term to the right-hand side */
235.3295 +            refer->form = remove_constant(mpl, refer->form, &temp);
235.3296 +            refer->lbnd = refer->ubnd = - temp;
235.3297 +         }
235.3298 +         else if (con->lbnd != NULL && con->ubnd == NULL)
235.3299 +         {  /* constraint a * x + b >= c * y + d is transformed to the
235.3300 +               standard form a * x - c * y >= d - b */
235.3301 +            double temp;
235.3302 +            xassert(con->type == A_CONSTRAINT);
235.3303 +            refer->form = linear_comb(mpl,
235.3304 +               +1.0, refer->form,
235.3305 +               -1.0, eval_formula(mpl, con->lbnd));
235.3306 +            refer->form = remove_constant(mpl, refer->form, &temp);
235.3307 +            refer->lbnd = - temp;
235.3308 +            refer->ubnd = 0.0;
235.3309 +         }
235.3310 +         else if (con->lbnd == NULL && con->ubnd != NULL)
235.3311 +         {  /* constraint a * x + b <= c * y + d is transformed to the
235.3312 +               standard form a * x - c * y <= d - b */
235.3313 +            double temp;
235.3314 +            xassert(con->type == A_CONSTRAINT);
235.3315 +            refer->form = linear_comb(mpl,
235.3316 +               +1.0, refer->form,
235.3317 +               -1.0, eval_formula(mpl, con->ubnd));
235.3318 +            refer->form = remove_constant(mpl, refer->form, &temp);
235.3319 +            refer->lbnd = 0.0;
235.3320 +            refer->ubnd = - temp;
235.3321 +         }
235.3322 +         else if (con->lbnd == con->ubnd)
235.3323 +         {  /* constraint a * x + b = c * y + d is transformed to the
235.3324 +               standard form a * x - c * y = d - b */
235.3325 +            double temp;
235.3326 +            xassert(con->type == A_CONSTRAINT);
235.3327 +            refer->form = linear_comb(mpl,
235.3328 +               +1.0, refer->form,
235.3329 +               -1.0, eval_formula(mpl, con->lbnd));
235.3330 +            refer->form = remove_constant(mpl, refer->form, &temp);
235.3331 +            refer->lbnd = refer->ubnd = - temp;
235.3332 +         }
235.3333 +         else
235.3334 +         {  /* ranged constraint c <= a * x + b <= d is transformed to
235.3335 +               the standard form c - b <= a * x <= d - b */
235.3336 +            double temp, temp1, temp2;
235.3337 +            xassert(con->type == A_CONSTRAINT);
235.3338 +            refer->form = remove_constant(mpl, refer->form, &temp);
235.3339 +            xassert(remove_constant(mpl, eval_formula(mpl, con->lbnd),
235.3340 +               &temp1) == NULL);
235.3341 +            xassert(remove_constant(mpl, eval_formula(mpl, con->ubnd),
235.3342 +               &temp2) == NULL);
235.3343 +            refer->lbnd = fp_sub(mpl, temp1, temp);
235.3344 +            refer->ubnd = fp_sub(mpl, temp2, temp);
235.3345 +         }
235.3346 +#if 1 /* 15/V-2010 */
235.3347 +         /* solution has not been obtained by the solver yet */
235.3348 +         refer->stat = 0;
235.3349 +         refer->prim = refer->dual = 0.0;
235.3350 +#endif
235.3351 +      }
235.3352 +      return refer;
235.3353 +}
235.3354 +
235.3355 +/*----------------------------------------------------------------------
235.3356 +-- eval_member_con - evaluate reference to elemental constraint.
235.3357 +--
235.3358 +-- This routine evaluates a reference to elemental constraint assigned
235.3359 +-- to member of specified model constraint and returns it on exit. */
235.3360 +
235.3361 +struct eval_con_info
235.3362 +{     /* working info used by the routine eval_member_con */
235.3363 +      CONSTRAINT *con;
235.3364 +      /* model constraint */
235.3365 +      TUPLE *tuple;
235.3366 +      /* n-tuple, which defines constraint member */
235.3367 +      ELEMCON *refer;
235.3368 +      /* evaluated reference to elemental constraint */
235.3369 +};
235.3370 +
235.3371 +static void eval_con_func(MPL *mpl, void *_info)
235.3372 +{     /* this is auxiliary routine to work within domain scope */
235.3373 +      struct eval_con_info *info = _info;
235.3374 +      info->refer = take_member_con(mpl, info->con, info->tuple);
235.3375 +      return;
235.3376 +}
235.3377 +
235.3378 +ELEMCON *eval_member_con      /* returns reference */
235.3379 +(     MPL *mpl,
235.3380 +      CONSTRAINT *con,        /* not changed */
235.3381 +      TUPLE *tuple            /* not changed */
235.3382 +)
235.3383 +{     /* this routine evaluates constraint member */
235.3384 +      struct eval_con_info _info, *info = &_info;
235.3385 +      xassert(con->dim == tuple_dimen(mpl, tuple));
235.3386 +      info->con = con;
235.3387 +      info->tuple = tuple;
235.3388 +      /* evaluate member, which has given n-tuple */
235.3389 +      if (eval_within_domain(mpl, info->con->domain, info->tuple, info,
235.3390 +         eval_con_func))
235.3391 +         out_of_domain(mpl, con->name, info->tuple);
235.3392 +      /* bring evaluated reference to the calling program */
235.3393 +      return info->refer;
235.3394 +}
235.3395 +
235.3396 +/*----------------------------------------------------------------------
235.3397 +-- eval_whole_con - evaluate model constraint over entire domain.
235.3398 +--
235.3399 +-- This routine evaluates all members of specified model constraint over
235.3400 +-- entire domain. */
235.3401 +
235.3402 +static int whole_con_func(MPL *mpl, void *info)
235.3403 +{     /* this is auxiliary routine to work within domain scope */
235.3404 +      CONSTRAINT *con = (CONSTRAINT *)info;
235.3405 +      TUPLE *tuple = get_domain_tuple(mpl, con->domain);
235.3406 +      eval_member_con(mpl, con, tuple);
235.3407 +      delete_tuple(mpl, tuple);
235.3408 +      return 0;
235.3409 +}
235.3410 +
235.3411 +void eval_whole_con(MPL *mpl, CONSTRAINT *con)
235.3412 +{     loop_within_domain(mpl, con->domain, con, whole_con_func);
235.3413 +      return;
235.3414 +}
235.3415 +
235.3416 +/*----------------------------------------------------------------------
235.3417 +-- clean_constraint - clean model constraint.
235.3418 +--
235.3419 +-- This routine cleans specified model constraint that assumes deleting
235.3420 +-- all stuff dynamically allocated during the generation phase. */
235.3421 +
235.3422 +void clean_constraint(MPL *mpl, CONSTRAINT *con)
235.3423 +{     MEMBER *memb;
235.3424 +      /* clean subscript domain */
235.3425 +      clean_domain(mpl, con->domain);
235.3426 +      /* clean code for computing main linear form */
235.3427 +      clean_code(mpl, con->code);
235.3428 +      /* clean code for computing lower bound */
235.3429 +      clean_code(mpl, con->lbnd);
235.3430 +      /* clean code for computing upper bound */
235.3431 +      if (con->ubnd != con->lbnd) clean_code(mpl, con->ubnd);
235.3432 +      /* delete content array */
235.3433 +      for (memb = con->array->head; memb != NULL; memb = memb->next)
235.3434 +      {  delete_formula(mpl, memb->value.con->form);
235.3435 +         dmp_free_atom(mpl->elemcons, memb->value.con, sizeof(ELEMCON));
235.3436 +      }
235.3437 +      delete_array(mpl, con->array), con->array = NULL;
235.3438 +      return;
235.3439 +}
235.3440 +
235.3441 +/**********************************************************************/
235.3442 +/* * *                        PSEUDO-CODE                         * * */
235.3443 +/**********************************************************************/
235.3444 +
235.3445 +/*----------------------------------------------------------------------
235.3446 +-- eval_numeric - evaluate pseudo-code to determine numeric value.
235.3447 +--
235.3448 +-- This routine evaluates specified pseudo-code to determine resultant
235.3449 +-- numeric value, which is returned on exit. */
235.3450 +
235.3451 +struct iter_num_info
235.3452 +{     /* working info used by the routine iter_num_func */
235.3453 +      CODE *code;
235.3454 +      /* pseudo-code for iterated operation to be performed */
235.3455 +      double value;
235.3456 +      /* resultant value */
235.3457 +};
235.3458 +
235.3459 +static int iter_num_func(MPL *mpl, void *_info)
235.3460 +{     /* this is auxiliary routine used to perform iterated operation
235.3461 +         on numeric "integrand" within domain scope */
235.3462 +      struct iter_num_info *info = _info;
235.3463 +      double temp;
235.3464 +      temp = eval_numeric(mpl, info->code->arg.loop.x);
235.3465 +      switch (info->code->op)
235.3466 +      {  case O_SUM:
235.3467 +            /* summation over domain */
235.3468 +            info->value = fp_add(mpl, info->value, temp);
235.3469 +            break;
235.3470 +         case O_PROD:
235.3471 +            /* multiplication over domain */
235.3472 +            info->value = fp_mul(mpl, info->value, temp);
235.3473 +            break;
235.3474 +         case O_MINIMUM:
235.3475 +            /* minimum over domain */
235.3476 +            if (info->value > temp) info->value = temp;
235.3477 +            break;
235.3478 +         case O_MAXIMUM:
235.3479 +            /* maximum over domain */
235.3480 +            if (info->value < temp) info->value = temp;
235.3481 +            break;
235.3482 +         default:
235.3483 +            xassert(info != info);
235.3484 +      }
235.3485 +      return 0;
235.3486 +}
235.3487 +
235.3488 +double eval_numeric(MPL *mpl, CODE *code)
235.3489 +{     double value;
235.3490 +      xassert(code != NULL);
235.3491 +      xassert(code->type == A_NUMERIC);
235.3492 +      xassert(code->dim == 0);
235.3493 +      /* if the operation has a side effect, invalidate and delete the
235.3494 +         resultant value */
235.3495 +      if (code->vflag && code->valid)
235.3496 +      {  code->valid = 0;
235.3497 +         delete_value(mpl, code->type, &code->value);
235.3498 +      }
235.3499 +      /* if resultant value is valid, no evaluation is needed */
235.3500 +      if (code->valid)
235.3501 +      {  value = code->value.num;
235.3502 +         goto done;
235.3503 +      }
235.3504 +      /* evaluate pseudo-code recursively */
235.3505 +      switch (code->op)
235.3506 +      {  case O_NUMBER:
235.3507 +            /* take floating-point number */
235.3508 +            value = code->arg.num;
235.3509 +            break;
235.3510 +         case O_MEMNUM:
235.3511 +            /* take member of numeric parameter */
235.3512 +            {  TUPLE *tuple;
235.3513 +               ARG_LIST *e;
235.3514 +               tuple = create_tuple(mpl);
235.3515 +               for (e = code->arg.par.list; e != NULL; e = e->next)
235.3516 +                  tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
235.3517 +                     e->x));
235.3518 +               value = eval_member_num(mpl, code->arg.par.par, tuple);
235.3519 +               delete_tuple(mpl, tuple);
235.3520 +            }
235.3521 +            break;
235.3522 +         case O_MEMVAR:
235.3523 +            /* take computed value of elemental variable */
235.3524 +            {  TUPLE *tuple;
235.3525 +               ARG_LIST *e;
235.3526 +#if 1 /* 15/V-2010 */
235.3527 +               ELEMVAR *var;
235.3528 +#endif
235.3529 +               tuple = create_tuple(mpl);
235.3530 +               for (e = code->arg.var.list; e != NULL; e = e->next)
235.3531 +                  tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
235.3532 +                     e->x));
235.3533 +#if 0 /* 15/V-2010 */
235.3534 +               value = eval_member_var(mpl, code->arg.var.var, tuple)
235.3535 +                  ->value;
235.3536 +#else
235.3537 +               var = eval_member_var(mpl, code->arg.var.var, tuple);
235.3538 +               switch (code->arg.var.suff)
235.3539 +               {  case DOT_LB:
235.3540 +                     if (var->var->lbnd == NULL)
235.3541 +                        value = -DBL_MAX;
235.3542 +                     else
235.3543 +                        value = var->lbnd;
235.3544 +                     break;
235.3545 +                  case DOT_UB:
235.3546 +                     if (var->var->ubnd == NULL)
235.3547 +                        value = +DBL_MAX;
235.3548 +                     else
235.3549 +                        value = var->ubnd;
235.3550 +                     break;
235.3551 +                  case DOT_STATUS:
235.3552 +                     value = var->stat;
235.3553 +                     break;
235.3554 +                  case DOT_VAL:
235.3555 +                     value = var->prim;
235.3556 +                     break;
235.3557 +                  case DOT_DUAL:
235.3558 +                     value = var->dual;
235.3559 +                     break;
235.3560 +                  default:
235.3561 +                     xassert(code != code);
235.3562 +               }
235.3563 +#endif
235.3564 +               delete_tuple(mpl, tuple);
235.3565 +            }
235.3566 +            break;
235.3567 +#if 1 /* 15/V-2010 */
235.3568 +         case O_MEMCON:
235.3569 +            /* take computed value of elemental constraint */
235.3570 +            {  TUPLE *tuple;
235.3571 +               ARG_LIST *e;
235.3572 +               ELEMCON *con;
235.3573 +               tuple = create_tuple(mpl);
235.3574 +               for (e = code->arg.con.list; e != NULL; e = e->next)
235.3575 +                  tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
235.3576 +                     e->x));
235.3577 +               con = eval_member_con(mpl, code->arg.con.con, tuple);
235.3578 +               switch (code->arg.con.suff)
235.3579 +               {  case DOT_LB:
235.3580 +                     if (con->con->lbnd == NULL)
235.3581 +                        value = -DBL_MAX;
235.3582 +                     else
235.3583 +                        value = con->lbnd;
235.3584 +                     break;
235.3585 +                  case DOT_UB:
235.3586 +                     if (con->con->ubnd == NULL)
235.3587 +                        value = +DBL_MAX;
235.3588 +                     else
235.3589 +                        value = con->ubnd;
235.3590 +                     break;
235.3591 +                  case DOT_STATUS:
235.3592 +                     value = con->stat;
235.3593 +                     break;
235.3594 +                  case DOT_VAL:
235.3595 +                     value = con->prim;
235.3596 +                     break;
235.3597 +                  case DOT_DUAL:
235.3598 +                     value = con->dual;
235.3599 +                     break;
235.3600 +                  default:
235.3601 +                     xassert(code != code);
235.3602 +               }
235.3603 +               delete_tuple(mpl, tuple);
235.3604 +            }
235.3605 +            break;
235.3606 +#endif
235.3607 +         case O_IRAND224:
235.3608 +            /* pseudo-random in [0, 2^24-1] */
235.3609 +            value = fp_irand224(mpl);
235.3610 +            break;
235.3611 +         case O_UNIFORM01:
235.3612 +            /* pseudo-random in [0, 1) */
235.3613 +            value = fp_uniform01(mpl);
235.3614 +            break;
235.3615 +         case O_NORMAL01:
235.3616 +            /* gaussian random, mu = 0, sigma = 1 */
235.3617 +            value = fp_normal01(mpl);
235.3618 +            break;
235.3619 +         case O_GMTIME:
235.3620 +            /* current calendar time */
235.3621 +            value = fn_gmtime(mpl);
235.3622 +            break;
235.3623 +         case O_CVTNUM:
235.3624 +            /* conversion to numeric */
235.3625 +            {  SYMBOL *sym;
235.3626 +               sym = eval_symbolic(mpl, code->arg.arg.x);
235.3627 +#if 0 /* 23/XI-2008 */
235.3628 +               if (sym->str != NULL)
235.3629 +                  error(mpl, "cannot convert %s to floating-point numbe"
235.3630 +                     "r", format_symbol(mpl, sym));
235.3631 +               value = sym->num;
235.3632 +#else
235.3633 +               if (sym->str == NULL)
235.3634 +                  value = sym->num;
235.3635 +               else
235.3636 +               {  if (str2num(sym->str, &value))
235.3637 +                     error(mpl, "cannot convert %s to floating-point nu"
235.3638 +                        "mber", format_symbol(mpl, sym));
235.3639 +               }
235.3640 +#endif
235.3641 +               delete_symbol(mpl, sym);
235.3642 +            }
235.3643 +            break;
235.3644 +         case O_PLUS:
235.3645 +            /* unary plus */
235.3646 +            value = + eval_numeric(mpl, code->arg.arg.x);
235.3647 +            break;
235.3648 +         case O_MINUS:
235.3649 +            /* unary minus */
235.3650 +            value = - eval_numeric(mpl, code->arg.arg.x);
235.3651 +            break;
235.3652 +         case O_ABS:
235.3653 +            /* absolute value */
235.3654 +            value = fabs(eval_numeric(mpl, code->arg.arg.x));
235.3655 +            break;
235.3656 +         case O_CEIL:
235.3657 +            /* round upward ("ceiling of x") */
235.3658 +            value = ceil(eval_numeric(mpl, code->arg.arg.x));
235.3659 +            break;
235.3660 +         case O_FLOOR:
235.3661 +            /* round downward ("floor of x") */
235.3662 +            value = floor(eval_numeric(mpl, code->arg.arg.x));
235.3663 +            break;
235.3664 +         case O_EXP:
235.3665 +            /* base-e exponential */
235.3666 +            value = fp_exp(mpl, eval_numeric(mpl, code->arg.arg.x));
235.3667 +            break;
235.3668 +         case O_LOG:
235.3669 +            /* natural logarithm */
235.3670 +            value = fp_log(mpl, eval_numeric(mpl, code->arg.arg.x));
235.3671 +            break;
235.3672 +         case O_LOG10:
235.3673 +            /* common (decimal) logarithm */
235.3674 +            value = fp_log10(mpl, eval_numeric(mpl, code->arg.arg.x));
235.3675 +            break;
235.3676 +         case O_SQRT:
235.3677 +            /* square root */
235.3678 +            value = fp_sqrt(mpl, eval_numeric(mpl, code->arg.arg.x));
235.3679 +            break;
235.3680 +         case O_SIN:
235.3681 +            /* trigonometric sine */
235.3682 +            value = fp_sin(mpl, eval_numeric(mpl, code->arg.arg.x));
235.3683 +            break;
235.3684 +         case O_COS:
235.3685 +            /* trigonometric cosine */
235.3686 +            value = fp_cos(mpl, eval_numeric(mpl, code->arg.arg.x));
235.3687 +            break;
235.3688 +         case O_ATAN:
235.3689 +            /* trigonometric arctangent (one argument) */
235.3690 +            value = fp_atan(mpl, eval_numeric(mpl, code->arg.arg.x));
235.3691 +            break;
235.3692 +         case O_ATAN2:
235.3693 +            /* trigonometric arctangent (two arguments) */
235.3694 +            value = fp_atan2(mpl,
235.3695 +               eval_numeric(mpl, code->arg.arg.x),
235.3696 +               eval_numeric(mpl, code->arg.arg.y));
235.3697 +            break;
235.3698 +         case O_ROUND:
235.3699 +            /* round to nearest integer */
235.3700 +            value = fp_round(mpl,
235.3701 +               eval_numeric(mpl, code->arg.arg.x), 0.0);
235.3702 +            break;
235.3703 +         case O_ROUND2:
235.3704 +            /* round to n fractional digits */
235.3705 +            value = fp_round(mpl,
235.3706 +               eval_numeric(mpl, code->arg.arg.x),
235.3707 +               eval_numeric(mpl, code->arg.arg.y));
235.3708 +            break;
235.3709 +         case O_TRUNC:
235.3710 +            /* truncate to nearest integer */
235.3711 +            value = fp_trunc(mpl,
235.3712 +               eval_numeric(mpl, code->arg.arg.x), 0.0);
235.3713 +            break;
235.3714 +         case O_TRUNC2:
235.3715 +            /* truncate to n fractional digits */
235.3716 +            value = fp_trunc(mpl,
235.3717 +               eval_numeric(mpl, code->arg.arg.x),
235.3718 +               eval_numeric(mpl, code->arg.arg.y));
235.3719 +            break;
235.3720 +         case O_ADD:
235.3721 +            /* addition */
235.3722 +            value = fp_add(mpl,
235.3723 +               eval_numeric(mpl, code->arg.arg.x),
235.3724 +               eval_numeric(mpl, code->arg.arg.y));
235.3725 +            break;
235.3726 +         case O_SUB:
235.3727 +            /* subtraction */
235.3728 +            value = fp_sub(mpl,
235.3729 +               eval_numeric(mpl, code->arg.arg.x),
235.3730 +               eval_numeric(mpl, code->arg.arg.y));
235.3731 +            break;
235.3732 +         case O_LESS:
235.3733 +            /* non-negative subtraction */
235.3734 +            value = fp_less(mpl,
235.3735 +               eval_numeric(mpl, code->arg.arg.x),
235.3736 +               eval_numeric(mpl, code->arg.arg.y));
235.3737 +            break;
235.3738 +         case O_MUL:
235.3739 +            /* multiplication */
235.3740 +            value = fp_mul(mpl,
235.3741 +               eval_numeric(mpl, code->arg.arg.x),
235.3742 +               eval_numeric(mpl, code->arg.arg.y));
235.3743 +            break;
235.3744 +         case O_DIV:
235.3745 +            /* division */
235.3746 +            value = fp_div(mpl,
235.3747 +               eval_numeric(mpl, code->arg.arg.x),
235.3748 +               eval_numeric(mpl, code->arg.arg.y));
235.3749 +            break;
235.3750 +         case O_IDIV:
235.3751 +            /* quotient of exact division */
235.3752 +            value = fp_idiv(mpl,
235.3753 +               eval_numeric(mpl, code->arg.arg.x),
235.3754 +               eval_numeric(mpl, code->arg.arg.y));
235.3755 +            break;
235.3756 +         case O_MOD:
235.3757 +            /* remainder of exact division */
235.3758 +            value = fp_mod(mpl,
235.3759 +               eval_numeric(mpl, code->arg.arg.x),
235.3760 +               eval_numeric(mpl, code->arg.arg.y));
235.3761 +            break;
235.3762 +         case O_POWER:
235.3763 +            /* exponentiation (raise to power) */
235.3764 +            value = fp_power(mpl,
235.3765 +               eval_numeric(mpl, code->arg.arg.x),
235.3766 +               eval_numeric(mpl, code->arg.arg.y));
235.3767 +            break;
235.3768 +         case O_UNIFORM:
235.3769 +            /* pseudo-random in [a, b) */
235.3770 +            value = fp_uniform(mpl,
235.3771 +               eval_numeric(mpl, code->arg.arg.x),
235.3772 +               eval_numeric(mpl, code->arg.arg.y));
235.3773 +            break;
235.3774 +         case O_NORMAL:
235.3775 +            /* gaussian random, given mu and sigma */
235.3776 +            value = fp_normal(mpl,
235.3777 +               eval_numeric(mpl, code->arg.arg.x),
235.3778 +               eval_numeric(mpl, code->arg.arg.y));
235.3779 +            break;
235.3780 +         case O_CARD:
235.3781 +            {  ELEMSET *set;
235.3782 +               set = eval_elemset(mpl, code->arg.arg.x);
235.3783 +               value = set->size;
235.3784 +               delete_array(mpl, set);
235.3785 +            }
235.3786 +            break;
235.3787 +         case O_LENGTH:
235.3788 +            {  SYMBOL *sym;
235.3789 +               char str[MAX_LENGTH+1];
235.3790 +               sym = eval_symbolic(mpl, code->arg.arg.x);
235.3791 +               if (sym->str == NULL)
235.3792 +                  sprintf(str, "%.*g", DBL_DIG, sym->num);
235.3793 +               else
235.3794 +                  fetch_string(mpl, sym->str, str);
235.3795 +               delete_symbol(mpl, sym);
235.3796 +               value = strlen(str);
235.3797 +            }
235.3798 +            break;
235.3799 +         case O_STR2TIME:
235.3800 +            {  SYMBOL *sym;
235.3801 +               char str[MAX_LENGTH+1], fmt[MAX_LENGTH+1];
235.3802 +               sym = eval_symbolic(mpl, code->arg.arg.x);
235.3803 +               if (sym->str == NULL)
235.3804 +                  sprintf(str, "%.*g", DBL_DIG, sym->num);
235.3805 +               else
235.3806 +                  fetch_string(mpl, sym->str, str);
235.3807 +               delete_symbol(mpl, sym);
235.3808 +               sym = eval_symbolic(mpl, code->arg.arg.y);
235.3809 +               if (sym->str == NULL)
235.3810 +                  sprintf(fmt, "%.*g", DBL_DIG, sym->num);
235.3811 +               else
235.3812 +                  fetch_string(mpl, sym->str, fmt);
235.3813 +               delete_symbol(mpl, sym);
235.3814 +               value = fn_str2time(mpl, str, fmt);
235.3815 +            }
235.3816 +            break;
235.3817 +         case O_FORK:
235.3818 +            /* if-then-else */
235.3819 +            if (eval_logical(mpl, code->arg.arg.x))
235.3820 +               value = eval_numeric(mpl, code->arg.arg.y);
235.3821 +            else if (code->arg.arg.z == NULL)
235.3822 +               value = 0.0;
235.3823 +            else
235.3824 +               value = eval_numeric(mpl, code->arg.arg.z);
235.3825 +            break;
235.3826 +         case O_MIN:
235.3827 +            /* minimal value (n-ary) */
235.3828 +            {  ARG_LIST *e;
235.3829 +               double temp;
235.3830 +               value = +DBL_MAX;
235.3831 +               for (e = code->arg.list; e != NULL; e = e->next)
235.3832 +               {  temp = eval_numeric(mpl, e->x);
235.3833 +                  if (value > temp) value = temp;
235.3834 +               }
235.3835 +            }
235.3836 +            break;
235.3837 +         case O_MAX:
235.3838 +            /* maximal value (n-ary) */
235.3839 +            {  ARG_LIST *e;
235.3840 +               double temp;
235.3841 +               value = -DBL_MAX;
235.3842 +               for (e = code->arg.list; e != NULL; e = e->next)
235.3843 +               {  temp = eval_numeric(mpl, e->x);
235.3844 +                  if (value < temp) value = temp;
235.3845 +               }
235.3846 +            }
235.3847 +            break;
235.3848 +         case O_SUM:
235.3849 +            /* summation over domain */
235.3850 +            {  struct iter_num_info _info, *info = &_info;
235.3851 +               info->code = code;
235.3852 +               info->value = 0.0;
235.3853 +               loop_within_domain(mpl, code->arg.loop.domain, info,
235.3854 +                  iter_num_func);
235.3855 +               value = info->value;
235.3856 +            }
235.3857 +            break;
235.3858 +         case O_PROD:
235.3859 +            /* multiplication over domain */
235.3860 +            {  struct iter_num_info _info, *info = &_info;
235.3861 +               info->code = code;
235.3862 +               info->value = 1.0;
235.3863 +               loop_within_domain(mpl, code->arg.loop.domain, info,
235.3864 +                  iter_num_func);
235.3865 +               value = info->value;
235.3866 +            }
235.3867 +            break;
235.3868 +         case O_MINIMUM:
235.3869 +            /* minimum over domain */
235.3870 +            {  struct iter_num_info _info, *info = &_info;
235.3871 +               info->code = code;
235.3872 +               info->value = +DBL_MAX;
235.3873 +               loop_within_domain(mpl, code->arg.loop.domain, info,
235.3874 +                  iter_num_func);
235.3875 +               if (info->value == +DBL_MAX)
235.3876 +                  error(mpl, "min{} over empty set; result undefined");
235.3877 +               value = info->value;
235.3878 +            }
235.3879 +            break;
235.3880 +         case O_MAXIMUM:
235.3881 +            /* maximum over domain */
235.3882 +            {  struct iter_num_info _info, *info = &_info;
235.3883 +               info->code = code;
235.3884 +               info->value = -DBL_MAX;
235.3885 +               loop_within_domain(mpl, code->arg.loop.domain, info,
235.3886 +                  iter_num_func);
235.3887 +               if (info->value == -DBL_MAX)
235.3888 +                  error(mpl, "max{} over empty set; result undefined");
235.3889 +               value = info->value;
235.3890 +            }
235.3891 +            break;
235.3892 +         default:
235.3893 +            xassert(code != code);
235.3894 +      }
235.3895 +      /* save resultant value */
235.3896 +      xassert(!code->valid);
235.3897 +      code->valid = 1;
235.3898 +      code->value.num = value;
235.3899 +done: return value;
235.3900 +}
235.3901 +
235.3902 +/*----------------------------------------------------------------------
235.3903 +-- eval_symbolic - evaluate pseudo-code to determine symbolic value.
235.3904 +--
235.3905 +-- This routine evaluates specified pseudo-code to determine resultant
235.3906 +-- symbolic value, which is returned on exit. */
235.3907 +
235.3908 +SYMBOL *eval_symbolic(MPL *mpl, CODE *code)
235.3909 +{     SYMBOL *value;
235.3910 +      xassert(code != NULL);
235.3911 +      xassert(code->type == A_SYMBOLIC);
235.3912 +      xassert(code->dim == 0);
235.3913 +      /* if the operation has a side effect, invalidate and delete the
235.3914 +         resultant value */
235.3915 +      if (code->vflag && code->valid)
235.3916 +      {  code->valid = 0;
235.3917 +         delete_value(mpl, code->type, &code->value);
235.3918 +      }
235.3919 +      /* if resultant value is valid, no evaluation is needed */
235.3920 +      if (code->valid)
235.3921 +      {  value = copy_symbol(mpl, code->value.sym);
235.3922 +         goto done;
235.3923 +      }
235.3924 +      /* evaluate pseudo-code recursively */
235.3925 +      switch (code->op)
235.3926 +      {  case O_STRING:
235.3927 +            /* take character string */
235.3928 +            value = create_symbol_str(mpl, create_string(mpl,
235.3929 +               code->arg.str));
235.3930 +            break;
235.3931 +         case O_INDEX:
235.3932 +            /* take dummy index */
235.3933 +            xassert(code->arg.index.slot->value != NULL);
235.3934 +            value = copy_symbol(mpl, code->arg.index.slot->value);
235.3935 +            break;
235.3936 +         case O_MEMSYM:
235.3937 +            /* take member of symbolic parameter */
235.3938 +            {  TUPLE *tuple;
235.3939 +               ARG_LIST *e;
235.3940 +               tuple = create_tuple(mpl);
235.3941 +               for (e = code->arg.par.list; e != NULL; e = e->next)
235.3942 +                  tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
235.3943 +                     e->x));
235.3944 +               value = eval_member_sym(mpl, code->arg.par.par, tuple);
235.3945 +               delete_tuple(mpl, tuple);
235.3946 +            }
235.3947 +            break;
235.3948 +         case O_CVTSYM:
235.3949 +            /* conversion to symbolic */
235.3950 +            value = create_symbol_num(mpl, eval_numeric(mpl,
235.3951 +               code->arg.arg.x));
235.3952 +            break;
235.3953 +         case O_CONCAT:
235.3954 +            /* concatenation */
235.3955 +            value = concat_symbols(mpl,
235.3956 +               eval_symbolic(mpl, code->arg.arg.x),
235.3957 +               eval_symbolic(mpl, code->arg.arg.y));
235.3958 +            break;
235.3959 +         case O_FORK:
235.3960 +            /* if-then-else */
235.3961 +            if (eval_logical(mpl, code->arg.arg.x))
235.3962 +               value = eval_symbolic(mpl, code->arg.arg.y);
235.3963 +            else if (code->arg.arg.z == NULL)
235.3964 +               value = create_symbol_num(mpl, 0.0);
235.3965 +            else
235.3966 +               value = eval_symbolic(mpl, code->arg.arg.z);
235.3967 +            break;
235.3968 +         case O_SUBSTR:
235.3969 +         case O_SUBSTR3:
235.3970 +            {  double pos, len;
235.3971 +               char str[MAX_LENGTH+1];
235.3972 +               value = eval_symbolic(mpl, code->arg.arg.x);
235.3973 +               if (value->str == NULL)
235.3974 +                  sprintf(str, "%.*g", DBL_DIG, value->num);
235.3975 +               else
235.3976 +                  fetch_string(mpl, value->str, str);
235.3977 +               delete_symbol(mpl, value);
235.3978 +               if (code->op == O_SUBSTR)
235.3979 +               {  pos = eval_numeric(mpl, code->arg.arg.y);
235.3980 +                  if (pos != floor(pos))
235.3981 +                     error(mpl, "substr('...', %.*g); non-integer secon"
235.3982 +                        "d argument", DBL_DIG, pos);
235.3983 +                  if (pos < 1 || pos > strlen(str) + 1)
235.3984 +                     error(mpl, "substr('...', %.*g); substring out of "
235.3985 +                        "range", DBL_DIG, pos);
235.3986 +               }
235.3987 +               else
235.3988 +               {  pos = eval_numeric(mpl, code->arg.arg.y);
235.3989 +                  len = eval_numeric(mpl, code->arg.arg.z);
235.3990 +                  if (pos != floor(pos) || len != floor(len))
235.3991 +                     error(mpl, "substr('...', %.*g, %.*g); non-integer"
235.3992 +                        " second and/or third argument", DBL_DIG, pos,
235.3993 +                        DBL_DIG, len);
235.3994 +                  if (pos < 1 || len < 0 || pos + len > strlen(str) + 1)
235.3995 +                     error(mpl, "substr('...', %.*g, %.*g); substring o"
235.3996 +                        "ut of range", DBL_DIG, pos, DBL_DIG, len);
235.3997 +                  str[(int)pos + (int)len - 1] = '\0';
235.3998 +               }
235.3999 +               value = create_symbol_str(mpl, create_string(mpl, str +
235.4000 +                  (int)pos - 1));
235.4001 +            }
235.4002 +            break;
235.4003 +         case O_TIME2STR:
235.4004 +            {  double num;
235.4005 +               SYMBOL *sym;
235.4006 +               char str[MAX_LENGTH+1], fmt[MAX_LENGTH+1];
235.4007 +               num = eval_numeric(mpl, code->arg.arg.x);
235.4008 +               sym = eval_symbolic(mpl, code->arg.arg.y);
235.4009 +               if (sym->str == NULL)
235.4010 +                  sprintf(fmt, "%.*g", DBL_DIG, sym->num);
235.4011 +               else
235.4012 +                  fetch_string(mpl, sym->str, fmt);
235.4013 +               delete_symbol(mpl, sym);
235.4014 +               fn_time2str(mpl, str, num, fmt);
235.4015 +               value = create_symbol_str(mpl, create_string(mpl, str));
235.4016 +            }
235.4017 +            break;
235.4018 +         default:
235.4019 +            xassert(code != code);
235.4020 +      }
235.4021 +      /* save resultant value */
235.4022 +      xassert(!code->valid);
235.4023 +      code->valid = 1;
235.4024 +      code->value.sym = copy_symbol(mpl, value);
235.4025 +done: return value;
235.4026 +}
235.4027 +
235.4028 +/*----------------------------------------------------------------------
235.4029 +-- eval_logical - evaluate pseudo-code to determine logical value.
235.4030 +--
235.4031 +-- This routine evaluates specified pseudo-code to determine resultant
235.4032 +-- logical value, which is returned on exit. */
235.4033 +
235.4034 +struct iter_log_info
235.4035 +{     /* working info used by the routine iter_log_func */
235.4036 +      CODE *code;
235.4037 +      /* pseudo-code for iterated operation to be performed */
235.4038 +      int value;
235.4039 +      /* resultant value */
235.4040 +};
235.4041 +
235.4042 +static int iter_log_func(MPL *mpl, void *_info)
235.4043 +{     /* this is auxiliary routine used to perform iterated operation
235.4044 +         on logical "integrand" within domain scope */
235.4045 +      struct iter_log_info *info = _info;
235.4046 +      int ret = 0;
235.4047 +      switch (info->code->op)
235.4048 +      {  case O_FORALL:
235.4049 +            /* conjunction over domain */
235.4050 +            info->value &= eval_logical(mpl, info->code->arg.loop.x);
235.4051 +            if (!info->value) ret = 1;
235.4052 +            break;
235.4053 +         case O_EXISTS:
235.4054 +            /* disjunction over domain */
235.4055 +            info->value |= eval_logical(mpl, info->code->arg.loop.x);
235.4056 +            if (info->value) ret = 1;
235.4057 +            break;
235.4058 +         default:
235.4059 +            xassert(info != info);
235.4060 +      }
235.4061 +      return ret;
235.4062 +}
235.4063 +
235.4064 +int eval_logical(MPL *mpl, CODE *code)
235.4065 +{     int value;
235.4066 +      xassert(code->type == A_LOGICAL);
235.4067 +      xassert(code->dim == 0);
235.4068 +      /* if the operation has a side effect, invalidate and delete the
235.4069 +         resultant value */
235.4070 +      if (code->vflag && code->valid)
235.4071 +      {  code->valid = 0;
235.4072 +         delete_value(mpl, code->type, &code->value);
235.4073 +      }
235.4074 +      /* if resultant value is valid, no evaluation is needed */
235.4075 +      if (code->valid)
235.4076 +      {  value = code->value.bit;
235.4077 +         goto done;
235.4078 +      }
235.4079 +      /* evaluate pseudo-code recursively */
235.4080 +      switch (code->op)
235.4081 +      {  case O_CVTLOG:
235.4082 +            /* conversion to logical */
235.4083 +            value = (eval_numeric(mpl, code->arg.arg.x) != 0.0);
235.4084 +            break;
235.4085 +         case O_NOT:
235.4086 +            /* negation (logical "not") */
235.4087 +            value = !eval_logical(mpl, code->arg.arg.x);
235.4088 +            break;
235.4089 +         case O_LT:
235.4090 +            /* comparison on 'less than' */
235.4091 +#if 0 /* 02/VIII-2008 */
235.4092 +            value = (eval_numeric(mpl, code->arg.arg.x) <
235.4093 +                     eval_numeric(mpl, code->arg.arg.y));
235.4094 +#else
235.4095 +            xassert(code->arg.arg.x != NULL);
235.4096 +            if (code->arg.arg.x->type == A_NUMERIC)
235.4097 +               value = (eval_numeric(mpl, code->arg.arg.x) <
235.4098 +                        eval_numeric(mpl, code->arg.arg.y));
235.4099 +            else
235.4100 +            {  SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
235.4101 +               SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
235.4102 +               value = (compare_symbols(mpl, sym1, sym2) < 0);
235.4103 +               delete_symbol(mpl, sym1);
235.4104 +               delete_symbol(mpl, sym2);
235.4105 +            }
235.4106 +#endif
235.4107 +            break;
235.4108 +         case O_LE:
235.4109 +            /* comparison on 'not greater than' */
235.4110 +#if 0 /* 02/VIII-2008 */
235.4111 +            value = (eval_numeric(mpl, code->arg.arg.x) <=
235.4112 +                     eval_numeric(mpl, code->arg.arg.y));
235.4113 +#else
235.4114 +            xassert(code->arg.arg.x != NULL);
235.4115 +            if (code->arg.arg.x->type == A_NUMERIC)
235.4116 +               value = (eval_numeric(mpl, code->arg.arg.x) <=
235.4117 +                        eval_numeric(mpl, code->arg.arg.y));
235.4118 +            else
235.4119 +            {  SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
235.4120 +               SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
235.4121 +               value = (compare_symbols(mpl, sym1, sym2) <= 0);
235.4122 +               delete_symbol(mpl, sym1);
235.4123 +               delete_symbol(mpl, sym2);
235.4124 +            }
235.4125 +#endif
235.4126 +            break;
235.4127 +         case O_EQ:
235.4128 +            /* comparison on 'equal to' */
235.4129 +            xassert(code->arg.arg.x != NULL);
235.4130 +            if (code->arg.arg.x->type == A_NUMERIC)
235.4131 +               value = (eval_numeric(mpl, code->arg.arg.x) ==
235.4132 +                        eval_numeric(mpl, code->arg.arg.y));
235.4133 +            else
235.4134 +            {  SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
235.4135 +               SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
235.4136 +               value = (compare_symbols(mpl, sym1, sym2) == 0);
235.4137 +               delete_symbol(mpl, sym1);
235.4138 +               delete_symbol(mpl, sym2);
235.4139 +            }
235.4140 +            break;
235.4141 +         case O_GE:
235.4142 +            /* comparison on 'not less than' */
235.4143 +#if 0 /* 02/VIII-2008 */
235.4144 +            value = (eval_numeric(mpl, code->arg.arg.x) >=
235.4145 +                     eval_numeric(mpl, code->arg.arg.y));
235.4146 +#else
235.4147 +            xassert(code->arg.arg.x != NULL);
235.4148 +            if (code->arg.arg.x->type == A_NUMERIC)
235.4149 +               value = (eval_numeric(mpl, code->arg.arg.x) >=
235.4150 +                        eval_numeric(mpl, code->arg.arg.y));
235.4151 +            else
235.4152 +            {  SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
235.4153 +               SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
235.4154 +               value = (compare_symbols(mpl, sym1, sym2) >= 0);
235.4155 +               delete_symbol(mpl, sym1);
235.4156 +               delete_symbol(mpl, sym2);
235.4157 +            }
235.4158 +#endif
235.4159 +            break;
235.4160 +         case O_GT:
235.4161 +            /* comparison on 'greater than' */
235.4162 +#if 0 /* 02/VIII-2008 */
235.4163 +            value = (eval_numeric(mpl, code->arg.arg.x) >
235.4164 +                     eval_numeric(mpl, code->arg.arg.y));
235.4165 +#else
235.4166 +            xassert(code->arg.arg.x != NULL);
235.4167 +            if (code->arg.arg.x->type == A_NUMERIC)
235.4168 +               value = (eval_numeric(mpl, code->arg.arg.x) >
235.4169 +                        eval_numeric(mpl, code->arg.arg.y));
235.4170 +            else
235.4171 +            {  SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
235.4172 +               SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
235.4173 +               value = (compare_symbols(mpl, sym1, sym2) > 0);
235.4174 +               delete_symbol(mpl, sym1);
235.4175 +               delete_symbol(mpl, sym2);
235.4176 +            }
235.4177 +#endif
235.4178 +            break;
235.4179 +         case O_NE:
235.4180 +            /* comparison on 'not equal to' */
235.4181 +            xassert(code->arg.arg.x != NULL);
235.4182 +            if (code->arg.arg.x->type == A_NUMERIC)
235.4183 +               value = (eval_numeric(mpl, code->arg.arg.x) !=
235.4184 +                        eval_numeric(mpl, code->arg.arg.y));
235.4185 +            else
235.4186 +            {  SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
235.4187 +               SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
235.4188 +               value = (compare_symbols(mpl, sym1, sym2) != 0);
235.4189 +               delete_symbol(mpl, sym1);
235.4190 +               delete_symbol(mpl, sym2);
235.4191 +            }
235.4192 +            break;
235.4193 +         case O_AND:
235.4194 +            /* conjunction (logical "and") */
235.4195 +            value = eval_logical(mpl, code->arg.arg.x) &&
235.4196 +                    eval_logical(mpl, code->arg.arg.y);
235.4197 +            break;
235.4198 +         case O_OR:
235.4199 +            /* disjunction (logical "or") */
235.4200 +            value = eval_logical(mpl, code->arg.arg.x) ||
235.4201 +                    eval_logical(mpl, code->arg.arg.y);
235.4202 +            break;
235.4203 +         case O_IN:
235.4204 +            /* test on 'x in Y' */
235.4205 +            {  TUPLE *tuple;
235.4206 +               tuple = eval_tuple(mpl, code->arg.arg.x);
235.4207 +               value = is_member(mpl, code->arg.arg.y, tuple);
235.4208 +               delete_tuple(mpl, tuple);
235.4209 +            }
235.4210 +            break;
235.4211 +         case O_NOTIN:
235.4212 +            /* test on 'x not in Y' */
235.4213 +            {  TUPLE *tuple;
235.4214 +               tuple = eval_tuple(mpl, code->arg.arg.x);
235.4215 +               value = !is_member(mpl, code->arg.arg.y, tuple);
235.4216 +               delete_tuple(mpl, tuple);
235.4217 +            }
235.4218 +            break;
235.4219 +         case O_WITHIN:
235.4220 +            /* test on 'X within Y' */
235.4221 +            {  ELEMSET *set;
235.4222 +               MEMBER *memb;
235.4223 +               set = eval_elemset(mpl, code->arg.arg.x);
235.4224 +               value = 1;
235.4225 +               for (memb = set->head; memb != NULL; memb = memb->next)
235.4226 +               {  if (!is_member(mpl, code->arg.arg.y, memb->tuple))
235.4227 +                  {  value = 0;
235.4228 +                     break;
235.4229 +                  }
235.4230 +               }
235.4231 +               delete_elemset(mpl, set);
235.4232 +            }
235.4233 +            break;
235.4234 +         case O_NOTWITHIN:
235.4235 +            /* test on 'X not within Y' */
235.4236 +            {  ELEMSET *set;
235.4237 +               MEMBER *memb;
235.4238 +               set = eval_elemset(mpl, code->arg.arg.x);
235.4239 +               value = 1;
235.4240 +               for (memb = set->head; memb != NULL; memb = memb->next)
235.4241 +               {  if (is_member(mpl, code->arg.arg.y, memb->tuple))
235.4242 +                  {  value = 0;
235.4243 +                     break;
235.4244 +                  }
235.4245 +               }
235.4246 +               delete_elemset(mpl, set);
235.4247 +            }
235.4248 +            break;
235.4249 +         case O_FORALL:
235.4250 +            /* conjunction (A-quantification) */
235.4251 +            {  struct iter_log_info _info, *info = &_info;
235.4252 +               info->code = code;
235.4253 +               info->value = 1;
235.4254 +               loop_within_domain(mpl, code->arg.loop.domain, info,
235.4255 +                  iter_log_func);
235.4256 +               value = info->value;
235.4257 +            }
235.4258 +            break;
235.4259 +         case O_EXISTS:
235.4260 +            /* disjunction (E-quantification) */
235.4261 +            {  struct iter_log_info _info, *info = &_info;
235.4262 +               info->code = code;
235.4263 +               info->value = 0;
235.4264 +               loop_within_domain(mpl, code->arg.loop.domain, info,
235.4265 +                  iter_log_func);
235.4266 +               value = info->value;
235.4267 +            }
235.4268 +            break;
235.4269 +         default:
235.4270 +            xassert(code != code);
235.4271 +      }
235.4272 +      /* save resultant value */
235.4273 +      xassert(!code->valid);
235.4274 +      code->valid = 1;
235.4275 +      code->value.bit = value;
235.4276 +done: return value;
235.4277 +}
235.4278 +
235.4279 +/*----------------------------------------------------------------------
235.4280 +-- eval_tuple - evaluate pseudo-code to construct n-tuple.
235.4281 +--
235.4282 +-- This routine evaluates specified pseudo-code to construct resultant
235.4283 +-- n-tuple, which is returned on exit. */
235.4284 +
235.4285 +TUPLE *eval_tuple(MPL *mpl, CODE *code)
235.4286 +{     TUPLE *value;
235.4287 +      xassert(code != NULL);
235.4288 +      xassert(code->type == A_TUPLE);
235.4289 +      xassert(code->dim > 0);
235.4290 +      /* if the operation has a side effect, invalidate and delete the
235.4291 +         resultant value */
235.4292 +      if (code->vflag && code->valid)
235.4293 +      {  code->valid = 0;
235.4294 +         delete_value(mpl, code->type, &code->value);
235.4295 +      }
235.4296 +      /* if resultant value is valid, no evaluation is needed */
235.4297 +      if (code->valid)
235.4298 +      {  value = copy_tuple(mpl, code->value.tuple);
235.4299 +         goto done;
235.4300 +      }
235.4301 +      /* evaluate pseudo-code recursively */
235.4302 +      switch (code->op)
235.4303 +      {  case O_TUPLE:
235.4304 +            /* make n-tuple */
235.4305 +            {  ARG_LIST *e;
235.4306 +               value = create_tuple(mpl);
235.4307 +               for (e = code->arg.list; e != NULL; e = e->next)
235.4308 +                  value = expand_tuple(mpl, value, eval_symbolic(mpl,
235.4309 +                     e->x));
235.4310 +            }
235.4311 +            break;
235.4312 +         case O_CVTTUP:
235.4313 +            /* convert to 1-tuple */
235.4314 +            value = expand_tuple(mpl, create_tuple(mpl),
235.4315 +               eval_symbolic(mpl, code->arg.arg.x));
235.4316 +            break;
235.4317 +         default:
235.4318 +            xassert(code != code);
235.4319 +      }
235.4320 +      /* save resultant value */
235.4321 +      xassert(!code->valid);
235.4322 +      code->valid = 1;
235.4323 +      code->value.tuple = copy_tuple(mpl, value);
235.4324 +done: return value;
235.4325 +}
235.4326 +
235.4327 +/*----------------------------------------------------------------------
235.4328 +-- eval_elemset - evaluate pseudo-code to construct elemental set.
235.4329 +--
235.4330 +-- This routine evaluates specified pseudo-code to construct resultant
235.4331 +-- elemental set, which is returned on exit. */
235.4332 +
235.4333 +struct iter_set_info
235.4334 +{     /* working info used by the routine iter_set_func */
235.4335 +      CODE *code;
235.4336 +      /* pseudo-code for iterated operation to be performed */
235.4337 +      ELEMSET *value;
235.4338 +      /* resultant value */
235.4339 +};
235.4340 +
235.4341 +static int iter_set_func(MPL *mpl, void *_info)
235.4342 +{     /* this is auxiliary routine used to perform iterated operation
235.4343 +         on n-tuple "integrand" within domain scope */
235.4344 +      struct iter_set_info *info = _info;
235.4345 +      TUPLE *tuple;
235.4346 +      switch (info->code->op)
235.4347 +      {  case O_SETOF:
235.4348 +            /* compute next n-tuple and add it to the set; in this case
235.4349 +               duplicate n-tuples are silently ignored */
235.4350 +            tuple = eval_tuple(mpl, info->code->arg.loop.x);
235.4351 +            if (find_tuple(mpl, info->value, tuple) == NULL)
235.4352 +               add_tuple(mpl, info->value, tuple);
235.4353 +            else
235.4354 +               delete_tuple(mpl, tuple);
235.4355 +            break;
235.4356 +         case O_BUILD:
235.4357 +            /* construct next n-tuple using current values assigned to
235.4358 +               *free* dummy indices as its components and add it to the
235.4359 +               set; in this case duplicate n-tuples cannot appear */
235.4360 +            add_tuple(mpl, info->value, get_domain_tuple(mpl,
235.4361 +               info->code->arg.loop.domain));
235.4362 +            break;
235.4363 +         default:
235.4364 +            xassert(info != info);
235.4365 +      }
235.4366 +      return 0;
235.4367 +}
235.4368 +
235.4369 +ELEMSET *eval_elemset(MPL *mpl, CODE *code)
235.4370 +{     ELEMSET *value;
235.4371 +      xassert(code != NULL);
235.4372 +      xassert(code->type == A_ELEMSET);
235.4373 +      xassert(code->dim > 0);
235.4374 +      /* if the operation has a side effect, invalidate and delete the
235.4375 +         resultant value */
235.4376 +      if (code->vflag && code->valid)
235.4377 +      {  code->valid = 0;
235.4378 +         delete_value(mpl, code->type, &code->value);
235.4379 +      }
235.4380 +      /* if resultant value is valid, no evaluation is needed */
235.4381 +      if (code->valid)
235.4382 +      {  value = copy_elemset(mpl, code->value.set);
235.4383 +         goto done;
235.4384 +      }
235.4385 +      /* evaluate pseudo-code recursively */
235.4386 +      switch (code->op)
235.4387 +      {  case O_MEMSET:
235.4388 +            /* take member of set */
235.4389 +            {  TUPLE *tuple;
235.4390 +               ARG_LIST *e;
235.4391 +               tuple = create_tuple(mpl);
235.4392 +               for (e = code->arg.set.list; e != NULL; e = e->next)
235.4393 +                  tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
235.4394 +                     e->x));
235.4395 +               value = copy_elemset(mpl,
235.4396 +                  eval_member_set(mpl, code->arg.set.set, tuple));
235.4397 +               delete_tuple(mpl, tuple);
235.4398 +            }
235.4399 +            break;
235.4400 +         case O_MAKE:
235.4401 +            /* make elemental set of n-tuples */
235.4402 +            {  ARG_LIST *e;
235.4403 +               value = create_elemset(mpl, code->dim);
235.4404 +               for (e = code->arg.list; e != NULL; e = e->next)
235.4405 +                  check_then_add(mpl, value, eval_tuple(mpl, e->x));
235.4406 +            }
235.4407 +            break;
235.4408 +         case O_UNION:
235.4409 +            /* union of two elemental sets */
235.4410 +            value = set_union(mpl,
235.4411 +               eval_elemset(mpl, code->arg.arg.x),
235.4412 +               eval_elemset(mpl, code->arg.arg.y));
235.4413 +            break;
235.4414 +         case O_DIFF:
235.4415 +            /* difference between two elemental sets */
235.4416 +            value = set_diff(mpl,
235.4417 +               eval_elemset(mpl, code->arg.arg.x),
235.4418 +               eval_elemset(mpl, code->arg.arg.y));
235.4419 +            break;
235.4420 +         case O_SYMDIFF:
235.4421 +            /* symmetric difference between two elemental sets */
235.4422 +            value = set_symdiff(mpl,
235.4423 +               eval_elemset(mpl, code->arg.arg.x),
235.4424 +               eval_elemset(mpl, code->arg.arg.y));
235.4425 +            break;
235.4426 +         case O_INTER:
235.4427 +            /* intersection of two elemental sets */
235.4428 +            value = set_inter(mpl,
235.4429 +               eval_elemset(mpl, code->arg.arg.x),
235.4430 +               eval_elemset(mpl, code->arg.arg.y));
235.4431 +            break;
235.4432 +         case O_CROSS:
235.4433 +            /* cross (Cartesian) product of two elemental sets */
235.4434 +            value = set_cross(mpl,
235.4435 +               eval_elemset(mpl, code->arg.arg.x),
235.4436 +               eval_elemset(mpl, code->arg.arg.y));
235.4437 +            break;
235.4438 +         case O_DOTS:
235.4439 +            /* build "arithmetic" elemental set */
235.4440 +            value = create_arelset(mpl,
235.4441 +               eval_numeric(mpl, code->arg.arg.x),
235.4442 +               eval_numeric(mpl, code->arg.arg.y),
235.4443 +               code->arg.arg.z == NULL ? 1.0 : eval_numeric(mpl,
235.4444 +                  code->arg.arg.z));
235.4445 +            break;
235.4446 +         case O_FORK:
235.4447 +            /* if-then-else */
235.4448 +            if (eval_logical(mpl, code->arg.arg.x))
235.4449 +               value = eval_elemset(mpl, code->arg.arg.y);
235.4450 +            else
235.4451 +               value = eval_elemset(mpl, code->arg.arg.z);
235.4452 +            break;
235.4453 +         case O_SETOF:
235.4454 +            /* compute elemental set */
235.4455 +            {  struct iter_set_info _info, *info = &_info;
235.4456 +               info->code = code;
235.4457 +               info->value = create_elemset(mpl, code->dim);
235.4458 +               loop_within_domain(mpl, code->arg.loop.domain, info,
235.4459 +                  iter_set_func);
235.4460 +               value = info->value;
235.4461 +            }
235.4462 +            break;
235.4463 +         case O_BUILD:
235.4464 +            /* build elemental set identical to domain set */
235.4465 +            {  struct iter_set_info _info, *info = &_info;
235.4466 +               info->code = code;
235.4467 +               info->value = create_elemset(mpl, code->dim);
235.4468 +               loop_within_domain(mpl, code->arg.loop.domain, info,
235.4469 +                  iter_set_func);
235.4470 +               value = info->value;
235.4471 +            }
235.4472 +            break;
235.4473 +         default:
235.4474 +            xassert(code != code);
235.4475 +      }
235.4476 +      /* save resultant value */
235.4477 +      xassert(!code->valid);
235.4478 +      code->valid = 1;
235.4479 +      code->value.set = copy_elemset(mpl, value);
235.4480 +done: return value;
235.4481 +}
235.4482 +
235.4483 +/*----------------------------------------------------------------------
235.4484 +-- is_member - check if n-tuple is in set specified by pseudo-code.
235.4485 +--
235.4486 +-- This routine checks if given n-tuple is a member of elemental set
235.4487 +-- specified in the form of pseudo-code (i.e. by expression).
235.4488 +--
235.4489 +-- The n-tuple may have more components that dimension of the elemental
235.4490 +-- set, in which case the extra components are ignored. */
235.4491 +
235.4492 +static void null_func(MPL *mpl, void *info)
235.4493 +{     /* this is dummy routine used to enter the domain scope */
235.4494 +      xassert(mpl == mpl);
235.4495 +      xassert(info == NULL);
235.4496 +      return;
235.4497 +}
235.4498 +
235.4499 +int is_member(MPL *mpl, CODE *code, TUPLE *tuple)
235.4500 +{     int value;
235.4501 +      xassert(code != NULL);
235.4502 +      xassert(code->type == A_ELEMSET);
235.4503 +      xassert(code->dim > 0);
235.4504 +      xassert(tuple != NULL);
235.4505 +      switch (code->op)
235.4506 +      {  case O_MEMSET:
235.4507 +            /* check if given n-tuple is member of elemental set, which
235.4508 +               is assigned to member of model set */
235.4509 +            {  ARG_LIST *e;
235.4510 +               TUPLE *temp;
235.4511 +               ELEMSET *set;
235.4512 +               /* evaluate reference to elemental set */
235.4513 +               temp = create_tuple(mpl);
235.4514 +               for (e = code->arg.set.list; e != NULL; e = e->next)
235.4515 +                  temp = expand_tuple(mpl, temp, eval_symbolic(mpl,
235.4516 +                     e->x));
235.4517 +               set = eval_member_set(mpl, code->arg.set.set, temp);
235.4518 +               delete_tuple(mpl, temp);
235.4519 +               /* check if the n-tuple is contained in the set array */
235.4520 +               temp = build_subtuple(mpl, tuple, set->dim);
235.4521 +               value = (find_tuple(mpl, set, temp) != NULL);
235.4522 +               delete_tuple(mpl, temp);
235.4523 +            }
235.4524 +            break;
235.4525 +         case O_MAKE:
235.4526 +            /* check if given n-tuple is member of literal set */
235.4527 +            {  ARG_LIST *e;
235.4528 +               TUPLE *temp, *that;
235.4529 +               value = 0;
235.4530 +               temp = build_subtuple(mpl, tuple, code->dim);
235.4531 +               for (e = code->arg.list; e != NULL; e = e->next)
235.4532 +               {  that = eval_tuple(mpl, e->x);
235.4533 +                  value = (compare_tuples(mpl, temp, that) == 0);
235.4534 +                  delete_tuple(mpl, that);
235.4535 +                  if (value) break;
235.4536 +               }
235.4537 +               delete_tuple(mpl, temp);
235.4538 +            }
235.4539 +            break;
235.4540 +         case O_UNION:
235.4541 +            value = is_member(mpl, code->arg.arg.x, tuple) ||
235.4542 +                    is_member(mpl, code->arg.arg.y, tuple);
235.4543 +            break;
235.4544 +         case O_DIFF:
235.4545 +            value = is_member(mpl, code->arg.arg.x, tuple) &&
235.4546 +                   !is_member(mpl, code->arg.arg.y, tuple);
235.4547 +            break;
235.4548 +         case O_SYMDIFF:
235.4549 +            {  int in1 = is_member(mpl, code->arg.arg.x, tuple);
235.4550 +               int in2 = is_member(mpl, code->arg.arg.y, tuple);
235.4551 +               value = (in1 && !in2) || (!in1 && in2);
235.4552 +            }
235.4553 +            break;
235.4554 +         case O_INTER:
235.4555 +            value = is_member(mpl, code->arg.arg.x, tuple) &&
235.4556 +                    is_member(mpl, code->arg.arg.y, tuple);
235.4557 +            break;
235.4558 +         case O_CROSS:
235.4559 +            {  int j;
235.4560 +               value = is_member(mpl, code->arg.arg.x, tuple);
235.4561 +               if (value)
235.4562 +               {  for (j = 1; j <= code->arg.arg.x->dim; j++)
235.4563 +                  {  xassert(tuple != NULL);
235.4564 +                     tuple = tuple->next;
235.4565 +                  }
235.4566 +                  value = is_member(mpl, code->arg.arg.y, tuple);
235.4567 +               }
235.4568 +            }
235.4569 +            break;
235.4570 +         case O_DOTS:
235.4571 +            /* check if given 1-tuple is member of "arithmetic" set */
235.4572 +            {  int j;
235.4573 +               double x, t0, tf, dt;
235.4574 +               xassert(code->dim == 1);
235.4575 +               /* compute "parameters" of the "arithmetic" set */
235.4576 +               t0 = eval_numeric(mpl, code->arg.arg.x);
235.4577 +               tf = eval_numeric(mpl, code->arg.arg.y);
235.4578 +               if (code->arg.arg.z == NULL)
235.4579 +                  dt = 1.0;
235.4580 +               else
235.4581 +                  dt = eval_numeric(mpl, code->arg.arg.z);
235.4582 +               /* make sure the parameters are correct */
235.4583 +               arelset_size(mpl, t0, tf, dt);
235.4584 +               /* if component of 1-tuple is symbolic, not numeric, the
235.4585 +                  1-tuple cannot be member of "arithmetic" set */
235.4586 +               xassert(tuple->sym != NULL);
235.4587 +               if (tuple->sym->str != NULL)
235.4588 +               {  value = 0;
235.4589 +                  break;
235.4590 +               }
235.4591 +               /* determine numeric value of the component */
235.4592 +               x = tuple->sym->num;
235.4593 +               /* if the component value is out of the set range, the
235.4594 +                  1-tuple is not in the set */
235.4595 +               if (dt > 0.0 && !(t0 <= x && x <= tf) ||
235.4596 +                   dt < 0.0 && !(tf <= x && x <= t0))
235.4597 +               {  value = 0;
235.4598 +                  break;
235.4599 +               }
235.4600 +               /* estimate ordinal number of the 1-tuple in the set */
235.4601 +               j = (int)(((x - t0) / dt) + 0.5) + 1;
235.4602 +               /* perform the main check */
235.4603 +               value = (arelset_member(mpl, t0, tf, dt, j) == x);
235.4604 +            }
235.4605 +            break;
235.4606 +         case O_FORK:
235.4607 +            /* check if given n-tuple is member of conditional set */
235.4608 +            if (eval_logical(mpl, code->arg.arg.x))
235.4609 +               value = is_member(mpl, code->arg.arg.y, tuple);
235.4610 +            else
235.4611 +               value = is_member(mpl, code->arg.arg.z, tuple);
235.4612 +            break;
235.4613 +         case O_SETOF:
235.4614 +            /* check if given n-tuple is member of computed set */
235.4615 +            /* it is not clear how to efficiently perform the check not
235.4616 +               computing the entire elemental set :+( */
235.4617 +            error(mpl, "implementation restriction; in/within setof{} n"
235.4618 +               "ot allowed");
235.4619 +            break;
235.4620 +         case O_BUILD:
235.4621 +            /* check if given n-tuple is member of domain set */
235.4622 +            {  TUPLE *temp;
235.4623 +               temp = build_subtuple(mpl, tuple, code->dim);
235.4624 +               /* try to enter the domain scope; if it is successful,
235.4625 +                  the n-tuple is in the domain set */
235.4626 +               value = (eval_within_domain(mpl, code->arg.loop.domain,
235.4627 +                  temp, NULL, null_func) == 0);
235.4628 +               delete_tuple(mpl, temp);
235.4629 +            }
235.4630 +            break;
235.4631 +         default:
235.4632 +            xassert(code != code);
235.4633 +      }
235.4634 +      return value;
235.4635 +}
235.4636 +
235.4637 +/*----------------------------------------------------------------------
235.4638 +-- eval_formula - evaluate pseudo-code to construct linear form.
235.4639 +--
235.4640 +-- This routine evaluates specified pseudo-code to construct resultant
235.4641 +-- linear form, which is returned on exit. */
235.4642 +
235.4643 +struct iter_form_info
235.4644 +{     /* working info used by the routine iter_form_func */
235.4645 +      CODE *code;
235.4646 +      /* pseudo-code for iterated operation to be performed */
235.4647 +      FORMULA *value;
235.4648 +      /* resultant value */
235.4649 +      FORMULA *tail;
235.4650 +      /* pointer to the last term */
235.4651 +};
235.4652 +
235.4653 +static int iter_form_func(MPL *mpl, void *_info)
235.4654 +{     /* this is auxiliary routine used to perform iterated operation
235.4655 +         on linear form "integrand" within domain scope */
235.4656 +      struct iter_form_info *info = _info;
235.4657 +      switch (info->code->op)
235.4658 +      {  case O_SUM:
235.4659 +            /* summation over domain */
235.4660 +#if 0
235.4661 +            info->value =
235.4662 +               linear_comb(mpl,
235.4663 +                  +1.0, info->value,
235.4664 +                  +1.0, eval_formula(mpl, info->code->arg.loop.x));
235.4665 +#else
235.4666 +            /* the routine linear_comb needs to look through all terms
235.4667 +               of both linear forms to reduce identical terms, so using
235.4668 +               it here is not a good idea (for example, evaluation of
235.4669 +               sum{i in 1..n} x[i] required quadratic time); the better
235.4670 +               idea is to gather all terms of the integrand in one list
235.4671 +               and reduce identical terms only once after all terms of
235.4672 +               the resultant linear form have been evaluated */
235.4673 +            {  FORMULA *form, *term;
235.4674 +               form = eval_formula(mpl, info->code->arg.loop.x);
235.4675 +               if (info->value == NULL)
235.4676 +               {  xassert(info->tail == NULL);
235.4677 +                  info->value = form;
235.4678 +               }
235.4679 +               else
235.4680 +               {  xassert(info->tail != NULL);
235.4681 +                  info->tail->next = form;
235.4682 +               }
235.4683 +               for (term = form; term != NULL; term = term->next)
235.4684 +                  info->tail = term;
235.4685 +            }
235.4686 +#endif
235.4687 +            break;
235.4688 +         default:
235.4689 +            xassert(info != info);
235.4690 +      }
235.4691 +      return 0;
235.4692 +}
235.4693 +
235.4694 +FORMULA *eval_formula(MPL *mpl, CODE *code)
235.4695 +{     FORMULA *value;
235.4696 +      xassert(code != NULL);
235.4697 +      xassert(code->type == A_FORMULA);
235.4698 +      xassert(code->dim == 0);
235.4699 +      /* if the operation has a side effect, invalidate and delete the
235.4700 +         resultant value */
235.4701 +      if (code->vflag && code->valid)
235.4702 +      {  code->valid = 0;
235.4703 +         delete_value(mpl, code->type, &code->value);
235.4704 +      }
235.4705 +      /* if resultant value is valid, no evaluation is needed */
235.4706 +      if (code->valid)
235.4707 +      {  value = copy_formula(mpl, code->value.form);
235.4708 +         goto done;
235.4709 +      }
235.4710 +      /* evaluate pseudo-code recursively */
235.4711 +      switch (code->op)
235.4712 +      {  case O_MEMVAR:
235.4713 +            /* take member of variable */
235.4714 +            {  TUPLE *tuple;
235.4715 +               ARG_LIST *e;
235.4716 +               tuple = create_tuple(mpl);
235.4717 +               for (e = code->arg.var.list; e != NULL; e = e->next)
235.4718 +                  tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
235.4719 +                     e->x));
235.4720 +#if 1 /* 15/V-2010 */
235.4721 +               xassert(code->arg.var.suff == DOT_NONE);
235.4722 +#endif
235.4723 +               value = single_variable(mpl,
235.4724 +                  eval_member_var(mpl, code->arg.var.var, tuple));
235.4725 +               delete_tuple(mpl, tuple);
235.4726 +            }
235.4727 +            break;
235.4728 +         case O_CVTLFM:
235.4729 +            /* convert to linear form */
235.4730 +            value = constant_term(mpl, eval_numeric(mpl,
235.4731 +               code->arg.arg.x));
235.4732 +            break;
235.4733 +         case O_PLUS:
235.4734 +            /* unary plus */
235.4735 +            value = linear_comb(mpl,
235.4736 +                0.0, constant_term(mpl, 0.0),
235.4737 +               +1.0, eval_formula(mpl, code->arg.arg.x));
235.4738 +            break;
235.4739 +         case O_MINUS:
235.4740 +            /* unary minus */
235.4741 +            value = linear_comb(mpl,
235.4742 +                0.0, constant_term(mpl, 0.0),
235.4743 +               -1.0, eval_formula(mpl, code->arg.arg.x));
235.4744 +            break;
235.4745 +         case O_ADD:
235.4746 +            /* addition */
235.4747 +            value = linear_comb(mpl,
235.4748 +               +1.0, eval_formula(mpl, code->arg.arg.x),
235.4749 +               +1.0, eval_formula(mpl, code->arg.arg.y));
235.4750 +            break;
235.4751 +         case O_SUB:
235.4752 +            /* subtraction */
235.4753 +            value = linear_comb(mpl,
235.4754 +               +1.0, eval_formula(mpl, code->arg.arg.x),
235.4755 +               -1.0, eval_formula(mpl, code->arg.arg.y));
235.4756 +            break;
235.4757 +         case O_MUL:
235.4758 +            /* multiplication */
235.4759 +            xassert(code->arg.arg.x != NULL);
235.4760 +            xassert(code->arg.arg.y != NULL);
235.4761 +            if (code->arg.arg.x->type == A_NUMERIC)
235.4762 +            {  xassert(code->arg.arg.y->type == A_FORMULA);
235.4763 +               value = linear_comb(mpl,
235.4764 +                  eval_numeric(mpl, code->arg.arg.x),
235.4765 +                  eval_formula(mpl, code->arg.arg.y),
235.4766 +                  0.0, constant_term(mpl, 0.0));
235.4767 +            }
235.4768 +            else
235.4769 +            {  xassert(code->arg.arg.x->type == A_FORMULA);
235.4770 +               xassert(code->arg.arg.y->type == A_NUMERIC);
235.4771 +               value = linear_comb(mpl,
235.4772 +                  eval_numeric(mpl, code->arg.arg.y),
235.4773 +                  eval_formula(mpl, code->arg.arg.x),
235.4774 +                  0.0, constant_term(mpl, 0.0));
235.4775 +            }
235.4776 +            break;
235.4777 +         case O_DIV:
235.4778 +            /* division */
235.4779 +            value = linear_comb(mpl,
235.4780 +               fp_div(mpl, 1.0, eval_numeric(mpl, code->arg.arg.y)),
235.4781 +               eval_formula(mpl, code->arg.arg.x),
235.4782 +               0.0, constant_term(mpl, 0.0));
235.4783 +            break;
235.4784 +         case O_FORK:
235.4785 +            /* if-then-else */
235.4786 +            if (eval_logical(mpl, code->arg.arg.x))
235.4787 +               value = eval_formula(mpl, code->arg.arg.y);
235.4788 +            else if (code->arg.arg.z == NULL)
235.4789 +               value = constant_term(mpl, 0.0);
235.4790 +            else
235.4791 +               value = eval_formula(mpl, code->arg.arg.z);
235.4792 +            break;
235.4793 +         case O_SUM:
235.4794 +            /* summation over domain */
235.4795 +            {  struct iter_form_info _info, *info = &_info;
235.4796 +               info->code = code;
235.4797 +               info->value = constant_term(mpl, 0.0);
235.4798 +               info->tail = NULL;
235.4799 +               loop_within_domain(mpl, code->arg.loop.domain, info,
235.4800 +                  iter_form_func);
235.4801 +               value = reduce_terms(mpl, info->value);
235.4802 +            }
235.4803 +            break;
235.4804 +         default:
235.4805 +            xassert(code != code);
235.4806 +      }
235.4807 +      /* save resultant value */
235.4808 +      xassert(!code->valid);
235.4809 +      code->valid = 1;
235.4810 +      code->value.form = copy_formula(mpl, value);
235.4811 +done: return value;
235.4812 +}
235.4813 +
235.4814 +/*----------------------------------------------------------------------
235.4815 +-- clean_code - clean pseudo-code.
235.4816 +--
235.4817 +-- This routine recursively cleans specified pseudo-code that assumes
235.4818 +-- deleting all temporary resultant values. */
235.4819 +
235.4820 +void clean_code(MPL *mpl, CODE *code)
235.4821 +{     ARG_LIST *e;
235.4822 +      /* if no pseudo-code is specified, do nothing */
235.4823 +      if (code == NULL) goto done;
235.4824 +      /* if resultant value is valid (exists), delete it */
235.4825 +      if (code->valid)
235.4826 +      {  code->valid = 0;
235.4827 +         delete_value(mpl, code->type, &code->value);
235.4828 +      }
235.4829 +      /* recursively clean pseudo-code for operands */
235.4830 +      switch (code->op)
235.4831 +      {  case O_NUMBER:
235.4832 +         case O_STRING:
235.4833 +         case O_INDEX:
235.4834 +            break;
235.4835 +         case O_MEMNUM:
235.4836 +         case O_MEMSYM:
235.4837 +            for (e = code->arg.par.list; e != NULL; e = e->next)
235.4838 +               clean_code(mpl, e->x);
235.4839 +            break;
235.4840 +         case O_MEMSET:
235.4841 +            for (e = code->arg.set.list; e != NULL; e = e->next)
235.4842 +               clean_code(mpl, e->x);
235.4843 +            break;
235.4844 +         case O_MEMVAR:
235.4845 +            for (e = code->arg.var.list; e != NULL; e = e->next)
235.4846 +               clean_code(mpl, e->x);
235.4847 +            break;
235.4848 +#if 1 /* 15/V-2010 */
235.4849 +         case O_MEMCON:
235.4850 +            for (e = code->arg.con.list; e != NULL; e = e->next)
235.4851 +               clean_code(mpl, e->x);
235.4852 +            break;
235.4853 +#endif
235.4854 +         case O_TUPLE:
235.4855 +         case O_MAKE:
235.4856 +            for (e = code->arg.list; e != NULL; e = e->next)
235.4857 +               clean_code(mpl, e->x);
235.4858 +            break;
235.4859 +         case O_SLICE:
235.4860 +            xassert(code != code);
235.4861 +         case O_IRAND224:
235.4862 +         case O_UNIFORM01:
235.4863 +         case O_NORMAL01:
235.4864 +         case O_GMTIME:
235.4865 +            break;
235.4866 +         case O_CVTNUM:
235.4867 +         case O_CVTSYM:
235.4868 +         case O_CVTLOG:
235.4869 +         case O_CVTTUP:
235.4870 +         case O_CVTLFM:
235.4871 +         case O_PLUS:
235.4872 +         case O_MINUS:
235.4873 +         case O_NOT:
235.4874 +         case O_ABS:
235.4875 +         case O_CEIL:
235.4876 +         case O_FLOOR:
235.4877 +         case O_EXP:
235.4878 +         case O_LOG:
235.4879 +         case O_LOG10:
235.4880 +         case O_SQRT:
235.4881 +         case O_SIN:
235.4882 +         case O_COS:
235.4883 +         case O_ATAN:
235.4884 +         case O_ROUND:
235.4885 +         case O_TRUNC:
235.4886 +         case O_CARD:
235.4887 +         case O_LENGTH:
235.4888 +            /* unary operation */
235.4889 +            clean_code(mpl, code->arg.arg.x);
235.4890 +            break;
235.4891 +         case O_ADD:
235.4892 +         case O_SUB:
235.4893 +         case O_LESS:
235.4894 +         case O_MUL:
235.4895 +         case O_DIV:
235.4896 +         case O_IDIV:
235.4897 +         case O_MOD:
235.4898 +         case O_POWER:
235.4899 +         case O_ATAN2:
235.4900 +         case O_ROUND2:
235.4901 +         case O_TRUNC2:
235.4902 +         case O_UNIFORM:
235.4903 +         case O_NORMAL:
235.4904 +         case O_CONCAT:
235.4905 +         case O_LT:
235.4906 +         case O_LE:
235.4907 +         case O_EQ:
235.4908 +         case O_GE:
235.4909 +         case O_GT:
235.4910 +         case O_NE:
235.4911 +         case O_AND:
235.4912 +         case O_OR:
235.4913 +         case O_UNION:
235.4914 +         case O_DIFF:
235.4915 +         case O_SYMDIFF:
235.4916 +         case O_INTER:
235.4917 +         case O_CROSS:
235.4918 +         case O_IN:
235.4919 +         case O_NOTIN:
235.4920 +         case O_WITHIN:
235.4921 +         case O_NOTWITHIN:
235.4922 +         case O_SUBSTR:
235.4923 +         case O_STR2TIME:
235.4924 +         case O_TIME2STR:
235.4925 +            /* binary operation */
235.4926 +            clean_code(mpl, code->arg.arg.x);
235.4927 +            clean_code(mpl, code->arg.arg.y);
235.4928 +            break;
235.4929 +         case O_DOTS:
235.4930 +         case O_FORK:
235.4931 +         case O_SUBSTR3:
235.4932 +            /* ternary operation */
235.4933 +            clean_code(mpl, code->arg.arg.x);
235.4934 +            clean_code(mpl, code->arg.arg.y);
235.4935 +            clean_code(mpl, code->arg.arg.z);
235.4936 +            break;
235.4937 +         case O_MIN:
235.4938 +         case O_MAX:
235.4939 +            /* n-ary operation */
235.4940 +            for (e = code->arg.list; e != NULL; e = e->next)
235.4941 +               clean_code(mpl, e->x);
235.4942 +            break;
235.4943 +         case O_SUM:
235.4944 +         case O_PROD:
235.4945 +         case O_MINIMUM:
235.4946 +         case O_MAXIMUM:
235.4947 +         case O_FORALL:
235.4948 +         case O_EXISTS:
235.4949 +         case O_SETOF:
235.4950 +         case O_BUILD:
235.4951 +            /* iterated operation */
235.4952 +            clean_domain(mpl, code->arg.loop.domain);
235.4953 +            clean_code(mpl, code->arg.loop.x);
235.4954 +            break;
235.4955 +         default:
235.4956 +            xassert(code->op != code->op);
235.4957 +      }
235.4958 +done: return;
235.4959 +}
235.4960 +
235.4961 +#if 1 /* 11/II-2008 */
235.4962 +/**********************************************************************/
235.4963 +/* * *                        DATA TABLES                         * * */
235.4964 +/**********************************************************************/
235.4965 +
235.4966 +int mpl_tab_num_args(TABDCA *dca)
235.4967 +{     /* returns the number of arguments */
235.4968 +      return dca->na;
235.4969 +}
235.4970 +
235.4971 +const char *mpl_tab_get_arg(TABDCA *dca, int k)
235.4972 +{     /* returns pointer to k-th argument */
235.4973 +      xassert(1 <= k && k <= dca->na);
235.4974 +      return dca->arg[k];
235.4975 +}
235.4976 +
235.4977 +int mpl_tab_num_flds(TABDCA *dca)
235.4978 +{     /* returns the number of fields */
235.4979 +      return dca->nf;
235.4980 +}
235.4981 +
235.4982 +const char *mpl_tab_get_name(TABDCA *dca, int k)
235.4983 +{     /* returns pointer to name of k-th field */
235.4984 +      xassert(1 <= k && k <= dca->nf);
235.4985 +      return dca->name[k];
235.4986 +}
235.4987 +
235.4988 +int mpl_tab_get_type(TABDCA *dca, int k)
235.4989 +{     /* returns type of k-th field */
235.4990 +      xassert(1 <= k && k <= dca->nf);
235.4991 +      return dca->type[k];
235.4992 +}
235.4993 +
235.4994 +double mpl_tab_get_num(TABDCA *dca, int k)
235.4995 +{     /* returns numeric value of k-th field */
235.4996 +      xassert(1 <= k && k <= dca->nf);
235.4997 +      xassert(dca->type[k] == 'N');
235.4998 +      return dca->num[k];
235.4999 +}
235.5000 +
235.5001 +const char *mpl_tab_get_str(TABDCA *dca, int k)
235.5002 +{     /* returns pointer to string value of k-th field */
235.5003 +      xassert(1 <= k && k <= dca->nf);
235.5004 +      xassert(dca->type[k] == 'S');
235.5005 +      xassert(dca->str[k] != NULL);
235.5006 +      return dca->str[k];
235.5007 +}
235.5008 +
235.5009 +void mpl_tab_set_num(TABDCA *dca, int k, double num)
235.5010 +{     /* assign numeric value to k-th field */
235.5011 +      xassert(1 <= k && k <= dca->nf);
235.5012 +      xassert(dca->type[k] == '?');
235.5013 +      dca->type[k] = 'N';
235.5014 +      dca->num[k] = num;
235.5015 +      return;
235.5016 +}
235.5017 +
235.5018 +void mpl_tab_set_str(TABDCA *dca, int k, const char *str)
235.5019 +{     /* assign string value to k-th field */
235.5020 +      xassert(1 <= k && k <= dca->nf);
235.5021 +      xassert(dca->type[k] == '?');
235.5022 +      xassert(strlen(str) <= MAX_LENGTH);
235.5023 +      xassert(dca->str[k] != NULL);
235.5024 +      dca->type[k] = 'S';
235.5025 +      strcpy(dca->str[k], str);
235.5026 +      return;
235.5027 +}
235.5028 +
235.5029 +static int write_func(MPL *mpl, void *info)
235.5030 +{     /* this is auxiliary routine to work within domain scope */
235.5031 +      TABLE *tab = info;
235.5032 +      TABDCA *dca = mpl->dca;
235.5033 +      TABOUT *out;
235.5034 +      SYMBOL *sym;
235.5035 +      int k;
235.5036 +      char buf[MAX_LENGTH+1];
235.5037 +      /* evaluate field values */
235.5038 +      k = 0;
235.5039 +      for (out = tab->u.out.list; out != NULL; out = out->next)
235.5040 +      {  k++;
235.5041 +         switch (out->code->type)
235.5042 +         {  case A_NUMERIC:
235.5043 +               dca->type[k] = 'N';
235.5044 +               dca->num[k] = eval_numeric(mpl, out->code);
235.5045 +               dca->str[k][0] = '\0';
235.5046 +               break;
235.5047 +            case A_SYMBOLIC:
235.5048 +               sym = eval_symbolic(mpl, out->code);
235.5049 +               if (sym->str == NULL)
235.5050 +               {  dca->type[k] = 'N';
235.5051 +                  dca->num[k] = sym->num;
235.5052 +                  dca->str[k][0] = '\0';
235.5053 +               }
235.5054 +               else
235.5055 +               {  dca->type[k] = 'S';
235.5056 +                  dca->num[k] = 0.0;
235.5057 +                  fetch_string(mpl, sym->str, buf);
235.5058 +                  strcpy(dca->str[k], buf);
235.5059 +               }
235.5060 +               delete_symbol(mpl, sym);
235.5061 +               break;
235.5062 +            default:
235.5063 +               xassert(out != out);
235.5064 +         }
235.5065 +      }
235.5066 +      /* write record to output table */
235.5067 +      mpl_tab_drv_write(mpl);
235.5068 +      return 0;
235.5069 +}
235.5070 +
235.5071 +void execute_table(MPL *mpl, TABLE *tab)
235.5072 +{     /* execute table statement */
235.5073 +      TABARG *arg;
235.5074 +      TABFLD *fld;
235.5075 +      TABIN *in;
235.5076 +      TABOUT *out;
235.5077 +      TABDCA *dca;
235.5078 +      SET *set;
235.5079 +      int k;
235.5080 +      char buf[MAX_LENGTH+1];
235.5081 +      /* allocate table driver communication area */
235.5082 +      xassert(mpl->dca == NULL);
235.5083 +      mpl->dca = dca = xmalloc(sizeof(TABDCA));
235.5084 +      dca->id = 0;
235.5085 +      dca->link = NULL;
235.5086 +      dca->na = 0;
235.5087 +      dca->arg = NULL;
235.5088 +      dca->nf = 0;
235.5089 +      dca->name = NULL;
235.5090 +      dca->type = NULL;
235.5091 +      dca->num = NULL;
235.5092 +      dca->str = NULL;
235.5093 +      /* allocate arguments */
235.5094 +      xassert(dca->na == 0);
235.5095 +      for (arg = tab->arg; arg != NULL; arg = arg->next)
235.5096 +         dca->na++;
235.5097 +      dca->arg = xcalloc(1+dca->na, sizeof(char *));
235.5098 +#if 1 /* 28/IX-2008 */
235.5099 +      for (k = 1; k <= dca->na; k++) dca->arg[k] = NULL;
235.5100 +#endif
235.5101 +      /* evaluate argument values */
235.5102 +      k = 0;
235.5103 +      for (arg = tab->arg; arg != NULL; arg = arg->next)
235.5104 +      {  SYMBOL *sym;
235.5105 +         k++;
235.5106 +         xassert(arg->code->type == A_SYMBOLIC);
235.5107 +         sym = eval_symbolic(mpl, arg->code);
235.5108 +         if (sym->str == NULL)
235.5109 +            sprintf(buf, "%.*g", DBL_DIG, sym->num);
235.5110 +         else
235.5111 +            fetch_string(mpl, sym->str, buf);
235.5112 +         delete_symbol(mpl, sym);
235.5113 +         dca->arg[k] = xmalloc(strlen(buf)+1);
235.5114 +         strcpy(dca->arg[k], buf);
235.5115 +      }
235.5116 +      /* perform table input/output */
235.5117 +      switch (tab->type)
235.5118 +      {  case A_INPUT:  goto read_table;
235.5119 +         case A_OUTPUT: goto write_table;
235.5120 +         default:       xassert(tab != tab);
235.5121 +      }
235.5122 +read_table:
235.5123 +      /* read data from input table */
235.5124 +      /* add the only member to the control set and assign it empty
235.5125 +         elemental set */
235.5126 +      set = tab->u.in.set;
235.5127 +      if (set != NULL)
235.5128 +      {  if (set->data)
235.5129 +            error(mpl, "%s already provided with data", set->name);
235.5130 +         xassert(set->array->head == NULL);
235.5131 +         add_member(mpl, set->array, NULL)->value.set =
235.5132 +            create_elemset(mpl, set->dimen);
235.5133 +         set->data = 1;
235.5134 +      }
235.5135 +      /* check parameters specified in the input list */
235.5136 +      for (in = tab->u.in.list; in != NULL; in = in->next)
235.5137 +      {  if (in->par->data)
235.5138 +            error(mpl, "%s already provided with data", in->par->name);
235.5139 +         in->par->data = 1;
235.5140 +      }
235.5141 +      /* allocate and initialize fields */
235.5142 +      xassert(dca->nf == 0);
235.5143 +      for (fld = tab->u.in.fld; fld != NULL; fld = fld->next)
235.5144 +         dca->nf++;
235.5145 +      for (in = tab->u.in.list; in != NULL; in = in->next)
235.5146 +         dca->nf++;
235.5147 +      dca->name = xcalloc(1+dca->nf, sizeof(char *));
235.5148 +      dca->type = xcalloc(1+dca->nf, sizeof(int));
235.5149 +      dca->num = xcalloc(1+dca->nf, sizeof(double));
235.5150 +      dca->str = xcalloc(1+dca->nf, sizeof(char *));
235.5151 +      k = 0;
235.5152 +      for (fld = tab->u.in.fld; fld != NULL; fld = fld->next)
235.5153 +      {  k++;
235.5154 +         dca->name[k] = fld->name;
235.5155 +         dca->type[k] = '?';
235.5156 +         dca->num[k] = 0.0;
235.5157 +         dca->str[k] = xmalloc(MAX_LENGTH+1);
235.5158 +         dca->str[k][0] = '\0';
235.5159 +      }
235.5160 +      for (in = tab->u.in.list; in != NULL; in = in->next)
235.5161 +      {  k++;
235.5162 +         dca->name[k] = in->name;
235.5163 +         dca->type[k] = '?';
235.5164 +         dca->num[k] = 0.0;
235.5165 +         dca->str[k] = xmalloc(MAX_LENGTH+1);
235.5166 +         dca->str[k][0] = '\0';
235.5167 +      }
235.5168 +      /* open input table */
235.5169 +      mpl_tab_drv_open(mpl, 'R');
235.5170 +      /* read and process records */
235.5171 +      for (;;)
235.5172 +      {  TUPLE *tup;
235.5173 +         /* reset field types */
235.5174 +         for (k = 1; k <= dca->nf; k++)
235.5175 +            dca->type[k] = '?';
235.5176 +         /* read next record */
235.5177 +         if (mpl_tab_drv_read(mpl)) break;
235.5178 +         /* all fields must be set by the driver */
235.5179 +         for (k = 1; k <= dca->nf; k++)
235.5180 +         {  if (dca->type[k] == '?')
235.5181 +               error(mpl, "field %s missing in input table",
235.5182 +                  dca->name[k]);
235.5183 +         }
235.5184 +         /* construct n-tuple */
235.5185 +         tup = create_tuple(mpl);
235.5186 +         k = 0;
235.5187 +         for (fld = tab->u.in.fld; fld != NULL; fld = fld->next)
235.5188 +         {  k++;
235.5189 +            xassert(k <= dca->nf);
235.5190 +            switch (dca->type[k])
235.5191 +            {  case 'N':
235.5192 +                  tup = expand_tuple(mpl, tup, create_symbol_num(mpl,
235.5193 +                     dca->num[k]));
235.5194 +                  break;
235.5195 +               case 'S':
235.5196 +                  xassert(strlen(dca->str[k]) <= MAX_LENGTH);
235.5197 +                  tup = expand_tuple(mpl, tup, create_symbol_str(mpl,
235.5198 +                     create_string(mpl, dca->str[k])));
235.5199 +                  break;
235.5200 +               default:
235.5201 +                  xassert(dca != dca);
235.5202 +            }
235.5203 +         }
235.5204 +         /* add n-tuple just read to the control set */
235.5205 +         if (tab->u.in.set != NULL)
235.5206 +            check_then_add(mpl, tab->u.in.set->array->head->value.set,
235.5207 +               copy_tuple(mpl, tup));
235.5208 +         /* assign values to the parameters in the input list */
235.5209 +         for (in = tab->u.in.list; in != NULL; in = in->next)
235.5210 +         {  MEMBER *memb;
235.5211 +            k++;
235.5212 +            xassert(k <= dca->nf);
235.5213 +            /* there must be no member with the same n-tuple */
235.5214 +            if (find_member(mpl, in->par->array, tup) != NULL)
235.5215 +               error(mpl, "%s%s already defined", in->par->name,
235.5216 +               format_tuple(mpl, '[', tup));
235.5217 +            /* create new parameter member with given n-tuple */
235.5218 +            memb = add_member(mpl, in->par->array, copy_tuple(mpl, tup))
235.5219 +               ;
235.5220 +            /* assign value to the parameter member */
235.5221 +            switch (in->par->type)
235.5222 +            {  case A_NUMERIC:
235.5223 +               case A_INTEGER:
235.5224 +               case A_BINARY:
235.5225 +                  if (dca->type[k] != 'N')
235.5226 +                     error(mpl, "%s requires numeric data",
235.5227 +                        in->par->name);
235.5228 +                  memb->value.num = dca->num[k];
235.5229 +                  break;
235.5230 +               case A_SYMBOLIC:
235.5231 +                  switch (dca->type[k])
235.5232 +                  {  case 'N':
235.5233 +                        memb->value.sym = create_symbol_num(mpl,
235.5234 +                           dca->num[k]);
235.5235 +                        break;
235.5236 +                     case 'S':
235.5237 +                        xassert(strlen(dca->str[k]) <= MAX_LENGTH);
235.5238 +                        memb->value.sym = create_symbol_str(mpl,
235.5239 +                           create_string(mpl,dca->str[k]));
235.5240 +                        break;
235.5241 +                     default:
235.5242 +                        xassert(dca != dca);
235.5243 +                  }
235.5244 +                  break;
235.5245 +               default:
235.5246 +                  xassert(in != in);
235.5247 +            }
235.5248 +         }
235.5249 +         /* n-tuple is no more needed */
235.5250 +         delete_tuple(mpl, tup);
235.5251 +      }
235.5252 +      /* close input table */
235.5253 +      mpl_tab_drv_close(mpl);
235.5254 +      goto done;
235.5255 +write_table:
235.5256 +      /* write data to output table */
235.5257 +      /* allocate and initialize fields */
235.5258 +      xassert(dca->nf == 0);
235.5259 +      for (out = tab->u.out.list; out != NULL; out = out->next)
235.5260 +         dca->nf++;
235.5261 +      dca->name = xcalloc(1+dca->nf, sizeof(char *));
235.5262 +      dca->type = xcalloc(1+dca->nf, sizeof(int));
235.5263 +      dca->num = xcalloc(1+dca->nf, sizeof(double));
235.5264 +      dca->str = xcalloc(1+dca->nf, sizeof(char *));
235.5265 +      k = 0;
235.5266 +      for (out = tab->u.out.list; out != NULL; out = out->next)
235.5267 +      {  k++;
235.5268 +         dca->name[k] = out->name;
235.5269 +         dca->type[k] = '?';
235.5270 +         dca->num[k] = 0.0;
235.5271 +         dca->str[k] = xmalloc(MAX_LENGTH+1);
235.5272 +         dca->str[k][0] = '\0';
235.5273 +      }
235.5274 +      /* open output table */
235.5275 +      mpl_tab_drv_open(mpl, 'W');
235.5276 +      /* evaluate fields and write records */
235.5277 +      loop_within_domain(mpl, tab->u.out.domain, tab, write_func);
235.5278 +      /* close output table */
235.5279 +      mpl_tab_drv_close(mpl);
235.5280 +done: /* free table driver communication area */
235.5281 +      free_dca(mpl);
235.5282 +      return;
235.5283 +}
235.5284 +
235.5285 +void free_dca(MPL *mpl)
235.5286 +{     /* free table driver communucation area */
235.5287 +      TABDCA *dca = mpl->dca;
235.5288 +      int k;
235.5289 +      if (dca != NULL)
235.5290 +      {  if (dca->link != NULL)
235.5291 +            mpl_tab_drv_close(mpl);
235.5292 +         if (dca->arg != NULL)
235.5293 +         {  for (k = 1; k <= dca->na; k++)
235.5294 +#if 1 /* 28/IX-2008 */
235.5295 +               if (dca->arg[k] != NULL)
235.5296 +#endif
235.5297 +               xfree(dca->arg[k]);
235.5298 +            xfree(dca->arg);
235.5299 +         }
235.5300 +         if (dca->name != NULL) xfree(dca->name);
235.5301 +         if (dca->type != NULL) xfree(dca->type);
235.5302 +         if (dca->num != NULL) xfree(dca->num);
235.5303 +         if (dca->str != NULL)
235.5304 +         {  for (k = 1; k <= dca->nf; k++)
235.5305 +               xfree(dca->str[k]);
235.5306 +            xfree(dca->str);
235.5307 +         }
235.5308 +         xfree(dca), mpl->dca = NULL;
235.5309 +      }
235.5310 +      return;
235.5311 +}
235.5312 +
235.5313 +void clean_table(MPL *mpl, TABLE *tab)
235.5314 +{     /* clean table statement */
235.5315 +      TABARG *arg;
235.5316 +      TABOUT *out;
235.5317 +      /* clean string list */
235.5318 +      for (arg = tab->arg; arg != NULL; arg = arg->next)
235.5319 +         clean_code(mpl, arg->code);
235.5320 +      switch (tab->type)
235.5321 +      {  case A_INPUT:
235.5322 +            break;
235.5323 +         case A_OUTPUT:
235.5324 +            /* clean subscript domain */
235.5325 +            clean_domain(mpl, tab->u.out.domain);
235.5326 +            /* clean output list */
235.5327 +            for (out = tab->u.out.list; out != NULL; out = out->next)
235.5328 +               clean_code(mpl, out->code);
235.5329 +            break;
235.5330 +         default:
235.5331 +            xassert(tab != tab);
235.5332 +      }
235.5333 +      return;
235.5334 +}
235.5335 +#endif
235.5336 +
235.5337 +/**********************************************************************/
235.5338 +/* * *                      MODEL STATEMENTS                      * * */
235.5339 +/**********************************************************************/
235.5340 +
235.5341 +/*----------------------------------------------------------------------
235.5342 +-- execute_check - execute check statement.
235.5343 +--
235.5344 +-- This routine executes specified check statement. */
235.5345 +
235.5346 +static int check_func(MPL *mpl, void *info)
235.5347 +{     /* this is auxiliary routine to work within domain scope */
235.5348 +      CHECK *chk = (CHECK *)info;
235.5349 +      if (!eval_logical(mpl, chk->code))
235.5350 +         error(mpl, "check%s failed", format_tuple(mpl, '[',
235.5351 +            get_domain_tuple(mpl, chk->domain)));
235.5352 +      return 0;
235.5353 +}
235.5354 +
235.5355 +void execute_check(MPL *mpl, CHECK *chk)
235.5356 +{     loop_within_domain(mpl, chk->domain, chk, check_func);
235.5357 +      return;
235.5358 +}
235.5359 +
235.5360 +/*----------------------------------------------------------------------
235.5361 +-- clean_check - clean check statement.
235.5362 +--
235.5363 +-- This routine cleans specified check statement that assumes deleting
235.5364 +-- all stuff dynamically allocated on generating/postsolving phase. */
235.5365 +
235.5366 +void clean_check(MPL *mpl, CHECK *chk)
235.5367 +{     /* clean subscript domain */
235.5368 +      clean_domain(mpl, chk->domain);
235.5369 +      /* clean pseudo-code for computing predicate */
235.5370 +      clean_code(mpl, chk->code);
235.5371 +      return;
235.5372 +}
235.5373 +
235.5374 +/*----------------------------------------------------------------------
235.5375 +-- execute_display - execute display statement.
235.5376 +--
235.5377 +-- This routine executes specified display statement. */
235.5378 +
235.5379 +static void display_set(MPL *mpl, SET *set, MEMBER *memb)
235.5380 +{     /* display member of model set */
235.5381 +      ELEMSET *s = memb->value.set;
235.5382 +      MEMBER *m;
235.5383 +      write_text(mpl, "%s%s%s\n", set->name,
235.5384 +         format_tuple(mpl, '[', memb->tuple),
235.5385 +         s->head == NULL ? " is empty" : ":");
235.5386 +      for (m = s->head; m != NULL; m = m->next)
235.5387 +         write_text(mpl, "   %s\n", format_tuple(mpl, '(', m->tuple));
235.5388 +      return;
235.5389 +}
235.5390 +
235.5391 +static void display_par(MPL *mpl, PARAMETER *par, MEMBER *memb)
235.5392 +{     /* display member of model parameter */
235.5393 +      switch (par->type)
235.5394 +      {  case A_NUMERIC:
235.5395 +         case A_INTEGER:
235.5396 +         case A_BINARY:
235.5397 +            write_text(mpl, "%s%s = %.*g\n", par->name,
235.5398 +               format_tuple(mpl, '[', memb->tuple),
235.5399 +               DBL_DIG, memb->value.num);
235.5400 +            break;
235.5401 +         case A_SYMBOLIC:
235.5402 +            write_text(mpl, "%s%s = %s\n", par->name,
235.5403 +               format_tuple(mpl, '[', memb->tuple),
235.5404 +               format_symbol(mpl, memb->value.sym));
235.5405 +            break;
235.5406 +         default:
235.5407 +            xassert(par != par);
235.5408 +      }
235.5409 +      return;
235.5410 +}
235.5411 +
235.5412 +#if 1 /* 15/V-2010 */
235.5413 +static void display_var(MPL *mpl, VARIABLE *var, MEMBER *memb,
235.5414 +      int suff)
235.5415 +{     /* display member of model variable */
235.5416 +      if (suff == DOT_NONE || suff == DOT_VAL)
235.5417 +         write_text(mpl, "%s%s.val = %.*g\n", var->name,
235.5418 +            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
235.5419 +            memb->value.var->prim);
235.5420 +      else if (suff == DOT_LB)
235.5421 +         write_text(mpl, "%s%s.lb = %.*g\n", var->name,
235.5422 +            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
235.5423 +            memb->value.var->var->lbnd == NULL ? -DBL_MAX :
235.5424 +            memb->value.var->lbnd);
235.5425 +      else if (suff == DOT_UB)
235.5426 +         write_text(mpl, "%s%s.ub = %.*g\n", var->name,
235.5427 +            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
235.5428 +            memb->value.var->var->ubnd == NULL ? +DBL_MAX :
235.5429 +            memb->value.var->ubnd);
235.5430 +      else if (suff == DOT_STATUS)
235.5431 +         write_text(mpl, "%s%s.status = %d\n", var->name, format_tuple
235.5432 +            (mpl, '[', memb->tuple), memb->value.var->stat);
235.5433 +      else if (suff == DOT_DUAL)
235.5434 +         write_text(mpl, "%s%s.dual = %.*g\n", var->name,
235.5435 +            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
235.5436 +            memb->value.var->dual);
235.5437 +      else
235.5438 +         xassert(suff != suff);
235.5439 +      return;
235.5440 +}
235.5441 +#endif
235.5442 +
235.5443 +#if 1 /* 15/V-2010 */
235.5444 +static void display_con(MPL *mpl, CONSTRAINT *con, MEMBER *memb,
235.5445 +      int suff)
235.5446 +{     /* display member of model constraint */
235.5447 +      if (suff == DOT_NONE || suff == DOT_VAL)
235.5448 +         write_text(mpl, "%s%s.val = %.*g\n", con->name,
235.5449 +            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
235.5450 +            memb->value.con->prim);
235.5451 +      else if (suff == DOT_LB)
235.5452 +         write_text(mpl, "%s%s.lb = %.*g\n", con->name,
235.5453 +            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
235.5454 +            memb->value.con->con->lbnd == NULL ? -DBL_MAX :
235.5455 +            memb->value.con->lbnd);
235.5456 +      else if (suff == DOT_UB)
235.5457 +         write_text(mpl, "%s%s.ub = %.*g\n", con->name,
235.5458 +            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
235.5459 +            memb->value.con->con->ubnd == NULL ? +DBL_MAX :
235.5460 +            memb->value.con->ubnd);
235.5461 +      else if (suff == DOT_STATUS)
235.5462 +         write_text(mpl, "%s%s.status = %d\n", con->name, format_tuple
235.5463 +            (mpl, '[', memb->tuple), memb->value.con->stat);
235.5464 +      else if (suff == DOT_DUAL)
235.5465 +         write_text(mpl, "%s%s.dual = %.*g\n", con->name,
235.5466 +            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
235.5467 +            memb->value.con->dual);
235.5468 +      else
235.5469 +         xassert(suff != suff);
235.5470 +      return;
235.5471 +}
235.5472 +#endif
235.5473 +
235.5474 +static void display_memb(MPL *mpl, CODE *code)
235.5475 +{     /* display member specified by pseudo-code */
235.5476 +      MEMBER memb;
235.5477 +      ARG_LIST *e;
235.5478 +      xassert(code->op == O_MEMNUM || code->op == O_MEMSYM
235.5479 +         || code->op == O_MEMSET || code->op == O_MEMVAR
235.5480 +         || code->op == O_MEMCON);
235.5481 +      memb.tuple = create_tuple(mpl);
235.5482 +      for (e = code->arg.par.list; e != NULL; e = e->next)
235.5483 +         memb.tuple = expand_tuple(mpl, memb.tuple, eval_symbolic(mpl,
235.5484 +            e->x));
235.5485 +      switch (code->op)
235.5486 +      {  case O_MEMNUM:
235.5487 +            memb.value.num = eval_member_num(mpl, code->arg.par.par,
235.5488 +               memb.tuple);
235.5489 +            display_par(mpl, code->arg.par.par, &memb);
235.5490 +            break;
235.5491 +         case O_MEMSYM:
235.5492 +            memb.value.sym = eval_member_sym(mpl, code->arg.par.par,
235.5493 +               memb.tuple);
235.5494 +            display_par(mpl, code->arg.par.par, &memb);
235.5495 +            delete_symbol(mpl, memb.value.sym);
235.5496 +            break;
235.5497 +         case O_MEMSET:
235.5498 +            memb.value.set = eval_member_set(mpl, code->arg.set.set,
235.5499 +               memb.tuple);
235.5500 +            display_set(mpl, code->arg.set.set, &memb);
235.5501 +            break;
235.5502 +         case O_MEMVAR:
235.5503 +            memb.value.var = eval_member_var(mpl, code->arg.var.var,
235.5504 +               memb.tuple);
235.5505 +            display_var
235.5506 +               (mpl, code->arg.var.var, &memb, code->arg.var.suff);
235.5507 +            break;
235.5508 +         case O_MEMCON:
235.5509 +            memb.value.con = eval_member_con(mpl, code->arg.con.con,
235.5510 +               memb.tuple);
235.5511 +            display_con
235.5512 +               (mpl, code->arg.con.con, &memb, code->arg.con.suff);
235.5513 +            break;
235.5514 +         default:
235.5515 +            xassert(code != code);
235.5516 +      }
235.5517 +      delete_tuple(mpl, memb.tuple);
235.5518 +      return;
235.5519 +}
235.5520 +
235.5521 +static void display_code(MPL *mpl, CODE *code)
235.5522 +{     /* display value of expression */
235.5523 +      switch (code->type)
235.5524 +      {  case A_NUMERIC:
235.5525 +            /* numeric value */
235.5526 +            {  double num;
235.5527 +               num = eval_numeric(mpl, code);
235.5528 +               write_text(mpl, "%.*g\n", DBL_DIG, num);
235.5529 +            }
235.5530 +            break;
235.5531 +         case A_SYMBOLIC:
235.5532 +            /* symbolic value */
235.5533 +            {  SYMBOL *sym;
235.5534 +               sym = eval_symbolic(mpl, code);
235.5535 +               write_text(mpl, "%s\n", format_symbol(mpl, sym));
235.5536 +               delete_symbol(mpl, sym);
235.5537 +            }
235.5538 +            break;
235.5539 +         case A_LOGICAL:
235.5540 +            /* logical value */
235.5541 +            {  int bit;
235.5542 +               bit = eval_logical(mpl, code);
235.5543 +               write_text(mpl, "%s\n", bit ? "true" : "false");
235.5544 +            }
235.5545 +            break;
235.5546 +         case A_TUPLE:
235.5547 +            /* n-tuple */
235.5548 +            {  TUPLE *tuple;
235.5549 +               tuple = eval_tuple(mpl, code);
235.5550 +               write_text(mpl, "%s\n", format_tuple(mpl, '(', tuple));
235.5551 +               delete_tuple(mpl, tuple);
235.5552 +            }
235.5553 +            break;
235.5554 +         case A_ELEMSET:
235.5555 +            /* elemental set */
235.5556 +            {  ELEMSET *set;
235.5557 +               MEMBER *memb;
235.5558 +               set = eval_elemset(mpl, code);
235.5559 +               if (set->head == 0)
235.5560 +                  write_text(mpl, "set is empty\n");
235.5561 +               for (memb = set->head; memb != NULL; memb = memb->next)
235.5562 +                  write_text(mpl, "   %s\n", format_tuple(mpl, '(',
235.5563 +                     memb->tuple));
235.5564 +               delete_elemset(mpl, set);
235.5565 +            }
235.5566 +            break;
235.5567 +         case A_FORMULA:
235.5568 +            /* linear form */
235.5569 +            {  FORMULA *form, *term;
235.5570 +               form = eval_formula(mpl, code);
235.5571 +               if (form == NULL)
235.5572 +                  write_text(mpl, "linear form is empty\n");
235.5573 +               for (term = form; term != NULL; term = term->next)
235.5574 +               {  if (term->var == NULL)
235.5575 +                     write_text(mpl, "   %.*g\n", term->coef);
235.5576 +                  else
235.5577 +                     write_text(mpl, "   %.*g %s%s\n", DBL_DIG,
235.5578 +                        term->coef, term->var->var->name,
235.5579 +                        format_tuple(mpl, '[', term->var->memb->tuple));
235.5580 +               }
235.5581 +               delete_formula(mpl, form);
235.5582 +            }
235.5583 +            break;
235.5584 +         default:
235.5585 +            xassert(code != code);
235.5586 +      }
235.5587 +      return;
235.5588 +}
235.5589 +
235.5590 +static int display_func(MPL *mpl, void *info)
235.5591 +{     /* this is auxiliary routine to work within domain scope */
235.5592 +      DISPLAY *dpy = (DISPLAY *)info;
235.5593 +      DISPLAY1 *entry;
235.5594 +      for (entry = dpy->list; entry != NULL; entry = entry->next)
235.5595 +      {  if (entry->type == A_INDEX)
235.5596 +         {  /* dummy index */
235.5597 +            DOMAIN_SLOT *slot = entry->u.slot;
235.5598 +            write_text(mpl, "%s = %s\n", slot->name,
235.5599 +            format_symbol(mpl, slot->value));
235.5600 +         }
235.5601 +         else if (entry->type == A_SET)
235.5602 +         {  /* model set */
235.5603 +            SET *set = entry->u.set;
235.5604 +            MEMBER *memb;
235.5605 +            if (set->assign != NULL)
235.5606 +            {  /* the set has assignment expression; evaluate all its
235.5607 +                  members over entire domain */
235.5608 +               eval_whole_set(mpl, set);
235.5609 +            }
235.5610 +            else
235.5611 +            {  /* the set has no assignment expression; refer to its
235.5612 +                  any existing member ignoring resultant value to check
235.5613 +                  the data provided the data section */
235.5614 +#if 1 /* 12/XII-2008 */
235.5615 +               if (set->gadget != NULL && set->data == 0)
235.5616 +               {  /* initialize the set with data from a plain set */
235.5617 +                  saturate_set(mpl, set);
235.5618 +               }
235.5619 +#endif
235.5620 +               if (set->array->head != NULL)
235.5621 +                  eval_member_set(mpl, set, set->array->head->tuple);
235.5622 +            }
235.5623 +            /* display all members of the set array */
235.5624 +            if (set->array->head == NULL)
235.5625 +               write_text(mpl, "%s has empty content\n", set->name);
235.5626 +            for (memb = set->array->head; memb != NULL; memb =
235.5627 +               memb->next) display_set(mpl, set, memb);
235.5628 +         }
235.5629 +         else if (entry->type == A_PARAMETER)
235.5630 +         {  /* model parameter */
235.5631 +            PARAMETER *par = entry->u.par;
235.5632 +            MEMBER *memb;
235.5633 +            if (par->assign != NULL)
235.5634 +            {  /* the parameter has an assignment expression; evaluate
235.5635 +                  all its member over entire domain */
235.5636 +               eval_whole_par(mpl, par);
235.5637 +            }
235.5638 +            else
235.5639 +            {  /* the parameter has no assignment expression; refer to
235.5640 +                  its any existing member ignoring resultant value to
235.5641 +                  check the data provided in the data section */
235.5642 +               if (par->array->head != NULL)
235.5643 +               {  if (par->type != A_SYMBOLIC)
235.5644 +                     eval_member_num(mpl, par, par->array->head->tuple);
235.5645 +                  else
235.5646 +                     delete_symbol(mpl, eval_member_sym(mpl, par,
235.5647 +                        par->array->head->tuple));
235.5648 +               }
235.5649 +            }
235.5650 +            /* display all members of the parameter array */
235.5651 +            if (par->array->head == NULL)
235.5652 +               write_text(mpl, "%s has empty content\n", par->name);
235.5653 +            for (memb = par->array->head; memb != NULL; memb =
235.5654 +               memb->next) display_par(mpl, par, memb);
235.5655 +         }
235.5656 +         else if (entry->type == A_VARIABLE)
235.5657 +         {  /* model variable */
235.5658 +            VARIABLE *var = entry->u.var;
235.5659 +            MEMBER *memb;
235.5660 +            xassert(mpl->flag_p);
235.5661 +            /* display all members of the variable array */
235.5662 +            if (var->array->head == NULL)
235.5663 +               write_text(mpl, "%s has empty content\n", var->name);
235.5664 +            for (memb = var->array->head; memb != NULL; memb =
235.5665 +               memb->next) display_var(mpl, var, memb, DOT_NONE);
235.5666 +         }
235.5667 +         else if (entry->type == A_CONSTRAINT)
235.5668 +         {  /* model constraint */
235.5669 +            CONSTRAINT *con = entry->u.con;
235.5670 +            MEMBER *memb;
235.5671 +            xassert(mpl->flag_p);
235.5672 +            /* display all members of the constraint array */
235.5673 +            if (con->array->head == NULL)
235.5674 +               write_text(mpl, "%s has empty content\n", con->name);
235.5675 +            for (memb = con->array->head; memb != NULL; memb =
235.5676 +               memb->next) display_con(mpl, con, memb, DOT_NONE);
235.5677 +         }
235.5678 +         else if (entry->type == A_EXPRESSION)
235.5679 +         {  /* expression */
235.5680 +            CODE *code = entry->u.code;
235.5681 +            if (code->op == O_MEMNUM || code->op == O_MEMSYM ||
235.5682 +                code->op == O_MEMSET || code->op == O_MEMVAR ||
235.5683 +                code->op == O_MEMCON)
235.5684 +               display_memb(mpl, code);
235.5685 +            else
235.5686 +               display_code(mpl, code);
235.5687 +         }
235.5688 +         else
235.5689 +            xassert(entry != entry);
235.5690 +      }
235.5691 +      return 0;
235.5692 +}
235.5693 +
235.5694 +void execute_display(MPL *mpl, DISPLAY *dpy)
235.5695 +{     loop_within_domain(mpl, dpy->domain, dpy, display_func);
235.5696 +      return;
235.5697 +}
235.5698 +
235.5699 +/*----------------------------------------------------------------------
235.5700 +-- clean_display - clean display statement.
235.5701 +--
235.5702 +-- This routine cleans specified display statement that assumes deleting
235.5703 +-- all stuff dynamically allocated on generating/postsolving phase. */
235.5704 +
235.5705 +void clean_display(MPL *mpl, DISPLAY *dpy)
235.5706 +{     DISPLAY1 *d;
235.5707 +#if 0 /* 15/V-2010 */
235.5708 +      ARG_LIST *e;
235.5709 +#endif
235.5710 +      /* clean subscript domain */
235.5711 +      clean_domain(mpl, dpy->domain);
235.5712 +      /* clean display list */
235.5713 +      for (d = dpy->list; d != NULL; d = d->next)
235.5714 +      {  /* clean pseudo-code for computing expression */
235.5715 +         if (d->type == A_EXPRESSION)
235.5716 +            clean_code(mpl, d->u.code);
235.5717 +#if 0 /* 15/V-2010 */
235.5718 +         /* clean pseudo-code for computing subscripts */
235.5719 +         for (e = d->list; e != NULL; e = e->next)
235.5720 +            clean_code(mpl, e->x);
235.5721 +#endif
235.5722 +      }
235.5723 +      return;
235.5724 +}
235.5725 +
235.5726 +/*----------------------------------------------------------------------
235.5727 +-- execute_printf - execute printf statement.
235.5728 +--
235.5729 +-- This routine executes specified printf statement. */
235.5730 +
235.5731 +#if 1 /* 14/VII-2006 */
235.5732 +static void print_char(MPL *mpl, int c)
235.5733 +{     if (mpl->prt_fp == NULL)
235.5734 +         write_char(mpl, c);
235.5735 +      else
235.5736 +         xfputc(c, mpl->prt_fp);
235.5737 +      return;
235.5738 +}
235.5739 +
235.5740 +static void print_text(MPL *mpl, char *fmt, ...)
235.5741 +{     va_list arg;
235.5742 +      char buf[OUTBUF_SIZE], *c;
235.5743 +      va_start(arg, fmt);
235.5744 +      vsprintf(buf, fmt, arg);
235.5745 +      xassert(strlen(buf) < sizeof(buf));
235.5746 +      va_end(arg);
235.5747 +      for (c = buf; *c != '\0'; c++) print_char(mpl, *c);
235.5748 +      return;
235.5749 +}
235.5750 +#endif
235.5751 +
235.5752 +static int printf_func(MPL *mpl, void *info)
235.5753 +{     /* this is auxiliary routine to work within domain scope */
235.5754 +      PRINTF *prt = (PRINTF *)info;
235.5755 +      PRINTF1 *entry;
235.5756 +      SYMBOL *sym;
235.5757 +      char fmt[MAX_LENGTH+1], *c, *from, save;
235.5758 +      /* evaluate format control string */
235.5759 +      sym = eval_symbolic(mpl, prt->fmt);
235.5760 +      if (sym->str == NULL)
235.5761 +         sprintf(fmt, "%.*g", DBL_DIG, sym->num);
235.5762 +      else
235.5763 +         fetch_string(mpl, sym->str, fmt);
235.5764 +      delete_symbol(mpl, sym);
235.5765 +      /* scan format control string and perform formatting output */
235.5766 +      entry = prt->list;
235.5767 +      for (c = fmt; *c != '\0'; c++)
235.5768 +      {  if (*c == '%')
235.5769 +         {  /* scan format specifier */
235.5770 +            from = c++;
235.5771 +            if (*c == '%')
235.5772 +            {  print_char(mpl, '%');
235.5773 +               continue;
235.5774 +            }
235.5775 +            if (entry == NULL) break;
235.5776 +            /* scan optional flags */
235.5777 +            while (*c == '-' || *c == '+' || *c == ' ' || *c == '#' ||
235.5778 +                   *c == '0') c++;
235.5779 +            /* scan optional minimum field width */
235.5780 +            while (isdigit((unsigned char)*c)) c++;
235.5781 +            /* scan optional precision */
235.5782 +            if (*c == '.')
235.5783 +            {  c++;
235.5784 +               while (isdigit((unsigned char)*c)) c++;
235.5785 +            }
235.5786 +            /* scan conversion specifier and perform formatting */
235.5787 +            save = *(c+1), *(c+1) = '\0';
235.5788 +            if (*c == 'd' || *c == 'i' || *c == 'e' || *c == 'E' ||
235.5789 +                *c == 'f' || *c == 'F' || *c == 'g' || *c == 'G')
235.5790 +            {  /* the specifier requires numeric value */
235.5791 +               double value;
235.5792 +               xassert(entry != NULL);
235.5793 +               switch (entry->code->type)
235.5794 +               {  case A_NUMERIC:
235.5795 +                     value = eval_numeric(mpl, entry->code);
235.5796 +                     break;
235.5797 +                  case A_SYMBOLIC:
235.5798 +                     sym = eval_symbolic(mpl, entry->code);
235.5799 +                     if (sym->str != NULL)
235.5800 +                        error(mpl, "cannot convert %s to floating-point"
235.5801 +                           " number", format_symbol(mpl, sym));
235.5802 +                     value = sym->num;
235.5803 +                     delete_symbol(mpl, sym);
235.5804 +                     break;
235.5805 +                  case A_LOGICAL:
235.5806 +                     if (eval_logical(mpl, entry->code))
235.5807 +                        value = 1.0;
235.5808 +                     else
235.5809 +                        value = 0.0;
235.5810 +                     break;
235.5811 +                  default:
235.5812 +                     xassert(entry != entry);
235.5813 +               }
235.5814 +               if (*c == 'd' || *c == 'i')
235.5815 +               {  double int_max = (double)INT_MAX;
235.5816 +                  if (!(-int_max <= value && value <= +int_max))
235.5817 +                     error(mpl, "cannot convert %.*g to integer",
235.5818 +                        DBL_DIG, value);
235.5819 +                  print_text(mpl, from, (int)floor(value + 0.5));
235.5820 +               }
235.5821 +               else
235.5822 +                  print_text(mpl, from, value);
235.5823 +            }
235.5824 +            else if (*c == 's')
235.5825 +            {  /* the specifier requires symbolic value */
235.5826 +               char value[MAX_LENGTH+1];
235.5827 +               switch (entry->code->type)
235.5828 +               {  case A_NUMERIC:
235.5829 +                     sprintf(value, "%.*g", DBL_DIG, eval_numeric(mpl,
235.5830 +                        entry->code));
235.5831 +                     break;
235.5832 +                  case A_LOGICAL:
235.5833 +                     if (eval_logical(mpl, entry->code))
235.5834 +                        strcpy(value, "T");
235.5835 +                     else
235.5836 +                        strcpy(value, "F");
235.5837 +                     break;
235.5838 +                  case A_SYMBOLIC:
235.5839 +                     sym = eval_symbolic(mpl, entry->code);
235.5840 +                     if (sym->str == NULL)
235.5841 +                        sprintf(value, "%.*g", DBL_DIG, sym->num);
235.5842 +                     else
235.5843 +                        fetch_string(mpl, sym->str, value);
235.5844 +                     delete_symbol(mpl, sym);
235.5845 +                     break;
235.5846 +                  default:
235.5847 +                     xassert(entry != entry);
235.5848 +               }
235.5849 +               print_text(mpl, from, value);
235.5850 +            }
235.5851 +            else
235.5852 +               error(mpl, "format specifier missing or invalid");
235.5853 +            *(c+1) = save;
235.5854 +            entry = entry->next;
235.5855 +         }
235.5856 +         else if (*c == '\\')
235.5857 +         {  /* write some control character */
235.5858 +            c++;
235.5859 +            if (*c == 't')
235.5860 +               print_char(mpl, '\t');
235.5861 +            else if (*c == 'n')
235.5862 +               print_char(mpl, '\n');
235.5863 +#if 1 /* 28/X-2010 */
235.5864 +            else if (*c == '\0')
235.5865 +            {  /* format string ends with backslash */
235.5866 +               error(mpl, "invalid use of escape character \\ in format"
235.5867 +                  " control string");
235.5868 +            }
235.5869 +#endif
235.5870 +            else
235.5871 +               print_char(mpl, *c);
235.5872 +         }
235.5873 +         else
235.5874 +         {  /* write character without formatting */
235.5875 +            print_char(mpl, *c);
235.5876 +         }
235.5877 +      }
235.5878 +      return 0;
235.5879 +}
235.5880 +
235.5881 +#if 0 /* 14/VII-2006 */
235.5882 +void execute_printf(MPL *mpl, PRINTF *prt)
235.5883 +{     loop_within_domain(mpl, prt->domain, prt, printf_func);
235.5884 +      return;
235.5885 +}
235.5886 +#else
235.5887 +void execute_printf(MPL *mpl, PRINTF *prt)
235.5888 +{     if (prt->fname == NULL)
235.5889 +      {  /* switch to the standard output */
235.5890 +         if (mpl->prt_fp != NULL)
235.5891 +         {  xfclose(mpl->prt_fp), mpl->prt_fp = NULL;
235.5892 +            xfree(mpl->prt_file), mpl->prt_file = NULL;
235.5893 +         }
235.5894 +      }
235.5895 +      else
235.5896 +      {  /* evaluate file name string */
235.5897 +         SYMBOL *sym;
235.5898 +         char fname[MAX_LENGTH+1];
235.5899 +         sym = eval_symbolic(mpl, prt->fname);
235.5900 +         if (sym->str == NULL)
235.5901 +            sprintf(fname, "%.*g", DBL_DIG, sym->num);
235.5902 +         else
235.5903 +            fetch_string(mpl, sym->str, fname);
235.5904 +         delete_symbol(mpl, sym);
235.5905 +         /* close the current print file, if necessary */
235.5906 +         if (mpl->prt_fp != NULL &&
235.5907 +            (!prt->app || strcmp(mpl->prt_file, fname) != 0))
235.5908 +         {  xfclose(mpl->prt_fp), mpl->prt_fp = NULL;
235.5909 +            xfree(mpl->prt_file), mpl->prt_file = NULL;
235.5910 +         }
235.5911 +         /* open the specified print file, if necessary */
235.5912 +         if (mpl->prt_fp == NULL)
235.5913 +         {  mpl->prt_fp = xfopen(fname, prt->app ? "a" : "w");
235.5914 +            if (mpl->prt_fp == NULL)
235.5915 +               error(mpl, "unable to open `%s' for writing - %s",
235.5916 +                  fname, xerrmsg());
235.5917 +            mpl->prt_file = xmalloc(strlen(fname)+1);
235.5918 +            strcpy(mpl->prt_file, fname);
235.5919 +         }
235.5920 +      }
235.5921 +      loop_within_domain(mpl, prt->domain, prt, printf_func);
235.5922 +      if (mpl->prt_fp != NULL)
235.5923 +      {  xfflush(mpl->prt_fp);
235.5924 +         if (xferror(mpl->prt_fp))
235.5925 +            error(mpl, "writing error to `%s' - %s", mpl->prt_file,
235.5926 +               xerrmsg());
235.5927 +      }
235.5928 +      return;
235.5929 +}
235.5930 +#endif
235.5931 +
235.5932 +/*----------------------------------------------------------------------
235.5933 +-- clean_printf - clean printf statement.
235.5934 +--
235.5935 +-- This routine cleans specified printf statement that assumes deleting
235.5936 +-- all stuff dynamically allocated on generating/postsolving phase. */
235.5937 +
235.5938 +void clean_printf(MPL *mpl, PRINTF *prt)
235.5939 +{     PRINTF1 *p;
235.5940 +      /* clean subscript domain */
235.5941 +      clean_domain(mpl, prt->domain);
235.5942 +      /* clean pseudo-code for computing format string */
235.5943 +      clean_code(mpl, prt->fmt);
235.5944 +      /* clean printf list */
235.5945 +      for (p = prt->list; p != NULL; p = p->next)
235.5946 +      {  /* clean pseudo-code for computing value to be printed */
235.5947 +         clean_code(mpl, p->code);
235.5948 +      }
235.5949 +#if 1 /* 14/VII-2006 */
235.5950 +      /* clean pseudo-code for computing file name string */
235.5951 +      clean_code(mpl, prt->fname);
235.5952 +#endif
235.5953 +      return;
235.5954 +}
235.5955 +
235.5956 +/*----------------------------------------------------------------------
235.5957 +-- execute_for - execute for statement.
235.5958 +--
235.5959 +-- This routine executes specified for statement. */
235.5960 +
235.5961 +static int for_func(MPL *mpl, void *info)
235.5962 +{     /* this is auxiliary routine to work within domain scope */
235.5963 +      FOR *fur = (FOR *)info;
235.5964 +      STATEMENT *stmt, *save;
235.5965 +      save = mpl->stmt;
235.5966 +      for (stmt = fur->list; stmt != NULL; stmt = stmt->next)
235.5967 +         execute_statement(mpl, stmt);
235.5968 +      mpl->stmt = save;
235.5969 +      return 0;
235.5970 +}
235.5971 +
235.5972 +void execute_for(MPL *mpl, FOR *fur)
235.5973 +{     loop_within_domain(mpl, fur->domain, fur, for_func);
235.5974 +      return;
235.5975 +}
235.5976 +
235.5977 +/*----------------------------------------------------------------------
235.5978 +-- clean_for - clean for statement.
235.5979 +--
235.5980 +-- This routine cleans specified for statement that assumes deleting all
235.5981 +-- stuff dynamically allocated on generating/postsolving phase. */
235.5982 +
235.5983 +void clean_for(MPL *mpl, FOR *fur)
235.5984 +{     STATEMENT *stmt;
235.5985 +      /* clean subscript domain */
235.5986 +      clean_domain(mpl, fur->domain);
235.5987 +      /* clean all sub-statements */
235.5988 +      for (stmt = fur->list; stmt != NULL; stmt = stmt->next)
235.5989 +         clean_statement(mpl, stmt);
235.5990 +      return;
235.5991 +}
235.5992 +
235.5993 +/*----------------------------------------------------------------------
235.5994 +-- execute_statement - execute specified model statement.
235.5995 +--
235.5996 +-- This routine executes specified model statement. */
235.5997 +
235.5998 +void execute_statement(MPL *mpl, STATEMENT *stmt)
235.5999 +{     mpl->stmt = stmt;
235.6000 +      switch (stmt->type)
235.6001 +      {  case A_SET:
235.6002 +         case A_PARAMETER:
235.6003 +         case A_VARIABLE:
235.6004 +            break;
235.6005 +         case A_CONSTRAINT:
235.6006 +            xprintf("Generating %s...\n", stmt->u.con->name);
235.6007 +            eval_whole_con(mpl, stmt->u.con);
235.6008 +            break;
235.6009 +         case A_TABLE:
235.6010 +            switch (stmt->u.tab->type)
235.6011 +            {  case A_INPUT:
235.6012 +                  xprintf("Reading %s...\n", stmt->u.tab->name);
235.6013 +                  break;
235.6014 +               case A_OUTPUT:
235.6015 +                  xprintf("Writing %s...\n", stmt->u.tab->name);
235.6016 +                  break;
235.6017 +               default:
235.6018 +                  xassert(stmt != stmt);
235.6019 +            }
235.6020 +            execute_table(mpl, stmt->u.tab);
235.6021 +            break;
235.6022 +         case A_SOLVE:
235.6023 +            break;
235.6024 +         case A_CHECK:
235.6025 +            xprintf("Checking (line %d)...\n", stmt->line);
235.6026 +            execute_check(mpl, stmt->u.chk);
235.6027 +            break;
235.6028 +         case A_DISPLAY:
235.6029 +            write_text(mpl, "Display statement at line %d\n",
235.6030 +               stmt->line);
235.6031 +            execute_display(mpl, stmt->u.dpy);
235.6032 +            break;
235.6033 +         case A_PRINTF:
235.6034 +            execute_printf(mpl, stmt->u.prt);
235.6035 +            break;
235.6036 +         case A_FOR:
235.6037 +            execute_for(mpl, stmt->u.fur);
235.6038 +            break;
235.6039 +         default:
235.6040 +            xassert(stmt != stmt);
235.6041 +      }
235.6042 +      return;
235.6043 +}
235.6044 +
235.6045 +/*----------------------------------------------------------------------
235.6046 +-- clean_statement - clean specified model statement.
235.6047 +--
235.6048 +-- This routine cleans specified model statement that assumes deleting
235.6049 +-- all stuff dynamically allocated on generating/postsolving phase. */
235.6050 +
235.6051 +void clean_statement(MPL *mpl, STATEMENT *stmt)
235.6052 +{     switch(stmt->type)
235.6053 +      {  case A_SET:
235.6054 +            clean_set(mpl, stmt->u.set); break;
235.6055 +         case A_PARAMETER:
235.6056 +            clean_parameter(mpl, stmt->u.par); break;
235.6057 +         case A_VARIABLE:
235.6058 +            clean_variable(mpl, stmt->u.var); break;
235.6059 +         case A_CONSTRAINT:
235.6060 +            clean_constraint(mpl, stmt->u.con); break;
235.6061 +#if 1 /* 11/II-2008 */
235.6062 +         case A_TABLE:
235.6063 +            clean_table(mpl, stmt->u.tab); break;
235.6064 +#endif
235.6065 +         case A_SOLVE:
235.6066 +            break;
235.6067 +         case A_CHECK:
235.6068 +            clean_check(mpl, stmt->u.chk); break;
235.6069 +         case A_DISPLAY:
235.6070 +            clean_display(mpl, stmt->u.dpy); break;
235.6071 +         case A_PRINTF:
235.6072 +            clean_printf(mpl, stmt->u.prt); break;
235.6073 +         case A_FOR:
235.6074 +            clean_for(mpl, stmt->u.fur); break;
235.6075 +         default:
235.6076 +            xassert(stmt != stmt);
235.6077 +      }
235.6078 +      return;
235.6079 +}
235.6080 +
235.6081 +/* eof */
   236.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   236.2 +++ b/src/glpmpl04.c	Mon Dec 06 13:09:21 2010 +0100
   236.3 @@ -0,0 +1,1424 @@
   236.4 +/* glpmpl04.c */
   236.5 +
   236.6 +/***********************************************************************
   236.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   236.8 +*
   236.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  236.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  236.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  236.12 +*  E-mail: <mao@gnu.org>.
  236.13 +*
  236.14 +*  GLPK is free software: you can redistribute it and/or modify it
  236.15 +*  under the terms of the GNU General Public License as published by
  236.16 +*  the Free Software Foundation, either version 3 of the License, or
  236.17 +*  (at your option) any later version.
  236.18 +*
  236.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  236.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  236.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  236.22 +*  License for more details.
  236.23 +*
  236.24 +*  You should have received a copy of the GNU General Public License
  236.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  236.26 +***********************************************************************/
  236.27 +
  236.28 +#define _GLPSTD_ERRNO
  236.29 +#define _GLPSTD_STDIO
  236.30 +#include "glpmpl.h"
  236.31 +#define xfault xerror
  236.32 +#define dmp_create_poolx(size) dmp_create_pool()
  236.33 +
  236.34 +/**********************************************************************/
  236.35 +/* * *              GENERATING AND POSTSOLVING MODEL              * * */
  236.36 +/**********************************************************************/
  236.37 +
  236.38 +/*----------------------------------------------------------------------
  236.39 +-- alloc_content - allocate content arrays for all model objects.
  236.40 +--
  236.41 +-- This routine allocates content arrays for all existing model objects
  236.42 +-- and thereby finalizes creating model.
  236.43 +--
  236.44 +-- This routine must be called immediately after reading model section,
  236.45 +-- i.e. before reading data section or generating model. */
  236.46 +
  236.47 +void alloc_content(MPL *mpl)
  236.48 +{     STATEMENT *stmt;
  236.49 +      /* walk through all model statements */
  236.50 +      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
  236.51 +      {  switch (stmt->type)
  236.52 +         {  case A_SET:
  236.53 +               /* model set */
  236.54 +               xassert(stmt->u.set->array == NULL);
  236.55 +               stmt->u.set->array = create_array(mpl, A_ELEMSET,
  236.56 +                  stmt->u.set->dim);
  236.57 +               break;
  236.58 +            case A_PARAMETER:
  236.59 +               /* model parameter */
  236.60 +               xassert(stmt->u.par->array == NULL);
  236.61 +               switch (stmt->u.par->type)
  236.62 +               {  case A_NUMERIC:
  236.63 +                  case A_INTEGER:
  236.64 +                  case A_BINARY:
  236.65 +                     stmt->u.par->array = create_array(mpl, A_NUMERIC,
  236.66 +                        stmt->u.par->dim);
  236.67 +                     break;
  236.68 +                  case A_SYMBOLIC:
  236.69 +                     stmt->u.par->array = create_array(mpl, A_SYMBOLIC,
  236.70 +                        stmt->u.par->dim);
  236.71 +                     break;
  236.72 +                  default:
  236.73 +                     xassert(stmt != stmt);
  236.74 +               }
  236.75 +               break;
  236.76 +            case A_VARIABLE:
  236.77 +               /* model variable */
  236.78 +               xassert(stmt->u.var->array == NULL);
  236.79 +               stmt->u.var->array = create_array(mpl, A_ELEMVAR,
  236.80 +                  stmt->u.var->dim);
  236.81 +               break;
  236.82 +            case A_CONSTRAINT:
  236.83 +               /* model constraint/objective */
  236.84 +               xassert(stmt->u.con->array == NULL);
  236.85 +               stmt->u.con->array = create_array(mpl, A_ELEMCON,
  236.86 +                  stmt->u.con->dim);
  236.87 +               break;
  236.88 +#if 1 /* 11/II-2008 */
  236.89 +            case A_TABLE:
  236.90 +#endif
  236.91 +            case A_SOLVE:
  236.92 +            case A_CHECK:
  236.93 +            case A_DISPLAY:
  236.94 +            case A_PRINTF:
  236.95 +            case A_FOR:
  236.96 +               /* functional statements have no content array */
  236.97 +               break;
  236.98 +            default:
  236.99 +               xassert(stmt != stmt);
 236.100 +         }
 236.101 +      }
 236.102 +      return;
 236.103 +}
 236.104 +
 236.105 +/*----------------------------------------------------------------------
 236.106 +-- generate_model - generate model.
 236.107 +--
 236.108 +-- This routine executes the model statements which precede the solve
 236.109 +-- statement. */
 236.110 +
 236.111 +void generate_model(MPL *mpl)
 236.112 +{     STATEMENT *stmt;
 236.113 +      xassert(!mpl->flag_p);
 236.114 +      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
 236.115 +      {  execute_statement(mpl, stmt);
 236.116 +         if (mpl->stmt->type == A_SOLVE) break;
 236.117 +      }
 236.118 +      mpl->stmt = stmt;
 236.119 +      return;
 236.120 +}
 236.121 +
 236.122 +/*----------------------------------------------------------------------
 236.123 +-- build_problem - build problem instance.
 236.124 +--
 236.125 +-- This routine builds lists of rows and columns for problem instance,
 236.126 +-- which corresponds to the generated model. */
 236.127 +
 236.128 +void build_problem(MPL *mpl)
 236.129 +{     STATEMENT *stmt;
 236.130 +      MEMBER *memb;
 236.131 +      VARIABLE *v;
 236.132 +      CONSTRAINT *c;
 236.133 +      FORMULA *t;
 236.134 +      int i, j;
 236.135 +      xassert(mpl->m == 0);
 236.136 +      xassert(mpl->n == 0);
 236.137 +      xassert(mpl->row == NULL);
 236.138 +      xassert(mpl->col == NULL);
 236.139 +      /* check that all elemental variables has zero column numbers */
 236.140 +      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
 236.141 +      {  if (stmt->type == A_VARIABLE)
 236.142 +         {  v = stmt->u.var;
 236.143 +            for (memb = v->array->head; memb != NULL; memb = memb->next)
 236.144 +               xassert(memb->value.var->j == 0);
 236.145 +         }
 236.146 +      }
 236.147 +      /* assign row numbers to elemental constraints and objectives */
 236.148 +      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
 236.149 +      {  if (stmt->type == A_CONSTRAINT)
 236.150 +         {  c = stmt->u.con;
 236.151 +            for (memb = c->array->head; memb != NULL; memb = memb->next)
 236.152 +            {  xassert(memb->value.con->i == 0);
 236.153 +               memb->value.con->i = ++mpl->m;
 236.154 +               /* walk through linear form and mark elemental variables,
 236.155 +                  which are referenced at least once */
 236.156 +               for (t = memb->value.con->form; t != NULL; t = t->next)
 236.157 +               {  xassert(t->var != NULL);
 236.158 +                  t->var->memb->value.var->j = -1;
 236.159 +               }
 236.160 +            }
 236.161 +         }
 236.162 +      }
 236.163 +      /* assign column numbers to marked elemental variables */
 236.164 +      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
 236.165 +      {  if (stmt->type == A_VARIABLE)
 236.166 +         {  v = stmt->u.var;
 236.167 +            for (memb = v->array->head; memb != NULL; memb = memb->next)
 236.168 +               if (memb->value.var->j != 0) memb->value.var->j =
 236.169 +                  ++mpl->n;
 236.170 +         }
 236.171 +      }
 236.172 +      /* build list of rows */
 236.173 +      mpl->row = xcalloc(1+mpl->m, sizeof(ELEMCON *));
 236.174 +      for (i = 1; i <= mpl->m; i++) mpl->row[i] = NULL;
 236.175 +      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
 236.176 +      {  if (stmt->type == A_CONSTRAINT)
 236.177 +         {  c = stmt->u.con;
 236.178 +            for (memb = c->array->head; memb != NULL; memb = memb->next)
 236.179 +            {  i = memb->value.con->i;
 236.180 +               xassert(1 <= i && i <= mpl->m);
 236.181 +               xassert(mpl->row[i] == NULL);
 236.182 +               mpl->row[i] = memb->value.con;
 236.183 +            }
 236.184 +         }
 236.185 +      }
 236.186 +      for (i = 1; i <= mpl->m; i++) xassert(mpl->row[i] != NULL);
 236.187 +      /* build list of columns */
 236.188 +      mpl->col = xcalloc(1+mpl->n, sizeof(ELEMVAR *));
 236.189 +      for (j = 1; j <= mpl->n; j++) mpl->col[j] = NULL;
 236.190 +      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
 236.191 +      {  if (stmt->type == A_VARIABLE)
 236.192 +         {  v = stmt->u.var;
 236.193 +            for (memb = v->array->head; memb != NULL; memb = memb->next)
 236.194 +            {  j = memb->value.var->j;
 236.195 +               if (j == 0) continue;
 236.196 +               xassert(1 <= j && j <= mpl->n);
 236.197 +               xassert(mpl->col[j] == NULL);
 236.198 +               mpl->col[j] = memb->value.var;
 236.199 +            }
 236.200 +         }
 236.201 +      }
 236.202 +      for (j = 1; j <= mpl->n; j++) xassert(mpl->col[j] != NULL);
 236.203 +      return;
 236.204 +}
 236.205 +
 236.206 +/*----------------------------------------------------------------------
 236.207 +-- postsolve_model - postsolve model.
 236.208 +--
 236.209 +-- This routine executes the model statements which follow the solve
 236.210 +-- statement. */
 236.211 +
 236.212 +void postsolve_model(MPL *mpl)
 236.213 +{     STATEMENT *stmt;
 236.214 +      xassert(!mpl->flag_p);
 236.215 +      mpl->flag_p = 1;
 236.216 +      for (stmt = mpl->stmt; stmt != NULL; stmt = stmt->next)
 236.217 +         execute_statement(mpl, stmt);
 236.218 +      mpl->stmt = NULL;
 236.219 +      return;
 236.220 +}
 236.221 +
 236.222 +/*----------------------------------------------------------------------
 236.223 +-- clean_model - clean model content.
 236.224 +--
 236.225 +-- This routine cleans the model content that assumes deleting all stuff
 236.226 +-- dynamically allocated on generating/postsolving phase.
 236.227 +--
 236.228 +-- Actually cleaning model content is not needed. This function is used
 236.229 +-- mainly to be sure that there were no logical errors on using dynamic
 236.230 +-- memory pools during the generation phase.
 236.231 +--
 236.232 +-- NOTE: This routine must not be called if any errors were detected on
 236.233 +--       the generation phase. */
 236.234 +
 236.235 +void clean_model(MPL *mpl)
 236.236 +{     STATEMENT *stmt;
 236.237 +      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
 236.238 +         clean_statement(mpl, stmt);
 236.239 +      /* check that all atoms have been returned to their pools */
 236.240 +      if (dmp_in_use(mpl->strings).lo != 0)
 236.241 +         error(mpl, "internal logic error: %d string segment(s) were lo"
 236.242 +            "st", dmp_in_use(mpl->strings).lo);
 236.243 +      if (dmp_in_use(mpl->symbols).lo != 0)
 236.244 +         error(mpl, "internal logic error: %d symbol(s) were lost",
 236.245 +            dmp_in_use(mpl->symbols).lo);
 236.246 +      if (dmp_in_use(mpl->tuples).lo != 0)
 236.247 +         error(mpl, "internal logic error: %d n-tuple component(s) were"
 236.248 +            " lost", dmp_in_use(mpl->tuples).lo);
 236.249 +      if (dmp_in_use(mpl->arrays).lo != 0)
 236.250 +         error(mpl, "internal logic error: %d array(s) were lost",
 236.251 +            dmp_in_use(mpl->arrays).lo);
 236.252 +      if (dmp_in_use(mpl->members).lo != 0)
 236.253 +         error(mpl, "internal logic error: %d array member(s) were lost"
 236.254 +            , dmp_in_use(mpl->members).lo);
 236.255 +      if (dmp_in_use(mpl->elemvars).lo != 0)
 236.256 +         error(mpl, "internal logic error: %d elemental variable(s) wer"
 236.257 +            "e lost", dmp_in_use(mpl->elemvars).lo);
 236.258 +      if (dmp_in_use(mpl->formulae).lo != 0)
 236.259 +         error(mpl, "internal logic error: %d linear term(s) were lost",
 236.260 +            dmp_in_use(mpl->formulae).lo);
 236.261 +      if (dmp_in_use(mpl->elemcons).lo != 0)
 236.262 +         error(mpl, "internal logic error: %d elemental constraint(s) w"
 236.263 +            "ere lost", dmp_in_use(mpl->elemcons).lo);
 236.264 +      return;
 236.265 +}
 236.266 +
 236.267 +/**********************************************************************/
 236.268 +/* * *                        INPUT/OUTPUT                        * * */
 236.269 +/**********************************************************************/
 236.270 +
 236.271 +/*----------------------------------------------------------------------
 236.272 +-- open_input - open input text file.
 236.273 +--
 236.274 +-- This routine opens the input text file for scanning. */
 236.275 +
 236.276 +void open_input(MPL *mpl, char *file)
 236.277 +{     mpl->line = 0;
 236.278 +      mpl->c = '\n';
 236.279 +      mpl->token = 0;
 236.280 +      mpl->imlen = 0;
 236.281 +      mpl->image[0] = '\0';
 236.282 +      mpl->value = 0.0;
 236.283 +      mpl->b_token = T_EOF;
 236.284 +      mpl->b_imlen = 0;
 236.285 +      mpl->b_image[0] = '\0';
 236.286 +      mpl->b_value = 0.0;
 236.287 +      mpl->f_dots = 0;
 236.288 +      mpl->f_scan = 0;
 236.289 +      mpl->f_token = 0;
 236.290 +      mpl->f_imlen = 0;
 236.291 +      mpl->f_image[0] = '\0';
 236.292 +      mpl->f_value = 0.0;
 236.293 +      memset(mpl->context, ' ', CONTEXT_SIZE);
 236.294 +      mpl->c_ptr = 0;
 236.295 +      xassert(mpl->in_fp == NULL);
 236.296 +      mpl->in_fp = xfopen(file, "r");
 236.297 +      if (mpl->in_fp == NULL)
 236.298 +         error(mpl, "unable to open %s - %s", file, xerrmsg());
 236.299 +      mpl->in_file = file;
 236.300 +      /* scan the very first character */
 236.301 +      get_char(mpl);
 236.302 +      /* scan the very first token */
 236.303 +      get_token(mpl);
 236.304 +      return;
 236.305 +}
 236.306 +
 236.307 +/*----------------------------------------------------------------------
 236.308 +-- read_char - read next character from input text file.
 236.309 +--
 236.310 +-- This routine returns a next ASCII character read from the input text
 236.311 +-- file. If the end of file has been reached, EOF is returned. */
 236.312 +
 236.313 +int read_char(MPL *mpl)
 236.314 +{     int c;
 236.315 +      xassert(mpl->in_fp != NULL);
 236.316 +      c = xfgetc(mpl->in_fp);
 236.317 +      if (c < 0)
 236.318 +      {  if (xferror(mpl->in_fp))
 236.319 +            error(mpl, "read error on %s - %s", mpl->in_file,
 236.320 +               xerrmsg());
 236.321 +         c = EOF;
 236.322 +      }
 236.323 +      return c;
 236.324 +}
 236.325 +
 236.326 +/*----------------------------------------------------------------------
 236.327 +-- close_input - close input text file.
 236.328 +--
 236.329 +-- This routine closes the input text file. */
 236.330 +
 236.331 +void close_input(MPL *mpl)
 236.332 +{     xassert(mpl->in_fp != NULL);
 236.333 +      xfclose(mpl->in_fp);
 236.334 +      mpl->in_fp = NULL;
 236.335 +      mpl->in_file = NULL;
 236.336 +      return;
 236.337 +}
 236.338 +
 236.339 +/*----------------------------------------------------------------------
 236.340 +-- open_output - open output text file.
 236.341 +--
 236.342 +-- This routine opens the output text file for writing data produced by
 236.343 +-- display and printf statements. */
 236.344 +
 236.345 +void open_output(MPL *mpl, char *file)
 236.346 +{     xassert(mpl->out_fp == NULL);
 236.347 +      if (file == NULL)
 236.348 +      {  file = "<stdout>";
 236.349 +         mpl->out_fp = (void *)stdout;
 236.350 +      }
 236.351 +      else
 236.352 +      {  mpl->out_fp = xfopen(file, "w");
 236.353 +         if (mpl->out_fp == NULL)
 236.354 +            error(mpl, "unable to create %s - %s", file, xerrmsg());
 236.355 +      }
 236.356 +      mpl->out_file = xmalloc(strlen(file)+1);
 236.357 +      strcpy(mpl->out_file, file);
 236.358 +      return;
 236.359 +}
 236.360 +
 236.361 +/*----------------------------------------------------------------------
 236.362 +-- write_char - write next character to output text file.
 236.363 +--
 236.364 +-- This routine writes an ASCII character to the output text file. */
 236.365 +
 236.366 +void write_char(MPL *mpl, int c)
 236.367 +{     xassert(mpl->out_fp != NULL);
 236.368 +      if (mpl->out_fp == (void *)stdout)
 236.369 +         xprintf("%c", c);
 236.370 +      else
 236.371 +         xfprintf(mpl->out_fp, "%c", c);
 236.372 +      return;
 236.373 +}
 236.374 +
 236.375 +/*----------------------------------------------------------------------
 236.376 +-- write_text - format and write text to output text file.
 236.377 +--
 236.378 +-- This routine formats a text using the format control string and then
 236.379 +-- writes this text to the output text file. */
 236.380 +
 236.381 +void write_text(MPL *mpl, char *fmt, ...)
 236.382 +{     va_list arg;
 236.383 +      char buf[OUTBUF_SIZE], *c;
 236.384 +      va_start(arg, fmt);
 236.385 +      vsprintf(buf, fmt, arg);
 236.386 +      xassert(strlen(buf) < sizeof(buf));
 236.387 +      va_end(arg);
 236.388 +      for (c = buf; *c != '\0'; c++) write_char(mpl, *c);
 236.389 +      return;
 236.390 +}
 236.391 +
 236.392 +/*----------------------------------------------------------------------
 236.393 +-- flush_output - finalize writing data to output text file.
 236.394 +--
 236.395 +-- This routine finalizes writing data to the output text file. */
 236.396 +
 236.397 +void flush_output(MPL *mpl)
 236.398 +{     xassert(mpl->out_fp != NULL);
 236.399 +      if (mpl->out_fp != (void *)stdout)
 236.400 +      {  xfflush(mpl->out_fp);
 236.401 +         if (xferror(mpl->out_fp))
 236.402 +            error(mpl, "write error on %s - %s", mpl->out_file,
 236.403 +               xerrmsg());
 236.404 +      }
 236.405 +      return;
 236.406 +}
 236.407 +
 236.408 +/**********************************************************************/
 236.409 +/* * *                      SOLVER INTERFACE                      * * */
 236.410 +/**********************************************************************/
 236.411 +
 236.412 +/*----------------------------------------------------------------------
 236.413 +-- error - print error message and terminate model processing.
 236.414 +--
 236.415 +-- This routine formats and prints an error message and then terminates
 236.416 +-- model processing. */
 236.417 +
 236.418 +void error(MPL *mpl, char *fmt, ...)
 236.419 +{     va_list arg;
 236.420 +      char msg[4095+1];
 236.421 +      va_start(arg, fmt);
 236.422 +      vsprintf(msg, fmt, arg);
 236.423 +      xassert(strlen(msg) < sizeof(msg));
 236.424 +      va_end(arg);
 236.425 +      switch (mpl->phase)
 236.426 +      {  case 1:
 236.427 +         case 2:
 236.428 +            /* translation phase */
 236.429 +            xprintf("%s:%d: %s\n",
 236.430 +               mpl->in_file == NULL ? "(unknown)" : mpl->in_file,
 236.431 +               mpl->line, msg);
 236.432 +            print_context(mpl);
 236.433 +            break;
 236.434 +         case 3:
 236.435 +            /* generation/postsolve phase */
 236.436 +            xprintf("%s:%d: %s\n",
 236.437 +               mpl->mod_file == NULL ? "(unknown)" : mpl->mod_file,
 236.438 +               mpl->stmt == NULL ? 0 : mpl->stmt->line, msg);
 236.439 +            break;
 236.440 +         default:
 236.441 +            xassert(mpl != mpl);
 236.442 +      }
 236.443 +      mpl->phase = 4;
 236.444 +      longjmp(mpl->jump, 1);
 236.445 +      /* no return */
 236.446 +}
 236.447 +
 236.448 +/*----------------------------------------------------------------------
 236.449 +-- warning - print warning message and continue model processing.
 236.450 +--
 236.451 +-- This routine formats and prints a warning message and returns to the
 236.452 +-- calling program. */
 236.453 +
 236.454 +void warning(MPL *mpl, char *fmt, ...)
 236.455 +{     va_list arg;
 236.456 +      char msg[4095+1];
 236.457 +      va_start(arg, fmt);
 236.458 +      vsprintf(msg, fmt, arg);
 236.459 +      xassert(strlen(msg) < sizeof(msg));
 236.460 +      va_end(arg);
 236.461 +      switch (mpl->phase)
 236.462 +      {  case 1:
 236.463 +         case 2:
 236.464 +            /* translation phase */
 236.465 +            xprintf("%s:%d: warning: %s\n",
 236.466 +               mpl->in_file == NULL ? "(unknown)" : mpl->in_file,
 236.467 +               mpl->line, msg);
 236.468 +            break;
 236.469 +         case 3:
 236.470 +            /* generation/postsolve phase */
 236.471 +            xprintf("%s:%d: warning: %s\n",
 236.472 +               mpl->mod_file == NULL ? "(unknown)" : mpl->mod_file,
 236.473 +               mpl->stmt == NULL ? 0 : mpl->stmt->line, msg);
 236.474 +            break;
 236.475 +         default:
 236.476 +            xassert(mpl != mpl);
 236.477 +      }
 236.478 +      return;
 236.479 +}
 236.480 +
 236.481 +/*----------------------------------------------------------------------
 236.482 +-- mpl_initialize - create and initialize translator database.
 236.483 +--
 236.484 +-- *Synopsis*
 236.485 +--
 236.486 +-- #include "glpmpl.h"
 236.487 +-- MPL *mpl_initialize(void);
 236.488 +--
 236.489 +-- *Description*
 236.490 +--
 236.491 +-- The routine mpl_initialize creates and initializes the database used
 236.492 +-- by the GNU MathProg translator.
 236.493 +--
 236.494 +-- *Returns*
 236.495 +--
 236.496 +-- The routine returns a pointer to the database created. */
 236.497 +
 236.498 +MPL *mpl_initialize(void)
 236.499 +{     MPL *mpl;
 236.500 +      mpl = xmalloc(sizeof(MPL));
 236.501 +      /* scanning segment */
 236.502 +      mpl->line = 0;
 236.503 +      mpl->c = 0;
 236.504 +      mpl->token = 0;
 236.505 +      mpl->imlen = 0;
 236.506 +      mpl->image = xcalloc(MAX_LENGTH+1, sizeof(char));
 236.507 +      mpl->image[0] = '\0';
 236.508 +      mpl->value = 0.0;
 236.509 +      mpl->b_token = 0;
 236.510 +      mpl->b_imlen = 0;
 236.511 +      mpl->b_image = xcalloc(MAX_LENGTH+1, sizeof(char));
 236.512 +      mpl->b_image[0] = '\0';
 236.513 +      mpl->b_value = 0.0;
 236.514 +      mpl->f_dots = 0;
 236.515 +      mpl->f_scan = 0;
 236.516 +      mpl->f_token = 0;
 236.517 +      mpl->f_imlen = 0;
 236.518 +      mpl->f_image = xcalloc(MAX_LENGTH+1, sizeof(char));
 236.519 +      mpl->f_image[0] = '\0';
 236.520 +      mpl->f_value = 0.0;
 236.521 +      mpl->context = xcalloc(CONTEXT_SIZE, sizeof(char));
 236.522 +      memset(mpl->context, ' ', CONTEXT_SIZE);
 236.523 +      mpl->c_ptr = 0;
 236.524 +      mpl->flag_d = 0;
 236.525 +      /* translating segment */
 236.526 +      mpl->pool = dmp_create_poolx(0);
 236.527 +      mpl->tree = avl_create_tree(avl_strcmp, NULL);
 236.528 +      mpl->model = NULL;
 236.529 +      mpl->flag_x = 0;
 236.530 +      mpl->as_within = 0;
 236.531 +      mpl->as_in = 0;
 236.532 +      mpl->as_binary = 0;
 236.533 +      mpl->flag_s = 0;
 236.534 +      /* common segment */
 236.535 +      mpl->strings = dmp_create_poolx(sizeof(STRING));
 236.536 +      mpl->symbols = dmp_create_poolx(sizeof(SYMBOL));
 236.537 +      mpl->tuples = dmp_create_poolx(sizeof(TUPLE));
 236.538 +      mpl->arrays = dmp_create_poolx(sizeof(ARRAY));
 236.539 +      mpl->members = dmp_create_poolx(sizeof(MEMBER));
 236.540 +      mpl->elemvars = dmp_create_poolx(sizeof(ELEMVAR));
 236.541 +      mpl->formulae = dmp_create_poolx(sizeof(FORMULA));
 236.542 +      mpl->elemcons = dmp_create_poolx(sizeof(ELEMCON));
 236.543 +      mpl->a_list = NULL;
 236.544 +      mpl->sym_buf = xcalloc(255+1, sizeof(char));
 236.545 +      mpl->sym_buf[0] = '\0';
 236.546 +      mpl->tup_buf = xcalloc(255+1, sizeof(char));
 236.547 +      mpl->tup_buf[0] = '\0';
 236.548 +      /* generating/postsolving segment */
 236.549 +      mpl->rand = rng_create_rand();
 236.550 +      mpl->flag_p = 0;
 236.551 +      mpl->stmt = NULL;
 236.552 +#if 1 /* 11/II-2008 */
 236.553 +      mpl->dca = NULL;
 236.554 +#endif
 236.555 +      mpl->m = 0;
 236.556 +      mpl->n = 0;
 236.557 +      mpl->row = NULL;
 236.558 +      mpl->col = NULL;
 236.559 +      /* input/output segment */
 236.560 +      mpl->in_fp = NULL;
 236.561 +      mpl->in_file = NULL;
 236.562 +      mpl->out_fp = NULL;
 236.563 +      mpl->out_file = NULL;
 236.564 +      mpl->prt_fp = NULL;
 236.565 +      mpl->prt_file = NULL;
 236.566 +      /* solver interface segment */
 236.567 +      if (setjmp(mpl->jump)) xassert(mpl != mpl);
 236.568 +      mpl->phase = 0;
 236.569 +      mpl->mod_file = NULL;
 236.570 +      mpl->mpl_buf = xcalloc(255+1, sizeof(char));
 236.571 +      mpl->mpl_buf[0] = '\0';
 236.572 +      return mpl;
 236.573 +}
 236.574 +
 236.575 +/*----------------------------------------------------------------------
 236.576 +-- mpl_read_model - read model section and optional data section.
 236.577 +--
 236.578 +-- *Synopsis*
 236.579 +--
 236.580 +-- #include "glpmpl.h"
 236.581 +-- int mpl_read_model(MPL *mpl, char *file, int skip_data);
 236.582 +--
 236.583 +-- *Description*
 236.584 +--
 236.585 +-- The routine mpl_read_model reads model section and optionally data
 236.586 +-- section, which may follow the model section, from the text file,
 236.587 +-- whose name is the character string file, performs translating model
 236.588 +-- statements and data blocks, and stores all the information in the
 236.589 +-- translator database.
 236.590 +--
 236.591 +-- The parameter skip_data is a flag. If the input file contains the
 236.592 +-- data section and this flag is set, the data section is not read as
 236.593 +-- if there were no data section and a warning message is issued. This
 236.594 +-- allows reading the data section from another input file.
 236.595 +--
 236.596 +-- This routine should be called once after the routine mpl_initialize
 236.597 +-- and before other API routines.
 236.598 +--
 236.599 +-- *Returns*
 236.600 +--
 236.601 +-- The routine mpl_read_model returns one the following codes:
 236.602 +--
 236.603 +-- 1 - translation successful. The input text file contains only model
 236.604 +--     section. In this case the calling program may call the routine
 236.605 +--     mpl_read_data to read data section from another file.
 236.606 +-- 2 - translation successful. The input text file contains both model
 236.607 +--     and data section.
 236.608 +-- 4 - processing failed due to some errors. In this case the calling
 236.609 +--     program should call the routine mpl_terminate to terminate model
 236.610 +--     processing. */
 236.611 +
 236.612 +int mpl_read_model(MPL *mpl, char *file, int skip_data)
 236.613 +{     if (mpl->phase != 0)
 236.614 +         xfault("mpl_read_model: invalid call sequence\n");
 236.615 +      if (file == NULL)
 236.616 +         xfault("mpl_read_model: no input filename specified\n");
 236.617 +      /* set up error handler */
 236.618 +      if (setjmp(mpl->jump)) goto done;
 236.619 +      /* translate model section */
 236.620 +      mpl->phase = 1;
 236.621 +      xprintf("Reading model section from %s...\n", file);
 236.622 +      open_input(mpl, file);
 236.623 +      model_section(mpl);
 236.624 +      if (mpl->model == NULL)
 236.625 +         error(mpl, "empty model section not allowed");
 236.626 +      /* save name of the input text file containing model section for
 236.627 +         error diagnostics during the generation phase */
 236.628 +      mpl->mod_file = xcalloc(strlen(file)+1, sizeof(char));
 236.629 +      strcpy(mpl->mod_file, mpl->in_file);
 236.630 +      /* allocate content arrays for all model objects */
 236.631 +      alloc_content(mpl);
 236.632 +      /* optional data section may begin with the keyword 'data' */
 236.633 +      if (is_keyword(mpl, "data"))
 236.634 +      {  if (skip_data)
 236.635 +         {  warning(mpl, "data section ignored");
 236.636 +            goto skip;
 236.637 +         }
 236.638 +         mpl->flag_d = 1;
 236.639 +         get_token(mpl /* data */);
 236.640 +         if (mpl->token != T_SEMICOLON)
 236.641 +            error(mpl, "semicolon missing where expected");
 236.642 +         get_token(mpl /* ; */);
 236.643 +         /* translate data section */
 236.644 +         mpl->phase = 2;
 236.645 +         xprintf("Reading data section from %s...\n", file);
 236.646 +         data_section(mpl);
 236.647 +      }
 236.648 +      /* process end statement */
 236.649 +      end_statement(mpl);
 236.650 +skip: xprintf("%d line%s were read\n",
 236.651 +         mpl->line, mpl->line == 1 ? "" : "s");
 236.652 +      close_input(mpl);
 236.653 +done: /* return to the calling program */
 236.654 +      return mpl->phase;
 236.655 +}
 236.656 +
 236.657 +/*----------------------------------------------------------------------
 236.658 +-- mpl_read_data - read data section.
 236.659 +--
 236.660 +-- *Synopsis*
 236.661 +--
 236.662 +-- #include "glpmpl.h"
 236.663 +-- int mpl_read_data(MPL *mpl, char *file);
 236.664 +--
 236.665 +-- *Description*
 236.666 +--
 236.667 +-- The routine mpl_read_data reads data section from the text file,
 236.668 +-- whose name is the character string file, performs translating data
 236.669 +-- blocks, and stores the data read in the translator database.
 236.670 +--
 236.671 +-- If this routine is used, it should be called once after the routine
 236.672 +-- mpl_read_model and if the latter returned the code 1.
 236.673 +--
 236.674 +-- *Returns*
 236.675 +--
 236.676 +-- The routine mpl_read_data returns one of the following codes:
 236.677 +--
 236.678 +-- 2 - data section has been successfully processed.
 236.679 +-- 4 - processing failed due to some errors. In this case the calling
 236.680 +--     program should call the routine mpl_terminate to terminate model
 236.681 +--     processing. */
 236.682 +
 236.683 +int mpl_read_data(MPL *mpl, char *file)
 236.684 +#if 0 /* 02/X-2008 */
 236.685 +{     if (mpl->phase != 1)
 236.686 +#else
 236.687 +{     if (!(mpl->phase == 1 || mpl->phase == 2))
 236.688 +#endif
 236.689 +         xfault("mpl_read_data: invalid call sequence\n");
 236.690 +      if (file == NULL)
 236.691 +         xfault("mpl_read_data: no input filename specified\n");
 236.692 +      /* set up error handler */
 236.693 +      if (setjmp(mpl->jump)) goto done;
 236.694 +      /* process data section */
 236.695 +      mpl->phase = 2;
 236.696 +      xprintf("Reading data section from %s...\n", file);
 236.697 +      mpl->flag_d = 1;
 236.698 +      open_input(mpl, file);
 236.699 +      /* in this case the keyword 'data' is optional */
 236.700 +      if (is_literal(mpl, "data"))
 236.701 +      {  get_token(mpl /* data */);
 236.702 +         if (mpl->token != T_SEMICOLON)
 236.703 +            error(mpl, "semicolon missing where expected");
 236.704 +         get_token(mpl /* ; */);
 236.705 +      }
 236.706 +      data_section(mpl);
 236.707 +      /* process end statement */
 236.708 +      end_statement(mpl);
 236.709 +      xprintf("%d line%s were read\n",
 236.710 +         mpl->line, mpl->line == 1 ? "" : "s");
 236.711 +      close_input(mpl);
 236.712 +done: /* return to the calling program */
 236.713 +      return mpl->phase;
 236.714 +}
 236.715 +
 236.716 +/*----------------------------------------------------------------------
 236.717 +-- mpl_generate - generate model.
 236.718 +--
 236.719 +-- *Synopsis*
 236.720 +--
 236.721 +-- #include "glpmpl.h"
 236.722 +-- int mpl_generate(MPL *mpl, char *file);
 236.723 +--
 236.724 +-- *Description*
 236.725 +--
 236.726 +-- The routine mpl_generate generates the model using its description
 236.727 +-- stored in the translator database. This phase means generating all
 236.728 +-- variables, constraints, and objectives, executing check and display
 236.729 +-- statements, which precede the solve statement (if it is presented),
 236.730 +-- and building the problem instance.
 236.731 +--
 236.732 +-- The character string file specifies the name of output text file, to
 236.733 +-- which output produced by display statements should be written. It is
 236.734 +-- allowed to specify NULL, in which case the output goes to stdout via
 236.735 +-- the routine print.
 236.736 +--
 236.737 +-- This routine should be called once after the routine mpl_read_model
 236.738 +-- or mpl_read_data and if one of the latters returned the code 2.
 236.739 +--
 236.740 +-- *Returns*
 236.741 +--
 236.742 +-- The routine mpl_generate returns one of the following codes:
 236.743 +--
 236.744 +-- 3 - model has been successfully generated. In this case the calling
 236.745 +--     program may call other api routines to obtain components of the
 236.746 +--     problem instance from the translator database.
 236.747 +-- 4 - processing failed due to some errors. In this case the calling
 236.748 +--     program should call the routine mpl_terminate to terminate model
 236.749 +--     processing. */
 236.750 +
 236.751 +int mpl_generate(MPL *mpl, char *file)
 236.752 +{     if (!(mpl->phase == 1 || mpl->phase == 2))
 236.753 +         xfault("mpl_generate: invalid call sequence\n");
 236.754 +      /* set up error handler */
 236.755 +      if (setjmp(mpl->jump)) goto done;
 236.756 +      /* generate model */
 236.757 +      mpl->phase = 3;
 236.758 +      open_output(mpl, file);
 236.759 +      generate_model(mpl);
 236.760 +      flush_output(mpl);
 236.761 +      /* build problem instance */
 236.762 +      build_problem(mpl);
 236.763 +      /* generation phase has been finished */
 236.764 +      xprintf("Model has been successfully generated\n");
 236.765 +done: /* return to the calling program */
 236.766 +      return mpl->phase;
 236.767 +}
 236.768 +
 236.769 +/*----------------------------------------------------------------------
 236.770 +-- mpl_get_prob_name - obtain problem (model) name.
 236.771 +--
 236.772 +-- *Synopsis*
 236.773 +--
 236.774 +-- #include "glpmpl.h"
 236.775 +-- char *mpl_get_prob_name(MPL *mpl);
 236.776 +--
 236.777 +-- *Returns*
 236.778 +--
 236.779 +-- The routine mpl_get_prob_name returns a pointer to internal buffer,
 236.780 +-- which contains symbolic name of the problem (model).
 236.781 +--
 236.782 +-- *Note*
 236.783 +--
 236.784 +-- Currently MathProg has no feature to assign a symbolic name to the
 236.785 +-- model. Therefore the routine mpl_get_prob_name tries to construct
 236.786 +-- such name using the name of input text file containing model section,
 236.787 +-- although this is not a good idea (due to portability problems). */
 236.788 +
 236.789 +char *mpl_get_prob_name(MPL *mpl)
 236.790 +{     char *name = mpl->mpl_buf;
 236.791 +      char *file = mpl->mod_file;
 236.792 +      int k;
 236.793 +      if (mpl->phase != 3)
 236.794 +         xfault("mpl_get_prob_name: invalid call sequence\n");
 236.795 +      for (;;)
 236.796 +      {  if (strchr(file, '/') != NULL)
 236.797 +            file = strchr(file, '/') + 1;
 236.798 +         else if (strchr(file, '\\') != NULL)
 236.799 +            file = strchr(file, '\\') + 1;
 236.800 +         else if (strchr(file, ':') != NULL)
 236.801 +            file = strchr(file, ':') + 1;
 236.802 +         else
 236.803 +            break;
 236.804 +      }
 236.805 +      for (k = 0; ; k++)
 236.806 +      {  if (k == 255) break;
 236.807 +         if (!(isalnum((unsigned char)*file) || *file == '_')) break;
 236.808 +         name[k] = *file++;
 236.809 +      }
 236.810 +      if (k == 0)
 236.811 +         strcpy(name, "Unknown");
 236.812 +      else
 236.813 +         name[k] = '\0';
 236.814 +      xassert(strlen(name) <= 255);
 236.815 +      return name;
 236.816 +}
 236.817 +
 236.818 +/*----------------------------------------------------------------------
 236.819 +-- mpl_get_num_rows - determine number of rows.
 236.820 +--
 236.821 +-- *Synopsis*
 236.822 +--
 236.823 +-- #include "glpmpl.h"
 236.824 +-- int mpl_get_num_rows(MPL *mpl);
 236.825 +--
 236.826 +-- *Returns*
 236.827 +--
 236.828 +-- The routine mpl_get_num_rows returns total number of rows in the
 236.829 +-- problem, where each row is an individual constraint or objective. */
 236.830 +
 236.831 +int mpl_get_num_rows(MPL *mpl)
 236.832 +{     if (mpl->phase != 3)
 236.833 +         xfault("mpl_get_num_rows: invalid call sequence\n");
 236.834 +      return mpl->m;
 236.835 +}
 236.836 +
 236.837 +/*----------------------------------------------------------------------
 236.838 +-- mpl_get_num_cols - determine number of columns.
 236.839 +--
 236.840 +-- *Synopsis*
 236.841 +--
 236.842 +-- #include "glpmpl.h"
 236.843 +-- int mpl_get_num_cols(MPL *mpl);
 236.844 +--
 236.845 +-- *Returns*
 236.846 +--
 236.847 +-- The routine mpl_get_num_cols returns total number of columns in the
 236.848 +-- problem, where each column is an individual variable. */
 236.849 +
 236.850 +int mpl_get_num_cols(MPL *mpl)
 236.851 +{     if (mpl->phase != 3)
 236.852 +         xfault("mpl_get_num_cols: invalid call sequence\n");
 236.853 +      return mpl->n;
 236.854 +}
 236.855 +
 236.856 +/*----------------------------------------------------------------------
 236.857 +-- mpl_get_row_name - obtain row name.
 236.858 +--
 236.859 +-- *Synopsis*
 236.860 +--
 236.861 +-- #include "glpmpl.h"
 236.862 +-- char *mpl_get_row_name(MPL *mpl, int i);
 236.863 +--
 236.864 +-- *Returns*
 236.865 +--
 236.866 +-- The routine mpl_get_row_name returns a pointer to internal buffer,
 236.867 +-- which contains symbolic name of i-th row of the problem. */
 236.868 +
 236.869 +char *mpl_get_row_name(MPL *mpl, int i)
 236.870 +{     char *name = mpl->mpl_buf, *t;
 236.871 +      int len;
 236.872 +      if (mpl->phase != 3)
 236.873 +         xfault("mpl_get_row_name: invalid call sequence\n");
 236.874 +      if (!(1 <= i && i <= mpl->m))
 236.875 +         xfault("mpl_get_row_name: i = %d; row number out of range\n",
 236.876 +            i);
 236.877 +      strcpy(name, mpl->row[i]->con->name);
 236.878 +      len = strlen(name);
 236.879 +      xassert(len <= 255);
 236.880 +      t = format_tuple(mpl, '[', mpl->row[i]->memb->tuple);
 236.881 +      while (*t)
 236.882 +      {  if (len == 255) break;
 236.883 +         name[len++] = *t++;
 236.884 +      }
 236.885 +      name[len] = '\0';
 236.886 +      if (len == 255) strcpy(name+252, "...");
 236.887 +      xassert(strlen(name) <= 255);
 236.888 +      return name;
 236.889 +}
 236.890 +
 236.891 +/*----------------------------------------------------------------------
 236.892 +-- mpl_get_row_kind - determine row kind.
 236.893 +--
 236.894 +-- *Synopsis*
 236.895 +--
 236.896 +-- #include "glpmpl.h"
 236.897 +-- int mpl_get_row_kind(MPL *mpl, int i);
 236.898 +--
 236.899 +-- *Returns*
 236.900 +--
 236.901 +-- The routine mpl_get_row_kind returns the kind of i-th row, which can
 236.902 +-- be one of the following:
 236.903 +--
 236.904 +-- MPL_ST  - non-free (constraint) row;
 236.905 +-- MPL_MIN - free (objective) row to be minimized;
 236.906 +-- MPL_MAX - free (objective) row to be maximized. */
 236.907 +
 236.908 +int mpl_get_row_kind(MPL *mpl, int i)
 236.909 +{     int kind;
 236.910 +      if (mpl->phase != 3)
 236.911 +         xfault("mpl_get_row_kind: invalid call sequence\n");
 236.912 +      if (!(1 <= i && i <= mpl->m))
 236.913 +         xfault("mpl_get_row_kind: i = %d; row number out of range\n",
 236.914 +            i);
 236.915 +      switch (mpl->row[i]->con->type)
 236.916 +      {  case A_CONSTRAINT:
 236.917 +            kind = MPL_ST; break;
 236.918 +         case A_MINIMIZE:
 236.919 +            kind = MPL_MIN; break;
 236.920 +         case A_MAXIMIZE:
 236.921 +            kind = MPL_MAX; break;
 236.922 +         default:
 236.923 +            xassert(mpl != mpl);
 236.924 +      }
 236.925 +      return kind;
 236.926 +}
 236.927 +
 236.928 +/*----------------------------------------------------------------------
 236.929 +-- mpl_get_row_bnds - obtain row bounds.
 236.930 +--
 236.931 +-- *Synopsis*
 236.932 +--
 236.933 +-- #include "glpmpl.h"
 236.934 +-- int mpl_get_row_bnds(MPL *mpl, int i, double *lb, double *ub);
 236.935 +--
 236.936 +-- *Description*
 236.937 +--
 236.938 +-- The routine mpl_get_row_bnds stores lower and upper bounds of i-th
 236.939 +-- row of the problem to the locations, which the parameters lb and ub
 236.940 +-- point to, respectively. Besides the routine returns the type of the
 236.941 +-- i-th row.
 236.942 +--
 236.943 +-- If some of the parameters lb and ub is NULL, the corresponding bound
 236.944 +-- value is not stored.
 236.945 +--
 236.946 +-- Types and bounds have the following meaning:
 236.947 +--
 236.948 +--     Type           Bounds          Note
 236.949 +--    -----------------------------------------------------------
 236.950 +--    MPL_FR   -inf <  f(x) <  +inf   Free linear form
 236.951 +--    MPL_LO     lb <= f(x) <  +inf   Inequality f(x) >= lb
 236.952 +--    MPL_UP   -inf <  f(x) <=  ub    Inequality f(x) <= ub
 236.953 +--    MPL_DB     lb <= f(x) <=  ub    Inequality lb <= f(x) <= ub
 236.954 +--    MPL_FX           f(x)  =  lb    Equality f(x) = lb
 236.955 +--
 236.956 +-- where f(x) is the corresponding linear form of the i-th row.
 236.957 +--
 236.958 +-- If the row has no lower bound, *lb is set to zero; if the row has
 236.959 +-- no upper bound, *ub is set to zero; and if the row is of fixed type,
 236.960 +-- both *lb and *ub are set to the same value.
 236.961 +--
 236.962 +-- *Returns*
 236.963 +--
 236.964 +-- The routine returns the type of the i-th row as it is stated in the
 236.965 +-- table above. */
 236.966 +
 236.967 +int mpl_get_row_bnds(MPL *mpl, int i, double *_lb, double *_ub)
 236.968 +{     ELEMCON *con;
 236.969 +      int type;
 236.970 +      double lb, ub;
 236.971 +      if (mpl->phase != 3)
 236.972 +         xfault("mpl_get_row_bnds: invalid call sequence\n");
 236.973 +      if (!(1 <= i && i <= mpl->m))
 236.974 +         xfault("mpl_get_row_bnds: i = %d; row number out of range\n",
 236.975 +            i);
 236.976 +      con = mpl->row[i];
 236.977 +#if 0 /* 21/VII-2006 */
 236.978 +      if (con->con->lbnd == NULL && con->con->ubnd == NULL)
 236.979 +         type = MPL_FR, lb = ub = 0.0;
 236.980 +      else if (con->con->ubnd == NULL)
 236.981 +         type = MPL_LO, lb = con->lbnd, ub = 0.0;
 236.982 +      else if (con->con->lbnd == NULL)
 236.983 +         type = MPL_UP, lb = 0.0, ub = con->ubnd;
 236.984 +      else if (con->con->lbnd != con->con->ubnd)
 236.985 +         type = MPL_DB, lb = con->lbnd, ub = con->ubnd;
 236.986 +      else
 236.987 +         type = MPL_FX, lb = ub = con->lbnd;
 236.988 +#else
 236.989 +      lb = (con->con->lbnd == NULL ? -DBL_MAX : con->lbnd);
 236.990 +      ub = (con->con->ubnd == NULL ? +DBL_MAX : con->ubnd);
 236.991 +      if (lb == -DBL_MAX && ub == +DBL_MAX)
 236.992 +         type = MPL_FR, lb = ub = 0.0;
 236.993 +      else if (ub == +DBL_MAX)
 236.994 +         type = MPL_LO, ub = 0.0;
 236.995 +      else if (lb == -DBL_MAX)
 236.996 +         type = MPL_UP, lb = 0.0;
 236.997 +      else if (con->con->lbnd != con->con->ubnd)
 236.998 +         type = MPL_DB;
 236.999 +      else
236.1000 +         type = MPL_FX;
236.1001 +#endif
236.1002 +      if (_lb != NULL) *_lb = lb;
236.1003 +      if (_ub != NULL) *_ub = ub;
236.1004 +      return type;
236.1005 +}
236.1006 +
236.1007 +/*----------------------------------------------------------------------
236.1008 +-- mpl_get_mat_row - obtain row of the constraint matrix.
236.1009 +--
236.1010 +-- *Synopsis*
236.1011 +--
236.1012 +-- #include "glpmpl.h"
236.1013 +-- int mpl_get_mat_row(MPL *mpl, int i, int ndx[], double val[]);
236.1014 +--
236.1015 +-- *Description*
236.1016 +--
236.1017 +-- The routine mpl_get_mat_row stores column indices and numeric values
236.1018 +-- of constraint coefficients for the i-th row to locations ndx[1], ...,
236.1019 +-- ndx[len] and val[1], ..., val[len], respectively, where 0 <= len <= n
236.1020 +-- is number of (structural) non-zero constraint coefficients, and n is
236.1021 +-- number of columns in the problem.
236.1022 +--
236.1023 +-- If the parameter ndx is NULL, column indices are not stored. If the
236.1024 +-- parameter val is NULL, numeric values are not stored.
236.1025 +--
236.1026 +-- Note that free rows may have constant terms, which are not part of
236.1027 +-- the constraint matrix and therefore not reported by this routine. The
236.1028 +-- constant term of a particular row can be obtained, if necessary, via
236.1029 +-- the routine mpl_get_row_c0.
236.1030 +--
236.1031 +-- *Returns*
236.1032 +--
236.1033 +-- The routine mpl_get_mat_row returns len, which is length of i-th row
236.1034 +-- of the constraint matrix (i.e. number of non-zero coefficients). */
236.1035 +
236.1036 +int mpl_get_mat_row(MPL *mpl, int i, int ndx[], double val[])
236.1037 +{     FORMULA *term;
236.1038 +      int len = 0;
236.1039 +      if (mpl->phase != 3)
236.1040 +         xfault("mpl_get_mat_row: invalid call sequence\n");
236.1041 +      if (!(1 <= i && i <= mpl->m))
236.1042 +         xfault("mpl_get_mat_row: i = %d; row number out of range\n",
236.1043 +            i);
236.1044 +      for (term = mpl->row[i]->form; term != NULL; term = term->next)
236.1045 +      {  xassert(term->var != NULL);
236.1046 +         len++;
236.1047 +         xassert(len <= mpl->n);
236.1048 +         if (ndx != NULL) ndx[len] = term->var->j;
236.1049 +         if (val != NULL) val[len] = term->coef;
236.1050 +      }
236.1051 +      return len;
236.1052 +}
236.1053 +
236.1054 +/*----------------------------------------------------------------------
236.1055 +-- mpl_get_row_c0 - obtain constant term of free row.
236.1056 +--
236.1057 +-- *Synopsis*
236.1058 +--
236.1059 +-- #include "glpmpl.h"
236.1060 +-- double mpl_get_row_c0(MPL *mpl, int i);
236.1061 +--
236.1062 +-- *Returns*
236.1063 +--
236.1064 +-- The routine mpl_get_row_c0 returns numeric value of constant term of
236.1065 +-- i-th row.
236.1066 +--
236.1067 +-- Note that only free rows may have non-zero constant terms. Therefore
236.1068 +-- if i-th row is not free, the routine returns zero. */
236.1069 +
236.1070 +double mpl_get_row_c0(MPL *mpl, int i)
236.1071 +{     ELEMCON *con;
236.1072 +      double c0;
236.1073 +      if (mpl->phase != 3)
236.1074 +         xfault("mpl_get_row_c0: invalid call sequence\n");
236.1075 +      if (!(1 <= i && i <= mpl->m))
236.1076 +         xfault("mpl_get_row_c0: i = %d; row number out of range\n",
236.1077 +            i);
236.1078 +      con = mpl->row[i];
236.1079 +      if (con->con->lbnd == NULL && con->con->ubnd == NULL)
236.1080 +         c0 = - con->lbnd;
236.1081 +      else
236.1082 +         c0 = 0.0;
236.1083 +      return c0;
236.1084 +}
236.1085 +
236.1086 +/*----------------------------------------------------------------------
236.1087 +-- mpl_get_col_name - obtain column name.
236.1088 +--
236.1089 +-- *Synopsis*
236.1090 +--
236.1091 +-- #include "glpmpl.h"
236.1092 +-- char *mpl_get_col_name(MPL *mpl, int j);
236.1093 +--
236.1094 +-- *Returns*
236.1095 +--
236.1096 +-- The routine mpl_get_col_name returns a pointer to internal buffer,
236.1097 +-- which contains symbolic name of j-th column of the problem. */
236.1098 +
236.1099 +char *mpl_get_col_name(MPL *mpl, int j)
236.1100 +{     char *name = mpl->mpl_buf, *t;
236.1101 +      int len;
236.1102 +      if (mpl->phase != 3)
236.1103 +         xfault("mpl_get_col_name: invalid call sequence\n");
236.1104 +      if (!(1 <= j && j <= mpl->n))
236.1105 +         xfault("mpl_get_col_name: j = %d; column number out of range\n"
236.1106 +            , j);
236.1107 +      strcpy(name, mpl->col[j]->var->name);
236.1108 +      len = strlen(name);
236.1109 +      xassert(len <= 255);
236.1110 +      t = format_tuple(mpl, '[', mpl->col[j]->memb->tuple);
236.1111 +      while (*t)
236.1112 +      {  if (len == 255) break;
236.1113 +         name[len++] = *t++;
236.1114 +      }
236.1115 +      name[len] = '\0';
236.1116 +      if (len == 255) strcpy(name+252, "...");
236.1117 +      xassert(strlen(name) <= 255);
236.1118 +      return name;
236.1119 +}
236.1120 +
236.1121 +/*----------------------------------------------------------------------
236.1122 +-- mpl_get_col_kind - determine column kind.
236.1123 +--
236.1124 +-- *Synopsis*
236.1125 +--
236.1126 +-- #include "glpmpl.h"
236.1127 +-- int mpl_get_col_kind(MPL *mpl, int j);
236.1128 +--
236.1129 +-- *Returns*
236.1130 +--
236.1131 +-- The routine mpl_get_col_kind returns the kind of j-th column, which
236.1132 +-- can be one of the following:
236.1133 +--
236.1134 +-- MPL_NUM - continuous variable;
236.1135 +-- MPL_INT - integer variable;
236.1136 +-- MPL_BIN - binary variable.
236.1137 +--
236.1138 +-- Note that column kinds are defined independently on type and bounds
236.1139 +-- (reported by the routine mpl_get_col_bnds) of corresponding columns.
236.1140 +-- This means, in particular, that bounds of an integer column may be
236.1141 +-- fractional, or a binary column may have lower and upper bounds that
236.1142 +-- are not 0 and 1 (or it may have no lower/upper bound at all). */
236.1143 +
236.1144 +int mpl_get_col_kind(MPL *mpl, int j)
236.1145 +{     int kind;
236.1146 +      if (mpl->phase != 3)
236.1147 +         xfault("mpl_get_col_kind: invalid call sequence\n");
236.1148 +      if (!(1 <= j && j <= mpl->n))
236.1149 +         xfault("mpl_get_col_kind: j = %d; column number out of range\n"
236.1150 +            , j);
236.1151 +      switch (mpl->col[j]->var->type)
236.1152 +      {  case A_NUMERIC:
236.1153 +            kind = MPL_NUM; break;
236.1154 +         case A_INTEGER:
236.1155 +            kind = MPL_INT; break;
236.1156 +         case A_BINARY:
236.1157 +            kind = MPL_BIN; break;
236.1158 +         default:
236.1159 +            xassert(mpl != mpl);
236.1160 +      }
236.1161 +      return kind;
236.1162 +}
236.1163 +
236.1164 +/*----------------------------------------------------------------------
236.1165 +-- mpl_get_col_bnds - obtain column bounds.
236.1166 +--
236.1167 +-- *Synopsis*
236.1168 +--
236.1169 +-- #include "glpmpl.h"
236.1170 +-- int mpl_get_col_bnds(MPL *mpl, int j, double *lb, double *ub);
236.1171 +--
236.1172 +-- *Description*
236.1173 +--
236.1174 +-- The routine mpl_get_col_bnds stores lower and upper bound of j-th
236.1175 +-- column of the problem to the locations, which the parameters lb and
236.1176 +-- ub point to, respectively. Besides the routine returns the type of
236.1177 +-- the j-th column.
236.1178 +--
236.1179 +-- If some of the parameters lb and ub is NULL, the corresponding bound
236.1180 +-- value is not stored.
236.1181 +--
236.1182 +-- Types and bounds have the following meaning:
236.1183 +--
236.1184 +--     Type         Bounds         Note
236.1185 +--    ------------------------------------------------------
236.1186 +--    MPL_FR   -inf <  x <  +inf   Free (unbounded) variable
236.1187 +--    MPL_LO     lb <= x <  +inf   Variable with lower bound
236.1188 +--    MPL_UP   -inf <  x <=  ub    Variable with upper bound
236.1189 +--    MPL_DB     lb <= x <=  ub    Double-bounded variable
236.1190 +--    MPL_FX           x  =  lb    Fixed variable
236.1191 +--
236.1192 +-- where x is individual variable corresponding to the j-th column.
236.1193 +--
236.1194 +-- If the column has no lower bound, *lb is set to zero; if the column
236.1195 +-- has no upper bound, *ub is set to zero; and if the column is of fixed
236.1196 +-- type, both *lb and *ub are set to the same value.
236.1197 +--
236.1198 +-- *Returns*
236.1199 +--
236.1200 +-- The routine returns the type of the j-th column as it is stated in
236.1201 +-- the table above. */
236.1202 +
236.1203 +int mpl_get_col_bnds(MPL *mpl, int j, double *_lb, double *_ub)
236.1204 +{     ELEMVAR *var;
236.1205 +      int type;
236.1206 +      double lb, ub;
236.1207 +      if (mpl->phase != 3)
236.1208 +         xfault("mpl_get_col_bnds: invalid call sequence\n");
236.1209 +      if (!(1 <= j && j <= mpl->n))
236.1210 +         xfault("mpl_get_col_bnds: j = %d; column number out of range\n"
236.1211 +            , j);
236.1212 +      var = mpl->col[j];
236.1213 +#if 0 /* 21/VII-2006 */
236.1214 +      if (var->var->lbnd == NULL && var->var->ubnd == NULL)
236.1215 +         type = MPL_FR, lb = ub = 0.0;
236.1216 +      else if (var->var->ubnd == NULL)
236.1217 +         type = MPL_LO, lb = var->lbnd, ub = 0.0;
236.1218 +      else if (var->var->lbnd == NULL)
236.1219 +         type = MPL_UP, lb = 0.0, ub = var->ubnd;
236.1220 +      else if (var->var->lbnd != var->var->ubnd)
236.1221 +         type = MPL_DB, lb = var->lbnd, ub = var->ubnd;
236.1222 +      else
236.1223 +         type = MPL_FX, lb = ub = var->lbnd;
236.1224 +#else
236.1225 +      lb = (var->var->lbnd == NULL ? -DBL_MAX : var->lbnd);
236.1226 +      ub = (var->var->ubnd == NULL ? +DBL_MAX : var->ubnd);
236.1227 +      if (lb == -DBL_MAX && ub == +DBL_MAX)
236.1228 +         type = MPL_FR, lb = ub = 0.0;
236.1229 +      else if (ub == +DBL_MAX)
236.1230 +         type = MPL_LO, ub = 0.0;
236.1231 +      else if (lb == -DBL_MAX)
236.1232 +         type = MPL_UP, lb = 0.0;
236.1233 +      else if (var->var->lbnd != var->var->ubnd)
236.1234 +         type = MPL_DB;
236.1235 +      else
236.1236 +         type = MPL_FX;
236.1237 +#endif
236.1238 +      if (_lb != NULL) *_lb = lb;
236.1239 +      if (_ub != NULL) *_ub = ub;
236.1240 +      return type;
236.1241 +}
236.1242 +
236.1243 +/*----------------------------------------------------------------------
236.1244 +-- mpl_has_solve_stmt - check if model has solve statement.
236.1245 +--
236.1246 +-- *Synopsis*
236.1247 +--
236.1248 +-- #include "glpmpl.h"
236.1249 +-- int mpl_has_solve_stmt(MPL *mpl);
236.1250 +--
236.1251 +-- *Returns*
236.1252 +--
236.1253 +-- If the model has the solve statement, the routine returns non-zero,
236.1254 +-- otherwise zero is returned. */
236.1255 +
236.1256 +int mpl_has_solve_stmt(MPL *mpl)
236.1257 +{     if (mpl->phase != 3)
236.1258 +         xfault("mpl_has_solve_stmt: invalid call sequence\n");
236.1259 +      return mpl->flag_s;
236.1260 +}
236.1261 +
236.1262 +#if 1 /* 15/V-2010 */
236.1263 +void mpl_put_row_soln(MPL *mpl, int i, int stat, double prim,
236.1264 +      double dual)
236.1265 +{     /* store row (constraint/objective) solution components */
236.1266 +      xassert(mpl->phase == 3);
236.1267 +      xassert(1 <= i && i <= mpl->m);
236.1268 +      mpl->row[i]->stat = stat;
236.1269 +      mpl->row[i]->prim = prim;
236.1270 +      mpl->row[i]->dual = dual;
236.1271 +      return;
236.1272 +}
236.1273 +#endif
236.1274 +
236.1275 +#if 1 /* 15/V-2010 */
236.1276 +void mpl_put_col_soln(MPL *mpl, int j, int stat, double prim,
236.1277 +      double dual)
236.1278 +{     /* store column (variable) solution components */
236.1279 +      xassert(mpl->phase == 3);
236.1280 +      xassert(1 <= j && j <= mpl->n);
236.1281 +      mpl->col[j]->stat = stat;
236.1282 +      mpl->col[j]->prim = prim;
236.1283 +      mpl->col[j]->dual = dual;
236.1284 +      return;
236.1285 +}
236.1286 +#endif
236.1287 +
236.1288 +#if 0 /* 15/V-2010 */
236.1289 +/*----------------------------------------------------------------------
236.1290 +-- mpl_put_col_value - store column value.
236.1291 +--
236.1292 +-- *Synopsis*
236.1293 +--
236.1294 +-- #include "glpmpl.h"
236.1295 +-- void mpl_put_col_value(MPL *mpl, int j, double val);
236.1296 +--
236.1297 +-- *Description*
236.1298 +--
236.1299 +-- The routine mpl_put_col_value stores numeric value of j-th column
236.1300 +-- into the translator database. It is assumed that the column value is
236.1301 +-- provided by the solver. */
236.1302 +
236.1303 +void mpl_put_col_value(MPL *mpl, int j, double val)
236.1304 +{     if (mpl->phase != 3)
236.1305 +         xfault("mpl_put_col_value: invalid call sequence\n");
236.1306 +      if (!(1 <= j && j <= mpl->n))
236.1307 +         xfault(
236.1308 +         "mpl_put_col_value: j = %d; column number out of range\n", j);
236.1309 +      mpl->col[j]->prim = val;
236.1310 +      return;
236.1311 +}
236.1312 +#endif
236.1313 +
236.1314 +/*----------------------------------------------------------------------
236.1315 +-- mpl_postsolve - postsolve model.
236.1316 +--
236.1317 +-- *Synopsis*
236.1318 +--
236.1319 +-- #include "glpmpl.h"
236.1320 +-- int mpl_postsolve(MPL *mpl);
236.1321 +--
236.1322 +-- *Description*
236.1323 +--
236.1324 +-- The routine mpl_postsolve performs postsolving of the model using
236.1325 +-- its description stored in the translator database. This phase means
236.1326 +-- executing statements, which follow the solve statement.
236.1327 +--
236.1328 +-- If this routine is used, it should be called once after the routine
236.1329 +-- mpl_generate and if the latter returned the code 3.
236.1330 +--
236.1331 +-- *Returns*
236.1332 +--
236.1333 +-- The routine mpl_postsolve returns one of the following codes:
236.1334 +--
236.1335 +-- 3 - model has been successfully postsolved.
236.1336 +-- 4 - processing failed due to some errors. In this case the calling
236.1337 +--     program should call the routine mpl_terminate to terminate model
236.1338 +--     processing. */
236.1339 +
236.1340 +int mpl_postsolve(MPL *mpl)
236.1341 +{     if (!(mpl->phase == 3 && !mpl->flag_p))
236.1342 +         xfault("mpl_postsolve: invalid call sequence\n");
236.1343 +      /* set up error handler */
236.1344 +      if (setjmp(mpl->jump)) goto done;
236.1345 +      /* perform postsolving */
236.1346 +      postsolve_model(mpl);
236.1347 +      flush_output(mpl);
236.1348 +      /* postsolving phase has been finished */
236.1349 +      xprintf("Model has been successfully processed\n");
236.1350 +done: /* return to the calling program */
236.1351 +      return mpl->phase;
236.1352 +}
236.1353 +
236.1354 +/*----------------------------------------------------------------------
236.1355 +-- mpl_terminate - free all resources used by translator.
236.1356 +--
236.1357 +-- *Synopsis*
236.1358 +--
236.1359 +-- #include "glpmpl.h"
236.1360 +-- void mpl_terminate(MPL *mpl);
236.1361 +--
236.1362 +-- *Description*
236.1363 +--
236.1364 +-- The routine mpl_terminate frees all the resources used by the GNU
236.1365 +-- MathProg translator. */
236.1366 +
236.1367 +void mpl_terminate(MPL *mpl)
236.1368 +{     if (setjmp(mpl->jump)) xassert(mpl != mpl);
236.1369 +      switch (mpl->phase)
236.1370 +      {  case 0:
236.1371 +         case 1:
236.1372 +         case 2:
236.1373 +         case 3:
236.1374 +            /* there were no errors; clean the model content */
236.1375 +            clean_model(mpl);
236.1376 +            xassert(mpl->a_list == NULL);
236.1377 +#if 1 /* 11/II-2008 */
236.1378 +            xassert(mpl->dca == NULL);
236.1379 +#endif
236.1380 +            break;
236.1381 +         case 4:
236.1382 +            /* model processing has been finished due to error; delete
236.1383 +               search trees, which may be created for some arrays */
236.1384 +            {  ARRAY *a;
236.1385 +               for (a = mpl->a_list; a != NULL; a = a->next)
236.1386 +                  if (a->tree != NULL) avl_delete_tree(a->tree);
236.1387 +            }
236.1388 +#if 1 /* 11/II-2008 */
236.1389 +            free_dca(mpl);
236.1390 +#endif
236.1391 +            break;
236.1392 +         default:
236.1393 +            xassert(mpl != mpl);
236.1394 +      }
236.1395 +      /* delete the translator database */
236.1396 +      xfree(mpl->image);
236.1397 +      xfree(mpl->b_image);
236.1398 +      xfree(mpl->f_image);
236.1399 +      xfree(mpl->context);
236.1400 +      dmp_delete_pool(mpl->pool);
236.1401 +      avl_delete_tree(mpl->tree);
236.1402 +      dmp_delete_pool(mpl->strings);
236.1403 +      dmp_delete_pool(mpl->symbols);
236.1404 +      dmp_delete_pool(mpl->tuples);
236.1405 +      dmp_delete_pool(mpl->arrays);
236.1406 +      dmp_delete_pool(mpl->members);
236.1407 +      dmp_delete_pool(mpl->elemvars);
236.1408 +      dmp_delete_pool(mpl->formulae);
236.1409 +      dmp_delete_pool(mpl->elemcons);
236.1410 +      xfree(mpl->sym_buf);
236.1411 +      xfree(mpl->tup_buf);
236.1412 +      rng_delete_rand(mpl->rand);
236.1413 +      if (mpl->row != NULL) xfree(mpl->row);
236.1414 +      if (mpl->col != NULL) xfree(mpl->col);
236.1415 +      if (mpl->in_fp != NULL) xfclose(mpl->in_fp);
236.1416 +      if (mpl->out_fp != NULL && mpl->out_fp != (void *)stdout)
236.1417 +         xfclose(mpl->out_fp);
236.1418 +      if (mpl->out_file != NULL) xfree(mpl->out_file);
236.1419 +      if (mpl->prt_fp != NULL) xfclose(mpl->prt_fp);
236.1420 +      if (mpl->prt_file != NULL) xfree(mpl->prt_file);
236.1421 +      if (mpl->mod_file != NULL) xfree(mpl->mod_file);
236.1422 +      xfree(mpl->mpl_buf);
236.1423 +      xfree(mpl);
236.1424 +      return;
236.1425 +}
236.1426 +
236.1427 +/* eof */
   237.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   237.2 +++ b/src/glpmpl05.c	Mon Dec 06 13:09:21 2010 +0100
   237.3 @@ -0,0 +1,562 @@
   237.4 +/* glpmpl05.c */
   237.5 +
   237.6 +/***********************************************************************
   237.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   237.8 +*
   237.9 +*  Authors: Andrew Makhorin <mao@gnu.org>
  237.10 +*           Heinrich Schuchardt <xypron.glpk@gmx.de>
  237.11 +*
  237.12 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  237.13 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  237.14 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  237.15 +*  E-mail: <mao@gnu.org>.
  237.16 +*
  237.17 +*  GLPK is free software: you can redistribute it and/or modify it
  237.18 +*  under the terms of the GNU General Public License as published by
  237.19 +*  the Free Software Foundation, either version 3 of the License, or
  237.20 +*  (at your option) any later version.
  237.21 +*
  237.22 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  237.23 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  237.24 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  237.25 +*  License for more details.
  237.26 +*
  237.27 +*  You should have received a copy of the GNU General Public License
  237.28 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  237.29 +***********************************************************************/
  237.30 +
  237.31 +#define _GLPSTD_STDIO
  237.32 +#define _GLPSTD_TIME
  237.33 +#include "glpmpl.h"
  237.34 +
  237.35 +double fn_gmtime(MPL *mpl)
  237.36 +{     /* obtain the current calendar time (UTC) */
  237.37 +      time_t timer;
  237.38 +      struct tm *tm;
  237.39 +      int j;
  237.40 +      time(&timer);
  237.41 +      if (timer == (time_t)(-1))
  237.42 +err:     error(mpl, "gmtime(); unable to obtain current calendar time");
  237.43 +      tm = gmtime(&timer);
  237.44 +      if (tm == NULL) goto err;
  237.45 +      j = jday(tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year);
  237.46 +      if (j < 0) goto err;
  237.47 +      return (((double)(j - jday(1, 1, 1970)) * 24.0 +
  237.48 +         (double)tm->tm_hour) * 60.0 + (double)tm->tm_min) * 60.0 +
  237.49 +         (double)tm->tm_sec;
  237.50 +}
  237.51 +
  237.52 +static char *week[] = { "Monday", "Tuesday", "Wednesday", "Thursday",
  237.53 +      "Friday", "Saturday", "Sunday" };
  237.54 +
  237.55 +static char *moon[] = { "January", "February", "March", "April", "May",
  237.56 +      "June", "July", "August", "September", "October", "November",
  237.57 +      "December" };
  237.58 +
  237.59 +static void error1(MPL *mpl, const char *str, const char *s,
  237.60 +      const char *fmt, const char *f, const char *msg)
  237.61 +{     xprintf("Input string passed to str2time:\n");
  237.62 +      xprintf("%s\n", str);
  237.63 +      xprintf("%*s\n", (s - str) + 1, "^");
  237.64 +      xprintf("Format string passed to str2time:\n");
  237.65 +      xprintf("%s\n", fmt);
  237.66 +      xprintf("%*s\n", (f - fmt) + 1, "^");
  237.67 +      error(mpl, "%s", msg);
  237.68 +      /* no return */
  237.69 +}
  237.70 +
  237.71 +double fn_str2time(MPL *mpl, const char *str, const char *fmt)
  237.72 +{     /* convert character string to the calendar time */
  237.73 +      int j, year, month, day, hh, mm, ss, zone;
  237.74 +      const char *s, *f;
  237.75 +      year = month = day = hh = mm = ss = -1, zone = INT_MAX;
  237.76 +      s = str;
  237.77 +      for (f = fmt; *f != '\0'; f++)
  237.78 +      {  if (*f == '%')
  237.79 +         {  f++;
  237.80 +            if (*f == 'b' || *f == 'h')
  237.81 +            {  /* the abbreviated month name */
  237.82 +               int k;
  237.83 +               char *name;
  237.84 +               if (month >= 0)
  237.85 +                  error1(mpl, str, s, fmt, f, "month multiply specified"
  237.86 +                     );
  237.87 +               while (*s == ' ') s++;
  237.88 +               for (month = 1; month <= 12; month++)
  237.89 +               {  name = moon[month-1];
  237.90 +                  for (k = 0; k <= 2; k++)
  237.91 +                  {  if (toupper((unsigned char)s[k]) !=
  237.92 +                         toupper((unsigned char)name[k])) goto next;
  237.93 +                  }
  237.94 +                  s += 3;
  237.95 +                  for (k = 3; name[k] != '\0'; k++)
  237.96 +                  {  if (toupper((unsigned char)*s) !=
  237.97 +                         toupper((unsigned char)name[k])) break;
  237.98 +                     s++;
  237.99 +                  }
 237.100 +                  break;
 237.101 +next:             ;
 237.102 +               }
 237.103 +               if (month > 12)
 237.104 +                  error1(mpl, str, s, fmt, f, "abbreviated month name m"
 237.105 +                     "issing or invalid");
 237.106 +            }
 237.107 +            else if (*f == 'd')
 237.108 +            {  /* the day of the month as a decimal number (01..31) */
 237.109 +               if (day >= 0)
 237.110 +                  error1(mpl, str, s, fmt, f, "day multiply specified");
 237.111 +               while (*s == ' ') s++;
 237.112 +               if (!('0' <= *s && *s <= '9'))
 237.113 +                  error1(mpl, str, s, fmt, f, "day missing or invalid");
 237.114 +               day = (*s++) - '0';
 237.115 +               if ('0' <= *s && *s <= '9')
 237.116 +                  day = 10 * day + ((*s++) - '0');
 237.117 +               if (!(1 <= day && day <= 31))
 237.118 +                  error1(mpl, str, s, fmt, f, "day out of range");
 237.119 +            }
 237.120 +            else if (*f == 'H')
 237.121 +            {  /* the hour as a decimal number, using a 24-hour clock
 237.122 +                  (00..23) */
 237.123 +               if (hh >= 0)
 237.124 +                  error1(mpl, str, s, fmt, f, "hour multiply specified")
 237.125 +                     ;
 237.126 +               while (*s == ' ') s++;
 237.127 +               if (!('0' <= *s && *s <= '9'))
 237.128 +                  error1(mpl, str, s, fmt, f, "hour missing or invalid")
 237.129 +                     ;
 237.130 +               hh = (*s++) - '0';
 237.131 +               if ('0' <= *s && *s <= '9')
 237.132 +                  hh = 10 * hh + ((*s++) - '0');
 237.133 +               if (!(0 <= hh && hh <= 23))
 237.134 +                  error1(mpl, str, s, fmt, f, "hour out of range");
 237.135 +            }
 237.136 +            else if (*f == 'm')
 237.137 +            {  /* the month as a decimal number (01..12) */
 237.138 +               if (month >= 0)
 237.139 +                  error1(mpl, str, s, fmt, f, "month multiply specified"
 237.140 +                     );
 237.141 +               while (*s == ' ') s++;
 237.142 +               if (!('0' <= *s && *s <= '9'))
 237.143 +                  error1(mpl, str, s, fmt, f, "month missing or invalid"
 237.144 +                     );
 237.145 +               month = (*s++) - '0';
 237.146 +               if ('0' <= *s && *s <= '9')
 237.147 +                  month = 10 * month + ((*s++) - '0');
 237.148 +               if (!(1 <= month && month <= 12))
 237.149 +                  error1(mpl, str, s, fmt, f, "month out of range");
 237.150 +            }
 237.151 +            else if (*f == 'M')
 237.152 +            {  /* the minute as a decimal number (00..59) */
 237.153 +               if (mm >= 0)
 237.154 +                  error1(mpl, str, s, fmt, f, "minute multiply specifie"
 237.155 +                     "d");
 237.156 +               while (*s == ' ') s++;
 237.157 +               if (!('0' <= *s && *s <= '9'))
 237.158 +                  error1(mpl, str, s, fmt, f, "minute missing or invali"
 237.159 +                     "d");
 237.160 +               mm = (*s++) - '0';
 237.161 +               if ('0' <= *s && *s <= '9')
 237.162 +                  mm = 10 * mm + ((*s++) - '0');
 237.163 +               if (!(0 <= mm && mm <= 59))
 237.164 +                  error1(mpl, str, s, fmt, f, "minute out of range");
 237.165 +            }
 237.166 +            else if (*f == 'S')
 237.167 +            {  /* the second as a decimal number (00..60) */
 237.168 +               if (ss >= 0)
 237.169 +                  error1(mpl, str, s, fmt, f, "second multiply specifie"
 237.170 +                     "d");
 237.171 +               while (*s == ' ') s++;
 237.172 +               if (!('0' <= *s && *s <= '9'))
 237.173 +                  error1(mpl, str, s, fmt, f, "second missing or invali"
 237.174 +                     "d");
 237.175 +               ss = (*s++) - '0';
 237.176 +               if ('0' <= *s && *s <= '9')
 237.177 +                  ss = 10 * ss + ((*s++) - '0');
 237.178 +               if (!(0 <= ss && ss <= 60))
 237.179 +                  error1(mpl, str, s, fmt, f, "second out of range");
 237.180 +            }
 237.181 +            else if (*f == 'y')
 237.182 +            {  /* the year without a century as a decimal number
 237.183 +                  (00..99); the values 00 to 68 mean the years 2000 to
 237.184 +                  2068 while the values 69 to 99 mean the years 1969 to
 237.185 +                  1999 */
 237.186 +               if (year >= 0)
 237.187 +                  error1(mpl, str, s, fmt, f, "year multiply specified")
 237.188 +                     ;
 237.189 +               while (*s == ' ') s++;
 237.190 +               if (!('0' <= *s && *s <= '9'))
 237.191 +                  error1(mpl, str, s, fmt, f, "year missing or invalid")
 237.192 +                     ;
 237.193 +               year = (*s++) - '0';
 237.194 +               if ('0' <= *s && *s <= '9')
 237.195 +                  year = 10 * year + ((*s++) - '0');
 237.196 +               year += (year >= 69 ? 1900 : 2000);
 237.197 +            }
 237.198 +            else if (*f == 'Y')
 237.199 +            {  /* the year as a decimal number, using the Gregorian
 237.200 +                  calendar */
 237.201 +               if (year >= 0)
 237.202 +                  error1(mpl, str, s, fmt, f, "year multiply specified")
 237.203 +                     ;
 237.204 +               while (*s == ' ') s++;
 237.205 +               if (!('0' <= *s && *s <= '9'))
 237.206 +                  error1(mpl, str, s, fmt, f, "year missing or invalid")
 237.207 +                     ;
 237.208 +               year = 0;
 237.209 +               for (j = 1; j <= 4; j++)
 237.210 +               {  if (!('0' <= *s && *s <= '9')) break;
 237.211 +                  year = 10 * year + ((*s++) - '0');
 237.212 +               }
 237.213 +               if (!(1 <= year && year <= 4000))
 237.214 +                  error1(mpl, str, s, fmt, f, "year out of range");
 237.215 +            }
 237.216 +            else if (*f == 'z')
 237.217 +            {  /* time zone offset in the form zhhmm */
 237.218 +               int z, hh, mm;
 237.219 +               if (zone != INT_MAX)
 237.220 +                  error1(mpl, str, s, fmt, f, "time zone offset multipl"
 237.221 +                     "y specified");
 237.222 +               while (*s == ' ') s++;
 237.223 +               if (*s == 'Z')
 237.224 +               {  z = hh = mm = 0, s++;
 237.225 +                  goto skip;
 237.226 +               }
 237.227 +               if (*s == '+')
 237.228 +                  z = +1, s++;
 237.229 +               else if (*s == '-')
 237.230 +                  z = -1, s++;
 237.231 +               else
 237.232 +                  error1(mpl, str, s, fmt, f, "time zone offset sign mi"
 237.233 +                     "ssing");
 237.234 +               hh = 0;
 237.235 +               for (j = 1; j <= 2; j++)
 237.236 +               {  if (!('0' <= *s && *s <= '9'))
 237.237 +err1:                error1(mpl, str, s, fmt, f, "time zone offset valu"
 237.238 +                        "e incomplete or invalid");
 237.239 +                  hh = 10 * hh + ((*s++) - '0');
 237.240 +               }
 237.241 +               if (hh > 23)
 237.242 +err2:             error1(mpl, str, s, fmt, f, "time zone offset value o"
 237.243 +                     "ut of range");
 237.244 +               if (*s == ':')
 237.245 +               {  s++;
 237.246 +                  if (!('0' <= *s && *s <= '9')) goto err1;
 237.247 +               }
 237.248 +               mm = 0;
 237.249 +               if (!('0' <= *s && *s <= '9')) goto skip;
 237.250 +               for (j = 1; j <= 2; j++)
 237.251 +               {  if (!('0' <= *s && *s <= '9')) goto err1;
 237.252 +                  mm = 10 * mm + ((*s++) - '0');
 237.253 +               }
 237.254 +               if (mm > 59) goto err2;
 237.255 +skip:          zone = z * (60 * hh + mm);
 237.256 +            }
 237.257 +            else if (*f == '%')
 237.258 +            {  /* literal % character */
 237.259 +               goto test;
 237.260 +            }
 237.261 +            else
 237.262 +               error1(mpl, str, s, fmt, f, "invalid conversion specifie"
 237.263 +                  "r");
 237.264 +         }
 237.265 +         else if (*f == ' ')
 237.266 +            ;
 237.267 +         else
 237.268 +test:    {  /* check a matching character in the input string */
 237.269 +            if (*s != *f)
 237.270 +               error1(mpl, str, s, fmt, f, "character mismatch");
 237.271 +            s++;
 237.272 +         }
 237.273 +      }
 237.274 +      if (year < 0) year = 1970;
 237.275 +      if (month < 0) month = 1;
 237.276 +      if (day < 0) day = 1;
 237.277 +      if (hh < 0) hh = 0;
 237.278 +      if (mm < 0) mm = 0;
 237.279 +      if (ss < 0) ss = 0;
 237.280 +      if (zone == INT_MAX) zone = 0;
 237.281 +      j = jday(day, month, year);
 237.282 +      xassert(j >= 0);
 237.283 +      return (((double)(j - jday(1, 1, 1970)) * 24.0 + (double)hh) *
 237.284 +         60.0 + (double)mm) * 60.0 + (double)ss - 60.0 * (double)zone;
 237.285 +}
 237.286 +
 237.287 +static void error2(MPL *mpl, const char *fmt, const char *f,
 237.288 +      const char *msg)
 237.289 +{     xprintf("Format string passed to time2str:\n");
 237.290 +      xprintf("%s\n", fmt);
 237.291 +      xprintf("%*s\n", (f - fmt) + 1, "^");
 237.292 +      error(mpl, "%s", msg);
 237.293 +      /* no return */
 237.294 +}
 237.295 +
 237.296 +static int weekday(int j)
 237.297 +{     /* determine weekday number (1 = Mon, ..., 7 = Sun) */
 237.298 +      return (j + jday(1, 1, 1970)) % 7 + 1;
 237.299 +}
 237.300 +
 237.301 +static int firstday(int year)
 237.302 +{     /* determine the first day of the first week for a specified year
 237.303 +         according to ISO 8601 */
 237.304 +      int j;
 237.305 +      /* if 1 January is Monday, Tuesday, Wednesday or Thursday, it is
 237.306 +         in week 01; if 1 January is Friday, Saturday or Sunday, it is
 237.307 +         in week 52 or 53 of the previous year */
 237.308 +      j = jday(1, 1, year) - jday(1, 1, 1970);
 237.309 +      switch (weekday(j))
 237.310 +      {  case 1: /* 1 Jan is Mon */ j += 0; break;
 237.311 +         case 2: /* 1 Jan is Tue */ j -= 1; break;
 237.312 +         case 3: /* 1 Jan is Wed */ j -= 2; break;
 237.313 +         case 4: /* 1 Jan is Thu */ j -= 3; break;
 237.314 +         case 5: /* 1 Jan is Fri */ j += 3; break;
 237.315 +         case 6: /* 1 Jan is Sat */ j += 2; break;
 237.316 +         case 7: /* 1 Jan is Sun */ j += 1; break;
 237.317 +         default: xassert(j != j);
 237.318 +      }
 237.319 +      /* the first day of the week must be Monday */
 237.320 +      xassert(weekday(j) == 1);
 237.321 +      return j;
 237.322 +}
 237.323 +
 237.324 +void fn_time2str(MPL *mpl, char *str, double t, const char *fmt)
 237.325 +{     /* convert the calendar time to character string */
 237.326 +      int j, year, month, day, hh, mm, ss, len;
 237.327 +      double temp;
 237.328 +      const char *f;
 237.329 +      char buf[MAX_LENGTH+1];
 237.330 +      if (!(-62135596800.0 <= t && t <= 64092211199.0))
 237.331 +         error(mpl, "time2str(%.*g,...); argument out of range",
 237.332 +            DBL_DIG, t);
 237.333 +      t = floor(t + 0.5);
 237.334 +      temp = fabs(t) / 86400.0;
 237.335 +      j = (int)floor(temp);
 237.336 +      if (t < 0.0)
 237.337 +      {  if (temp == floor(temp))
 237.338 +            j = - j;
 237.339 +         else
 237.340 +            j = - (j + 1);
 237.341 +      }
 237.342 +      xassert(jdate(j + jday(1, 1, 1970), &day, &month, &year) == 0);
 237.343 +      ss = (int)(t - 86400.0 * (double)j);
 237.344 +      xassert(0 <= ss && ss < 86400);
 237.345 +      mm = ss / 60, ss %= 60;
 237.346 +      hh = mm / 60, mm %= 60;
 237.347 +      len = 0;
 237.348 +      for (f = fmt; *f != '\0'; f++)
 237.349 +      {  if (*f == '%')
 237.350 +         {  f++;
 237.351 +            if (*f == 'a')
 237.352 +            {  /* the abbreviated weekday name */
 237.353 +               memcpy(buf, week[weekday(j)-1], 3), buf[3] = '\0';
 237.354 +            }
 237.355 +            else if (*f == 'A')
 237.356 +            {  /* the full weekday name */
 237.357 +               strcpy(buf, week[weekday(j)-1]);
 237.358 +            }
 237.359 +            else if (*f == 'b' || *f == 'h')
 237.360 +            {  /* the abbreviated month name */
 237.361 +               memcpy(buf, moon[month-1], 3), buf[3] = '\0';
 237.362 +            }
 237.363 +            else if (*f == 'B')
 237.364 +            {  /* the full month name */
 237.365 +               strcpy(buf, moon[month-1]);
 237.366 +            }
 237.367 +            else if (*f == 'C')
 237.368 +            {  /* the century of the year */
 237.369 +               sprintf(buf, "%02d", year / 100);
 237.370 +            }
 237.371 +            else if (*f == 'd')
 237.372 +            {  /* the day of the month as a decimal number (01..31) */
 237.373 +               sprintf(buf, "%02d", day);
 237.374 +            }
 237.375 +            else if (*f == 'D')
 237.376 +            {  /* the date using the format %m/%d/%y */
 237.377 +               sprintf(buf, "%02d/%02d/%02d", month, day, year % 100);
 237.378 +            }
 237.379 +            else if (*f == 'e')
 237.380 +            {  /* the day of the month like with %d, but padded with
 237.381 +                  blank (1..31) */
 237.382 +               sprintf(buf, "%2d", day);
 237.383 +            }
 237.384 +            else if (*f == 'F')
 237.385 +            {  /* the date using the format %Y-%m-%d */
 237.386 +               sprintf(buf, "%04d-%02d-%02d", year, month, day);
 237.387 +            }
 237.388 +            else if (*f == 'g')
 237.389 +            {  /* the year corresponding to the ISO week number, but
 237.390 +                  without the century (range 00 through 99); this has
 237.391 +                  the same format and value as %y, except that if the
 237.392 +                  ISO week number (see %V) belongs to the previous or
 237.393 +                  next year, that year is used instead */
 237.394 +               int iso;
 237.395 +               if (j < firstday(year))
 237.396 +                  iso = year - 1;
 237.397 +               else if (j < firstday(year + 1))
 237.398 +                  iso = year;
 237.399 +               else
 237.400 +                  iso = year + 1;
 237.401 +               sprintf(buf, "%02d", iso % 100);
 237.402 +            }
 237.403 +            else if (*f == 'G')
 237.404 +            {  /* the year corresponding to the ISO week number; this
 237.405 +                  has the same format and value as %Y, excepth that if
 237.406 +                  the ISO week number (see %V) belongs to the previous
 237.407 +                  or next year, that year is used instead */
 237.408 +               int iso;
 237.409 +               if (j < firstday(year))
 237.410 +                  iso = year - 1;
 237.411 +               else if (j < firstday(year + 1))
 237.412 +                  iso = year;
 237.413 +               else
 237.414 +                  iso = year + 1;
 237.415 +               sprintf(buf, "%04d", iso);
 237.416 +            }
 237.417 +            else if (*f == 'H')
 237.418 +            {  /* the hour as a decimal number, using a 24-hour clock
 237.419 +                  (00..23) */
 237.420 +               sprintf(buf, "%02d", hh);
 237.421 +            }
 237.422 +            else if (*f == 'I')
 237.423 +            {  /* the hour as a decimal number, using a 12-hour clock
 237.424 +                  (01..12) */
 237.425 +               sprintf(buf, "%02d",
 237.426 +                  hh == 0 ? 12 : hh <= 12 ? hh : hh - 12);
 237.427 +            }
 237.428 +            else if (*f == 'j')
 237.429 +            {  /* the day of the year as a decimal number (001..366) */
 237.430 +               sprintf(buf, "%03d",
 237.431 +                  jday(day, month, year) - jday(1, 1, year) + 1);
 237.432 +            }
 237.433 +            else if (*f == 'k')
 237.434 +            {  /* the hour as a decimal number, using a 24-hour clock
 237.435 +                  like %H, but padded with blank (0..23) */
 237.436 +               sprintf(buf, "%2d", hh);
 237.437 +            }
 237.438 +            else if (*f == 'l')
 237.439 +            {  /* the hour as a decimal number, using a 12-hour clock
 237.440 +                  like %I, but padded with blank (1..12) */
 237.441 +               sprintf(buf, "%2d",
 237.442 +                  hh == 0 ? 12 : hh <= 12 ? hh : hh - 12);
 237.443 +            }
 237.444 +            else if (*f == 'm')
 237.445 +            {  /* the month as a decimal number (01..12) */
 237.446 +               sprintf(buf, "%02d", month);
 237.447 +            }
 237.448 +            else if (*f == 'M')
 237.449 +            {  /* the minute as a decimal number (00..59) */
 237.450 +               sprintf(buf, "%02d", mm);
 237.451 +            }
 237.452 +            else if (*f == 'p')
 237.453 +            {  /* either AM or PM, according to the given time value;
 237.454 +                  noon is treated as PM and midnight as AM */
 237.455 +               strcpy(buf, hh <= 11 ? "AM" : "PM");
 237.456 +            }
 237.457 +            else if (*f == 'P')
 237.458 +            {  /* either am or pm, according to the given time value;
 237.459 +                  noon is treated as pm and midnight as am */
 237.460 +               strcpy(buf, hh <= 11 ? "am" : "pm");
 237.461 +            }
 237.462 +            else if (*f == 'r')
 237.463 +            {  /* the calendar time using the format %I:%M:%S %p */
 237.464 +               sprintf(buf, "%02d:%02d:%02d %s",
 237.465 +                  hh == 0 ? 12 : hh <= 12 ? hh : hh - 12,
 237.466 +                  mm, ss, hh <= 11 ? "AM" : "PM");
 237.467 +            }
 237.468 +            else if (*f == 'R')
 237.469 +            {  /* the hour and minute using the format %H:%M */
 237.470 +               sprintf(buf, "%02d:%02d", hh, mm);
 237.471 +            }
 237.472 +            else if (*f == 'S')
 237.473 +            {  /* the second as a decimal number (00..59) */
 237.474 +               sprintf(buf, "%02d", ss);
 237.475 +            }
 237.476 +            else if (*f == 'T')
 237.477 +            {  /* the time of day using the format %H:%M:%S */
 237.478 +               sprintf(buf, "%02d:%02d:%02d", hh, mm, ss);
 237.479 +            }
 237.480 +            else if (*f == 'u')
 237.481 +            {  /* the day of the week as a decimal number (1..7),
 237.482 +                  Monday being 1 */
 237.483 +               sprintf(buf, "%d", weekday(j));
 237.484 +            }
 237.485 +            else if (*f == 'U')
 237.486 +            {  /* the week number of the current year as a decimal
 237.487 +                  number (range 00 through 53), starting with the first
 237.488 +                  Sunday as the first day of the first week; days
 237.489 +                  preceding the first Sunday in the year are considered
 237.490 +                  to be in week 00 */
 237.491 +#if 1 /* 09/I-2009 */
 237.492 +#undef sun
 237.493 +/* causes compilation error in SunOS */
 237.494 +#endif
 237.495 +               int sun;
 237.496 +               /* sun = the first Sunday of the year */
 237.497 +               sun = jday(1, 1, year) - jday(1, 1, 1970);
 237.498 +               sun += (7 - weekday(sun));
 237.499 +               sprintf(buf, "%02d", (j + 7 - sun) / 7);
 237.500 +            }
 237.501 +            else if (*f == 'V')
 237.502 +            {  /* the ISO week number as a decimal number (range 01
 237.503 +                  through 53); ISO weeks start with Monday and end with
 237.504 +                  Sunday; week 01 of a year is the first week which has
 237.505 +                  the majority of its days in that year; week 01 of
 237.506 +                  a year can contain days from the previous year; the
 237.507 +                  week before week 01 of a year is the last week (52 or
 237.508 +                  53) of the previous year even if it contains days
 237.509 +                  from the new year */
 237.510 +               int iso;
 237.511 +               if (j < firstday(year))
 237.512 +                  iso = j - firstday(year - 1);
 237.513 +               else if (j < firstday(year + 1))
 237.514 +                  iso = j - firstday(year);
 237.515 +               else
 237.516 +                  iso = j - firstday(year + 1);
 237.517 +               sprintf(buf, "%02d", iso / 7 + 1);
 237.518 +            }
 237.519 +            else if (*f == 'w')
 237.520 +            {  /* the day of the week as a decimal number (0..6),
 237.521 +                  Sunday being 0 */
 237.522 +               sprintf(buf, "%d", weekday(j) % 7);
 237.523 +            }
 237.524 +            else if (*f == 'W')
 237.525 +            {  /* the week number of the current year as a decimal
 237.526 +                  number (range 00 through 53), starting with the first
 237.527 +                  Monday as the first day of the first week; days
 237.528 +                  preceding the first Monday in the year are considered
 237.529 +                  to be in week 00 */
 237.530 +               int mon;
 237.531 +               /* mon = the first Monday of the year */
 237.532 +               mon = jday(1, 1, year) - jday(1, 1, 1970);
 237.533 +               mon += (8 - weekday(mon)) % 7;
 237.534 +               sprintf(buf, "%02d", (j + 7 - mon) / 7);
 237.535 +            }
 237.536 +            else if (*f == 'y')
 237.537 +            {  /* the year without a century as a decimal number
 237.538 +                  (00..99) */
 237.539 +               sprintf(buf, "%02d", year % 100);
 237.540 +            }
 237.541 +            else if (*f == 'Y')
 237.542 +            {  /* the year as a decimal number, using the Gregorian
 237.543 +                  calendar */
 237.544 +               sprintf(buf, "%04d", year);
 237.545 +            }
 237.546 +            else if (*f == '%')
 237.547 +            {  /* a literal % character */
 237.548 +               buf[0] = '%', buf[1] = '\0';
 237.549 +            }
 237.550 +            else
 237.551 +               error2(mpl, fmt, f, "invalid conversion specifier");
 237.552 +         }
 237.553 +         else
 237.554 +            buf[0] = *f, buf[1] = '\0';
 237.555 +         if (len + strlen(buf) > MAX_LENGTH)
 237.556 +            error(mpl, "time2str; output string length exceeds %d chara"
 237.557 +               "cters", MAX_LENGTH);
 237.558 +         memcpy(str+len, buf, strlen(buf));
 237.559 +         len += strlen(buf);
 237.560 +      }
 237.561 +      str[len] = '\0';
 237.562 +      return;
 237.563 +}
 237.564 +
 237.565 +/* eof */
   238.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   238.2 +++ b/src/glpmpl06.c	Mon Dec 06 13:09:21 2010 +0100
   238.3 @@ -0,0 +1,1002 @@
   238.4 +/* glpmpl06.c */
   238.5 +
   238.6 +/***********************************************************************
   238.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   238.8 +*
   238.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  238.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  238.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  238.12 +*  E-mail: <mao@gnu.org>.
  238.13 +*
  238.14 +*  GLPK is free software: you can redistribute it and/or modify it
  238.15 +*  under the terms of the GNU General Public License as published by
  238.16 +*  the Free Software Foundation, either version 3 of the License, or
  238.17 +*  (at your option) any later version.
  238.18 +*
  238.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  238.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  238.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  238.22 +*  License for more details.
  238.23 +*
  238.24 +*  You should have received a copy of the GNU General Public License
  238.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  238.26 +***********************************************************************/
  238.27 +
  238.28 +#define _GLPSTD_ERRNO
  238.29 +#define _GLPSTD_STDIO
  238.30 +#include "glpmpl.h"
  238.31 +#include "glpsql.h"
  238.32 +
  238.33 +/**********************************************************************/
  238.34 +
  238.35 +#define CSV_FIELD_MAX 50
  238.36 +/* maximal number of fields in record */
  238.37 +
  238.38 +#define CSV_FDLEN_MAX 100
  238.39 +/* maximal field length */
  238.40 +
  238.41 +struct csv
  238.42 +{     /* comma-separated values file */
  238.43 +      int mode;
  238.44 +      /* 'R' = reading; 'W' = writing */
  238.45 +      char *fname;
  238.46 +      /* name of csv file */
  238.47 +      FILE *fp;
  238.48 +      /* stream assigned to csv file */
  238.49 +      jmp_buf jump;
  238.50 +      /* address for non-local go to in case of error */
  238.51 +      int count;
  238.52 +      /* record count */
  238.53 +      /*--------------------------------------------------------------*/
  238.54 +      /* used only for input csv file */
  238.55 +      int c;
  238.56 +      /* current character or EOF */
  238.57 +      int what;
  238.58 +      /* current marker: */
  238.59 +#define CSV_EOF   0  /* end-of-file */
  238.60 +#define CSV_EOR   1  /* end-of-record */
  238.61 +#define CSV_NUM   2  /* floating-point number */
  238.62 +#define CSV_STR   3  /* character string */
  238.63 +      char field[CSV_FDLEN_MAX+1];
  238.64 +      /* current field just read */
  238.65 +      int nf;
  238.66 +      /* number of fields in the csv file */
  238.67 +      int ref[1+CSV_FIELD_MAX];
  238.68 +      /* ref[k] = k', if k-th field of the csv file corresponds to
  238.69 +         k'-th field in the table statement; if ref[k] = 0, k-th field
  238.70 +         of the csv file is ignored */
  238.71 +#if 1 /* 01/VI-2010 */
  238.72 +      int nskip;
  238.73 +      /* number of comment records preceding the header record */
  238.74 +#endif
  238.75 +};
  238.76 +
  238.77 +#undef read_char
  238.78 +
  238.79 +static void read_char(struct csv *csv)
  238.80 +{     /* read character from csv data file */
  238.81 +      int c;
  238.82 +      xassert(csv->c != EOF);
  238.83 +      if (csv->c == '\n') csv->count++;
  238.84 +loop: c = fgetc(csv->fp);
  238.85 +      if (ferror(csv->fp))
  238.86 +      {  xprintf("%s:%d: read error - %s\n", csv->fname, csv->count,
  238.87 +            strerror(errno));
  238.88 +         longjmp(csv->jump, 0);
  238.89 +      }
  238.90 +      if (feof(csv->fp))
  238.91 +      {  if (csv->c == '\n')
  238.92 +         {  csv->count--;
  238.93 +            c = EOF;
  238.94 +         }
  238.95 +         else
  238.96 +         {  xprintf("%s:%d: warning: missing final end-of-line\n",
  238.97 +               csv->fname, csv->count);
  238.98 +            c = '\n';
  238.99 +         }
 238.100 +      }
 238.101 +      else if (c == '\r')
 238.102 +         goto loop;
 238.103 +      else if (c == '\n')
 238.104 +         ;
 238.105 +      else if (iscntrl(c))
 238.106 +      {  xprintf("%s:%d: invalid control character 0x%02X\n",
 238.107 +            csv->fname, csv->count, c);
 238.108 +         longjmp(csv->jump, 0);
 238.109 +      }
 238.110 +      csv->c = c;
 238.111 +      return;
 238.112 +}
 238.113 +
 238.114 +static void read_field(struct csv *csv)
 238.115 +{     /* read field from csv data file */
 238.116 +      /* check for end of file */
 238.117 +      if (csv->c == EOF)
 238.118 +      {  csv->what = CSV_EOF;
 238.119 +         strcpy(csv->field, "EOF");
 238.120 +         goto done;
 238.121 +      }
 238.122 +      /* check for end of record */
 238.123 +      if (csv->c == '\n')
 238.124 +      {  csv->what = CSV_EOR;
 238.125 +         strcpy(csv->field, "EOR");
 238.126 +         read_char(csv);
 238.127 +         if (csv->c == ',')
 238.128 +err1:    {  xprintf("%s:%d: empty field not allowed\n", csv->fname,
 238.129 +               csv->count);
 238.130 +            longjmp(csv->jump, 0);
 238.131 +         }
 238.132 +         if (csv->c == '\n')
 238.133 +         {  xprintf("%s:%d: empty record not allowed\n", csv->fname,
 238.134 +               csv->count);
 238.135 +            longjmp(csv->jump, 0);
 238.136 +         }
 238.137 +#if 1 /* 01/VI-2010 */
 238.138 +         /* skip comment records; may appear only before the very first
 238.139 +            record containing field names */
 238.140 +         if (csv->c == '#' && csv->count == 1)
 238.141 +         {  while (csv->c == '#')
 238.142 +            {  while (csv->c != '\n')
 238.143 +                  read_char(csv);
 238.144 +               read_char(csv);
 238.145 +               csv->nskip++;
 238.146 +            }
 238.147 +         }
 238.148 +#endif
 238.149 +         goto done;
 238.150 +      }
 238.151 +      /* skip comma before next field */
 238.152 +      if (csv->c == ',')
 238.153 +         read_char(csv);
 238.154 +      /* read field */
 238.155 +      if (csv->c == '\'' || csv->c == '"')
 238.156 +      {  /* read a field enclosed in quotes */
 238.157 +         int quote = csv->c, len = 0;
 238.158 +         csv->what = CSV_STR;
 238.159 +         /* skip opening quote */
 238.160 +         read_char(csv);
 238.161 +         /* read field characters within quotes */
 238.162 +         for (;;)
 238.163 +         {  /* check for closing quote and read it */
 238.164 +            if (csv->c == quote)
 238.165 +            {  read_char(csv);
 238.166 +               if (csv->c == quote)
 238.167 +                  ;
 238.168 +               else if (csv->c == ',' || csv->c == '\n')
 238.169 +                  break;
 238.170 +               else
 238.171 +               {  xprintf("%s:%d: invalid field\n", csv->fname,
 238.172 +                     csv->count);
 238.173 +                  longjmp(csv->jump, 0);
 238.174 +               }
 238.175 +            }
 238.176 +            /* check the current field length */
 238.177 +            if (len == CSV_FDLEN_MAX)
 238.178 +err2:       {  xprintf("%s:%d: field too long\n", csv->fname,
 238.179 +                  csv->count);
 238.180 +               longjmp(csv->jump, 0);
 238.181 +            }
 238.182 +            /* add the current character to the field */
 238.183 +            csv->field[len++] = (char)csv->c;
 238.184 +            /* read the next character */
 238.185 +            read_char(csv);
 238.186 +         }
 238.187 +         /* the field has been read */
 238.188 +         if (len == 0) goto err1;
 238.189 +         csv->field[len] = '\0';
 238.190 +      }
 238.191 +      else
 238.192 +      {  /* read a field not enclosed in quotes */
 238.193 +         int len = 0;
 238.194 +         double temp;
 238.195 +         csv->what = CSV_NUM;
 238.196 +         while (!(csv->c == ',' || csv->c == '\n'))
 238.197 +         {  /* quotes within the field are not allowed */
 238.198 +            if (csv->c == '\'' || csv->c == '"')
 238.199 +            {  xprintf("%s:%d: invalid use of single or double quote wi"
 238.200 +                  "thin field\n", csv->fname, csv->count);
 238.201 +               longjmp(csv->jump, 0);
 238.202 +            }
 238.203 +            /* check the current field length */
 238.204 +            if (len == CSV_FDLEN_MAX) goto err2;
 238.205 +            /* add the current character to the field */
 238.206 +            csv->field[len++] = (char)csv->c;
 238.207 +            /* read the next character */
 238.208 +            read_char(csv);
 238.209 +         }
 238.210 +         /* the field has been read */
 238.211 +         if (len == 0) goto err1;
 238.212 +         csv->field[len] = '\0';
 238.213 +         /* check the field type */
 238.214 +         if (str2num(csv->field, &temp)) csv->what = CSV_STR;
 238.215 +      }
 238.216 +done: return;
 238.217 +}
 238.218 +
 238.219 +static struct csv *csv_open_file(TABDCA *dca, int mode)
 238.220 +{     /* open csv data file */
 238.221 +      struct csv *csv;
 238.222 +      /* create control structure */
 238.223 +      csv = xmalloc(sizeof(struct csv));
 238.224 +      csv->mode = mode;
 238.225 +      csv->fname = NULL;
 238.226 +      csv->fp = NULL;
 238.227 +      if (setjmp(csv->jump)) goto fail;
 238.228 +      csv->count = 0;
 238.229 +      csv->c = '\n';
 238.230 +      csv->what = 0;
 238.231 +      csv->field[0] = '\0';
 238.232 +      csv->nf = 0;
 238.233 +      /* try to open the csv data file */
 238.234 +      if (mpl_tab_num_args(dca) < 2)
 238.235 +      {  xprintf("csv_driver: file name not specified\n");
 238.236 +         longjmp(csv->jump, 0);
 238.237 +      }
 238.238 +      csv->fname = xmalloc(strlen(mpl_tab_get_arg(dca, 2))+1);
 238.239 +      strcpy(csv->fname, mpl_tab_get_arg(dca, 2));
 238.240 +      if (mode == 'R')
 238.241 +      {  /* open the file for reading */
 238.242 +         int k;
 238.243 +         csv->fp = fopen(csv->fname, "r");
 238.244 +         if (csv->fp == NULL)
 238.245 +         {  xprintf("csv_driver: unable to open %s - %s\n",
 238.246 +               csv->fname, strerror(errno));
 238.247 +            longjmp(csv->jump, 0);
 238.248 +         }
 238.249 +#if 1 /* 01/VI-2010 */
 238.250 +         csv->nskip = 0;
 238.251 +#endif
 238.252 +         /* skip fake new-line */
 238.253 +         read_field(csv);
 238.254 +         xassert(csv->what == CSV_EOR);
 238.255 +         /* read field names */
 238.256 +         xassert(csv->nf == 0);
 238.257 +         for (;;)
 238.258 +         {  read_field(csv);
 238.259 +            if (csv->what == CSV_EOR)
 238.260 +               break;
 238.261 +            if (csv->what != CSV_STR)
 238.262 +            {  xprintf("%s:%d: invalid field name\n", csv->fname,
 238.263 +                  csv->count);
 238.264 +               longjmp(csv->jump, 0);
 238.265 +            }
 238.266 +            if (csv->nf == CSV_FIELD_MAX)
 238.267 +            {  xprintf("%s:%d: too many fields\n", csv->fname,
 238.268 +                  csv->count);
 238.269 +               longjmp(csv->jump, 0);
 238.270 +            }
 238.271 +            csv->nf++;
 238.272 +            /* find corresponding field in the table statement */
 238.273 +            for (k = mpl_tab_num_flds(dca); k >= 1; k--)
 238.274 +            {  if (strcmp(mpl_tab_get_name(dca, k), csv->field) == 0)
 238.275 +                  break;
 238.276 +            }
 238.277 +            csv->ref[csv->nf] = k;
 238.278 +         }
 238.279 +         /* find dummy RECNO field in the table statement */
 238.280 +         for (k = mpl_tab_num_flds(dca); k >= 1; k--)
 238.281 +            if (strcmp(mpl_tab_get_name(dca, k), "RECNO") == 0) break;
 238.282 +         csv->ref[0] = k;
 238.283 +      }
 238.284 +      else if (mode == 'W')
 238.285 +      {  /* open the file for writing */
 238.286 +         int k, nf;
 238.287 +         csv->fp = fopen(csv->fname, "w");
 238.288 +         if (csv->fp == NULL)
 238.289 +         {  xprintf("csv_driver: unable to create %s - %s\n",
 238.290 +               csv->fname, strerror(errno));
 238.291 +            longjmp(csv->jump, 0);
 238.292 +         }
 238.293 +         /* write field names */
 238.294 +         nf = mpl_tab_num_flds(dca);
 238.295 +         for (k = 1; k <= nf; k++)
 238.296 +            fprintf(csv->fp, "%s%c", mpl_tab_get_name(dca, k),
 238.297 +               k < nf ? ',' : '\n');
 238.298 +         csv->count++;
 238.299 +      }
 238.300 +      else
 238.301 +         xassert(mode != mode);
 238.302 +      /* the file has been open */
 238.303 +      return csv;
 238.304 +fail: /* the file cannot be open */
 238.305 +      if (csv->fname != NULL) xfree(csv->fname);
 238.306 +      if (csv->fp != NULL) fclose(csv->fp);
 238.307 +      xfree(csv);
 238.308 +      return NULL;
 238.309 +}
 238.310 +
 238.311 +static int csv_read_record(TABDCA *dca, struct csv *csv)
 238.312 +{     /* read next record from csv data file */
 238.313 +      int k, ret = 0;
 238.314 +      xassert(csv->mode == 'R');
 238.315 +      if (setjmp(csv->jump))
 238.316 +      {  ret = 1;
 238.317 +         goto done;
 238.318 +      }
 238.319 +      /* read dummy RECNO field */
 238.320 +      if (csv->ref[0] > 0)
 238.321 +#if 0 /* 01/VI-2010 */
 238.322 +         mpl_tab_set_num(dca, csv->ref[0], csv->count-1);
 238.323 +#else
 238.324 +         mpl_tab_set_num(dca, csv->ref[0], csv->count-csv->nskip-1);
 238.325 +#endif
 238.326 +      /* read fields */
 238.327 +      for (k = 1; k <= csv->nf; k++)
 238.328 +      {  read_field(csv);
 238.329 +         if (csv->what == CSV_EOF)
 238.330 +         {  /* end-of-file reached */
 238.331 +            xassert(k == 1);
 238.332 +            ret = -1;
 238.333 +            goto done;
 238.334 +         }
 238.335 +         else if (csv->what == CSV_EOR)
 238.336 +         {  /* end-of-record reached */
 238.337 +            int lack = csv->nf - k + 1;
 238.338 +            if (lack == 1)
 238.339 +               xprintf("%s:%d: one field missing\n", csv->fname,
 238.340 +                  csv->count);
 238.341 +            else
 238.342 +               xprintf("%s:%d: %d fields missing\n", csv->fname,
 238.343 +                  csv->count, lack);
 238.344 +            longjmp(csv->jump, 0);
 238.345 +         }
 238.346 +         else if (csv->what == CSV_NUM)
 238.347 +         {  /* floating-point number */
 238.348 +            if (csv->ref[k] > 0)
 238.349 +            {  double num;
 238.350 +               xassert(str2num(csv->field, &num) == 0);
 238.351 +               mpl_tab_set_num(dca, csv->ref[k], num);
 238.352 +            }
 238.353 +         }
 238.354 +         else if (csv->what == CSV_STR)
 238.355 +         {  /* character string */
 238.356 +            if (csv->ref[k] > 0)
 238.357 +               mpl_tab_set_str(dca, csv->ref[k], csv->field);
 238.358 +         }
 238.359 +         else
 238.360 +            xassert(csv != csv);
 238.361 +      }
 238.362 +      /* now there must be NL */
 238.363 +      read_field(csv);
 238.364 +      xassert(csv->what != CSV_EOF);
 238.365 +      if (csv->what != CSV_EOR)
 238.366 +      {  xprintf("%s:%d: too many fields\n", csv->fname, csv->count);
 238.367 +         longjmp(csv->jump, 0);
 238.368 +      }
 238.369 +done: return ret;
 238.370 +}
 238.371 +
 238.372 +static int csv_write_record(TABDCA *dca, struct csv *csv)
 238.373 +{     /* write next record to csv data file */
 238.374 +      int k, nf, ret = 0;
 238.375 +      const char *c;
 238.376 +      xassert(csv->mode == 'W');
 238.377 +      nf = mpl_tab_num_flds(dca);
 238.378 +      for (k = 1; k <= nf; k++)
 238.379 +      {  switch (mpl_tab_get_type(dca, k))
 238.380 +         {  case 'N':
 238.381 +               fprintf(csv->fp, "%.*g", DBL_DIG,
 238.382 +                  mpl_tab_get_num(dca, k));
 238.383 +               break;
 238.384 +            case 'S':
 238.385 +               fputc('"', csv->fp);
 238.386 +               for (c = mpl_tab_get_str(dca, k); *c != '\0'; c++)
 238.387 +               {  if (*c == '"')
 238.388 +                     fputc('"', csv->fp), fputc('"', csv->fp);
 238.389 +                  else
 238.390 +                     fputc(*c, csv->fp);
 238.391 +               }
 238.392 +               fputc('"', csv->fp);
 238.393 +               break;
 238.394 +            default:
 238.395 +               xassert(dca != dca);
 238.396 +         }
 238.397 +         fputc(k < nf ? ',' : '\n', csv->fp);
 238.398 +      }
 238.399 +      csv->count++;
 238.400 +      if (ferror(csv->fp))
 238.401 +      {  xprintf("%s:%d: write error - %s\n", csv->fname, csv->count,
 238.402 +            strerror(errno));
 238.403 +         ret = 1;
 238.404 +      }
 238.405 +      return ret;
 238.406 +}
 238.407 +
 238.408 +static int csv_close_file(TABDCA *dca, struct csv *csv)
 238.409 +{     /* close csv data file */
 238.410 +      int ret = 0;
 238.411 +      xassert(dca == dca);
 238.412 +      if (csv->mode == 'W')
 238.413 +      {  fflush(csv->fp);
 238.414 +         if (ferror(csv->fp))
 238.415 +         {  xprintf("%s:%d: write error - %s\n", csv->fname,
 238.416 +               csv->count, strerror(errno));
 238.417 +            ret = 1;
 238.418 +         }
 238.419 +      }
 238.420 +      xfree(csv->fname);
 238.421 +      fclose(csv->fp);
 238.422 +      xfree(csv);
 238.423 +      return ret;
 238.424 +}
 238.425 +
 238.426 +/**********************************************************************/
 238.427 +
 238.428 +#define DBF_FIELD_MAX 50
 238.429 +/* maximal number of fields in record */
 238.430 +
 238.431 +#define DBF_FDLEN_MAX 100
 238.432 +/* maximal field length */
 238.433 +
 238.434 +struct dbf
 238.435 +{     /* xBASE data file */
 238.436 +      int mode;
 238.437 +      /* 'R' = reading; 'W' = writing */
 238.438 +      char *fname;
 238.439 +      /* name of xBASE file */
 238.440 +      FILE *fp;
 238.441 +      /* stream assigned to xBASE file */
 238.442 +      jmp_buf jump;
 238.443 +      /* address for non-local go to in case of error */
 238.444 +      int offset;
 238.445 +      /* offset of a byte to be read next */
 238.446 +      int count;
 238.447 +      /* record count */
 238.448 +      int nf;
 238.449 +      /* number of fields */
 238.450 +      int ref[1+DBF_FIELD_MAX];
 238.451 +      /* ref[k] = k', if k-th field of the csv file corresponds to
 238.452 +         k'-th field in the table statement; if ref[k] = 0, k-th field
 238.453 +         of the csv file is ignored */
 238.454 +      int type[1+DBF_FIELD_MAX];
 238.455 +      /* type[k] is type of k-th field */
 238.456 +      int len[1+DBF_FIELD_MAX];
 238.457 +      /* len[k] is length of k-th field */
 238.458 +      int prec[1+DBF_FIELD_MAX];
 238.459 +      /* prec[k] is precision of k-th field */
 238.460 +};
 238.461 +
 238.462 +static int read_byte(struct dbf *dbf)
 238.463 +{     /* read byte from xBASE data file */
 238.464 +      int b;
 238.465 +      b = fgetc(dbf->fp);
 238.466 +      if (ferror(dbf->fp))
 238.467 +      {  xprintf("%s:0x%X: read error - %s\n", dbf->fname,
 238.468 +            dbf->offset, strerror(errno));
 238.469 +         longjmp(dbf->jump, 0);
 238.470 +      }
 238.471 +      if (feof(dbf->fp))
 238.472 +      {  xprintf("%s:0x%X: unexpected end of file\n", dbf->fname,
 238.473 +            dbf->offset);
 238.474 +         longjmp(dbf->jump, 0);
 238.475 +      }
 238.476 +      xassert(0x00 <= b && b <= 0xFF);
 238.477 +      dbf->offset++;
 238.478 +      return b;
 238.479 +}
 238.480 +
 238.481 +static void read_header(TABDCA *dca, struct dbf *dbf)
 238.482 +{     /* read xBASE data file header */
 238.483 +      int b, j, k, recl;
 238.484 +      char name[10+1];
 238.485 +      /* (ignored) */
 238.486 +      for (j = 1; j <= 10; j++)
 238.487 +         read_byte(dbf);
 238.488 +      /* length of each record, in bytes */
 238.489 +      recl = read_byte(dbf);
 238.490 +      recl += read_byte(dbf) << 8;
 238.491 +      /* (ignored) */
 238.492 +      for (j = 1; j <= 20; j++)
 238.493 +         read_byte(dbf);
 238.494 +      /* field descriptor array */
 238.495 +      xassert(dbf->nf == 0);
 238.496 +      for (;;)
 238.497 +      {  /* check for end of array */
 238.498 +         b = read_byte(dbf);
 238.499 +         if (b == 0x0D) break;
 238.500 +         if (dbf->nf == DBF_FIELD_MAX)
 238.501 +         {  xprintf("%s:0x%X: too many fields\n", dbf->fname,
 238.502 +               dbf->offset);
 238.503 +            longjmp(dbf->jump, 0);
 238.504 +         }
 238.505 +         dbf->nf++;
 238.506 +         /* field name */
 238.507 +         name[0] = (char)b;
 238.508 +         for (j = 1; j < 10; j++)
 238.509 +         {  b = read_byte(dbf);
 238.510 +            name[j] = (char)b;
 238.511 +         }
 238.512 +         name[10] = '\0';
 238.513 +         b = read_byte(dbf);
 238.514 +         if (b != 0x00)
 238.515 +         {  xprintf("%s:0x%X: invalid field name\n", dbf->fname,
 238.516 +               dbf->offset);
 238.517 +            longjmp(dbf->jump, 0);
 238.518 +         }
 238.519 +         /* find corresponding field in the table statement */
 238.520 +         for (k = mpl_tab_num_flds(dca); k >= 1; k--)
 238.521 +            if (strcmp(mpl_tab_get_name(dca, k), name) == 0) break;
 238.522 +         dbf->ref[dbf->nf] = k;
 238.523 +         /* field type */
 238.524 +         b = read_byte(dbf);
 238.525 +         if (!(b == 'C' || b == 'N'))
 238.526 +         {  xprintf("%s:0x%X: invalid field type\n", dbf->fname,
 238.527 +               dbf->offset);
 238.528 +            longjmp(dbf->jump, 0);
 238.529 +         }
 238.530 +         dbf->type[dbf->nf] = b;
 238.531 +         /* (ignored) */
 238.532 +         for (j = 1; j <= 4; j++)
 238.533 +            read_byte(dbf);
 238.534 +         /* field length */
 238.535 +         b = read_byte(dbf);
 238.536 +         if (b == 0)
 238.537 +         {  xprintf("%s:0x%X: invalid field length\n", dbf->fname,
 238.538 +               dbf->offset);
 238.539 +            longjmp(dbf->jump, 0);
 238.540 +         }
 238.541 +         if (b > DBF_FDLEN_MAX)
 238.542 +         {  xprintf("%s:0x%X: field too long\n", dbf->fname,
 238.543 +               dbf->offset);
 238.544 +            longjmp(dbf->jump, 0);
 238.545 +         }
 238.546 +         dbf->len[dbf->nf] = b;
 238.547 +         recl -= b;
 238.548 +         /* (ignored) */
 238.549 +         for (j = 1; j <= 15; j++)
 238.550 +            read_byte(dbf);
 238.551 +      }
 238.552 +      if (recl != 1)
 238.553 +      {  xprintf("%s:0x%X: invalid file header\n", dbf->fname,
 238.554 +            dbf->offset);
 238.555 +         longjmp(dbf->jump, 0);
 238.556 +      }
 238.557 +      /* find dummy RECNO field in the table statement */
 238.558 +      for (k = mpl_tab_num_flds(dca); k >= 1; k--)
 238.559 +         if (strcmp(mpl_tab_get_name(dca, k), "RECNO") == 0) break;
 238.560 +      dbf->ref[0] = k;
 238.561 +      return;
 238.562 +}
 238.563 +
 238.564 +static void parse_third_arg(TABDCA *dca, struct dbf *dbf)
 238.565 +{     /* parse xBASE file format (third argument) */
 238.566 +      int j, k, temp;
 238.567 +      const char *arg;
 238.568 +      dbf->nf = mpl_tab_num_flds(dca);
 238.569 +      arg = mpl_tab_get_arg(dca, 3), j = 0;
 238.570 +      for (k = 1; k <= dbf->nf; k++)
 238.571 +      {  /* parse specification of k-th field */
 238.572 +         if (arg[j] == '\0')
 238.573 +         {  xprintf("xBASE driver: field %s: specification missing\n",
 238.574 +               mpl_tab_get_name(dca, k));
 238.575 +            longjmp(dbf->jump, 0);
 238.576 +         }
 238.577 +         /* parse field type */
 238.578 +         if (arg[j] == 'C' || arg[j] == 'N')
 238.579 +            dbf->type[k] = arg[j], j++;
 238.580 +         else
 238.581 +         {  xprintf("xBASE driver: field %s: invalid field type\n",
 238.582 +               mpl_tab_get_name(dca, k));
 238.583 +            longjmp(dbf->jump, 0);
 238.584 +         }
 238.585 +         /* check for left parenthesis */
 238.586 +         if (arg[j] == '(')
 238.587 +            j++;
 238.588 +         else
 238.589 +err:     {  xprintf("xBASE driver: field %s: invalid field format\n",
 238.590 +               mpl_tab_get_name(dca, k));
 238.591 +            longjmp(dbf->jump, 0);
 238.592 +         }
 238.593 +         /* parse field length */
 238.594 +         temp = 0;
 238.595 +         while (isdigit(arg[j]))
 238.596 +         {  if (temp > DBF_FDLEN_MAX) break;
 238.597 +            temp = 10 * temp + (arg[j] - '0'), j++;
 238.598 +         }
 238.599 +         if (!(1 <= temp && temp <= DBF_FDLEN_MAX))
 238.600 +         {  xprintf("xBASE driver: field %s: invalid field length\n",
 238.601 +               mpl_tab_get_name(dca, k));
 238.602 +            longjmp(dbf->jump, 0);
 238.603 +         }
 238.604 +         dbf->len[k] = temp;
 238.605 +         /* parse optional field precision */
 238.606 +         if (dbf->type[k] == 'N' && arg[j] == ',')
 238.607 +         {  j++;
 238.608 +            temp = 0;
 238.609 +            while (isdigit(arg[j]))
 238.610 +            {  if (temp > dbf->len[k]) break;
 238.611 +               temp = 10 * temp + (arg[j] - '0'), j++;
 238.612 +            }
 238.613 +            if (temp > dbf->len[k])
 238.614 +            {  xprintf("xBASE driver: field %s: invalid field precision"
 238.615 +                  "\n", mpl_tab_get_name(dca, k));
 238.616 +               longjmp(dbf->jump, 0);
 238.617 +            }
 238.618 +            dbf->prec[k] = temp;
 238.619 +         }
 238.620 +         else
 238.621 +            dbf->prec[k] = 0;
 238.622 +         /* check for right parenthesis */
 238.623 +         if (arg[j] == ')')
 238.624 +            j++;
 238.625 +         else
 238.626 +            goto err;
 238.627 +      }
 238.628 +      /* ignore other specifications */
 238.629 +      return;
 238.630 +}
 238.631 +
 238.632 +static void write_byte(struct dbf *dbf, int b)
 238.633 +{     /* write byte to xBASE data file */
 238.634 +      fputc(b, dbf->fp);
 238.635 +      dbf->offset++;
 238.636 +      return;
 238.637 +}
 238.638 +
 238.639 +static void write_header(TABDCA *dca, struct dbf *dbf)
 238.640 +{     /* write xBASE data file header */
 238.641 +      int j, k, temp;
 238.642 +      const char *name;
 238.643 +      /* version number */
 238.644 +      write_byte(dbf, 0x03 /* file without DBT */);
 238.645 +      /* date of last update (YYMMDD) */
 238.646 +      write_byte(dbf, 70 /* 1970 */);
 238.647 +      write_byte(dbf, 1 /* January */);
 238.648 +      write_byte(dbf, 1 /* 1st */);
 238.649 +      /* number of records (unknown so far) */
 238.650 +      for (j = 1; j <= 4; j++)
 238.651 +         write_byte(dbf, 0xFF);
 238.652 +      /* length of the header, in bytes */
 238.653 +      temp = 32 + dbf->nf * 32 + 1;
 238.654 +      write_byte(dbf, temp);
 238.655 +      write_byte(dbf, temp >> 8);
 238.656 +      /* length of each record, in bytes */
 238.657 +      temp = 1;
 238.658 +      for (k = 1; k <= dbf->nf; k++)
 238.659 +         temp += dbf->len[k];
 238.660 +      write_byte(dbf, temp);
 238.661 +      write_byte(dbf, temp >> 8);
 238.662 +      /* (reserved) */
 238.663 +      for (j = 1; j <= 20; j++)
 238.664 +         write_byte(dbf, 0x00);
 238.665 +      /* field descriptor array */
 238.666 +      for (k = 1; k <= dbf->nf; k++)
 238.667 +      {  /* field name (terminated by 0x00) */
 238.668 +         name = mpl_tab_get_name(dca, k);
 238.669 +         for (j = 0; j < 10 && name[j] != '\0'; j++)
 238.670 +            write_byte(dbf, name[j]);
 238.671 +         for (j = j; j < 11; j++)
 238.672 +            write_byte(dbf, 0x00);
 238.673 +         /* field type */
 238.674 +         write_byte(dbf, dbf->type[k]);
 238.675 +         /* (reserved) */
 238.676 +         for (j = 1; j <= 4; j++)
 238.677 +            write_byte(dbf, 0x00);
 238.678 +         /* field length */
 238.679 +         write_byte(dbf, dbf->len[k]);
 238.680 +         /* field precision */
 238.681 +         write_byte(dbf, dbf->prec[k]);
 238.682 +         /* (reserved) */
 238.683 +         for (j = 1; j <= 14; j++)
 238.684 +            write_byte(dbf, 0x00);
 238.685 +      }
 238.686 +      /* end of header */
 238.687 +      write_byte(dbf, 0x0D);
 238.688 +      return;
 238.689 +}
 238.690 +
 238.691 +static struct dbf *dbf_open_file(TABDCA *dca, int mode)
 238.692 +{     /* open xBASE data file */
 238.693 +      struct dbf *dbf;
 238.694 +      /* create control structure */
 238.695 +      dbf = xmalloc(sizeof(struct dbf));
 238.696 +      dbf->mode = mode;
 238.697 +      dbf->fname = NULL;
 238.698 +      dbf->fp = NULL;
 238.699 +      if (setjmp(dbf->jump)) goto fail;
 238.700 +      dbf->offset = 0;
 238.701 +      dbf->count = 0;
 238.702 +      dbf->nf = 0;
 238.703 +      /* try to open the xBASE data file */
 238.704 +      if (mpl_tab_num_args(dca) < 2)
 238.705 +      {  xprintf("xBASE driver: file name not specified\n");
 238.706 +         longjmp(dbf->jump, 0);
 238.707 +      }
 238.708 +      dbf->fname = xmalloc(strlen(mpl_tab_get_arg(dca, 2))+1);
 238.709 +      strcpy(dbf->fname, mpl_tab_get_arg(dca, 2));
 238.710 +      if (mode == 'R')
 238.711 +      {  /* open the file for reading */
 238.712 +         dbf->fp = fopen(dbf->fname, "rb");
 238.713 +         if (dbf->fp == NULL)
 238.714 +         {  xprintf("xBASE driver: unable to open %s - %s\n",
 238.715 +               dbf->fname, strerror(errno));
 238.716 +            longjmp(dbf->jump, 0);
 238.717 +         }
 238.718 +         read_header(dca, dbf);
 238.719 +      }
 238.720 +      else if (mode == 'W')
 238.721 +      {  /* open the file for writing */
 238.722 +         if (mpl_tab_num_args(dca) < 3)
 238.723 +         {  xprintf("xBASE driver: file format not specified\n");
 238.724 +            longjmp(dbf->jump, 0);
 238.725 +         }
 238.726 +         parse_third_arg(dca, dbf);
 238.727 +         dbf->fp = fopen(dbf->fname, "wb");
 238.728 +         if (dbf->fp == NULL)
 238.729 +         {  xprintf("xBASE driver: unable to create %s - %s\n",
 238.730 +               dbf->fname, strerror(errno));
 238.731 +            longjmp(dbf->jump, 0);
 238.732 +         }
 238.733 +         write_header(dca, dbf);
 238.734 +      }
 238.735 +      else
 238.736 +         xassert(mode != mode);
 238.737 +      /* the file has been open */
 238.738 +      return dbf;
 238.739 +fail: /* the file cannot be open */
 238.740 +      if (dbf->fname != NULL) xfree(dbf->fname);
 238.741 +      if (dbf->fp != NULL) fclose(dbf->fp);
 238.742 +      xfree(dbf);
 238.743 +      return NULL;
 238.744 +}
 238.745 +
 238.746 +static int dbf_read_record(TABDCA *dca, struct dbf *dbf)
 238.747 +{     /* read next record from xBASE data file */
 238.748 +      int b, j, k, ret = 0;
 238.749 +      char buf[DBF_FDLEN_MAX+1];
 238.750 +      xassert(dbf->mode == 'R');
 238.751 +      if (setjmp(dbf->jump))
 238.752 +      {  ret = 1;
 238.753 +         goto done;
 238.754 +      }
 238.755 +      /* check record flag */
 238.756 +      b = read_byte(dbf);
 238.757 +      if (b == 0x1A)
 238.758 +      {  /* end of data */
 238.759 +         ret = -1;
 238.760 +         goto done;
 238.761 +      }
 238.762 +      if (b != 0x20)
 238.763 +      {  xprintf("%s:0x%X: invalid record flag\n", dbf->fname,
 238.764 +            dbf->offset);
 238.765 +         longjmp(dbf->jump, 0);
 238.766 +      }
 238.767 +      /* read dummy RECNO field */
 238.768 +      if (dbf->ref[0] > 0)
 238.769 +         mpl_tab_set_num(dca, dbf->ref[0], dbf->count+1);
 238.770 +      /* read fields */
 238.771 +      for (k = 1; k <= dbf->nf; k++)
 238.772 +      {  /* read k-th field */
 238.773 +         for (j = 0; j < dbf->len[k]; j++)
 238.774 +            buf[j] = (char)read_byte(dbf);
 238.775 +         buf[dbf->len[k]] = '\0';
 238.776 +         /* set field value */
 238.777 +         if (dbf->type[k] == 'C')
 238.778 +         {  /* character field */
 238.779 +            if (dbf->ref[k] > 0)
 238.780 +               mpl_tab_set_str(dca, dbf->ref[k], strtrim(buf));
 238.781 +         }
 238.782 +         else if (dbf->type[k] == 'N')
 238.783 +         {  /* numeric field */
 238.784 +            if (dbf->ref[k] > 0)
 238.785 +            {  double num;
 238.786 +               strspx(buf);
 238.787 +               xassert(str2num(buf, &num) == 0);
 238.788 +               mpl_tab_set_num(dca, dbf->ref[k], num);
 238.789 +            }
 238.790 +         }
 238.791 +         else
 238.792 +            xassert(dbf != dbf);
 238.793 +      }
 238.794 +      /* increase record count */
 238.795 +      dbf->count++;
 238.796 +done: return ret;
 238.797 +}
 238.798 +
 238.799 +static int dbf_write_record(TABDCA *dca, struct dbf *dbf)
 238.800 +{     /* write next record to xBASE data file */
 238.801 +      int j, k, ret = 0;
 238.802 +      char buf[255+1];
 238.803 +      xassert(dbf->mode == 'W');
 238.804 +      if (setjmp(dbf->jump))
 238.805 +      {  ret = 1;
 238.806 +         goto done;
 238.807 +      }
 238.808 +      /* record flag */
 238.809 +      write_byte(dbf, 0x20);
 238.810 +      xassert(dbf->nf == mpl_tab_num_flds(dca));
 238.811 +      for (k = 1; k <= dbf->nf; k++)
 238.812 +      {  if (dbf->type[k] == 'C')
 238.813 +         {  /* character field */
 238.814 +            const char *str;
 238.815 +            if (mpl_tab_get_type(dca, k) == 'N')
 238.816 +            {  sprintf(buf, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k));
 238.817 +               str = buf;
 238.818 +            }
 238.819 +            else if (mpl_tab_get_type(dca, k) == 'S')
 238.820 +               str = mpl_tab_get_str(dca, k);
 238.821 +            else
 238.822 +               xassert(dca != dca);
 238.823 +            if ((int)strlen(str) > dbf->len[k])
 238.824 +            {  xprintf("xBASE driver: field %s: cannot convert %.15s..."
 238.825 +                  " to field format\n", mpl_tab_get_name(dca, k), str);
 238.826 +               longjmp(dbf->jump, 0);
 238.827 +            }
 238.828 +            for (j = 0; j < dbf->len[k] && str[j] != '\0'; j++)
 238.829 +                write_byte(dbf, str[j]);
 238.830 +            for (j = j; j < dbf->len[k]; j++)
 238.831 +                write_byte(dbf, ' ');
 238.832 +         }
 238.833 +         else if (dbf->type[k] == 'N')
 238.834 +         {  /* numeric field */
 238.835 +            double num = mpl_tab_get_num(dca, k);
 238.836 +            if (fabs(num) > 1e20)
 238.837 +err:        {  xprintf("xBASE driver: field %s: cannot convert %g to fi"
 238.838 +                  "eld format\n", mpl_tab_get_name(dca, k), num);
 238.839 +               longjmp(dbf->jump, 0);
 238.840 +            }
 238.841 +            sprintf(buf, "%*.*f", dbf->len[k], dbf->prec[k], num);
 238.842 +            xassert(strlen(buf) < sizeof(buf));
 238.843 +            if ((int)strlen(buf) != dbf->len[k]) goto err;
 238.844 +            for (j = 0; j < dbf->len[k]; j++)
 238.845 +               write_byte(dbf, buf[j]);
 238.846 +         }
 238.847 +         else
 238.848 +            xassert(dbf != dbf);
 238.849 +      }
 238.850 +      /* increase record count */
 238.851 +      dbf->count++;
 238.852 +done: return ret;
 238.853 +}
 238.854 +
 238.855 +static int dbf_close_file(TABDCA *dca, struct dbf *dbf)
 238.856 +{     /* close xBASE data file */
 238.857 +      int ret = 0;
 238.858 +      xassert(dca == dca);
 238.859 +      if (dbf->mode == 'W')
 238.860 +      {  if (setjmp(dbf->jump))
 238.861 +         {  ret = 1;
 238.862 +            goto skip;
 238.863 +         }
 238.864 +         /* end-of-file flag */
 238.865 +         write_byte(dbf, 0x1A);
 238.866 +         /* number of records */
 238.867 +         dbf->offset = 4;
 238.868 +         if (fseek(dbf->fp, dbf->offset, SEEK_SET))
 238.869 +         {  xprintf("%s:0x%X: seek error - %s\n", dbf->fname,
 238.870 +               dbf->offset, strerror(errno));
 238.871 +            longjmp(dbf->jump, 0);
 238.872 +         }
 238.873 +         write_byte(dbf, dbf->count);
 238.874 +         write_byte(dbf, dbf->count >> 8);
 238.875 +         write_byte(dbf, dbf->count >> 16);
 238.876 +         write_byte(dbf, dbf->count >> 24);
 238.877 +         fflush(dbf->fp);
 238.878 +         if (ferror(dbf->fp))
 238.879 +         {  xprintf("%s:0x%X: write error - %s\n", dbf->fname,
 238.880 +               dbf->offset, strerror(errno));
 238.881 +            longjmp(dbf->jump, 0);
 238.882 +         }
 238.883 +skip:    ;
 238.884 +      }
 238.885 +      xfree(dbf->fname);
 238.886 +      fclose(dbf->fp);
 238.887 +      xfree(dbf);
 238.888 +      return ret;
 238.889 +}
 238.890 +
 238.891 +/**********************************************************************/
 238.892 +
 238.893 +#define TAB_CSV   1
 238.894 +#define TAB_XBASE 2
 238.895 +#define TAB_ODBC  3
 238.896 +#define TAB_MYSQL 4
 238.897 +
 238.898 +void mpl_tab_drv_open(MPL *mpl, int mode)
 238.899 +{     TABDCA *dca = mpl->dca;
 238.900 +      xassert(dca->id == 0);
 238.901 +      xassert(dca->link == NULL);
 238.902 +      xassert(dca->na >= 1);
 238.903 +      if (strcmp(dca->arg[1], "CSV") == 0)
 238.904 +      {  dca->id = TAB_CSV;
 238.905 +         dca->link = csv_open_file(dca, mode);
 238.906 +      }
 238.907 +      else if (strcmp(dca->arg[1], "xBASE") == 0)
 238.908 +      {  dca->id = TAB_XBASE;
 238.909 +         dca->link = dbf_open_file(dca, mode);
 238.910 +      }
 238.911 +      else if (strcmp(dca->arg[1], "ODBC") == 0 ||
 238.912 +               strcmp(dca->arg[1], "iODBC") == 0)
 238.913 +      {  dca->id = TAB_ODBC;
 238.914 +         dca->link = db_iodbc_open(dca, mode);
 238.915 +      }
 238.916 +      else if (strcmp(dca->arg[1], "MySQL") == 0)
 238.917 +      {  dca->id = TAB_MYSQL;
 238.918 +         dca->link = db_mysql_open(dca, mode);
 238.919 +      }
 238.920 +      else
 238.921 +         xprintf("Invalid table driver `%s'\n", dca->arg[1]);
 238.922 +      if (dca->link == NULL)
 238.923 +         error(mpl, "error on opening table %s",
 238.924 +            mpl->stmt->u.tab->name);
 238.925 +      return;
 238.926 +}
 238.927 +
 238.928 +int mpl_tab_drv_read(MPL *mpl)
 238.929 +{     TABDCA *dca = mpl->dca;
 238.930 +      int ret;
 238.931 +      switch (dca->id)
 238.932 +      {  case TAB_CSV:
 238.933 +            ret = csv_read_record(dca, dca->link);
 238.934 +            break;
 238.935 +         case TAB_XBASE:
 238.936 +            ret = dbf_read_record(dca, dca->link);
 238.937 +            break;
 238.938 +         case TAB_ODBC:
 238.939 +            ret = db_iodbc_read(dca, dca->link);
 238.940 +            break;
 238.941 +         case TAB_MYSQL:
 238.942 +            ret = db_mysql_read(dca, dca->link);
 238.943 +            break;
 238.944 +         default:
 238.945 +            xassert(dca != dca);
 238.946 +      }
 238.947 +      if (ret > 0)
 238.948 +         error(mpl, "error on reading data from table %s",
 238.949 +            mpl->stmt->u.tab->name);
 238.950 +      return ret;
 238.951 +}
 238.952 +
 238.953 +void mpl_tab_drv_write(MPL *mpl)
 238.954 +{     TABDCA *dca = mpl->dca;
 238.955 +      int ret;
 238.956 +      switch (dca->id)
 238.957 +      {  case TAB_CSV:
 238.958 +            ret = csv_write_record(dca, dca->link);
 238.959 +            break;
 238.960 +         case TAB_XBASE:
 238.961 +            ret = dbf_write_record(dca, dca->link);
 238.962 +            break;
 238.963 +         case TAB_ODBC:
 238.964 +            ret = db_iodbc_write(dca, dca->link);
 238.965 +            break;
 238.966 +         case TAB_MYSQL:
 238.967 +            ret = db_mysql_write(dca, dca->link);
 238.968 +            break;
 238.969 +         default:
 238.970 +            xassert(dca != dca);
 238.971 +      }
 238.972 +      if (ret)
 238.973 +         error(mpl, "error on writing data to table %s",
 238.974 +            mpl->stmt->u.tab->name);
 238.975 +      return;
 238.976 +}
 238.977 +
 238.978 +void mpl_tab_drv_close(MPL *mpl)
 238.979 +{     TABDCA *dca = mpl->dca;
 238.980 +      int ret;
 238.981 +      switch (dca->id)
 238.982 +      {  case TAB_CSV:
 238.983 +            ret = csv_close_file(dca, dca->link);
 238.984 +            break;
 238.985 +         case TAB_XBASE:
 238.986 +            ret = dbf_close_file(dca, dca->link);
 238.987 +            break;
 238.988 +         case TAB_ODBC:
 238.989 +            ret = db_iodbc_close(dca, dca->link);
 238.990 +            break;
 238.991 +         case TAB_MYSQL:
 238.992 +            ret = db_mysql_close(dca, dca->link);
 238.993 +            break;
 238.994 +         default:
 238.995 +            xassert(dca != dca);
 238.996 +      }
 238.997 +      dca->id = 0;
 238.998 +      dca->link = NULL;
 238.999 +      if (ret)
238.1000 +         error(mpl, "error on closing table %s",
238.1001 +            mpl->stmt->u.tab->name);
238.1002 +      return;
238.1003 +}
238.1004 +
238.1005 +/* eof */
   239.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   239.2 +++ b/src/glpmps.c	Mon Dec 06 13:09:21 2010 +0100
   239.3 @@ -0,0 +1,1401 @@
   239.4 +/* glpmps.c (MPS format routines) */
   239.5 +
   239.6 +/***********************************************************************
   239.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   239.8 +*
   239.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  239.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  239.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  239.12 +*  E-mail: <mao@gnu.org>.
  239.13 +*
  239.14 +*  GLPK is free software: you can redistribute it and/or modify it
  239.15 +*  under the terms of the GNU General Public License as published by
  239.16 +*  the Free Software Foundation, either version 3 of the License, or
  239.17 +*  (at your option) any later version.
  239.18 +*
  239.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  239.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  239.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  239.22 +*  License for more details.
  239.23 +*
  239.24 +*  You should have received a copy of the GNU General Public License
  239.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  239.26 +***********************************************************************/
  239.27 +
  239.28 +#include "glpapi.h"
  239.29 +
  239.30 +/***********************************************************************
  239.31 +*  NAME
  239.32 +*
  239.33 +*  glp_init_mpscp - initialize MPS format control parameters
  239.34 +*
  239.35 +*  SYNOPSIS
  239.36 +*
  239.37 +*  void glp_init_mpscp(glp_mpscp *parm);
  239.38 +*
  239.39 +*  DESCRIPTION
  239.40 +*
  239.41 +*  The routine glp_init_mpscp initializes control parameters, which are
  239.42 +*  used by the MPS input/output routines glp_read_mps and glp_write_mps,
  239.43 +*  with default values.
  239.44 +*
  239.45 +*  Default values of the control parameters are stored in the glp_mpscp
  239.46 +*  structure, which the parameter parm points to. */
  239.47 +
  239.48 +void glp_init_mpscp(glp_mpscp *parm)
  239.49 +{     parm->blank = '\0';
  239.50 +      parm->obj_name = NULL;
  239.51 +      parm->tol_mps = 1e-12;
  239.52 +      return;
  239.53 +}
  239.54 +
  239.55 +static void check_parm(const char *func, const glp_mpscp *parm)
  239.56 +{     /* check control parameters */
  239.57 +      if (!(0x00 <= parm->blank && parm->blank <= 0xFF) ||
  239.58 +          !(parm->blank == '\0' || isprint(parm->blank)))
  239.59 +         xerror("%s: blank = 0x%02X; invalid parameter\n",
  239.60 +            func, parm->blank);
  239.61 +      if (!(parm->obj_name == NULL || strlen(parm->obj_name) <= 255))
  239.62 +         xerror("%s: obj_name = \"%.12s...\"; parameter too long\n",
  239.63 +            func, parm->obj_name);
  239.64 +      if (!(0.0 <= parm->tol_mps && parm->tol_mps < 1.0))
  239.65 +         xerror("%s: tol_mps = %g; invalid parameter\n",
  239.66 +            func, parm->tol_mps);
  239.67 +      return;
  239.68 +}
  239.69 +
  239.70 +/***********************************************************************
  239.71 +*  NAME
  239.72 +*
  239.73 +*  glp_read_mps - read problem data in MPS format
  239.74 +*
  239.75 +*  SYNOPSIS
  239.76 +*
  239.77 +*  int glp_read_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
  239.78 +*     const char *fname);
  239.79 +*
  239.80 +*  DESCRIPTION
  239.81 +*
  239.82 +*  The routine glp_read_mps reads problem data in MPS format from a
  239.83 +*  text file.
  239.84 +*
  239.85 +*  The parameter fmt specifies the version of MPS format:
  239.86 +*
  239.87 +*  GLP_MPS_DECK - fixed (ancient) MPS format;
  239.88 +*  GLP_MPS_FILE - free (modern) MPS format.
  239.89 +*
  239.90 +*  The parameter parm is a pointer to the structure glp_mpscp, which
  239.91 +*  specifies control parameters used by the routine. If parm is NULL,
  239.92 +*  the routine uses default settings.
  239.93 +*
  239.94 +*  The character string fname specifies a name of the text file to be
  239.95 +*  read.
  239.96 +*
  239.97 +*  Note that before reading data the current content of the problem
  239.98 +*  object is completely erased with the routine glp_erase_prob.
  239.99 +*
 239.100 +*  RETURNS
 239.101 +*
 239.102 +*  If the operation was successful, the routine glp_read_mps returns
 239.103 +*  zero. Otherwise, it prints an error message and returns non-zero. */
 239.104 +
 239.105 +struct csa
 239.106 +{     /* common storage area */
 239.107 +      glp_prob *P;
 239.108 +      /* pointer to problem object */
 239.109 +      int deck;
 239.110 +      /* MPS format (0 - free, 1 - fixed) */
 239.111 +      const glp_mpscp *parm;
 239.112 +      /* pointer to control parameters */
 239.113 +      const char *fname;
 239.114 +      /* name of input MPS file */
 239.115 +      XFILE *fp;
 239.116 +      /* stream assigned to input MPS file */
 239.117 +      jmp_buf jump;
 239.118 +      /* label for go to in case of error */
 239.119 +      int recno;
 239.120 +      /* current record (card) number */
 239.121 +      int recpos;
 239.122 +      /* current record (card) position */
 239.123 +      int c;
 239.124 +      /* current character */
 239.125 +      int fldno;
 239.126 +      /* current field number */
 239.127 +      char field[255+1];
 239.128 +      /* current field content */
 239.129 +      int w80;
 239.130 +      /* warning 'record must not be longer than 80 chars' issued */
 239.131 +      int wef;
 239.132 +      /* warning 'extra fields detected beyond field 6' issued */
 239.133 +      int obj_row;
 239.134 +      /* objective row number */
 239.135 +      void *work1, *work2, *work3;
 239.136 +      /* working arrays */
 239.137 +};
 239.138 +
 239.139 +static void error(struct csa *csa, const char *fmt, ...)
 239.140 +{     /* print error message and terminate processing */
 239.141 +      va_list arg;
 239.142 +      xprintf("%s:%d: ", csa->fname, csa->recno);
 239.143 +      va_start(arg, fmt);
 239.144 +      xvprintf(fmt, arg);
 239.145 +      va_end(arg);
 239.146 +      longjmp(csa->jump, 1);
 239.147 +      /* no return */
 239.148 +}
 239.149 +
 239.150 +static void warning(struct csa *csa, const char *fmt, ...)
 239.151 +{     /* print warning message and continue processing */
 239.152 +      va_list arg;
 239.153 +      xprintf("%s:%d: warning: ", csa->fname, csa->recno);
 239.154 +      va_start(arg, fmt);
 239.155 +      xvprintf(fmt, arg);
 239.156 +      va_end(arg);
 239.157 +      return;
 239.158 +}
 239.159 +
 239.160 +static void read_char(struct csa *csa)
 239.161 +{     /* read next character */
 239.162 +      int c;
 239.163 +      if (csa->c == '\n')
 239.164 +         csa->recno++, csa->recpos = 0;
 239.165 +      csa->recpos++;
 239.166 +read: c = xfgetc(csa->fp);
 239.167 +      if (c < 0)
 239.168 +      {  if (xferror(csa->fp))
 239.169 +            error(csa, "read error - %s\n", xerrmsg());
 239.170 +         else if (csa->c == '\n')
 239.171 +            error(csa, "unexpected end of file\n");
 239.172 +         else
 239.173 +         {  warning(csa, "missing final end of line\n");
 239.174 +            c = '\n';
 239.175 +         }
 239.176 +      }
 239.177 +      else if (c == '\n')
 239.178 +         ;
 239.179 +      else if (csa->c == '\r')
 239.180 +      {  c = '\r';
 239.181 +         goto badc;
 239.182 +      }
 239.183 +      else if (csa->deck && c == '\r')
 239.184 +      {  csa->c = '\r';
 239.185 +         goto read;
 239.186 +      }
 239.187 +      else if (c == ' ')
 239.188 +         ;
 239.189 +      else if (isspace(c))
 239.190 +      {  if (csa->deck)
 239.191 +badc:       error(csa, "in fixed MPS format white-space character 0x%02"
 239.192 +               "X is not allowed\n", c);
 239.193 +         c = ' ';
 239.194 +      }
 239.195 +      else if (iscntrl(c))
 239.196 +         error(csa, "invalid control character 0x%02X\n", c);
 239.197 +      if (csa->deck && csa->recpos == 81 && c != '\n' && csa->w80 < 1)
 239.198 +      {  warning(csa, "in fixed MPS format record must not be longer th"
 239.199 +            "an 80 characters\n");
 239.200 +         csa->w80++;
 239.201 +      }
 239.202 +      csa->c = c;
 239.203 +      return;
 239.204 +}
 239.205 +
 239.206 +static int indicator(struct csa *csa, int name)
 239.207 +{     /* skip comment records and read possible indicator record */
 239.208 +      int ret;
 239.209 +      /* reset current field number */
 239.210 +      csa->fldno = 0;
 239.211 +loop: /* read the very first character of the next record */
 239.212 +      xassert(csa->c == '\n');
 239.213 +      read_char(csa);
 239.214 +      if (csa->c == ' ' || csa->c == '\n')
 239.215 +      {  /* data record */
 239.216 +         ret = 0;
 239.217 +      }
 239.218 +      else if (csa->c == '*')
 239.219 +      {  /* comment record */
 239.220 +         while (csa->c != '\n')
 239.221 +            read_char(csa);
 239.222 +         goto loop;
 239.223 +      }
 239.224 +      else
 239.225 +      {  /* indicator record */
 239.226 +         int len = 0;
 239.227 +         while (csa->c != ' ' && csa->c != '\n' && len < 12)
 239.228 +         {  csa->field[len++] = (char)csa->c;
 239.229 +            read_char(csa);
 239.230 +         }
 239.231 +         csa->field[len] = '\0';
 239.232 +         if (!(strcmp(csa->field, "NAME")    == 0 ||
 239.233 +               strcmp(csa->field, "ROWS")    == 0 ||
 239.234 +               strcmp(csa->field, "COLUMNS") == 0 ||
 239.235 +               strcmp(csa->field, "RHS")     == 0 ||
 239.236 +               strcmp(csa->field, "RANGES")  == 0 ||
 239.237 +               strcmp(csa->field, "BOUNDS")  == 0 ||
 239.238 +               strcmp(csa->field, "ENDATA")  == 0))
 239.239 +            error(csa, "invalid indicator record\n");
 239.240 +         if (!name)
 239.241 +         {  while (csa->c != '\n')
 239.242 +               read_char(csa);
 239.243 +         }
 239.244 +         ret = 1;
 239.245 +      }
 239.246 +      return ret;
 239.247 +}
 239.248 +
 239.249 +static void read_field(struct csa *csa)
 239.250 +{     /* read next field of the current data record */
 239.251 +      csa->fldno++;
 239.252 +      if (csa->deck)
 239.253 +      {  /* fixed MPS format */
 239.254 +         int beg, end, pos;
 239.255 +         /* determine predefined field positions */
 239.256 +         if (csa->fldno == 1)
 239.257 +            beg = 2, end = 3;
 239.258 +         else if (csa->fldno == 2)
 239.259 +            beg = 5, end = 12;
 239.260 +         else if (csa->fldno == 3)
 239.261 +            beg = 15, end = 22;
 239.262 +         else if (csa->fldno == 4)
 239.263 +            beg = 25, end = 36;
 239.264 +         else if (csa->fldno == 5)
 239.265 +            beg = 40, end = 47;
 239.266 +         else if (csa->fldno == 6)
 239.267 +            beg = 50, end = 61;
 239.268 +         else
 239.269 +            xassert(csa != csa);
 239.270 +         /* skip blanks preceding the current field */
 239.271 +         if (csa->c != '\n')
 239.272 +         {  pos = csa->recpos;
 239.273 +            while (csa->recpos < beg)
 239.274 +            {  if (csa->c == ' ')
 239.275 +                  ;
 239.276 +               else if (csa->c == '\n')
 239.277 +                  break;
 239.278 +               else
 239.279 +                  error(csa, "in fixed MPS format positions %d-%d must "
 239.280 +                     "be blank\n", pos, beg-1);
 239.281 +               read_char(csa);
 239.282 +            }
 239.283 +         }
 239.284 +         /* skip possible comment beginning in the field 3 or 5 */
 239.285 +         if ((csa->fldno == 3 || csa->fldno == 5) && csa->c == '$')
 239.286 +         {  while (csa->c != '\n')
 239.287 +               read_char(csa);
 239.288 +         }
 239.289 +         /* read the current field */
 239.290 +         for (pos = beg; pos <= end; pos++)
 239.291 +         {  if (csa->c == '\n') break;
 239.292 +            csa->field[pos-beg] = (char)csa->c;
 239.293 +            read_char(csa);
 239.294 +         }
 239.295 +         csa->field[pos-beg] = '\0';
 239.296 +         strtrim(csa->field);
 239.297 +         /* skip blanks following the last field */
 239.298 +         if (csa->fldno == 6 && csa->c != '\n')
 239.299 +         {  while (csa->recpos <= 72)
 239.300 +            {  if (csa->c == ' ')
 239.301 +                  ;
 239.302 +               else if (csa->c == '\n')
 239.303 +                  break;
 239.304 +               else
 239.305 +                  error(csa, "in fixed MPS format positions 62-72 must "
 239.306 +                     "be blank\n");
 239.307 +               read_char(csa);
 239.308 +            }
 239.309 +            while (csa->c != '\n')
 239.310 +               read_char(csa);
 239.311 +         }
 239.312 +      }
 239.313 +      else
 239.314 +      {  /* free MPS format */
 239.315 +         int len;
 239.316 +         /* skip blanks preceding the current field */
 239.317 +         while (csa->c == ' ')
 239.318 +            read_char(csa);
 239.319 +         /* skip possible comment */
 239.320 +         if (csa->c == '$')
 239.321 +         {  while (csa->c != '\n')
 239.322 +               read_char(csa);
 239.323 +         }
 239.324 +         /* read the current field */
 239.325 +         len = 0;
 239.326 +         while (!(csa->c == ' ' || csa->c == '\n'))
 239.327 +         {  if (len == 255)
 239.328 +               error(csa, "length of field %d exceeds 255 characters\n",
 239.329 +                  csa->fldno++);
 239.330 +            csa->field[len++] = (char)csa->c;
 239.331 +            read_char(csa);
 239.332 +         }
 239.333 +         csa->field[len] = '\0';
 239.334 +         /* skip anything following the last field (any extra fields
 239.335 +            are considered to be comments) */
 239.336 +         if (csa->fldno == 6)
 239.337 +         {  while (csa->c == ' ')
 239.338 +               read_char(csa);
 239.339 +            if (csa->c != '$' && csa->c != '\n' && csa->wef < 1)
 239.340 +            {  warning(csa, "some extra field(s) detected beyond field "
 239.341 +                  "6; field(s) ignored\n");
 239.342 +               csa->wef++;
 239.343 +            }
 239.344 +            while (csa->c != '\n')
 239.345 +               read_char(csa);
 239.346 +         }
 239.347 +      }
 239.348 +      return;
 239.349 +}
 239.350 +
 239.351 +static void patch_name(struct csa *csa, char *name)
 239.352 +{     /* process embedded blanks in symbolic name */
 239.353 +      int blank = csa->parm->blank;
 239.354 +      if (blank == '\0')
 239.355 +      {  /* remove emedded blanks */
 239.356 +         strspx(name);
 239.357 +      }
 239.358 +      else
 239.359 +      {  /* replace embedded blanks by specified character */
 239.360 +         for (; *name != '\0'; name++)
 239.361 +            if (*name == ' ') *name = (char)blank;
 239.362 +      }
 239.363 +      return;
 239.364 +}
 239.365 +
 239.366 +static double read_number(struct csa *csa)
 239.367 +{     /* read next field and convert it to floating-point number */
 239.368 +      double x;
 239.369 +      char *s;
 239.370 +      /* read next field */
 239.371 +      read_field(csa);
 239.372 +      xassert(csa->fldno == 4 || csa->fldno == 6);
 239.373 +      if (csa->field[0] == '\0')
 239.374 +         error(csa, "missing numeric value in field %d\n", csa->fldno);
 239.375 +      /* skip initial spaces of the field */
 239.376 +      for (s = csa->field; *s == ' '; s++);
 239.377 +      /* perform conversion */
 239.378 +      if (str2num(s, &x) != 0)
 239.379 +         error(csa, "cannot convert `%s' to floating-point number\n",
 239.380 +            s);
 239.381 +      return x;
 239.382 +}
 239.383 +
 239.384 +static void skip_field(struct csa *csa)
 239.385 +{     /* read and skip next field (assumed to be blank) */
 239.386 +      read_field(csa);
 239.387 +      if (csa->field[0] != '\0')
 239.388 +         error(csa, "field %d must be blank\n", csa->fldno);
 239.389 +      return;
 239.390 +}
 239.391 +
 239.392 +static void read_name(struct csa *csa)
 239.393 +{     /* read NAME indicator record */
 239.394 +      if (!(indicator(csa, 1) && strcmp(csa->field, "NAME") == 0))
 239.395 +         error(csa, "missing NAME indicator record\n");
 239.396 +      /* this indicator record looks like a data record; simulate that
 239.397 +         fields 1 and 2 were read */
 239.398 +      csa->fldno = 2;
 239.399 +      /* field 3: model name */
 239.400 +      read_field(csa), patch_name(csa, csa->field);
 239.401 +      if (csa->field[0] == '\0')
 239.402 +         warning(csa, "missing model name in field 3\n");
 239.403 +      else
 239.404 +         glp_set_prob_name(csa->P, csa->field);
 239.405 +      /* skip anything following field 3 */
 239.406 +      while (csa->c != '\n')
 239.407 +         read_char(csa);
 239.408 +      return;
 239.409 +}
 239.410 +
 239.411 +static void read_rows(struct csa *csa)
 239.412 +{     /* read ROWS section */
 239.413 +      int i, type;
 239.414 +loop: if (indicator(csa, 0)) goto done;
 239.415 +      /* field 1: row type */
 239.416 +      read_field(csa), strspx(csa->field);
 239.417 +      if (strcmp(csa->field, "N") == 0)
 239.418 +         type = GLP_FR;
 239.419 +      else if (strcmp(csa->field, "G") == 0)
 239.420 +         type = GLP_LO;
 239.421 +      else if (strcmp(csa->field, "L") == 0)
 239.422 +         type = GLP_UP;
 239.423 +      else if (strcmp(csa->field, "E") == 0)
 239.424 +         type = GLP_FX;
 239.425 +      else if (csa->field[0] == '\0')
 239.426 +         error(csa, "missing row type in field 1\n");
 239.427 +      else
 239.428 +         error(csa, "invalid row type in field 1\n");
 239.429 +      /* field 2: row name */
 239.430 +      read_field(csa), patch_name(csa, csa->field);
 239.431 +      if (csa->field[0] == '\0')
 239.432 +         error(csa, "missing row name in field 2\n");
 239.433 +      if (glp_find_row(csa->P, csa->field) != 0)
 239.434 +         error(csa, "row `%s' multiply specified\n", csa->field);
 239.435 +      i = glp_add_rows(csa->P, 1);
 239.436 +      glp_set_row_name(csa->P, i, csa->field);
 239.437 +      glp_set_row_bnds(csa->P, i, type, 0.0, 0.0);
 239.438 +      /* fields 3, 4, 5, and 6 must be blank */
 239.439 +      skip_field(csa);
 239.440 +      skip_field(csa);
 239.441 +      skip_field(csa);
 239.442 +      skip_field(csa);
 239.443 +      goto loop;
 239.444 +done: return;
 239.445 +}
 239.446 +
 239.447 +static void read_columns(struct csa *csa)
 239.448 +{     /* read COLUMNS section */
 239.449 +      int i, j, f, len, kind = GLP_CV, *ind;
 239.450 +      double aij, *val;
 239.451 +      char name[255+1], *flag;
 239.452 +      /* allocate working arrays */
 239.453 +      csa->work1 = ind = xcalloc(1+csa->P->m, sizeof(int));
 239.454 +      csa->work2 = val = xcalloc(1+csa->P->m, sizeof(double));
 239.455 +      csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char));
 239.456 +      memset(&flag[1], 0, csa->P->m);
 239.457 +      /* no current column exists */
 239.458 +      j = 0, len = 0;
 239.459 +loop: if (indicator(csa, 0)) goto done;
 239.460 +      /* field 1 must be blank */
 239.461 +      if (csa->deck)
 239.462 +      {  read_field(csa);
 239.463 +         if (csa->field[0] != '\0')
 239.464 +            error(csa, "field 1 must be blank\n");
 239.465 +      }
 239.466 +      else
 239.467 +         csa->fldno++;
 239.468 +      /* field 2: column or kind name */
 239.469 +      read_field(csa), patch_name(csa, csa->field);
 239.470 +      strcpy(name, csa->field);
 239.471 +      /* field 3: row name or keyword 'MARKER' */
 239.472 +      read_field(csa), patch_name(csa, csa->field);
 239.473 +      if (strcmp(csa->field, "'MARKER'") == 0)
 239.474 +      {  /* process kind data record */
 239.475 +         /* field 4 must be blank */
 239.476 +         if (csa->deck)
 239.477 +         {  read_field(csa);
 239.478 +            if (csa->field[0] != '\0')
 239.479 +               error(csa, "field 4 must be blank\n");
 239.480 +         }
 239.481 +         else
 239.482 +            csa->fldno++;
 239.483 +         /* field 5: keyword 'INTORG' or 'INTEND' */
 239.484 +         read_field(csa), patch_name(csa, csa->field);
 239.485 +         if (strcmp(csa->field, "'INTORG'") == 0)
 239.486 +            kind = GLP_IV;
 239.487 +         else if (strcmp(csa->field, "'INTEND'") == 0)
 239.488 +            kind = GLP_CV;
 239.489 +         else if (csa->field[0] == '\0')
 239.490 +            error(csa, "missing keyword in field 5\n");
 239.491 +         else
 239.492 +            error(csa, "invalid keyword in field 5\n");
 239.493 +         /* field 6 must be blank */
 239.494 +         skip_field(csa);
 239.495 +         goto loop;
 239.496 +      }
 239.497 +      /* process column name specified in field 2 */
 239.498 +      if (name[0] == '\0')
 239.499 +      {  /* the same column as in previous data record */
 239.500 +         if (j == 0)
 239.501 +            error(csa, "missing column name in field 2\n");
 239.502 +      }
 239.503 +      else if (j != 0 && strcmp(name, csa->P->col[j]->name) == 0)
 239.504 +      {  /* the same column as in previous data record */
 239.505 +         xassert(j != 0);
 239.506 +      }
 239.507 +      else
 239.508 +      {  /* store the current column */
 239.509 +         if (j != 0)
 239.510 +         {  glp_set_mat_col(csa->P, j, len, ind, val);
 239.511 +            while (len > 0) flag[ind[len--]] = 0;
 239.512 +         }
 239.513 +         /* create new column */
 239.514 +         if (glp_find_col(csa->P, name) != 0)
 239.515 +            error(csa, "column `%s' multiply specified\n", name);
 239.516 +         j = glp_add_cols(csa->P, 1);
 239.517 +         glp_set_col_name(csa->P, j, name);
 239.518 +         glp_set_col_kind(csa->P, j, kind);
 239.519 +         if (kind == GLP_CV)
 239.520 +            glp_set_col_bnds(csa->P, j, GLP_LO, 0.0, 0.0);
 239.521 +         else if (kind == GLP_IV)
 239.522 +            glp_set_col_bnds(csa->P, j, GLP_DB, 0.0, 1.0);
 239.523 +         else
 239.524 +            xassert(kind != kind);
 239.525 +      }
 239.526 +      /* process fields 3-4 and 5-6 */
 239.527 +      for (f = 3; f <= 5; f += 2)
 239.528 +      {  /* field 3 or 5: row name */
 239.529 +         if (f == 3)
 239.530 +         {  if (csa->field[0] == '\0')
 239.531 +               error(csa, "missing row name in field 3\n");
 239.532 +         }
 239.533 +         else
 239.534 +         {  read_field(csa), patch_name(csa, csa->field);
 239.535 +            if (csa->field[0] == '\0')
 239.536 +            {  /* if field 5 is blank, field 6 also must be blank */
 239.537 +               skip_field(csa);
 239.538 +               continue;
 239.539 +            }
 239.540 +         }
 239.541 +         i = glp_find_row(csa->P, csa->field);
 239.542 +         if (i == 0)
 239.543 +            error(csa, "row `%s' not found\n", csa->field);
 239.544 +         if (flag[i])
 239.545 +            error(csa, "duplicate coefficient in row `%s'\n",
 239.546 +               csa->field);
 239.547 +         /* field 4 or 6: coefficient value */
 239.548 +         aij = read_number(csa);
 239.549 +         if (fabs(aij) < csa->parm->tol_mps) aij = 0.0;
 239.550 +         len++, ind[len] = i, val[len] = aij, flag[i] = 1;
 239.551 +      }
 239.552 +      goto loop;
 239.553 +done: /* store the last column */
 239.554 +      if (j != 0)
 239.555 +         glp_set_mat_col(csa->P, j, len, ind, val);
 239.556 +      /* free working arrays */
 239.557 +      xfree(ind);
 239.558 +      xfree(val);
 239.559 +      xfree(flag);
 239.560 +      csa->work1 = csa->work2 = csa->work3 = NULL;
 239.561 +      return;
 239.562 +}
 239.563 +
 239.564 +static void read_rhs(struct csa *csa)
 239.565 +{     /* read RHS section */
 239.566 +      int i, f, v, type;
 239.567 +      double rhs;
 239.568 +      char name[255+1], *flag;
 239.569 +      /* allocate working array */
 239.570 +      csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char));
 239.571 +      memset(&flag[1], 0, csa->P->m);
 239.572 +      /* no current RHS vector exists */
 239.573 +      v = 0;
 239.574 +loop: if (indicator(csa, 0)) goto done;
 239.575 +      /* field 1 must be blank */
 239.576 +      if (csa->deck)
 239.577 +      {  read_field(csa);
 239.578 +         if (csa->field[0] != '\0')
 239.579 +            error(csa, "field 1 must be blank\n");
 239.580 +      }
 239.581 +      else
 239.582 +         csa->fldno++;
 239.583 +      /* field 2: RHS vector name */
 239.584 +      read_field(csa), patch_name(csa, csa->field);
 239.585 +      if (csa->field[0] == '\0')
 239.586 +      {  /* the same RHS vector as in previous data record */
 239.587 +         if (v == 0)
 239.588 +         {  warning(csa, "missing RHS vector name in field 2\n");
 239.589 +            goto blnk;
 239.590 +         }
 239.591 +      }
 239.592 +      else if (v != 0 && strcmp(csa->field, name) == 0)
 239.593 +      {  /* the same RHS vector as in previous data record */
 239.594 +         xassert(v != 0);
 239.595 +      }
 239.596 +      else
 239.597 +blnk: {  /* new RHS vector */
 239.598 +         if (v != 0)
 239.599 +            error(csa, "multiple RHS vectors not supported\n");
 239.600 +         v++;
 239.601 +         strcpy(name, csa->field);
 239.602 +      }
 239.603 +      /* process fields 3-4 and 5-6 */
 239.604 +      for (f = 3; f <= 5; f += 2)
 239.605 +      {  /* field 3 or 5: row name */
 239.606 +         read_field(csa), patch_name(csa, csa->field);
 239.607 +         if (csa->field[0] == '\0')
 239.608 +         {  if (f == 3)
 239.609 +               error(csa, "missing row name in field 3\n");
 239.610 +            else
 239.611 +            {  /* if field 5 is blank, field 6 also must be blank */
 239.612 +               skip_field(csa);
 239.613 +               continue;
 239.614 +            }
 239.615 +         }
 239.616 +         i = glp_find_row(csa->P, csa->field);
 239.617 +         if (i == 0)
 239.618 +            error(csa, "row `%s' not found\n", csa->field);
 239.619 +         if (flag[i])
 239.620 +            error(csa, "duplicate right-hand side for row `%s'\n",
 239.621 +               csa->field);
 239.622 +         /* field 4 or 6: right-hand side value */
 239.623 +         rhs = read_number(csa);
 239.624 +         if (fabs(rhs) < csa->parm->tol_mps) rhs = 0.0;
 239.625 +         type = csa->P->row[i]->type;
 239.626 +         if (type == GLP_FR)
 239.627 +         {  if (i == csa->obj_row)
 239.628 +               glp_set_obj_coef(csa->P, 0, rhs);
 239.629 +            else if (rhs != 0.0)
 239.630 +               warning(csa, "non-zero right-hand side for free row `%s'"
 239.631 +                  " ignored\n", csa->P->row[i]->name);
 239.632 +         }
 239.633 +         else
 239.634 +            glp_set_row_bnds(csa->P, i, type, rhs, rhs);
 239.635 +         flag[i] = 1;
 239.636 +      }
 239.637 +      goto loop;
 239.638 +done: /* free working array */
 239.639 +      xfree(flag);
 239.640 +      csa->work3 = NULL;
 239.641 +      return;
 239.642 +}
 239.643 +
 239.644 +static void read_ranges(struct csa *csa)
 239.645 +{     /* read RANGES section */
 239.646 +      int i, f, v, type;
 239.647 +      double rhs, rng;
 239.648 +      char name[255+1], *flag;
 239.649 +      /* allocate working array */
 239.650 +      csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char));
 239.651 +      memset(&flag[1], 0, csa->P->m);
 239.652 +      /* no current RANGES vector exists */
 239.653 +      v = 0;
 239.654 +loop: if (indicator(csa, 0)) goto done;
 239.655 +      /* field 1 must be blank */
 239.656 +      if (csa->deck)
 239.657 +      {  read_field(csa);
 239.658 +         if (csa->field[0] != '\0')
 239.659 +            error(csa, "field 1 must be blank\n");
 239.660 +      }
 239.661 +      else
 239.662 +         csa->fldno++;
 239.663 +      /* field 2: RANGES vector name */
 239.664 +      read_field(csa), patch_name(csa, csa->field);
 239.665 +      if (csa->field[0] == '\0')
 239.666 +      {  /* the same RANGES vector as in previous data record */
 239.667 +         if (v == 0)
 239.668 +         {  warning(csa, "missing RANGES vector name in field 2\n");
 239.669 +            goto blnk;
 239.670 +         }
 239.671 +      }
 239.672 +      else if (v != 0 && strcmp(csa->field, name) == 0)
 239.673 +      {  /* the same RANGES vector as in previous data record */
 239.674 +         xassert(v != 0);
 239.675 +      }
 239.676 +      else
 239.677 +blnk: {  /* new RANGES vector */
 239.678 +         if (v != 0)
 239.679 +            error(csa, "multiple RANGES vectors not supported\n");
 239.680 +         v++;
 239.681 +         strcpy(name, csa->field);
 239.682 +      }
 239.683 +      /* process fields 3-4 and 5-6 */
 239.684 +      for (f = 3; f <= 5; f += 2)
 239.685 +      {  /* field 3 or 5: row name */
 239.686 +         read_field(csa), patch_name(csa, csa->field);
 239.687 +         if (csa->field[0] == '\0')
 239.688 +         {  if (f == 3)
 239.689 +               error(csa, "missing row name in field 3\n");
 239.690 +            else
 239.691 +            {  /* if field 5 is blank, field 6 also must be blank */
 239.692 +               skip_field(csa);
 239.693 +               continue;
 239.694 +            }
 239.695 +         }
 239.696 +         i = glp_find_row(csa->P, csa->field);
 239.697 +         if (i == 0)
 239.698 +            error(csa, "row `%s' not found\n", csa->field);
 239.699 +         if (flag[i])
 239.700 +            error(csa, "duplicate range for row `%s'\n", csa->field);
 239.701 +         /* field 4 or 6: range value */
 239.702 +         rng = read_number(csa);
 239.703 +         if (fabs(rng) < csa->parm->tol_mps) rng = 0.0;
 239.704 +         type = csa->P->row[i]->type;
 239.705 +         if (type == GLP_FR)
 239.706 +            warning(csa, "range for free row `%s' ignored\n",
 239.707 +               csa->P->row[i]->name);
 239.708 +         else if (type == GLP_LO)
 239.709 +         {  rhs = csa->P->row[i]->lb;
 239.710 +            glp_set_row_bnds(csa->P, i, rhs == 0.0 ? GLP_FX : GLP_DB,
 239.711 +               rhs, rhs + fabs(rng));
 239.712 +         }
 239.713 +         else if (type == GLP_UP)
 239.714 +         {  rhs = csa->P->row[i]->ub;
 239.715 +            glp_set_row_bnds(csa->P, i, rhs == 0.0 ? GLP_FX : GLP_DB,
 239.716 +               rhs - fabs(rng), rhs);
 239.717 +         }
 239.718 +         else if (type == GLP_FX)
 239.719 +         {  rhs = csa->P->row[i]->lb;
 239.720 +            if (rng > 0.0)
 239.721 +               glp_set_row_bnds(csa->P, i, GLP_DB, rhs, rhs + rng);
 239.722 +            else if (rng < 0.0)
 239.723 +               glp_set_row_bnds(csa->P, i, GLP_DB, rhs + rng, rhs);
 239.724 +         }
 239.725 +         else
 239.726 +            xassert(type != type);
 239.727 +         flag[i] = 1;
 239.728 +      }
 239.729 +      goto loop;
 239.730 +done: /* free working array */
 239.731 +      xfree(flag);
 239.732 +      csa->work3 = NULL;
 239.733 +      return;
 239.734 +}
 239.735 +
 239.736 +static void read_bounds(struct csa *csa)
 239.737 +{     /* read BOUNDS section */
 239.738 +      GLPCOL *col;
 239.739 +      int j, v, mask, data;
 239.740 +      double bnd, lb, ub;
 239.741 +      char type[2+1], name[255+1], *flag;
 239.742 +      /* allocate working array */
 239.743 +      csa->work3 = flag = xcalloc(1+csa->P->n, sizeof(char));
 239.744 +      memset(&flag[1], 0, csa->P->n);
 239.745 +      /* no current BOUNDS vector exists */
 239.746 +      v = 0;
 239.747 +loop: if (indicator(csa, 0)) goto done;
 239.748 +      /* field 1: bound type */
 239.749 +      read_field(csa);
 239.750 +      if (strcmp(csa->field, "LO") == 0)
 239.751 +         mask = 0x01, data = 1;
 239.752 +      else if (strcmp(csa->field, "UP") == 0)
 239.753 +         mask = 0x10, data = 1;
 239.754 +      else if (strcmp(csa->field, "FX") == 0)
 239.755 +         mask = 0x11, data = 1;
 239.756 +      else if (strcmp(csa->field, "FR") == 0)
 239.757 +         mask = 0x11, data = 0;
 239.758 +      else if (strcmp(csa->field, "MI") == 0)
 239.759 +         mask = 0x01, data = 0;
 239.760 +      else if (strcmp(csa->field, "PL") == 0)
 239.761 +         mask = 0x10, data = 0;
 239.762 +      else if (strcmp(csa->field, "LI") == 0)
 239.763 +         mask = 0x01, data = 1;
 239.764 +      else if (strcmp(csa->field, "UI") == 0)
 239.765 +         mask = 0x10, data = 1;
 239.766 +      else if (strcmp(csa->field, "BV") == 0)
 239.767 +         mask = 0x11, data = 0;
 239.768 +      else if (csa->field[0] == '\0')
 239.769 +         error(csa, "missing bound type in field 1\n");
 239.770 +      else
 239.771 +         error(csa, "invalid bound type in field 1\n");
 239.772 +      strcpy(type, csa->field);
 239.773 +      /* field 2: BOUNDS vector name */
 239.774 +      read_field(csa), patch_name(csa, csa->field);
 239.775 +      if (csa->field[0] == '\0')
 239.776 +      {  /* the same BOUNDS vector as in previous data record */
 239.777 +         if (v == 0)
 239.778 +         {  warning(csa, "missing BOUNDS vector name in field 2\n");
 239.779 +            goto blnk;
 239.780 +         }
 239.781 +      }
 239.782 +      else if (v != 0 && strcmp(csa->field, name) == 0)
 239.783 +      {  /* the same BOUNDS vector as in previous data record */
 239.784 +         xassert(v != 0);
 239.785 +      }
 239.786 +      else
 239.787 +blnk: {  /* new BOUNDS vector */
 239.788 +         if (v != 0)
 239.789 +            error(csa, "multiple BOUNDS vectors not supported\n");
 239.790 +         v++;
 239.791 +         strcpy(name, csa->field);
 239.792 +      }
 239.793 +      /* field 3: column name */
 239.794 +      read_field(csa), patch_name(csa, csa->field);
 239.795 +      if (csa->field[0] == '\0')
 239.796 +         error(csa, "missing column name in field 3\n");
 239.797 +      j = glp_find_col(csa->P, csa->field);
 239.798 +      if (j == 0)
 239.799 +         error(csa, "column `%s' not found\n", csa->field);
 239.800 +      if ((flag[j] & mask) == 0x01)
 239.801 +         error(csa, "duplicate lower bound for column `%s'\n",
 239.802 +            csa->field);
 239.803 +      if ((flag[j] & mask) == 0x10)
 239.804 +         error(csa, "duplicate upper bound for column `%s'\n",
 239.805 +            csa->field);
 239.806 +      xassert((flag[j] & mask) == 0x00);
 239.807 +      /* field 4: bound value */
 239.808 +      if (data)
 239.809 +      {  bnd = read_number(csa);
 239.810 +         if (fabs(bnd) < csa->parm->tol_mps) bnd = 0.0;
 239.811 +      }
 239.812 +      else
 239.813 +         read_field(csa), bnd = 0.0;
 239.814 +      /* get current column bounds */
 239.815 +      col = csa->P->col[j];
 239.816 +      if (col->type == GLP_FR)
 239.817 +         lb = -DBL_MAX, ub = +DBL_MAX;
 239.818 +      else if (col->type == GLP_LO)
 239.819 +         lb = col->lb, ub = +DBL_MAX;
 239.820 +      else if (col->type == GLP_UP)
 239.821 +         lb = -DBL_MAX, ub = col->ub;
 239.822 +      else if (col->type == GLP_DB)
 239.823 +         lb = col->lb, ub = col->ub;
 239.824 +      else if (col->type == GLP_FX)
 239.825 +         lb = ub = col->lb;
 239.826 +      else
 239.827 +         xassert(col != col);
 239.828 +      /* change column bounds */
 239.829 +      if (strcmp(type, "LO") == 0)
 239.830 +         lb = bnd;
 239.831 +      else if (strcmp(type, "UP") == 0)
 239.832 +         ub = bnd;
 239.833 +      else if (strcmp(type, "FX") == 0)
 239.834 +         lb = ub = bnd;
 239.835 +      else if (strcmp(type, "FR") == 0)
 239.836 +         lb = -DBL_MAX, ub = +DBL_MAX;
 239.837 +      else if (strcmp(type, "MI") == 0)
 239.838 +         lb = -DBL_MAX;
 239.839 +      else if (strcmp(type, "PL") == 0)
 239.840 +         ub = +DBL_MAX;
 239.841 +      else if (strcmp(type, "LI") == 0)
 239.842 +      {  glp_set_col_kind(csa->P, j, GLP_IV);
 239.843 +         lb = ceil(bnd);
 239.844 +      }
 239.845 +      else if (strcmp(type, "UI") == 0)
 239.846 +      {  glp_set_col_kind(csa->P, j, GLP_IV);
 239.847 +         ub = floor(bnd);
 239.848 +      }
 239.849 +      else if (strcmp(type, "BV") == 0)
 239.850 +      {  glp_set_col_kind(csa->P, j, GLP_IV);
 239.851 +         lb = 0.0, ub = 1.0;
 239.852 +      }
 239.853 +      else
 239.854 +         xassert(type != type);
 239.855 +      /* set new column bounds */
 239.856 +      if (lb == -DBL_MAX && ub == +DBL_MAX)
 239.857 +         glp_set_col_bnds(csa->P, j, GLP_FR, lb, ub);
 239.858 +      else if (ub == +DBL_MAX)
 239.859 +         glp_set_col_bnds(csa->P, j, GLP_LO, lb, ub);
 239.860 +      else if (lb == -DBL_MAX)
 239.861 +         glp_set_col_bnds(csa->P, j, GLP_UP, lb, ub);
 239.862 +      else if (lb != ub)
 239.863 +         glp_set_col_bnds(csa->P, j, GLP_DB, lb, ub);
 239.864 +      else
 239.865 +         glp_set_col_bnds(csa->P, j, GLP_FX, lb, ub);
 239.866 +      flag[j] |= (char)mask;
 239.867 +      /* fields 5 and 6 must be blank */
 239.868 +      skip_field(csa);
 239.869 +      skip_field(csa);
 239.870 +      goto loop;
 239.871 +done: /* free working array */
 239.872 +      xfree(flag);
 239.873 +      csa->work3 = NULL;
 239.874 +      return;
 239.875 +}
 239.876 +
 239.877 +int glp_read_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
 239.878 +      const char *fname)
 239.879 +{     /* read problem data in MPS format */
 239.880 +      glp_mpscp _parm;
 239.881 +      struct csa _csa, *csa = &_csa;
 239.882 +      int ret;
 239.883 +      xprintf("Reading problem data from `%s'...\n", fname);
 239.884 +      if (!(fmt == GLP_MPS_DECK || fmt == GLP_MPS_FILE))
 239.885 +         xerror("glp_read_mps: fmt = %d; invalid parameter\n", fmt);
 239.886 +      if (parm == NULL)
 239.887 +         glp_init_mpscp(&_parm), parm = &_parm;
 239.888 +      /* check control parameters */
 239.889 +      check_parm("glp_read_mps", parm);
 239.890 +      /* initialize common storage area */
 239.891 +      csa->P = P;
 239.892 +      csa->deck = (fmt == GLP_MPS_DECK);
 239.893 +      csa->parm = parm;
 239.894 +      csa->fname = fname;
 239.895 +      csa->fp = NULL;
 239.896 +      if (setjmp(csa->jump))
 239.897 +      {  ret = 1;
 239.898 +         goto done;
 239.899 +      }
 239.900 +      csa->recno = csa->recpos = 0;
 239.901 +      csa->c = '\n';
 239.902 +      csa->fldno = 0;
 239.903 +      csa->field[0] = '\0';
 239.904 +      csa->w80 = csa->wef = 0;
 239.905 +      csa->obj_row = 0;
 239.906 +      csa->work1 = csa->work2 = csa->work3 = NULL;
 239.907 +      /* erase problem object */
 239.908 +      glp_erase_prob(P);
 239.909 +      glp_create_index(P);
 239.910 +      /* open input MPS file */
 239.911 +      csa->fp = xfopen(fname, "r");
 239.912 +      if (csa->fp == NULL)
 239.913 +      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
 239.914 +         ret = 1;
 239.915 +         goto done;
 239.916 +      }
 239.917 +      /* read NAME indicator record */
 239.918 +      read_name(csa);
 239.919 +      if (P->name != NULL)
 239.920 +         xprintf("Problem: %s\n", P->name);
 239.921 +      /* read ROWS section */
 239.922 +      if (!(indicator(csa, 0) && strcmp(csa->field, "ROWS") == 0))
 239.923 +         error(csa, "missing ROWS indicator record\n");
 239.924 +      read_rows(csa);
 239.925 +      /* determine objective row */
 239.926 +      if (parm->obj_name == NULL || parm->obj_name[0] == '\0')
 239.927 +      {  /* use the first row of N type */
 239.928 +         int i;
 239.929 +         for (i = 1; i <= P->m; i++)
 239.930 +         {  if (P->row[i]->type == GLP_FR)
 239.931 +            {  csa->obj_row = i;
 239.932 +               break;
 239.933 +            }
 239.934 +         }
 239.935 +         if (csa->obj_row == 0)
 239.936 +            warning(csa, "unable to determine objective row\n");
 239.937 +      }
 239.938 +      else
 239.939 +      {  /* use a row with specified name */
 239.940 +         int i;
 239.941 +         for (i = 1; i <= P->m; i++)
 239.942 +         {  xassert(P->row[i]->name != NULL);
 239.943 +            if (strcmp(parm->obj_name, P->row[i]->name) == 0)
 239.944 +            {  csa->obj_row = i;
 239.945 +               break;
 239.946 +            }
 239.947 +         }
 239.948 +         if (csa->obj_row == 0)
 239.949 +            error(csa, "objective row `%s' not found\n",
 239.950 +               parm->obj_name);
 239.951 +      }
 239.952 +      if (csa->obj_row != 0)
 239.953 +      {  glp_set_obj_name(P, P->row[csa->obj_row]->name);
 239.954 +         xprintf("Objective: %s\n", P->obj);
 239.955 +      }
 239.956 +      /* read COLUMNS section */
 239.957 +      if (strcmp(csa->field, "COLUMNS") != 0)
 239.958 +         error(csa, "missing COLUMNS indicator record\n");
 239.959 +      read_columns(csa);
 239.960 +      /* set objective coefficients */
 239.961 +      if (csa->obj_row != 0)
 239.962 +      {  GLPAIJ *aij;
 239.963 +         for (aij = P->row[csa->obj_row]->ptr; aij != NULL; aij =
 239.964 +            aij->r_next) glp_set_obj_coef(P, aij->col->j, aij->val);
 239.965 +      }
 239.966 +      /* read optional RHS section */
 239.967 +      if (strcmp(csa->field, "RHS") == 0)
 239.968 +         read_rhs(csa);
 239.969 +      /* read optional RANGES section */
 239.970 +      if (strcmp(csa->field, "RANGES") == 0)
 239.971 +         read_ranges(csa);
 239.972 +      /* read optional BOUNDS section */
 239.973 +      if (strcmp(csa->field, "BOUNDS") == 0)
 239.974 +         read_bounds(csa);
 239.975 +      /* read ENDATA indicator record */
 239.976 +      if (strcmp(csa->field, "ENDATA") != 0)
 239.977 +         error(csa, "invalid use of %s indicator record\n",
 239.978 +            csa->field);
 239.979 +      /* print some statistics */
 239.980 +      xprintf("%d row%s, %d column%s, %d non-zero%s\n",
 239.981 +         P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s",
 239.982 +         P->nnz, P->nnz == 1 ? "" : "s");
 239.983 +      if (glp_get_num_int(P) > 0)
 239.984 +      {  int ni = glp_get_num_int(P);
 239.985 +         int nb = glp_get_num_bin(P);
 239.986 +         if (ni == 1)
 239.987 +         {  if (nb == 0)
 239.988 +               xprintf("One variable is integer\n");
 239.989 +            else
 239.990 +               xprintf("One variable is binary\n");
 239.991 +         }
 239.992 +         else
 239.993 +         {  xprintf("%d integer variables, ", ni);
 239.994 +            if (nb == 0)
 239.995 +               xprintf("none");
 239.996 +            else if (nb == 1)
 239.997 +               xprintf("one");
 239.998 +            else if (nb == ni)
 239.999 +               xprintf("all");
239.1000 +            else
239.1001 +               xprintf("%d", nb);
239.1002 +            xprintf(" of which %s binary\n", nb == 1 ? "is" : "are");
239.1003 +         }
239.1004 +      }
239.1005 +      xprintf("%d records were read\n", csa->recno);
239.1006 +      /* problem data has been successfully read */
239.1007 +      glp_delete_index(P);
239.1008 +      glp_sort_matrix(P);
239.1009 +      ret = 0;
239.1010 +done: if (csa->fp != NULL) xfclose(csa->fp);
239.1011 +      if (csa->work1 != NULL) xfree(csa->work1);
239.1012 +      if (csa->work2 != NULL) xfree(csa->work2);
239.1013 +      if (csa->work3 != NULL) xfree(csa->work3);
239.1014 +      if (ret != 0) glp_erase_prob(P);
239.1015 +      return ret;
239.1016 +}
239.1017 +
239.1018 +/***********************************************************************
239.1019 +*  NAME
239.1020 +*
239.1021 +*  glp_write_mps - write problem data in MPS format
239.1022 +*
239.1023 +*  SYNOPSIS
239.1024 +*
239.1025 +*  int glp_write_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
239.1026 +*     const char *fname);
239.1027 +*
239.1028 +*  DESCRIPTION
239.1029 +*
239.1030 +*  The routine glp_write_mps writes problem data in MPS format to a
239.1031 +*  text file.
239.1032 +*
239.1033 +*  The parameter fmt specifies the version of MPS format:
239.1034 +*
239.1035 +*  GLP_MPS_DECK - fixed (ancient) MPS format;
239.1036 +*  GLP_MPS_FILE - free (modern) MPS format.
239.1037 +*
239.1038 +*  The parameter parm is a pointer to the structure glp_mpscp, which
239.1039 +*  specifies control parameters used by the routine. If parm is NULL,
239.1040 +*  the routine uses default settings.
239.1041 +*
239.1042 +*  The character string fname specifies a name of the text file to be
239.1043 +*  written.
239.1044 +*
239.1045 +*  RETURNS
239.1046 +*
239.1047 +*  If the operation was successful, the routine glp_read_mps returns
239.1048 +*  zero. Otherwise, it prints an error message and returns non-zero. */
239.1049 +
239.1050 +#define csa csa1
239.1051 +
239.1052 +struct csa
239.1053 +{     /* common storage area */
239.1054 +      glp_prob *P;
239.1055 +      /* pointer to problem object */
239.1056 +      int deck;
239.1057 +      /* MPS format (0 - free, 1 - fixed) */
239.1058 +      const glp_mpscp *parm;
239.1059 +      /* pointer to control parameters */
239.1060 +      char field[255+1];
239.1061 +      /* field buffer */
239.1062 +};
239.1063 +
239.1064 +static char *mps_name(struct csa *csa)
239.1065 +{     /* make problem name */
239.1066 +      char *f;
239.1067 +      if (csa->P->name == NULL)
239.1068 +         csa->field[0] = '\0';
239.1069 +      else if (csa->deck)
239.1070 +      {  strncpy(csa->field, csa->P->name, 8);
239.1071 +         csa->field[8] = '\0';
239.1072 +      }
239.1073 +      else
239.1074 +         strcpy(csa->field, csa->P->name);
239.1075 +      for (f = csa->field; *f != '\0'; f++)
239.1076 +         if (*f == ' ') *f = '_';
239.1077 +      return csa->field;
239.1078 +}
239.1079 +
239.1080 +static char *row_name(struct csa *csa, int i)
239.1081 +{     /* make i-th row name */
239.1082 +      char *f;
239.1083 +      xassert(0 <= i && i <= csa->P->m);
239.1084 +      if (i == 0 || csa->P->row[i]->name == NULL ||
239.1085 +          csa->deck && strlen(csa->P->row[i]->name) > 8)
239.1086 +         sprintf(csa->field, "R%07d", i);
239.1087 +      else
239.1088 +      {  strcpy(csa->field, csa->P->row[i]->name);
239.1089 +         for (f = csa->field; *f != '\0'; f++)
239.1090 +            if (*f == ' ') *f = '_';
239.1091 +      }
239.1092 +      return csa->field;
239.1093 +}
239.1094 +
239.1095 +static char *col_name(struct csa *csa, int j)
239.1096 +{     /* make j-th column name */
239.1097 +      char *f;
239.1098 +      xassert(1 <= j && j <= csa->P->n);
239.1099 +      if (csa->P->col[j]->name == NULL ||
239.1100 +          csa->deck && strlen(csa->P->col[j]->name) > 8)
239.1101 +         sprintf(csa->field, "C%07d", j);
239.1102 +      else
239.1103 +      {  strcpy(csa->field, csa->P->col[j]->name);
239.1104 +         for (f = csa->field; *f != '\0'; f++)
239.1105 +            if (*f == ' ') *f = '_';
239.1106 +      }
239.1107 +      return csa->field;
239.1108 +}
239.1109 +
239.1110 +static char *mps_numb(struct csa *csa, double val)
239.1111 +{     /* format floating-point number */
239.1112 +      int dig;
239.1113 +      char *exp;
239.1114 +      for (dig = 12; dig >= 6; dig--)
239.1115 +      {  if (val != 0.0 && fabs(val) < 0.002)
239.1116 +            sprintf(csa->field, "%.*E", dig-1, val);
239.1117 +         else
239.1118 +            sprintf(csa->field, "%.*G", dig, val);
239.1119 +         exp = strchr(csa->field, 'E');
239.1120 +         if (exp != NULL)
239.1121 +            sprintf(exp+1, "%d", atoi(exp+1));
239.1122 +         if (strlen(csa->field) <= 12) break;
239.1123 +      }
239.1124 +      xassert(strlen(csa->field) <= 12);
239.1125 +      return csa->field;
239.1126 +}
239.1127 +
239.1128 +int glp_write_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
239.1129 +      const char *fname)
239.1130 +{     /* write problem data in MPS format */
239.1131 +      glp_mpscp _parm;
239.1132 +      struct csa _csa, *csa = &_csa;
239.1133 +      XFILE *fp;
239.1134 +      int out_obj, one_col = 0, empty = 0;
239.1135 +      int i, j, recno, marker, count, gap, ret;
239.1136 +      xprintf("Writing problem data to `%s'...\n", fname);
239.1137 +      if (!(fmt == GLP_MPS_DECK || fmt == GLP_MPS_FILE))
239.1138 +         xerror("glp_write_mps: fmt = %d; invalid parameter\n", fmt);
239.1139 +      if (parm == NULL)
239.1140 +         glp_init_mpscp(&_parm), parm = &_parm;
239.1141 +      /* check control parameters */
239.1142 +      check_parm("glp_write_mps", parm);
239.1143 +      /* initialize common storage area */
239.1144 +      csa->P = P;
239.1145 +      csa->deck = (fmt == GLP_MPS_DECK);
239.1146 +      csa->parm = parm;
239.1147 +      /* create output MPS file */
239.1148 +      fp = xfopen(fname, "w"), recno = 0;
239.1149 +      if (fp == NULL)
239.1150 +      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
239.1151 +         ret = 1;
239.1152 +         goto done;
239.1153 +      }
239.1154 +      /* write comment records */
239.1155 +      xfprintf(fp, "* %-*s%s\n", P->name == NULL ? 1 : 12, "Problem:",
239.1156 +         P->name == NULL ? "" : P->name), recno++;
239.1157 +      xfprintf(fp, "* %-12s%s\n", "Class:", glp_get_num_int(P) == 0 ?
239.1158 +         "LP" : "MIP"), recno++;
239.1159 +      xfprintf(fp, "* %-12s%d\n", "Rows:", P->m), recno++;
239.1160 +      if (glp_get_num_int(P) == 0)
239.1161 +         xfprintf(fp, "* %-12s%d\n", "Columns:", P->n), recno++;
239.1162 +      else
239.1163 +         xfprintf(fp, "* %-12s%d (%d integer, %d binary)\n",
239.1164 +            "Columns:", P->n, glp_get_num_int(P), glp_get_num_bin(P)),
239.1165 +            recno++;
239.1166 +      xfprintf(fp, "* %-12s%d\n", "Non-zeros:", P->nnz), recno++;
239.1167 +      xfprintf(fp, "* %-12s%s\n", "Format:", csa->deck ? "Fixed MPS" :
239.1168 +         "Free MPS"), recno++;
239.1169 +      xfprintf(fp, "*\n", recno++);
239.1170 +      /* write NAME indicator record */
239.1171 +      xfprintf(fp, "NAME%*s%s\n",
239.1172 +         P->name == NULL ? 0 : csa->deck ? 10 : 1, "", mps_name(csa)),
239.1173 +         recno++;
239.1174 +#if 1
239.1175 +      /* determine whether to write the objective row */
239.1176 +      out_obj = 1;
239.1177 +      for (i = 1; i <= P->m; i++)
239.1178 +      {  if (P->row[i]->type == GLP_FR)
239.1179 +         {  out_obj = 0;
239.1180 +            break;
239.1181 +         }
239.1182 +      }
239.1183 +#endif
239.1184 +      /* write ROWS section */
239.1185 +      xfprintf(fp, "ROWS\n"), recno++;
239.1186 +      for (i = (out_obj ? 0 : 1); i <= P->m; i++)
239.1187 +      {  int type;
239.1188 +         type = (i == 0 ? GLP_FR : P->row[i]->type);
239.1189 +         if (type == GLP_FR)
239.1190 +            type = 'N';
239.1191 +         else if (type == GLP_LO)
239.1192 +            type = 'G';
239.1193 +         else if (type == GLP_UP)
239.1194 +            type = 'L';
239.1195 +         else if (type == GLP_DB || type == GLP_FX)
239.1196 +            type = 'E';
239.1197 +         else
239.1198 +            xassert(type != type);
239.1199 +         xfprintf(fp, " %c%*s%s\n", type, csa->deck ? 2 : 1, "",
239.1200 +            row_name(csa, i)), recno++;
239.1201 +      }
239.1202 +      /* write COLUMNS section */
239.1203 +      xfprintf(fp, "COLUMNS\n"), recno++;
239.1204 +      marker = 0;
239.1205 +      for (j = 1; j <= P->n; j++)
239.1206 +      {  GLPAIJ cj, *aij;
239.1207 +         int kind;
239.1208 +         kind = P->col[j]->kind;
239.1209 +         if (kind == GLP_CV)
239.1210 +         {  if (marker % 2 == 1)
239.1211 +            {  /* close current integer block */
239.1212 +               marker++;
239.1213 +               xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTEND'\n",
239.1214 +                  csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "",
239.1215 +                  csa->deck ? 17 : 1, ""), recno++;
239.1216 +            }
239.1217 +         }
239.1218 +         else if (kind == GLP_IV)
239.1219 +         {  if (marker % 2 == 0)
239.1220 +            {  /* open new integer block */
239.1221 +               marker++;
239.1222 +               xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTORG'\n",
239.1223 +                  csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "",
239.1224 +                  csa->deck ? 17 : 1, ""), recno++;
239.1225 +            }
239.1226 +         }
239.1227 +         else
239.1228 +            xassert(kind != kind);
239.1229 +         if (out_obj && P->col[j]->coef != 0.0)
239.1230 +         {  /* make fake objective coefficient */
239.1231 +            aij = &cj;
239.1232 +            aij->row = NULL;
239.1233 +            aij->val = P->col[j]->coef;
239.1234 +            aij->c_next = P->col[j]->ptr;
239.1235 +         }
239.1236 +         else
239.1237 +            aij = P->col[j]->ptr;
239.1238 +#if 1 /* FIXME */
239.1239 +         if (aij == NULL)
239.1240 +         {  /* empty column */
239.1241 +            empty++;
239.1242 +            xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "",
239.1243 +               csa->deck ? 8 : 1, col_name(csa, j));
239.1244 +            /* we need a row */
239.1245 +            xassert(P->m > 0);
239.1246 +            xfprintf(fp, "%*s%-*s",
239.1247 +               csa->deck ? 2 : 1, "", csa->deck ? 8 : 1,
239.1248 +               row_name(csa, 1));
239.1249 +            xfprintf(fp, "%*s0%*s$ empty column\n",
239.1250 +               csa->deck ? 13 : 1, "", csa->deck ? 3 : 1, ""), recno++;
239.1251 +         }
239.1252 +#endif
239.1253 +         count = 0;
239.1254 +         for (aij = aij; aij != NULL; aij = aij->c_next)
239.1255 +         {  if (one_col || count % 2 == 0)
239.1256 +               xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "",
239.1257 +                  csa->deck ? 8 : 1, col_name(csa, j));
239.1258 +            gap = (one_col || count % 2 == 0 ? 2 : 3);
239.1259 +            xfprintf(fp, "%*s%-*s",
239.1260 +               csa->deck ? gap : 1, "", csa->deck ? 8 : 1,
239.1261 +               row_name(csa, aij->row == NULL ? 0 : aij->row->i));
239.1262 +            xfprintf(fp, "%*s%*s",
239.1263 +               csa->deck ? 2 : 1, "", csa->deck ? 12 : 1,
239.1264 +               mps_numb(csa, aij->val)), count++;
239.1265 +            if (one_col || count % 2 == 0)
239.1266 +               xfprintf(fp, "\n"), recno++;
239.1267 +         }
239.1268 +         if (!(one_col || count % 2 == 0))
239.1269 +            xfprintf(fp, "\n"), recno++;
239.1270 +      }
239.1271 +      if (marker % 2 == 1)
239.1272 +      {  /* close last integer block */
239.1273 +         marker++;
239.1274 +         xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTEND'\n",
239.1275 +            csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "",
239.1276 +            csa->deck ? 17 : 1, ""), recno++;
239.1277 +      }
239.1278 +#if 1
239.1279 +      if (empty > 0)
239.1280 +         xprintf("Warning: problem has %d empty column(s)\n", empty);
239.1281 +#endif
239.1282 +      /* write RHS section */
239.1283 +      xfprintf(fp, "RHS\n"), recno++;
239.1284 +      count = 0;
239.1285 +      for (i = (out_obj ? 0 : 1); i <= P->m; i++)
239.1286 +      {  int type;
239.1287 +         double rhs;
239.1288 +         if (i == 0)
239.1289 +            rhs = P->c0;
239.1290 +         else
239.1291 +         {  type = P->row[i]->type;
239.1292 +            if (type == GLP_FR)
239.1293 +               rhs = 0.0;
239.1294 +            else if (type == GLP_LO)
239.1295 +               rhs = P->row[i]->lb;
239.1296 +            else if (type == GLP_UP)
239.1297 +               rhs = P->row[i]->ub;
239.1298 +            else if (type == GLP_DB || type == GLP_FX)
239.1299 +               rhs = P->row[i]->lb;
239.1300 +            else
239.1301 +               xassert(type != type);
239.1302 +         }
239.1303 +         if (rhs != 0.0)
239.1304 +         {  if (one_col || count % 2 == 0)
239.1305 +               xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "",
239.1306 +                  csa->deck ? 8 : 1, "RHS1");
239.1307 +            gap = (one_col || count % 2 == 0 ? 2 : 3);
239.1308 +            xfprintf(fp, "%*s%-*s",
239.1309 +               csa->deck ? gap : 1, "", csa->deck ? 8 : 1,
239.1310 +               row_name(csa, i));
239.1311 +            xfprintf(fp, "%*s%*s",
239.1312 +               csa->deck ? 2 : 1, "", csa->deck ? 12 : 1,
239.1313 +               mps_numb(csa, rhs)), count++;
239.1314 +            if (one_col || count % 2 == 0)
239.1315 +               xfprintf(fp, "\n"), recno++;
239.1316 +         }
239.1317 +      }
239.1318 +      if (!(one_col || count % 2 == 0))
239.1319 +         xfprintf(fp, "\n"), recno++;
239.1320 +      /* write RANGES section */
239.1321 +      for (i = P->m; i >= 1; i--)
239.1322 +         if (P->row[i]->type == GLP_DB) break;
239.1323 +      if (i == 0) goto bnds;
239.1324 +      xfprintf(fp, "RANGES\n"), recno++;
239.1325 +      count = 0;
239.1326 +      for (i = 1; i <= P->m; i++)
239.1327 +      {  if (P->row[i]->type == GLP_DB)
239.1328 +         {  if (one_col || count % 2 == 0)
239.1329 +               xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "",
239.1330 +                  csa->deck ? 8 : 1, "RNG1");
239.1331 +            gap = (one_col || count % 2 == 0 ? 2 : 3);
239.1332 +            xfprintf(fp, "%*s%-*s",
239.1333 +               csa->deck ? gap : 1, "", csa->deck ? 8 : 1,
239.1334 +               row_name(csa, i));
239.1335 +            xfprintf(fp, "%*s%*s",
239.1336 +               csa->deck ? 2 : 1, "", csa->deck ? 12 : 1,
239.1337 +               mps_numb(csa, P->row[i]->ub - P->row[i]->lb)), count++;
239.1338 +            if (one_col || count % 2 == 0)
239.1339 +               xfprintf(fp, "\n"), recno++;
239.1340 +         }
239.1341 +      }
239.1342 +      if (!(one_col || count % 2 == 0))
239.1343 +         xfprintf(fp, "\n"), recno++;
239.1344 +bnds: /* write BOUNDS section */
239.1345 +      for (j = P->n; j >= 1; j--)
239.1346 +         if (!(P->col[j]->type == GLP_LO && P->col[j]->lb == 0.0))
239.1347 +            break;
239.1348 +      if (j == 0) goto endt;
239.1349 +      xfprintf(fp, "BOUNDS\n"), recno++;
239.1350 +      for (j = 1; j <= P->n; j++)
239.1351 +      {  int type, data[2];
239.1352 +         double bnd[2];
239.1353 +         char *spec[2];
239.1354 +         spec[0] = spec[1] = NULL;
239.1355 +         type = P->col[j]->type;
239.1356 +         if (type == GLP_FR)
239.1357 +            spec[0] = "FR", data[0] = 0;
239.1358 +         else if (type == GLP_LO)
239.1359 +         {  if (P->col[j]->lb != 0.0)
239.1360 +               spec[0] = "LO", data[0] = 1, bnd[0] = P->col[j]->lb;
239.1361 +            if (P->col[j]->kind == GLP_IV)
239.1362 +               spec[1] = "PL", data[1] = 0;
239.1363 +         }
239.1364 +         else if (type == GLP_UP)
239.1365 +         {  spec[0] = "MI", data[0] = 0;
239.1366 +            spec[1] = "UP", data[1] = 1, bnd[1] = P->col[j]->ub;
239.1367 +         }
239.1368 +         else if (type == GLP_DB)
239.1369 +         {  if (P->col[j]->lb != 0.0)
239.1370 +               spec[0] = "LO", data[0] = 1, bnd[0] = P->col[j]->lb;
239.1371 +            spec[1] = "UP", data[1] = 1, bnd[1] = P->col[j]->ub;
239.1372 +         }
239.1373 +         else if (type == GLP_FX)
239.1374 +            spec[0] = "FX", data[0] = 1, bnd[0] = P->col[j]->lb;
239.1375 +         else
239.1376 +            xassert(type != type);
239.1377 +         for (i = 0; i <= 1; i++)
239.1378 +         {  if (spec[i] != NULL)
239.1379 +            {  xfprintf(fp, " %s %-*s%*s%-*s", spec[i],
239.1380 +                  csa->deck ? 8 : 1, "BND1", csa->deck ? 2 : 1, "",
239.1381 +                  csa->deck ? 8 : 1, col_name(csa, j));
239.1382 +               if (data[i])
239.1383 +                  xfprintf(fp, "%*s%*s", csa->deck ? 2 : 1, "",
239.1384 +                     csa->deck ? 12 : 1, mps_numb(csa, bnd[i]));
239.1385 +               xfprintf(fp, "\n"), recno++;
239.1386 +            }
239.1387 +         }
239.1388 +      }
239.1389 +endt: /* write ENDATA indicator record */
239.1390 +      xfprintf(fp, "ENDATA\n"), recno++;
239.1391 +      xfflush(fp);
239.1392 +      if (xferror(fp))
239.1393 +      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
239.1394 +         ret = 1;
239.1395 +         goto done;
239.1396 +      }
239.1397 +      /* problem data has been successfully written */
239.1398 +      xprintf("%d records were written\n", recno);
239.1399 +      ret = 0;
239.1400 +done: if (fp != NULL) xfclose(fp);
239.1401 +      return ret;
239.1402 +}
239.1403 +
239.1404 +/* eof */
   240.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   240.2 +++ b/src/glpnet.h	Mon Dec 06 13:09:21 2010 +0100
   240.3 @@ -0,0 +1,60 @@
   240.4 +/* glpnet.h (graph and network algorithms) */
   240.5 +
   240.6 +/***********************************************************************
   240.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   240.8 +*
   240.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  240.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  240.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  240.12 +*  E-mail: <mao@gnu.org>.
  240.13 +*
  240.14 +*  GLPK is free software: you can redistribute it and/or modify it
  240.15 +*  under the terms of the GNU General Public License as published by
  240.16 +*  the Free Software Foundation, either version 3 of the License, or
  240.17 +*  (at your option) any later version.
  240.18 +*
  240.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  240.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  240.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  240.22 +*  License for more details.
  240.23 +*
  240.24 +*  You should have received a copy of the GNU General Public License
  240.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  240.26 +***********************************************************************/
  240.27 +
  240.28 +#ifndef GLPNET_H
  240.29 +#define GLPNET_H
  240.30 +
  240.31 +#define mc21a _glp_mc21a
  240.32 +int mc21a(int n, const int icn[], const int ip[], const int lenr[],
  240.33 +      int iperm[], int pr[], int arp[], int cv[], int out[]);
  240.34 +/* permutations for zero-free diagonal */
  240.35 +
  240.36 +#define mc13d _glp_mc13d
  240.37 +int mc13d(int n, const int icn[], const int ip[], const int lenr[],
  240.38 +      int ior[], int ib[], int lowl[], int numb[], int prev[]);
  240.39 +/* permutations to block triangular form */
  240.40 +
  240.41 +#define okalg _glp_okalg
  240.42 +int okalg(int nv, int na, const int tail[], const int head[],
  240.43 +      const int low[], const int cap[], const int cost[], int x[],
  240.44 +      int pi[]);
  240.45 +/* out-of-kilter algorithm */
  240.46 +
  240.47 +#define ffalg _glp_ffalg
  240.48 +void ffalg(int nv, int na, const int tail[], const int head[],
  240.49 +      int s, int t, const int cap[], int x[], char cut[]);
  240.50 +/* Ford-Fulkerson algorithm */
  240.51 +
  240.52 +#define wclique _glp_wclique
  240.53 +int wclique(int n, const int w[], const unsigned char a[], int ind[]);
  240.54 +/* find maximum weight clique with Ostergard's algorithm */
  240.55 +
  240.56 +#define kellerman _glp_kellerman
  240.57 +int kellerman(int n, int (*func)(void *info, int i, int ind[]),
  240.58 +      void *info, void /* glp_graph */ *H);
  240.59 +/* cover edges by cliques with Kellerman's heuristic */
  240.60 +
  240.61 +#endif
  240.62 +
  240.63 +/* eof */
   241.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   241.2 +++ b/src/glpnet01.c	Mon Dec 06 13:09:21 2010 +0100
   241.3 @@ -0,0 +1,301 @@
   241.4 +/* glpnet01.c (permutations for zero-free diagonal) */
   241.5 +
   241.6 +/***********************************************************************
   241.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   241.8 +*
   241.9 +*  This code is the result of translation of the Fortran subroutines
  241.10 +*  MC21A and MC21B associated with the following paper:
  241.11 +*
  241.12 +*  I.S.Duff, Algorithm 575: Permutations for zero-free diagonal, ACM
  241.13 +*  Trans. on Math. Softw. 7 (1981), 387-390.
  241.14 +*
  241.15 +*  Use of ACM Algorithms is subject to the ACM Software Copyright and
  241.16 +*  License Agreement. See <http://www.acm.org/publications/policies>.
  241.17 +*
  241.18 +*  The translation was made by Andrew Makhorin <mao@gnu.org>.
  241.19 +*
  241.20 +*  GLPK is free software: you can redistribute it and/or modify it
  241.21 +*  under the terms of the GNU General Public License as published by
  241.22 +*  the Free Software Foundation, either version 3 of the License, or
  241.23 +*  (at your option) any later version.
  241.24 +*
  241.25 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  241.26 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  241.27 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  241.28 +*  License for more details.
  241.29 +*
  241.30 +*  You should have received a copy of the GNU General Public License
  241.31 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  241.32 +***********************************************************************/
  241.33 +
  241.34 +#include "glpnet.h"
  241.35 +
  241.36 +/***********************************************************************
  241.37 +*  NAME
  241.38 +*
  241.39 +*  mc21a - permutations for zero-free diagonal
  241.40 +*
  241.41 +*  SYNOPSIS
  241.42 +*
  241.43 +*  #include "glpnet.h"
  241.44 +*  int mc21a(int n, const int icn[], const int ip[], const int lenr[],
  241.45 +*     int iperm[], int pr[], int arp[], int cv[], int out[]);
  241.46 +*
  241.47 +*  DESCRIPTION
  241.48 +*
  241.49 +*  Given the pattern of nonzeros of a sparse matrix, the routine mc21a
  241.50 +*  attempts to find a permutation of its rows that makes the matrix have
  241.51 +*  no zeros on its diagonal.
  241.52 +*
  241.53 +*  INPUT PARAMETERS
  241.54 +*
  241.55 +*  n     order of matrix.
  241.56 +*
  241.57 +*  icn   array containing the column indices of the non-zeros. Those
  241.58 +*        belonging to a single row must be contiguous but the ordering
  241.59 +*        of column indices within each row is unimportant and wasted
  241.60 +*        space between rows is permitted.
  241.61 +*
  241.62 +*  ip    ip[i], i = 1,2,...,n, is the position in array icn of the
  241.63 +*        first column index of a non-zero in row i.
  241.64 +*
  241.65 +*  lenr  lenr[i], i = 1,2,...,n, is the number of non-zeros in row i.
  241.66 +*
  241.67 +*  OUTPUT PARAMETER
  241.68 +*
  241.69 +*  iperm contains permutation to make diagonal have the smallest
  241.70 +*        number of zeros on it. Elements (iperm[i], i), i = 1,2,...,n,
  241.71 +*        are non-zero at the end of the algorithm unless the matrix is
  241.72 +*        structurally singular. In this case, (iperm[i], i) will be
  241.73 +*        zero for n - numnz entries.
  241.74 +*
  241.75 +*  WORKING ARRAYS
  241.76 +*
  241.77 +*  pr    working array of length [1+n], where pr[0] is not used.
  241.78 +*        pr[i] is the previous row to i in the depth first search.
  241.79 +*
  241.80 +*  arp   working array of length [1+n], where arp[0] is not used.
  241.81 +*        arp[i] is one less than the number of non-zeros in row i which
  241.82 +*        have not been scanned when looking for a cheap assignment.
  241.83 +*
  241.84 +*  cv    working array of length [1+n], where cv[0] is not used.
  241.85 +*        cv[i] is the most recent row extension at which column i was
  241.86 +*        visited.
  241.87 +*
  241.88 +*  out   working array of length [1+n], where out[0] is not used.
  241.89 +*        out[i] is one less than the number of non-zeros in row i
  241.90 +*        which have not been scanned during one pass through the main
  241.91 +*        loop.
  241.92 +*
  241.93 +*  RETURNS
  241.94 +*
  241.95 +*  The routine mc21a returns numnz, the number of non-zeros on diagonal
  241.96 +*  of permuted matrix. */
  241.97 +
  241.98 +int mc21a(int n, const int icn[], const int ip[], const int lenr[],
  241.99 +      int iperm[], int pr[], int arp[], int cv[], int out[])
 241.100 +{     int i, ii, in1, in2, j, j1, jord, k, kk, numnz;
 241.101 +      /* Initialization of arrays. */
 241.102 +      for (i = 1; i <= n; i++)
 241.103 +      {  arp[i] = lenr[i] - 1;
 241.104 +         cv[i] = iperm[i] = 0;
 241.105 +      }
 241.106 +      numnz = 0;
 241.107 +      /* Main loop. */
 241.108 +      /* Each pass round this loop either results in a new assignment
 241.109 +         or gives a row with no assignment. */
 241.110 +      for (jord = 1; jord <= n; jord++)
 241.111 +      {  j = jord;
 241.112 +         pr[j] = -1;
 241.113 +         for (k = 1; k <= jord; k++)
 241.114 +         {  /* Look for a cheap assignment. */
 241.115 +            in1 = arp[j];
 241.116 +            if (in1 >= 0)
 241.117 +            {  in2 = ip[j] + lenr[j] - 1;
 241.118 +               in1 = in2 - in1;
 241.119 +               for (ii = in1; ii <= in2; ii++)
 241.120 +               {  i = icn[ii];
 241.121 +                  if (iperm[i] == 0) goto L110;
 241.122 +               }
 241.123 +               /* No cheap assignment in row. */
 241.124 +               arp[j] = -1;
 241.125 +            }
 241.126 +            /* Begin looking for assignment chain starting with row j.*/
 241.127 +            out[j] = lenr[j] - 1;
 241.128 +            /* Inner loop. Extends chain by one or backtracks. */
 241.129 +            for (kk = 1; kk <= jord; kk++)
 241.130 +            {  in1 = out[j];
 241.131 +               if (in1 >= 0)
 241.132 +               {  in2 = ip[j] + lenr[j] - 1;
 241.133 +                  in1 = in2 - in1;
 241.134 +                  /* Forward scan. */
 241.135 +                  for (ii = in1; ii <= in2; ii++)
 241.136 +                  {  i = icn[ii];
 241.137 +                     if (cv[i] != jord)
 241.138 +                     {  /* Column i has not yet been accessed during
 241.139 +                           this pass. */
 241.140 +                        j1 = j;
 241.141 +                        j = iperm[i];
 241.142 +                        cv[i] = jord;
 241.143 +                        pr[j] = j1;
 241.144 +                        out[j1] = in2 - ii - 1;
 241.145 +                        goto L100;
 241.146 +                     }
 241.147 +                  }
 241.148 +               }
 241.149 +               /* Backtracking step. */
 241.150 +               j = pr[j];
 241.151 +               if (j == -1) goto L130;
 241.152 +            }
 241.153 +L100:       ;
 241.154 +         }
 241.155 +L110:    /* New assignment is made. */
 241.156 +         iperm[i] = j;
 241.157 +         arp[j] = in2 - ii - 1;
 241.158 +         numnz++;
 241.159 +         for (k = 1; k <= jord; k++)
 241.160 +         {  j = pr[j];
 241.161 +            if (j == -1) break;
 241.162 +            ii = ip[j] + lenr[j] - out[j] - 2;
 241.163 +            i = icn[ii];
 241.164 +            iperm[i] = j;
 241.165 +         }
 241.166 +L130:    ;
 241.167 +      }
 241.168 +      /* If matrix is structurally singular, we now complete the
 241.169 +         permutation iperm. */
 241.170 +      if (numnz < n)
 241.171 +      {  for (i = 1; i <= n; i++)
 241.172 +            arp[i] = 0;
 241.173 +         k = 0;
 241.174 +         for (i = 1; i <= n; i++)
 241.175 +         {  if (iperm[i] == 0)
 241.176 +               out[++k] = i;
 241.177 +            else
 241.178 +               arp[iperm[i]] = i;
 241.179 +         }
 241.180 +         k = 0;
 241.181 +         for (i = 1; i <= n; i++)
 241.182 +         {  if (arp[i] == 0)
 241.183 +               iperm[out[++k]] = i;
 241.184 +         }
 241.185 +      }
 241.186 +      return numnz;
 241.187 +}
 241.188 +
 241.189 +/**********************************************************************/
 241.190 +
 241.191 +#if 0
 241.192 +#include "glplib.h"
 241.193 +
 241.194 +int sing;
 241.195 +
 241.196 +void ranmat(int m, int n, int icn[], int iptr[], int nnnp1, int *knum,
 241.197 +      int iw[]);
 241.198 +
 241.199 +void fa01bs(int max, int *nrand);
 241.200 +
 241.201 +int main(void)
 241.202 +{     /* test program for the routine mc21a */
 241.203 +      /* these runs on random matrices cause all possible statements in
 241.204 +         mc21a to be executed */
 241.205 +      int i, iold, j, j1, j2, jj, knum, l, licn, n, nov4, num, numnz;
 241.206 +      int ip[1+21], icn[1+1000], iperm[1+20], lenr[1+20], iw1[1+80];
 241.207 +      licn = 1000;
 241.208 +      /* run on random matrices of orders 1 through 20 */
 241.209 +      for (n = 1; n <= 20; n++)
 241.210 +      {  nov4 = n / 4;
 241.211 +         if (nov4 < 1) nov4 = 1;
 241.212 +L10:     fa01bs(nov4, &l);
 241.213 +         knum = l * n;
 241.214 +         /* knum is requested number of non-zeros in random matrix */
 241.215 +         if (knum > licn) goto L10;
 241.216 +         /* if sing is false, matrix is guaranteed structurally
 241.217 +            non-singular */
 241.218 +         sing = ((n / 2) * 2 == n);
 241.219 +         /* call to subroutine to generate random matrix */
 241.220 +         ranmat(n, n, icn, ip, n+1, &knum, iw1);
 241.221 +         /* knum is now actual number of non-zeros in random matrix */
 241.222 +         if (knum > licn) goto L10;
 241.223 +         xprintf("n = %2d; nz = %4d; sing = %d\n", n, knum, sing);
 241.224 +         /* set up array of row lengths */
 241.225 +         for (i = 1; i <= n; i++)
 241.226 +            lenr[i] = ip[i+1] - ip[i];
 241.227 +         /* call to mc21a */
 241.228 +         numnz = mc21a(n, icn, ip, lenr, iperm, &iw1[0], &iw1[n],
 241.229 +            &iw1[n+n], &iw1[n+n+n]);
 241.230 +         /* testing to see if there are numnz non-zeros on the diagonal
 241.231 +            of the permuted matrix. */
 241.232 +         num = 0;
 241.233 +         for (i = 1; i <= n; i++)
 241.234 +         {  iold = iperm[i];
 241.235 +            j1 = ip[iold];
 241.236 +            j2 = j1 + lenr[iold] - 1;
 241.237 +            if (j2 < j1) continue;
 241.238 +            for (jj = j1; jj <= j2; jj++)
 241.239 +            {  j = icn[jj];
 241.240 +               if (j == i)
 241.241 +               {  num++;
 241.242 +                  break;
 241.243 +               }
 241.244 +            }
 241.245 +         }
 241.246 +         if (num != numnz)
 241.247 +            xprintf("Failure in mc21a, numnz = %d instead of %d\n",
 241.248 +               numnz, num);
 241.249 +      }
 241.250 +      return 0;
 241.251 +}
 241.252 +
 241.253 +void ranmat(int m, int n, int icn[], int iptr[], int nnnp1, int *knum,
 241.254 +      int iw[])
 241.255 +{     /* subroutine to generate random matrix */
 241.256 +      int i, ii, inum, j, lrow, matnum;
 241.257 +      inum = (*knum / n) * 2;
 241.258 +      if (inum > n-1) inum = n-1;
 241.259 +      matnum = 1;
 241.260 +      /* each pass through this loop generates a row of the matrix */
 241.261 +      for (j = 1; j <= m; j++)
 241.262 +      {  iptr[j] = matnum;
 241.263 +         if (!(sing || j > n))
 241.264 +            icn[matnum++] = j;
 241.265 +         if (n == 1) continue;
 241.266 +         for (i = 1; i <= n; i++) iw[i] = 0;
 241.267 +         if (!sing) iw[j] = 1;
 241.268 +         fa01bs(inum, &lrow);
 241.269 +         lrow--;
 241.270 +         if (lrow == 0) continue;
 241.271 +         /* lrow off-diagonal non-zeros in row j of the matrix */
 241.272 +         for (ii = 1; ii <= lrow; ii++)
 241.273 +         {  for (;;)
 241.274 +            {  fa01bs(n, &i);
 241.275 +               if (iw[i] != 1) break;
 241.276 +            }
 241.277 +            iw[i] = 1;
 241.278 +            icn[matnum++] = i;
 241.279 +         }
 241.280 +      }
 241.281 +      for (i = m+1; i <= nnnp1; i++)
 241.282 +         iptr[i] = matnum;
 241.283 +      *knum = matnum - 1;
 241.284 +      return;
 241.285 +}
 241.286 +
 241.287 +double g = 1431655765.0;
 241.288 +
 241.289 +double fa01as(int i)
 241.290 +{     /* random number generator */
 241.291 +      g = fmod(g * 9228907.0, 4294967296.0);
 241.292 +      if (i >= 0)
 241.293 +         return g / 4294967296.0;
 241.294 +      else
 241.295 +         return 2.0 * g / 4294967296.0 - 1.0;
 241.296 +}
 241.297 +
 241.298 +void fa01bs(int max, int *nrand)
 241.299 +{     *nrand = (int)(fa01as(1) * (double)max) + 1;
 241.300 +      return;
 241.301 +}
 241.302 +#endif
 241.303 +
 241.304 +/* eof */
   242.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   242.2 +++ b/src/glpnet02.c	Mon Dec 06 13:09:21 2010 +0100
   242.3 @@ -0,0 +1,314 @@
   242.4 +/* glpnet02.c (permutations to block triangular form) */
   242.5 +
   242.6 +/***********************************************************************
   242.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   242.8 +*
   242.9 +*  This code is the result of translation of the Fortran subroutines
  242.10 +*  MC13D and MC13E associated with the following paper:
  242.11 +*
  242.12 +*  I.S.Duff, J.K.Reid, Algorithm 529: Permutations to block triangular
  242.13 +*  form, ACM Trans. on Math. Softw. 4 (1978), 189-192.
  242.14 +*
  242.15 +*  Use of ACM Algorithms is subject to the ACM Software Copyright and
  242.16 +*  License Agreement. See <http://www.acm.org/publications/policies>.
  242.17 +*
  242.18 +*  The translation was made by Andrew Makhorin <mao@gnu.org>.
  242.19 +*
  242.20 +*  GLPK is free software: you can redistribute it and/or modify it
  242.21 +*  under the terms of the GNU General Public License as published by
  242.22 +*  the Free Software Foundation, either version 3 of the License, or
  242.23 +*  (at your option) any later version.
  242.24 +*
  242.25 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  242.26 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  242.27 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  242.28 +*  License for more details.
  242.29 +*
  242.30 +*  You should have received a copy of the GNU General Public License
  242.31 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  242.32 +***********************************************************************/
  242.33 +
  242.34 +#include "glpnet.h"
  242.35 +
  242.36 +/***********************************************************************
  242.37 +*  NAME
  242.38 +*
  242.39 +*  mc13d - permutations to block triangular form
  242.40 +*
  242.41 +*  SYNOPSIS
  242.42 +*
  242.43 +*  #include "glpnet.h"
  242.44 +*  int mc13d(int n, const int icn[], const int ip[], const int lenr[],
  242.45 +*     int ior[], int ib[], int lowl[], int numb[], int prev[]);
  242.46 +*
  242.47 +*  DESCRIPTION
  242.48 +*
  242.49 +*  Given the column numbers of the nonzeros in each row of the sparse
  242.50 +*  matrix, the routine mc13d finds a symmetric permutation that makes
  242.51 +*  the matrix block lower triangular.
  242.52 +*
  242.53 +*  INPUT PARAMETERS
  242.54 +*
  242.55 +*  n     order of the matrix.
  242.56 +*
  242.57 +*  icn   array containing the column indices of the non-zeros. Those
  242.58 +*        belonging to a single row must be contiguous but the ordering
  242.59 +*        of column indices within each row is unimportant and wasted
  242.60 +*        space between rows is permitted.
  242.61 +*
  242.62 +*  ip    ip[i], i = 1,2,...,n, is the position in array icn of the
  242.63 +*        first column index of a non-zero in row i.
  242.64 +*
  242.65 +*  lenr  lenr[i], i = 1,2,...,n, is the number of non-zeros in row i.
  242.66 +*
  242.67 +*  OUTPUT PARAMETERS
  242.68 +*
  242.69 +*  ior   ior[i], i = 1,2,...,n, gives the position on the original
  242.70 +*        ordering of the row or column which is in position i in the
  242.71 +*        permuted form.
  242.72 +*
  242.73 +*  ib    ib[i], i = 1,2,...,num, is the row number in the permuted
  242.74 +*        matrix of the beginning of block i, 1 <= num <= n.
  242.75 +*
  242.76 +*  WORKING ARRAYS
  242.77 +*
  242.78 +*  arp   working array of length [1+n], where arp[0] is not used.
  242.79 +*        arp[i] is one less than the number of unsearched edges leaving
  242.80 +*        node i. At the end of the algorithm it is set to a permutation
  242.81 +*        which puts the matrix in block lower triangular form.
  242.82 +*
  242.83 +*  ib    working array of length [1+n], where ib[0] is not used.
  242.84 +*        ib[i] is the position in the ordering of the start of the ith
  242.85 +*        block. ib[n+1-i] holds the node number of the ith node on the
  242.86 +*        stack.
  242.87 +*
  242.88 +*  lowl  working array of length [1+n], where lowl[0] is not used.
  242.89 +*        lowl[i] is the smallest stack position of any node to which a
  242.90 +*        path from node i has been found. It is set to n+1 when node i
  242.91 +*        is removed from the stack.
  242.92 +*
  242.93 +*  numb  working array of length [1+n], where numb[0] is not used.
  242.94 +*        numb[i] is the position of node i in the stack if it is on it,
  242.95 +*        is the permuted order of node i for those nodes whose final
  242.96 +*        position has been found and is otherwise zero.
  242.97 +*
  242.98 +*  prev  working array of length [1+n], where prev[0] is not used.
  242.99 +*        prev[i] is the node at the end of the path when node i was
 242.100 +*        placed on the stack.
 242.101 +*
 242.102 +*  RETURNS
 242.103 +*
 242.104 +*  The routine mc13d returns num, the number of blocks found. */
 242.105 +
 242.106 +int mc13d(int n, const int icn[], const int ip[], const int lenr[],
 242.107 +      int ior[], int ib[], int lowl[], int numb[], int prev[])
 242.108 +{     int *arp = ior;
 242.109 +      int dummy, i, i1, i2, icnt, ii, isn, ist, ist1, iv, iw, j, lcnt,
 242.110 +         nnm1, num, stp;
 242.111 +      /* icnt is the number of nodes whose positions in final ordering
 242.112 +         have been found. */
 242.113 +      icnt = 0;
 242.114 +      /* num is the number of blocks that have been found. */
 242.115 +      num = 0;
 242.116 +      nnm1 = n + n - 1;
 242.117 +      /* Initialization of arrays. */
 242.118 +      for (j = 1; j <= n; j++)
 242.119 +      {  numb[j] = 0;
 242.120 +         arp[j] = lenr[j] - 1;
 242.121 +      }
 242.122 +      for (isn = 1; isn <= n; isn++)
 242.123 +      {  /* Look for a starting node. */
 242.124 +         if (numb[isn] != 0) continue;
 242.125 +         iv = isn;
 242.126 +         /* ist is the number of nodes on the stack ... it is the stack
 242.127 +            pointer. */
 242.128 +         ist = 1;
 242.129 +         /* Put node iv at beginning of stack. */
 242.130 +         lowl[iv] = numb[iv] = 1;
 242.131 +         ib[n] = iv;
 242.132 +         /* The body of this loop puts a new node on the stack or
 242.133 +            backtracks. */
 242.134 +         for (dummy = 1; dummy <= nnm1; dummy++)
 242.135 +         {  i1 = arp[iv];
 242.136 +            /* Have all edges leaving node iv been searched? */
 242.137 +            if (i1 >= 0)
 242.138 +            {  i2 = ip[iv] + lenr[iv] - 1;
 242.139 +               i1 = i2 - i1;
 242.140 +               /* Look at edges leaving node iv until one enters a new
 242.141 +                  node or all edges are exhausted. */
 242.142 +               for (ii = i1; ii <= i2; ii++)
 242.143 +               {  iw = icn[ii];
 242.144 +                  /* Has node iw been on stack already? */
 242.145 +                  if (numb[iw] == 0) goto L70;
 242.146 +                  /* Update value of lowl[iv] if necessary. */
 242.147 +                  if (lowl[iw] < lowl[iv]) lowl[iv] = lowl[iw];
 242.148 +               }
 242.149 +               /* There are no more edges leaving node iv. */
 242.150 +               arp[iv] = -1;
 242.151 +            }
 242.152 +            /* Is node iv the root of a block? */
 242.153 +            if (lowl[iv] < numb[iv]) goto L60;
 242.154 +            /* Order nodes in a block. */
 242.155 +            num++;
 242.156 +            ist1 = n + 1 - ist;
 242.157 +            lcnt = icnt + 1;
 242.158 +            /* Peel block off the top of the stack starting at the top
 242.159 +               and working down to the root of the block. */
 242.160 +            for (stp = ist1; stp <= n; stp++)
 242.161 +            {  iw = ib[stp];
 242.162 +               lowl[iw] = n + 1;
 242.163 +               numb[iw] = ++icnt;
 242.164 +               if (iw == iv) break;
 242.165 +            }
 242.166 +            ist = n - stp;
 242.167 +            ib[num] = lcnt;
 242.168 +            /* Are there any nodes left on the stack? */
 242.169 +            if (ist != 0) goto L60;
 242.170 +            /* Have all the nodes been ordered? */
 242.171 +            if (icnt < n) break;
 242.172 +            goto L100;
 242.173 +L60:        /* Backtrack to previous node on path. */
 242.174 +            iw = iv;
 242.175 +            iv = prev[iv];
 242.176 +            /* Update value of lowl[iv] if necessary. */
 242.177 +            if (lowl[iw] < lowl[iv]) lowl[iv] = lowl[iw];
 242.178 +            continue;
 242.179 +L70:        /* Put new node on the stack. */
 242.180 +            arp[iv] = i2 - ii - 1;
 242.181 +            prev[iw] = iv;
 242.182 +            iv = iw;
 242.183 +            lowl[iv] = numb[iv] = ++ist;
 242.184 +            ib[n+1-ist] = iv;
 242.185 +         }
 242.186 +      }
 242.187 +L100: /* Put permutation in the required form. */
 242.188 +      for (i = 1; i <= n; i++)
 242.189 +         arp[numb[i]] = i;
 242.190 +      return num;
 242.191 +}
 242.192 +
 242.193 +/**********************************************************************/
 242.194 +
 242.195 +#if 0
 242.196 +#include "glplib.h"
 242.197 +
 242.198 +void test(int n, int ipp);
 242.199 +
 242.200 +int main(void)
 242.201 +{     /* test program for routine mc13d */
 242.202 +      test( 1,   0);
 242.203 +      test( 2,   1);
 242.204 +      test( 2,   2);
 242.205 +      test( 3,   3);
 242.206 +      test( 4,   4);
 242.207 +      test( 5,  10);
 242.208 +      test(10,  10);
 242.209 +      test(10,  20);
 242.210 +      test(20,  20);
 242.211 +      test(20,  50);
 242.212 +      test(50,  50);
 242.213 +      test(50, 200);
 242.214 +      return 0;
 242.215 +}
 242.216 +
 242.217 +void fa01bs(int max, int *nrand);
 242.218 +
 242.219 +void setup(int n, char a[1+50][1+50], int ip[], int icn[], int lenr[]);
 242.220 +
 242.221 +void test(int n, int ipp)
 242.222 +{     int ip[1+50], icn[1+1000], ior[1+50], ib[1+51], iw[1+150],
 242.223 +         lenr[1+50];
 242.224 +      char a[1+50][1+50], hold[1+100];
 242.225 +      int i, ii, iblock, ij, index, j, jblock, jj, k9, num;
 242.226 +      xprintf("\n\n\nMatrix is of order %d and has %d off-diagonal non-"
 242.227 +         "zeros\n", n, ipp);
 242.228 +      for (j = 1; j <= n; j++)
 242.229 +      {  for (i = 1; i <= n; i++)
 242.230 +            a[i][j] = 0;
 242.231 +         a[j][j] = 1;
 242.232 +      }
 242.233 +      for (k9 = 1; k9 <= ipp; k9++)
 242.234 +      {  /* these statements should be replaced by calls to your
 242.235 +            favorite random number generator to place two pseudo-random
 242.236 +            numbers between 1 and n in the variables i and j */
 242.237 +         for (;;)
 242.238 +         {  fa01bs(n, &i);
 242.239 +            fa01bs(n, &j);
 242.240 +            if (!a[i][j]) break;
 242.241 +         }
 242.242 +         a[i][j] = 1;
 242.243 +      }
 242.244 +      /* setup converts matrix a[i,j] to required sparsity-oriented
 242.245 +         storage format */
 242.246 +      setup(n, a, ip, icn, lenr);
 242.247 +      num = mc13d(n, icn, ip, lenr, ior, ib, &iw[0], &iw[n], &iw[n+n]);
 242.248 +      /* output reordered matrix with blocking to improve clarity */
 242.249 +      xprintf("\nThe reordered matrix which has %d block%s is of the fo"
 242.250 +         "rm\n", num, num == 1 ? "" : "s");
 242.251 +      ib[num+1] = n + 1;
 242.252 +      index = 100;
 242.253 +      iblock = 1;
 242.254 +      for (i = 1; i <= n; i++)
 242.255 +      {  for (ij = 1; ij <= index; ij++)
 242.256 +            hold[ij] = ' ';
 242.257 +         if (i == ib[iblock])
 242.258 +         {  xprintf("\n");
 242.259 +            iblock++;
 242.260 +         }
 242.261 +         jblock = 1;
 242.262 +         index = 0;
 242.263 +         for (j = 1; j <= n; j++)
 242.264 +         {  if (j == ib[jblock])
 242.265 +            {  hold[++index] = ' ';
 242.266 +               jblock++;
 242.267 +            }
 242.268 +            ii = ior[i];
 242.269 +            jj = ior[j];
 242.270 +            hold[++index] = (char)(a[ii][jj] ? 'X' : '0');
 242.271 +         }
 242.272 +         xprintf("%.*s\n", index, &hold[1]);
 242.273 +      }
 242.274 +      xprintf("\nThe starting point for each block is given by\n");
 242.275 +      for (i = 1; i <= num; i++)
 242.276 +      {  if ((i - 1) % 12 == 0) xprintf("\n");
 242.277 +         xprintf(" %4d", ib[i]);
 242.278 +      }
 242.279 +      xprintf("\n");
 242.280 +      return;
 242.281 +}
 242.282 +
 242.283 +void setup(int n, char a[1+50][1+50], int ip[], int icn[], int lenr[])
 242.284 +{     int i, j, ind;
 242.285 +      for (i = 1; i <= n; i++)
 242.286 +         lenr[i] = 0;
 242.287 +      ind = 1;
 242.288 +      for (i = 1; i <= n; i++)
 242.289 +      {  ip[i] = ind;
 242.290 +         for (j = 1; j <= n; j++)
 242.291 +         {  if (a[i][j])
 242.292 +            {  lenr[i]++;
 242.293 +               icn[ind++] = j;
 242.294 +            }
 242.295 +         }
 242.296 +      }
 242.297 +      return;
 242.298 +}
 242.299 +
 242.300 +double g = 1431655765.0;
 242.301 +
 242.302 +double fa01as(int i)
 242.303 +{     /* random number generator */
 242.304 +      g = fmod(g * 9228907.0, 4294967296.0);
 242.305 +      if (i >= 0)
 242.306 +         return g / 4294967296.0;
 242.307 +      else
 242.308 +         return 2.0 * g / 4294967296.0 - 1.0;
 242.309 +}
 242.310 +
 242.311 +void fa01bs(int max, int *nrand)
 242.312 +{     *nrand = (int)(fa01as(1) * (double)max) + 1;
 242.313 +      return;
 242.314 +}
 242.315 +#endif
 242.316 +
 242.317 +/* eof */
   243.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   243.2 +++ b/src/glpnet03.c	Mon Dec 06 13:09:21 2010 +0100
   243.3 @@ -0,0 +1,776 @@
   243.4 +/* glpnet03.c (Klingman's network problem generator) */
   243.5 +
   243.6 +/***********************************************************************
   243.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   243.8 +*
   243.9 +*  This code is the result of translation of the Fortran program NETGEN
  243.10 +*  developed by Dr. Darwin Klingman, which is publically available from
  243.11 +*  NETLIB at <http://www.netlib.org/lp/generators>.
  243.12 +*
  243.13 +*  The translation was made by Andrew Makhorin <mao@gnu.org>.
  243.14 +*
  243.15 +*  GLPK is free software: you can redistribute it and/or modify it
  243.16 +*  under the terms of the GNU General Public License as published by
  243.17 +*  the Free Software Foundation, either version 3 of the License, or
  243.18 +*  (at your option) any later version.
  243.19 +*
  243.20 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  243.21 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  243.22 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  243.23 +*  License for more details.
  243.24 +*
  243.25 +*  You should have received a copy of the GNU General Public License
  243.26 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  243.27 +***********************************************************************/
  243.28 +
  243.29 +#include "glpapi.h"
  243.30 +
  243.31 +/***********************************************************************
  243.32 +*  NAME
  243.33 +*
  243.34 +*  glp_netgen - Klingman's network problem generator
  243.35 +*
  243.36 +*  SYNOPSIS
  243.37 +*
  243.38 +*  int glp_netgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
  243.39 +*     const int parm[1+15]);
  243.40 +*
  243.41 +*  DESCRIPTION
  243.42 +*
  243.43 +*  The routine glp_netgen is a network problem generator developed by
  243.44 +*  Dr. Darwin Klingman. It can create capacitated and uncapacitated
  243.45 +*  minimum cost flow (or transshipment), transportation, and assignment
  243.46 +*  problems.
  243.47 +*
  243.48 +*  The parameter G specifies the graph object, to which the generated
  243.49 +*  problem data have to be stored. Note that on entry the graph object
  243.50 +*  is erased with the routine glp_erase_graph.
  243.51 +*
  243.52 +*  The parameter v_rhs specifies an offset of the field of type double
  243.53 +*  in the vertex data block, to which the routine stores the supply or
  243.54 +*  demand value. If v_rhs < 0, the value is not stored.
  243.55 +*
  243.56 +*  The parameter a_cap specifies an offset of the field of type double
  243.57 +*  in the arc data block, to which the routine stores the arc capacity.
  243.58 +*  If a_cap < 0, the capacity is not stored.
  243.59 +*
  243.60 +*  The parameter a_cost specifies an offset of the field of type double
  243.61 +*  in the arc data block, to which the routine stores the per-unit cost
  243.62 +*  if the arc flow. If a_cost < 0, the cost is not stored.
  243.63 +*
  243.64 +*  The array parm contains description of the network to be generated:
  243.65 +*
  243.66 +*  parm[0]           not used
  243.67 +*  parm[1]  (iseed)  8-digit positive random number seed
  243.68 +*  parm[2]  (nprob)  8-digit problem id number
  243.69 +*  parm[3]  (nodes)  total number of nodes
  243.70 +*  parm[4]  (nsorc)  total number of source nodes (including
  243.71 +*                    transshipment nodes)
  243.72 +*  parm[5]  (nsink)  total number of sink nodes (including
  243.73 +*                    transshipment nodes)
  243.74 +*  parm[6]  (iarcs)  number of arcs
  243.75 +*  parm[7]  (mincst) minimum cost for arcs
  243.76 +*  parm[8]  (maxcst) maximum cost for arcs
  243.77 +*  parm[9]  (itsup)  total supply
  243.78 +*  parm[10] (ntsorc) number of transshipment source nodes
  243.79 +*  parm[11] (ntsink) number of transshipment sink nodes
  243.80 +*  parm[12] (iphic)  percentage of skeleton arcs to be given
  243.81 +*                    the maximum cost
  243.82 +*  parm[13] (ipcap)  percentage of arcs to be capacitated
  243.83 +*  parm[14] (mincap) minimum upper bound for capacitated arcs
  243.84 +*  parm[15] (maxcap) maximum upper bound for capacitated arcs
  243.85 +*
  243.86 +*  The routine generates a transportation problem if:
  243.87 +*
  243.88 +*     nsorc + nsink = nodes, ntsorc = 0, and ntsink = 0.
  243.89 +*
  243.90 +*  The routine generates an assignment problem if the requirements for
  243.91 +*  a transportation problem are met and:
  243.92 +*
  243.93 +*     nsorc = nsink and itsup = nsorc.
  243.94 +*
  243.95 +*  RETURNS
  243.96 +*
  243.97 +*  If the instance was successfully generated, the routine glp_netgen
  243.98 +*  returns zero; otherwise, if specified parameters are inconsistent,
  243.99 +*  the routine returns a non-zero error code.
 243.100 +*
 243.101 +*  REFERENCES
 243.102 +*
 243.103 +*  D.Klingman, A.Napier, and J.Stutz. NETGEN: A program for generating
 243.104 +*  large scale capacitated assignment, transportation, and minimum cost
 243.105 +*  flow networks. Management Science 20 (1974), 814-20. */
 243.106 +
 243.107 +struct csa
 243.108 +{     /* common storage area */
 243.109 +      glp_graph *G;
 243.110 +      int v_rhs, a_cap, a_cost;
 243.111 +      int nodes, iarcs, mincst, maxcst, itsup, nsorc, nsink, nonsor,
 243.112 +         nfsink, narcs, nsort, nftsor, ipcap, mincap, maxcap, ktl,
 243.113 +         nodlft, *ipred, *ihead, *itail, *iflag, *isup, *lsinks, mult,
 243.114 +         modul, i15, i16, jran;
 243.115 +};
 243.116 +
 243.117 +#define G      (csa->G)
 243.118 +#define v_rhs  (csa->v_rhs)
 243.119 +#define a_cap  (csa->a_cap)
 243.120 +#define a_cost (csa->a_cost)
 243.121 +#define nodes  (csa->nodes)
 243.122 +#define iarcs  (csa->iarcs)
 243.123 +#define mincst (csa->mincst)
 243.124 +#define maxcst (csa->maxcst)
 243.125 +#define itsup  (csa->itsup)
 243.126 +#define nsorc  (csa->nsorc)
 243.127 +#define nsink  (csa->nsink)
 243.128 +#define nonsor (csa->nonsor)
 243.129 +#define nfsink (csa->nfsink)
 243.130 +#define narcs  (csa->narcs)
 243.131 +#define nsort  (csa->nsort)
 243.132 +#define nftsor (csa->nftsor)
 243.133 +#define ipcap  (csa->ipcap)
 243.134 +#define mincap (csa->mincap)
 243.135 +#define maxcap (csa->maxcap)
 243.136 +#define ktl    (csa->ktl)
 243.137 +#define nodlft (csa->nodlft)
 243.138 +#if 0
 243.139 +/* spent a day to find out this bug */
 243.140 +#define ist    (csa->ist)
 243.141 +#else
 243.142 +#define ist    (ipred[0])
 243.143 +#endif
 243.144 +#define ipred  (csa->ipred)
 243.145 +#define ihead  (csa->ihead)
 243.146 +#define itail  (csa->itail)
 243.147 +#define iflag  (csa->iflag)
 243.148 +#define isup   (csa->isup)
 243.149 +#define lsinks (csa->lsinks)
 243.150 +#define mult   (csa->mult)
 243.151 +#define modul  (csa->modul)
 243.152 +#define i15    (csa->i15)
 243.153 +#define i16    (csa->i16)
 243.154 +#define jran   (csa->jran)
 243.155 +
 243.156 +static void cresup(struct csa *csa);
 243.157 +static void chain(struct csa *csa, int lpick, int lsorc);
 243.158 +static void chnarc(struct csa *csa, int lsorc);
 243.159 +static void sort(struct csa *csa);
 243.160 +static void pickj(struct csa *csa, int it);
 243.161 +static void assign(struct csa *csa);
 243.162 +static void setran(struct csa *csa, int iseed);
 243.163 +static int iran(struct csa *csa, int ilow, int ihigh);
 243.164 +
 243.165 +int glp_netgen(glp_graph *G_, int _v_rhs, int _a_cap, int _a_cost,
 243.166 +      const int parm[1+15])
 243.167 +{     struct csa _csa, *csa = &_csa;
 243.168 +      int iseed, nprob, ntsorc, ntsink, iphic, i, nskel, nltr, ltsink,
 243.169 +         ntrans, npsink, nftr, npsorc, ntravl, ntrrem, lsorc, lpick,
 243.170 +         nsksr, nsrchn, j, item, l, ks, k, ksp, li, n, ii, it, ih, icap,
 243.171 +         jcap, icost, jcost, ret;
 243.172 +      G = G_;
 243.173 +      v_rhs = _v_rhs;
 243.174 +      a_cap = _a_cap;
 243.175 +      a_cost = _a_cost;
 243.176 +      if (G != NULL)
 243.177 +      {  if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
 243.178 +            xerror("glp_netgen: v_rhs = %d; invalid offset\n", v_rhs);
 243.179 +         if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
 243.180 +            xerror("glp_netgen: a_cap = %d; invalid offset\n", a_cap);
 243.181 +         if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
 243.182 +            xerror("glp_netgen: a_cost = %d; invalid offset\n", a_cost);
 243.183 +      }
 243.184 +      /* Input the user's random number seed and fix it if
 243.185 +         non-positive. */
 243.186 +      iseed = parm[1];
 243.187 +      nprob = parm[2];
 243.188 +      if (iseed <= 0) iseed = 13502460;
 243.189 +      setran(csa, iseed);
 243.190 +      /* Input the user's problem characteristics. */
 243.191 +      nodes = parm[3];
 243.192 +      nsorc = parm[4];
 243.193 +      nsink = parm[5];
 243.194 +      iarcs = parm[6];
 243.195 +      mincst = parm[7];
 243.196 +      maxcst = parm[8];
 243.197 +      itsup = parm[9];
 243.198 +      ntsorc = parm[10];
 243.199 +      ntsink = parm[11];
 243.200 +      iphic = parm[12];
 243.201 +      ipcap = parm[13];
 243.202 +      mincap = parm[14];
 243.203 +      maxcap = parm[15];
 243.204 +      /* Check the size of the problem. */
 243.205 +      if (!(10 <= nodes && nodes <= 100000))
 243.206 +      {  ret = 1;
 243.207 +         goto done;
 243.208 +      }
 243.209 +      /* Check user supplied parameters for consistency. */
 243.210 +      if (!(nsorc >= 0 && nsink >= 0 && nsorc + nsink <= nodes))
 243.211 +      {  ret = 2;
 243.212 +         goto done;
 243.213 +      }
 243.214 +      if (iarcs < 0)
 243.215 +      {  ret = 3;
 243.216 +         goto done;
 243.217 +      }
 243.218 +      if (mincst > maxcst)
 243.219 +      {  ret = 4;
 243.220 +         goto done;
 243.221 +      }
 243.222 +      if (itsup < 0)
 243.223 +      {  ret = 5;
 243.224 +         goto done;
 243.225 +      }
 243.226 +      if (!(0 <= ntsorc && ntsorc <= nsorc))
 243.227 +      {  ret = 6;
 243.228 +         goto done;
 243.229 +      }
 243.230 +      if (!(0 <= ntsink && ntsink <= nsink))
 243.231 +      {  ret = 7;
 243.232 +         goto done;
 243.233 +      }
 243.234 +      if (!(0 <= iphic && iphic <= 100))
 243.235 +      {  ret = 8;
 243.236 +         goto done;
 243.237 +      }
 243.238 +      if (!(0 <= ipcap && ipcap <= 100))
 243.239 +      {  ret = 9;
 243.240 +         goto done;
 243.241 +      }
 243.242 +      if (mincap > maxcap)
 243.243 +      {  ret = 10;
 243.244 +         goto done;
 243.245 +      }
 243.246 +      /* Initailize the graph object. */
 243.247 +      if (G != NULL)
 243.248 +      {  glp_erase_graph(G, G->v_size, G->a_size);
 243.249 +         glp_add_vertices(G, nodes);
 243.250 +         if (v_rhs >= 0)
 243.251 +         {  double zero = 0.0;
 243.252 +            for (i = 1; i <= nodes; i++)
 243.253 +            {  glp_vertex *v = G->v[i];
 243.254 +               memcpy((char *)v->data + v_rhs, &zero, sizeof(double));
 243.255 +            }
 243.256 +         }
 243.257 +      }
 243.258 +      /* Allocate working arrays. */
 243.259 +      ipred = xcalloc(1+nodes, sizeof(int));
 243.260 +      ihead = xcalloc(1+nodes, sizeof(int));
 243.261 +      itail = xcalloc(1+nodes, sizeof(int));
 243.262 +      iflag = xcalloc(1+nodes, sizeof(int));
 243.263 +      isup = xcalloc(1+nodes, sizeof(int));
 243.264 +      lsinks = xcalloc(1+nodes, sizeof(int));
 243.265 +      /* Print the problem documentation records. */
 243.266 +      if (G == NULL)
 243.267 +      {  xprintf("BEGIN\n");
 243.268 +         xprintf("NETGEN PROBLEM%8d%10s%10d NODES AND%10d ARCS\n",
 243.269 +            nprob, "", nodes, iarcs);
 243.270 +         xprintf("USER:%11d%11d%11d%11d%11d%11d\nDATA:%11d%11d%11d%11d%"
 243.271 +            "11d%11d\n", iseed, nsorc, nsink, mincst,
 243.272 +            maxcst, itsup, ntsorc, ntsink, iphic, ipcap,
 243.273 +            mincap, maxcap);
 243.274 +      }
 243.275 +      else
 243.276 +         glp_set_graph_name(G, "NETGEN");
 243.277 +      /* Set various constants used in the program. */
 243.278 +      narcs = 0;
 243.279 +      nskel = 0;
 243.280 +      nltr = nodes - nsink;
 243.281 +      ltsink = nltr + ntsink;
 243.282 +      ntrans = nltr - nsorc;
 243.283 +      nfsink = nltr + 1;
 243.284 +      nonsor = nodes - nsorc + ntsorc;
 243.285 +      npsink = nsink - ntsink;
 243.286 +      nodlft = nodes - nsink + ntsink;
 243.287 +      nftr = nsorc + 1;
 243.288 +      nftsor = nsorc - ntsorc + 1;
 243.289 +      npsorc = nsorc - ntsorc;
 243.290 +      /* Randomly distribute the supply among the source nodes. */
 243.291 +      if (npsorc + npsink == nodes && npsorc == npsink &&
 243.292 +          itsup == nsorc)
 243.293 +      {  assign(csa);
 243.294 +         nskel = nsorc;
 243.295 +         goto L390;
 243.296 +      }
 243.297 +      cresup(csa);
 243.298 +      /* Print the supply records. */
 243.299 +      if (G == NULL)
 243.300 +      {  xprintf("SUPPLY\n");
 243.301 +         for (i = 1; i <= nsorc; i++)
 243.302 +            xprintf("%6s%6d%18s%10d\n", "", i, "", isup[i]);
 243.303 +         xprintf("ARCS\n");
 243.304 +      }
 243.305 +      else
 243.306 +      {  if (v_rhs >= 0)
 243.307 +         {  for (i = 1; i <= nsorc; i++)
 243.308 +            {  double temp = (double)isup[i];
 243.309 +               glp_vertex *v = G->v[i];
 243.310 +               memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
 243.311 +            }
 243.312 +         }
 243.313 +      }
 243.314 +      /* Make the sources point to themselves in ipred array. */
 243.315 +      for (i = 1; i <= nsorc; i++)
 243.316 +         ipred[i] = i;
 243.317 +      if (ntrans == 0) goto L170;
 243.318 +      /* Chain the transshipment nodes together in the ipred array. */
 243.319 +      ist = nftr;
 243.320 +      ipred[nltr] = 0;
 243.321 +      for (i = nftr; i < nltr; i++)
 243.322 +         ipred[i] = i+1;
 243.323 +      /* Form even length chains for 60 percent of the transshipments.*/
 243.324 +      ntravl = 6 * ntrans / 10;
 243.325 +      ntrrem = ntrans - ntravl;
 243.326 +L140: lsorc = 1;
 243.327 +      while (ntravl != 0)
 243.328 +      {  lpick = iran(csa, 1, ntravl + ntrrem);
 243.329 +         ntravl--;
 243.330 +         chain(csa, lpick, lsorc);
 243.331 +         if (lsorc == nsorc) goto L140;
 243.332 +         lsorc++;
 243.333 +      }
 243.334 +      /* Add the remaining transshipments to the chains. */
 243.335 +      while (ntrrem != 0)
 243.336 +      {
 243.337 +         lpick = iran(csa, 1, ntrrem);
 243.338 +         ntrrem--;
 243.339 +         lsorc = iran(csa, 1, nsorc);
 243.340 +         chain(csa, lpick, lsorc);
 243.341 +      }
 243.342 +L170: /* Set all demands equal to zero. */
 243.343 +      for (i = nfsink; i <= nodes; i++)
 243.344 +         ipred[i] = 0;
 243.345 +      /* The following loop takes one chain at a time (through the use
 243.346 +         of logic contained in the loop and calls to other routines) and
 243.347 +         creates the remaining network arcs. */
 243.348 +      for (lsorc = 1; lsorc <= nsorc; lsorc++)
 243.349 +      {  chnarc(csa, lsorc);
 243.350 +         for (i = nfsink; i <= nodes; i++)
 243.351 +            iflag[i] = 0;
 243.352 +         /* Choose the number of sinks to be hooked up to the current
 243.353 +            chain. */
 243.354 +         if (ntrans != 0)
 243.355 +            nsksr = (nsort * 2 * nsink) / ntrans;
 243.356 +         else
 243.357 +            nsksr = nsink / nsorc + 1;
 243.358 +         if (nsksr < 2) nsksr = 2;
 243.359 +         if (nsksr > nsink) nsksr = nsink;
 243.360 +         nsrchn = nsort;
 243.361 +         /* Randomly pick nsksr sinks and put their names in lsinks. */
 243.362 +         ktl = nsink;
 243.363 +         for (j = 1; j <= nsksr; j++)
 243.364 +         {  item = iran(csa, 1, ktl);
 243.365 +            ktl--;
 243.366 +            for (l = nfsink; l <= nodes; l++)
 243.367 +            {  if (iflag[l] != 1)
 243.368 +               {  item--;
 243.369 +                  if (item == 0) goto L230;
 243.370 +               }
 243.371 +            }
 243.372 +            break;
 243.373 +L230:       lsinks[j] = l;
 243.374 +            iflag[l] = 1;
 243.375 +         }
 243.376 +         /* If last source chain, add all sinks with zero demand to
 243.377 +            lsinks list. */
 243.378 +         if (lsorc == nsorc)
 243.379 +         {  for (j = nfsink; j <= nodes; j++)
 243.380 +            {  if (ipred[j] == 0 && iflag[j] != 1)
 243.381 +               {  nsksr++;
 243.382 +                  lsinks[nsksr] = j;
 243.383 +                  iflag[j] = 1;
 243.384 +               }
 243.385 +            }
 243.386 +         }
 243.387 +         /* Create demands for group of sinks in lsinks. */
 243.388 +         ks = isup[lsorc] / nsksr;
 243.389 +         k = ipred[lsorc];
 243.390 +         for (i = 1; i <= nsksr; i++)
 243.391 +         {  nsort++;
 243.392 +            ksp = iran(csa, 1, ks);
 243.393 +            j = iran(csa, 1, nsksr);
 243.394 +            itail[nsort] = k;
 243.395 +            li = lsinks[i];
 243.396 +            ihead[nsort] = li;
 243.397 +            ipred[li] += ksp;
 243.398 +            li = lsinks[j];
 243.399 +            ipred[li] += ks - ksp;
 243.400 +            n = iran(csa, 1, nsrchn);
 243.401 +            k = lsorc;
 243.402 +            for (ii = 1; ii <= n; ii++)
 243.403 +               k = ipred[k];
 243.404 +         }
 243.405 +         li = lsinks[1];
 243.406 +         ipred[li] += isup[lsorc] - ks * nsksr;
 243.407 +         nskel += nsort;
 243.408 +         /* Sort the arcs in the chain from source lsorc using itail as
 243.409 +            sort key. */
 243.410 +         sort(csa);
 243.411 +         /* Print this part of skeleton and create the arcs for these
 243.412 +            nodes. */
 243.413 +         i = 1;
 243.414 +         itail[nsort+1] = 0;
 243.415 +L300:    for (j = nftsor; j <= nodes; j++)
 243.416 +            iflag[j] = 0;
 243.417 +         ktl = nonsor - 1;
 243.418 +         it = itail[i];
 243.419 +         iflag[it] = 1;
 243.420 +L320:    ih = ihead[i];
 243.421 +         iflag[ih] = 1;
 243.422 +         narcs++;
 243.423 +         ktl--;
 243.424 +         /* Determine if this skeleton arc should be capacitated. */
 243.425 +         icap = itsup;
 243.426 +         jcap = iran(csa, 1, 100);
 243.427 +         if (jcap <= ipcap)
 243.428 +         {  icap = isup[lsorc];
 243.429 +            if (mincap > icap) icap = mincap;
 243.430 +         }
 243.431 +         /* Determine if this skeleton arc should have the maximum
 243.432 +            cost. */
 243.433 +         icost = maxcst;
 243.434 +         jcost = iran(csa, 1, 100);
 243.435 +         if (jcost > iphic)
 243.436 +            icost = iran(csa, mincst, maxcst);
 243.437 +         if (G == NULL)
 243.438 +            xprintf("%6s%6d%6d%2s%10d%10d\n", "", it, ih, "", icost,
 243.439 +               icap);
 243.440 +         else
 243.441 +         {  glp_arc *a = glp_add_arc(G, it, ih);
 243.442 +            if (a_cap >= 0)
 243.443 +            {  double temp = (double)icap;
 243.444 +               memcpy((char *)a->data + a_cap, &temp, sizeof(double));
 243.445 +            }
 243.446 +            if (a_cost >= 0)
 243.447 +            {  double temp = (double)icost;
 243.448 +               memcpy((char *)a->data + a_cost, &temp, sizeof(double));
 243.449 +            }
 243.450 +         }
 243.451 +         i++;
 243.452 +         if (itail[i] == it) goto L320;
 243.453 +         pickj(csa, it);
 243.454 +         if (i <= nsort) goto L300;
 243.455 +      }
 243.456 +      /* Create arcs from the transshipment sinks. */
 243.457 +      if (ntsink != 0)
 243.458 +      {  for (i = nfsink; i <= ltsink; i++)
 243.459 +         {  for (j = nftsor; j <= nodes; j++)
 243.460 +               iflag[j] = 0;
 243.461 +            ktl = nonsor - 1;
 243.462 +            iflag[i] = 1;
 243.463 +            pickj(csa, i);
 243.464 +         }
 243.465 +      }
 243.466 +L390: /* Print the demand records and end record. */
 243.467 +      if (G == NULL)
 243.468 +      {  xprintf("DEMAND\n");
 243.469 +         for (i = nfsink; i <= nodes; i++)
 243.470 +            xprintf("%6s%6d%18s%10d\n", "", i, "", ipred[i]);
 243.471 +         xprintf("END\n");
 243.472 +      }
 243.473 +      else
 243.474 +      {  if (v_rhs >= 0)
 243.475 +         {  for (i = nfsink; i <= nodes; i++)
 243.476 +            {  double temp = - (double)ipred[i];
 243.477 +               glp_vertex *v = G->v[i];
 243.478 +               memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
 243.479 +            }
 243.480 +         }
 243.481 +      }
 243.482 +      /* Free working arrays. */
 243.483 +      xfree(ipred);
 243.484 +      xfree(ihead);
 243.485 +      xfree(itail);
 243.486 +      xfree(iflag);
 243.487 +      xfree(isup);
 243.488 +      xfree(lsinks);
 243.489 +      /* The instance has been successfully generated. */
 243.490 +      ret = 0;
 243.491 +done: return ret;
 243.492 +}
 243.493 +
 243.494 +/***********************************************************************
 243.495 +*  The routine cresup randomly distributes the total supply among the
 243.496 +*  source nodes. */
 243.497 +
 243.498 +static void cresup(struct csa *csa)
 243.499 +{     int i, j, ks, ksp;
 243.500 +      xassert(itsup > nsorc);
 243.501 +      ks = itsup / nsorc;
 243.502 +      for (i = 1; i <= nsorc; i++)
 243.503 +         isup[i] = 0;
 243.504 +      for (i = 1; i <= nsorc; i++)
 243.505 +      {  ksp = iran(csa, 1, ks);
 243.506 +         j = iran(csa, 1, nsorc);
 243.507 +         isup[i] += ksp;
 243.508 +         isup[j] += ks - ksp;
 243.509 +      }
 243.510 +      j = iran(csa, 1, nsorc);
 243.511 +      isup[j] += itsup - ks * nsorc;
 243.512 +      return;
 243.513 +}
 243.514 +
 243.515 +/***********************************************************************
 243.516 +*  The routine chain adds node lpick to the end of the chain with source
 243.517 +*  node lsorc. */
 243.518 +
 243.519 +static void chain(struct csa *csa, int lpick, int lsorc)
 243.520 +{     int i, j, k, l, m;
 243.521 +      k = 0;
 243.522 +      m = ist;
 243.523 +      for (i = 1; i <= lpick; i++)
 243.524 +      {  l = k;
 243.525 +         k = m;
 243.526 +         m = ipred[k];
 243.527 +      }
 243.528 +      ipred[l] = m;
 243.529 +      j = ipred[lsorc];
 243.530 +      ipred[k] = j;
 243.531 +      ipred[lsorc] = k;
 243.532 +      return;
 243.533 +}
 243.534 +
 243.535 +/***********************************************************************
 243.536 +*  The routine chnarc puts the arcs in the chain from source lsorc into
 243.537 +*  the ihead and itail arrays for sorting. */
 243.538 +
 243.539 +static void chnarc(struct csa *csa, int lsorc)
 243.540 +{     int ito, ifrom;
 243.541 +      nsort = 0;
 243.542 +      ito = ipred[lsorc];
 243.543 +L10:  if (ito == lsorc) return;
 243.544 +      nsort++;
 243.545 +      ifrom = ipred[ito];
 243.546 +      ihead[nsort] = ito;
 243.547 +      itail[nsort] = ifrom;
 243.548 +      ito = ifrom;
 243.549 +      goto L10;
 243.550 +}
 243.551 +
 243.552 +/***********************************************************************
 243.553 +*  The routine sort sorts the nsort arcs in the ihead and itail arrays.
 243.554 +*  ihead is used as the sort key (i.e. forward star sort order). */
 243.555 +
 243.556 +static void sort(struct csa *csa)
 243.557 +{     int i, j, k, l, m, n, it;
 243.558 +      n = nsort;
 243.559 +      m = n;
 243.560 +L10:  m /= 2;
 243.561 +      if (m == 0) return;
 243.562 +      k = n - m;
 243.563 +      j = 1;
 243.564 +L20:  i = j;
 243.565 +L30:  l = i + m;
 243.566 +      if (itail[i] <= itail[l]) goto L40;
 243.567 +      it = itail[i];
 243.568 +      itail[i] = itail[l];
 243.569 +      itail[l] = it;
 243.570 +      it = ihead[i];
 243.571 +      ihead[i] = ihead[l];
 243.572 +      ihead[l] = it;
 243.573 +      i -= m;
 243.574 +      if (i >= 1) goto L30;
 243.575 +L40:  j++;
 243.576 +      if (j <= k) goto L20;
 243.577 +      goto L10;
 243.578 +}
 243.579 +
 243.580 +/***********************************************************************
 243.581 +*  The routine pickj creates a random number of arcs out of node 'it'.
 243.582 +*  Various parameters are dynamically adjusted in an attempt to ensure
 243.583 +*  that the generated network has the correct number of arcs. */
 243.584 +
 243.585 +static void pickj(struct csa *csa, int it)
 243.586 +{     int j, k, l, nn, nupbnd, icap, jcap, icost;
 243.587 +      if ((nodlft - 1) * 2 > iarcs - narcs - 1)
 243.588 +      {  nodlft--;
 243.589 +         return;
 243.590 +      }
 243.591 +      if ((iarcs - narcs + nonsor - ktl - 1) / nodlft - nonsor + 1 >= 0)
 243.592 +         k = nonsor;
 243.593 +      else
 243.594 +      {  nupbnd = (iarcs - narcs - nodlft) / nodlft * 2;
 243.595 +L40:     k = iran(csa, 1, nupbnd);
 243.596 +         if (nodlft == 1) k = iarcs - narcs;
 243.597 +         if ((nodlft - 1) * (nonsor - 1) < iarcs - narcs - k) goto L40;
 243.598 +      }
 243.599 +      nodlft--;
 243.600 +      for (j = 1; j <= k; j++)
 243.601 +      {  nn = iran(csa, 1, ktl);
 243.602 +         ktl--;
 243.603 +         for (l = nftsor; l <= nodes; l++)
 243.604 +         {  if (iflag[l] != 1)
 243.605 +            {  nn--;
 243.606 +               if (nn == 0) goto L70;
 243.607 +            }
 243.608 +         }
 243.609 +         return;
 243.610 +L70:     iflag[l] = 1;
 243.611 +         icap = itsup;
 243.612 +         jcap = iran(csa, 1, 100);
 243.613 +         if (jcap <= ipcap)
 243.614 +            icap = iran(csa, mincap, maxcap);
 243.615 +         icost = iran(csa, mincst, maxcst);
 243.616 +         if (G == NULL)
 243.617 +            xprintf("%6s%6d%6d%2s%10d%10d\n", "", it, l, "", icost,
 243.618 +               icap);
 243.619 +         else
 243.620 +         {  glp_arc *a = glp_add_arc(G, it, l);
 243.621 +            if (a_cap >= 0)
 243.622 +            {  double temp = (double)icap;
 243.623 +               memcpy((char *)a->data + a_cap, &temp, sizeof(double));
 243.624 +            }
 243.625 +            if (a_cost >= 0)
 243.626 +            {  double temp = (double)icost;
 243.627 +               memcpy((char *)a->data + a_cost, &temp, sizeof(double));
 243.628 +            }
 243.629 +         }
 243.630 +         narcs++;
 243.631 +      }
 243.632 +      return;
 243.633 +}
 243.634 +
 243.635 +/***********************************************************************
 243.636 +*  The routine assign generate assignment problems. It defines the unit
 243.637 +*  supplies, builds a skeleton, then calls pickj to create the arcs. */
 243.638 +
 243.639 +static void assign(struct csa *csa)
 243.640 +{     int i, it, nn, l, ll, icost;
 243.641 +      if (G == NULL)
 243.642 +         xprintf("SUPPLY\n");
 243.643 +      for (i = 1; i <= nsorc; i++)
 243.644 +      {  isup[i] = 1;
 243.645 +         iflag[i] = 0;
 243.646 +         if (G == NULL)
 243.647 +            xprintf("%6s%6d%18s%10d\n", "", i, "", isup[i]);
 243.648 +         else
 243.649 +         {  if (v_rhs >= 0)
 243.650 +            {  double temp = (double)isup[i];
 243.651 +               glp_vertex *v = G->v[i];
 243.652 +               memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
 243.653 +            }
 243.654 +         }
 243.655 +      }
 243.656 +      if (G == NULL)
 243.657 +         xprintf("ARCS\n");
 243.658 +      for (i = nfsink; i <= nodes; i++)
 243.659 +         ipred[i] = 1;
 243.660 +      for (it = 1; it <= nsorc; it++)
 243.661 +      {  for (i = nfsink; i <= nodes; i++)
 243.662 +            iflag[i] = 0;
 243.663 +         ktl = nsink - 1;
 243.664 +         nn = iran(csa, 1, nsink - it + 1);
 243.665 +         for (l = 1; l <= nsorc; l++)
 243.666 +         {  if (iflag[l] != 1)
 243.667 +            {  nn--;
 243.668 +               if (nn == 0) break;
 243.669 +            }
 243.670 +         }
 243.671 +         narcs++;
 243.672 +         ll = nsorc + l;
 243.673 +         icost = iran(csa, mincst, maxcst);
 243.674 +         if (G == NULL)
 243.675 +            xprintf("%6s%6d%6d%2s%10d%10d\n", "", it, ll, "", icost,
 243.676 +               isup[1]);
 243.677 +         else
 243.678 +         {  glp_arc *a = glp_add_arc(G, it, ll);
 243.679 +            if (a_cap >= 0)
 243.680 +            {  double temp = (double)isup[1];
 243.681 +               memcpy((char *)a->data + a_cap, &temp, sizeof(double));
 243.682 +            }
 243.683 +            if (a_cost >= 0)
 243.684 +            {  double temp = (double)icost;
 243.685 +               memcpy((char *)a->data + a_cost, &temp, sizeof(double));
 243.686 +            }
 243.687 +         }
 243.688 +         iflag[l] = 1;
 243.689 +         iflag[ll] = 1;
 243.690 +         pickj(csa, it);
 243.691 +      }
 243.692 +      return;
 243.693 +}
 243.694 +
 243.695 +/***********************************************************************
 243.696 +*  Portable congruential (uniform) random number generator:
 243.697 +*
 243.698 +*     next_value = ((7**5) * previous_value) modulo ((2**31)-1)
 243.699 +*
 243.700 +*  This generator consists of three routines:
 243.701 +*
 243.702 +*  (1) setran - initializes constants and seed
 243.703 +*  (2) iran   - generates an integer random number
 243.704 +*  (3) rran   - generates a real random number
 243.705 +*
 243.706 +*  The generator requires a machine with at least 32 bits of precision.
 243.707 +*  The seed (iseed) must be in the range [1,(2**31)-1]. */
 243.708 +
 243.709 +static void setran(struct csa *csa, int iseed)
 243.710 +{     xassert(iseed >= 1);
 243.711 +      mult = 16807;
 243.712 +      modul = 2147483647;
 243.713 +      i15 = 1 << 15;
 243.714 +      i16 = 1 << 16;
 243.715 +      jran = iseed;
 243.716 +      return;
 243.717 +}
 243.718 +
 243.719 +/***********************************************************************
 243.720 +*  The routine iran generates an integer random number between ilow and
 243.721 +*  ihigh. If ilow > ihigh then iran returns ihigh. */
 243.722 +
 243.723 +static int iran(struct csa *csa, int ilow, int ihigh)
 243.724 +{     int ixhi, ixlo, ixalo, leftlo, ixahi, ifulhi, irtlo, iover,
 243.725 +         irthi, j;
 243.726 +      ixhi = jran / i16;
 243.727 +      ixlo = jran - ixhi * i16;
 243.728 +      ixalo = ixlo * mult;
 243.729 +      leftlo = ixalo / i16;
 243.730 +      ixahi = ixhi * mult;
 243.731 +      ifulhi = ixahi + leftlo;
 243.732 +      irtlo = ixalo - leftlo * i16;
 243.733 +      iover = ifulhi / i15;
 243.734 +      irthi = ifulhi - iover * i15;
 243.735 +      jran = ((irtlo - modul) + irthi * i16) + iover;
 243.736 +      if (jran < 0) jran += modul;
 243.737 +      j = ihigh - ilow + 1;
 243.738 +      if (j > 0)
 243.739 +         return jran % j + ilow;
 243.740 +      else
 243.741 +         return ihigh;
 243.742 +}
 243.743 +
 243.744 +/**********************************************************************/
 243.745 +
 243.746 +#if 0
 243.747 +static int scan(char card[80+1], int pos, int len)
 243.748 +{     char buf[10+1];
 243.749 +      memcpy(buf, &card[pos-1], len);
 243.750 +      buf[len] = '\0';
 243.751 +      return atoi(buf);
 243.752 +}
 243.753 +
 243.754 +int main(void)
 243.755 +{     int parm[1+15];
 243.756 +      char card[80+1];
 243.757 +      xassert(fgets(card, sizeof(card), stdin) == card);
 243.758 +      parm[1] = scan(card, 1, 8);
 243.759 +      parm[2] = scan(card, 9, 8);
 243.760 +      xassert(fgets(card, sizeof(card), stdin) == card);
 243.761 +      parm[3] = scan(card, 1, 5);
 243.762 +      parm[4] = scan(card, 6, 5);
 243.763 +      parm[5] = scan(card, 11, 5);
 243.764 +      parm[6] = scan(card, 16, 5);
 243.765 +      parm[7] = scan(card, 21, 5);
 243.766 +      parm[8] = scan(card, 26, 5);
 243.767 +      parm[9] = scan(card, 31, 10);
 243.768 +      parm[10] = scan(card, 41, 5);
 243.769 +      parm[11] = scan(card, 46, 5);
 243.770 +      parm[12] = scan(card, 51, 5);
 243.771 +      parm[13] = scan(card, 56, 5);
 243.772 +      parm[14] = scan(card, 61, 10);
 243.773 +      parm[15] = scan(card, 71, 10);
 243.774 +      glp_netgen(NULL, 0, 0, 0, parm);
 243.775 +      return 0;
 243.776 +}
 243.777 +#endif
 243.778 +
 243.779 +/* eof */
   244.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   244.2 +++ b/src/glpnet04.c	Mon Dec 06 13:09:21 2010 +0100
   244.3 @@ -0,0 +1,768 @@
   244.4 +/* glpnet04.c (grid-like network problem generator) */
   244.5 +
   244.6 +/***********************************************************************
   244.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   244.8 +*
   244.9 +*  This code is a modified version of the program GRIDGEN, a grid-like
  244.10 +*  network problem generator developed by Yusin Lee and Jim Orlin.
  244.11 +*  The original code is publically available on the DIMACS ftp site at:
  244.12 +*  <ftp://dimacs.rutgers.edu/pub/netflow/generators/network/gridgen>.
  244.13 +*
  244.14 +*  All changes concern only the program interface, so this modified
  244.15 +*  version produces exactly the same instances as the original version.
  244.16 +*
  244.17 +*  Changes were made by Andrew Makhorin <mao@gnu.org>.
  244.18 +*
  244.19 +*  GLPK is free software: you can redistribute it and/or modify it
  244.20 +*  under the terms of the GNU General Public License as published by
  244.21 +*  the Free Software Foundation, either version 3 of the License, or
  244.22 +*  (at your option) any later version.
  244.23 +*
  244.24 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  244.25 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  244.26 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  244.27 +*  License for more details.
  244.28 +*
  244.29 +*  You should have received a copy of the GNU General Public License
  244.30 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  244.31 +***********************************************************************/
  244.32 +
  244.33 +#include "glpapi.h"
  244.34 +
  244.35 +/***********************************************************************
  244.36 +*  NAME
  244.37 +*
  244.38 +*  glp_gridgen - grid-like network problem generator
  244.39 +*
  244.40 +*  SYNOPSIS
  244.41 +*
  244.42 +*  int glp_gridgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
  244.43 +*     const int parm[1+14]);
  244.44 +*
  244.45 +*  DESCRIPTION
  244.46 +*
  244.47 +*  The routine glp_gridgen is a grid-like network problem generator
  244.48 +*  developed by Yusin Lee and Jim Orlin.
  244.49 +*
  244.50 +*  The parameter G specifies the graph object, to which the generated
  244.51 +*  problem data have to be stored. Note that on entry the graph object
  244.52 +*  is erased with the routine glp_erase_graph.
  244.53 +*
  244.54 +*  The parameter v_rhs specifies an offset of the field of type double
  244.55 +*  in the vertex data block, to which the routine stores the supply or
  244.56 +*  demand value. If v_rhs < 0, the value is not stored.
  244.57 +*
  244.58 +*  The parameter a_cap specifies an offset of the field of type double
  244.59 +*  in the arc data block, to which the routine stores the arc capacity.
  244.60 +*  If a_cap < 0, the capacity is not stored.
  244.61 +*
  244.62 +*  The parameter a_cost specifies an offset of the field of type double
  244.63 +*  in the arc data block, to which the routine stores the per-unit cost
  244.64 +*  if the arc flow. If a_cost < 0, the cost is not stored.
  244.65 +*
  244.66 +*  The array parm contains description of the network to be generated:
  244.67 +*
  244.68 +*  parm[0]  not used
  244.69 +*  parm[1]  two-ways arcs indicator:
  244.70 +*           1 - if links in both direction should be generated
  244.71 +*           0 - otherwise
  244.72 +*  parm[2]  random number seed (a positive integer)
  244.73 +*  parm[3]  number of nodes (the number of nodes generated might be
  244.74 +*           slightly different to make the network a grid)
  244.75 +*  parm[4]  grid width
  244.76 +*  parm[5]  number of sources
  244.77 +*  parm[6]  number of sinks
  244.78 +*  parm[7]  average degree
  244.79 +*  parm[8]  total flow
  244.80 +*  parm[9]  distribution of arc costs:
  244.81 +*           1 - uniform
  244.82 +*           2 - exponential
  244.83 +*  parm[10] lower bound for arc cost (uniform)
  244.84 +*           100 * lambda (exponential)
  244.85 +*  parm[11] upper bound for arc cost (uniform)
  244.86 +*           not used (exponential)
  244.87 +*  parm[12] distribution of arc capacities:
  244.88 +*           1 - uniform
  244.89 +*           2 - exponential
  244.90 +*  parm[13] lower bound for arc capacity (uniform)
  244.91 +*           100 * lambda (exponential)
  244.92 +*  parm[14] upper bound for arc capacity (uniform)
  244.93 +*           not used (exponential)
  244.94 +*
  244.95 +*  RETURNS
  244.96 +*
  244.97 +*  If the instance was successfully generated, the routine glp_gridgen
  244.98 +*  returns zero; otherwise, if specified parameters are inconsistent,
  244.99 +*  the routine returns a non-zero error code.
 244.100 +*
 244.101 +*  COMMENTS
 244.102 +*
 244.103 +*  This network generator generates a grid-like network plus a super
 244.104 +*  node. In additional to the arcs connecting the nodes in the grid,
 244.105 +*  there is an arc from each supply node to the super node and from the
 244.106 +*  super node to each demand node to guarantee feasiblity. These arcs
 244.107 +*  have very high costs and very big capacities.
 244.108 +*
 244.109 +*  The idea of this network generator is as follows: First, a grid of
 244.110 +*  n1 * n2 is generated. For example, 5 * 3. The nodes are numbered as
 244.111 +*  1 to 15, and the supernode is numbered as n1*n2+1. Then arcs between
 244.112 +*  adjacent nodes are generated. For these arcs, the user is allowed to
 244.113 +*  specify either to generate two-way arcs or one-way arcs. If two-way
 244.114 +*  arcs are to be generated, two arcs, one in each direction, will be
 244.115 +*  generated between each adjacent node pairs. Otherwise, only one arc
 244.116 +*  will be generated. If this is the case, the arcs will be generated
 244.117 +*  in alterntive directions as shown below.
 244.118 +*
 244.119 +*      1 ---> 2 ---> 3 ---> 4 ---> 5
 244.120 +*      |      ^      |      ^      |
 244.121 +*      |      |      |      |      |
 244.122 +*      V      |      V      |      V
 244.123 +*      6 <--- 7 <--- 8 <--- 9 <--- 10
 244.124 +*      |      ^      |      ^      |
 244.125 +*      |      |      |      |      |
 244.126 +*      V      |      V      |      V
 244.127 +*     11 --->12 --->13 --->14 ---> 15
 244.128 +*
 244.129 +*  Then the arcs between the super node and the source/sink nodes are
 244.130 +*  added as mentioned before. If the number of arcs still doesn't reach
 244.131 +*  the requirement, additional arcs will be added by uniformly picking
 244.132 +*  random node pairs. There is no checking to prevent multiple arcs
 244.133 +*  between any pair of nodes. However, there will be no self-arcs (arcs
 244.134 +*  that poins back to its tail node) in the network.
 244.135 +*
 244.136 +*  The source and sink nodes are selected uniformly in the network, and
 244.137 +*  the imbalances of each source/sink node are also assigned by uniform
 244.138 +*  distribution. */
 244.139 +
 244.140 +struct stat_para
 244.141 +{     /* structure for statistical distributions */
 244.142 +      int distribution;
 244.143 +      /* the distribution: */
 244.144 +#define UNIFORM      1  /* uniform distribution */
 244.145 +#define EXPONENTIAL  2  /* exponential distribution */
 244.146 +      double parameter[5];
 244.147 +      /* the parameters of the distribution */
 244.148 +};
 244.149 +
 244.150 +struct arcs
 244.151 +{     int from;
 244.152 +      /* the FROM node of that arc */
 244.153 +      int to;
 244.154 +      /* the TO node of that arc */
 244.155 +      int cost;
 244.156 +      /* original cost of that arc */
 244.157 +      int u;
 244.158 +      /* capacity of the arc */
 244.159 +};
 244.160 +
 244.161 +struct imbalance
 244.162 +{     int node;
 244.163 +      /* Node ID */
 244.164 +      int supply;
 244.165 +      /* Supply of that node */
 244.166 +};
 244.167 +
 244.168 +struct csa
 244.169 +{     /* common storage area */
 244.170 +      glp_graph *G;
 244.171 +      int v_rhs, a_cap, a_cost;
 244.172 +      int seed;
 244.173 +      /* random number seed */
 244.174 +      int seed_original;
 244.175 +      /* the original seed from input */
 244.176 +      int two_way;
 244.177 +      /* 0: generate arcs in both direction for the basic grid, except
 244.178 +         for the arcs to/from the super node.  1: o/w */
 244.179 +      int n_node;
 244.180 +      /* total number of nodes in the network, numbered 1 to n_node,
 244.181 +         including the super node, which is the last one */
 244.182 +      int n_arc;
 244.183 +      /* total number of arcs in the network, counting EVERY arc. */
 244.184 +      int n_grid_arc;
 244.185 +      /* number of arcs in the basic grid, including the arcs to/from
 244.186 +         the super node */
 244.187 +      int n_source, n_sink;
 244.188 +      /* number of source and sink nodes */
 244.189 +      int avg_degree;
 244.190 +      /* average degree, arcs to and from the super node are counted */
 244.191 +      int t_supply;
 244.192 +      /* total supply in the network */
 244.193 +      int n1, n2;
 244.194 +      /* the two edges of the network grid.  n1 >= n2 */
 244.195 +      struct imbalance *source_list, *sink_list;
 244.196 +      /* head of the array of source/sink nodes */
 244.197 +      struct stat_para arc_costs;
 244.198 +      /* the distribution of arc costs */
 244.199 +      struct stat_para capacities;
 244.200 +      /* distribution of the capacities of the arcs */
 244.201 +      struct arcs *arc_list;
 244.202 +      /* head of the arc list array.  Arcs in this array are in the
 244.203 +         order of grid_arcs, arcs to/from super node, and other arcs */
 244.204 +};
 244.205 +
 244.206 +#define G (csa->G)
 244.207 +#define v_rhs (csa->v_rhs)
 244.208 +#define a_cap (csa->a_cap)
 244.209 +#define a_cost (csa->a_cost)
 244.210 +#define seed (csa->seed)
 244.211 +#define seed_original (csa->seed_original)
 244.212 +#define two_way (csa->two_way)
 244.213 +#define n_node (csa->n_node)
 244.214 +#define n_arc (csa->n_arc)
 244.215 +#define n_grid_arc (csa->n_grid_arc)
 244.216 +#define n_source (csa->n_source)
 244.217 +#define n_sink (csa->n_sink)
 244.218 +#define avg_degree (csa->avg_degree)
 244.219 +#define t_supply (csa->t_supply)
 244.220 +#define n1 (csa->n1)
 244.221 +#define n2 (csa->n2)
 244.222 +#define source_list (csa->source_list)
 244.223 +#define sink_list (csa->sink_list)
 244.224 +#define arc_costs (csa->arc_costs)
 244.225 +#define capacities (csa->capacities)
 244.226 +#define arc_list (csa->arc_list)
 244.227 +
 244.228 +static void assign_capacities(struct csa *csa);
 244.229 +static void assign_costs(struct csa *csa);
 244.230 +static void assign_imbalance(struct csa *csa);
 244.231 +static int exponential(struct csa *csa, double lambda[1]);
 244.232 +static struct arcs *gen_additional_arcs(struct csa *csa, struct arcs
 244.233 +      *arc_ptr);
 244.234 +static struct arcs *gen_basic_grid(struct csa *csa, struct arcs
 244.235 +      *arc_ptr);
 244.236 +static void gen_more_arcs(struct csa *csa, struct arcs *arc_ptr);
 244.237 +static void generate(struct csa *csa);
 244.238 +static void output(struct csa *csa);
 244.239 +static double randy(struct csa *csa);
 244.240 +static void select_source_sinks(struct csa *csa);
 244.241 +static int uniform(struct csa *csa, double a[2]);
 244.242 +
 244.243 +int glp_gridgen(glp_graph *G_, int _v_rhs, int _a_cap, int _a_cost,
 244.244 +      const int parm[1+14])
 244.245 +{     struct csa _csa, *csa = &_csa;
 244.246 +      int n, ret;
 244.247 +      G = G_;
 244.248 +      v_rhs = _v_rhs;
 244.249 +      a_cap = _a_cap;
 244.250 +      a_cost = _a_cost;
 244.251 +      if (G != NULL)
 244.252 +      {  if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
 244.253 +            xerror("glp_gridgen: v_rhs = %d; invalid offset\n", v_rhs);
 244.254 +         if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
 244.255 +            xerror("glp_gridgen: a_cap = %d; invalid offset\n", a_cap);
 244.256 +         if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
 244.257 +            xerror("glp_gridgen: a_cost = %d; invalid offset\n", a_cost)
 244.258 +               ;
 244.259 +      }
 244.260 +      /* Check the parameters for consistency. */
 244.261 +      if (!(parm[1] == 0 || parm[1] == 1))
 244.262 +      {  ret = 1;
 244.263 +         goto done;
 244.264 +      }
 244.265 +      if (parm[2] < 1)
 244.266 +      {  ret = 2;
 244.267 +         goto done;
 244.268 +      }
 244.269 +      if (!(10 <= parm[3] && parm[3] <= 40000))
 244.270 +      {  ret = 3;
 244.271 +         goto done;
 244.272 +      }
 244.273 +      if (!(1 <= parm[4] && parm[4] <= 40000))
 244.274 +      {  ret = 4;
 244.275 +         goto done;
 244.276 +      }
 244.277 +      if (!(parm[5] >= 0 && parm[6] >= 0 && parm[5] + parm[6] <=
 244.278 +         parm[3]))
 244.279 +      {  ret = 5;
 244.280 +         goto done;
 244.281 +      }
 244.282 +      if (!(1 <= parm[7] && parm[7] <= parm[3]))
 244.283 +      {  ret = 6;
 244.284 +         goto done;
 244.285 +      }
 244.286 +      if (parm[8] < 0)
 244.287 +      {  ret = 7;
 244.288 +         goto done;
 244.289 +      }
 244.290 +      if (!(parm[9] == 1 || parm[9] == 2))
 244.291 +      {  ret = 8;
 244.292 +         goto done;
 244.293 +      }
 244.294 +      if (parm[9] == 1 && parm[10] > parm[11] ||
 244.295 +          parm[9] == 2 && parm[10] < 1)
 244.296 +      {  ret = 9;
 244.297 +         goto done;
 244.298 +      }
 244.299 +      if (!(parm[12] == 1 || parm[12] == 2))
 244.300 +      {  ret = 10;
 244.301 +         goto done;
 244.302 +      }
 244.303 +      if (parm[12] == 1 && !(0 <= parm[13] && parm[13] <= parm[14]) ||
 244.304 +          parm[12] == 2 && parm[13] < 1)
 244.305 +      {  ret = 11;
 244.306 +         goto done;
 244.307 +      }
 244.308 +      /* Initialize the graph object. */
 244.309 +      if (G != NULL)
 244.310 +      {  glp_erase_graph(G, G->v_size, G->a_size);
 244.311 +         glp_set_graph_name(G, "GRIDGEN");
 244.312 +      }
 244.313 +      /* Copy the generator parameters. */
 244.314 +      two_way = parm[1];
 244.315 +      seed_original = seed = parm[2];
 244.316 +      n_node = parm[3];
 244.317 +      n = parm[4];
 244.318 +      n_source = parm[5];
 244.319 +      n_sink = parm[6];
 244.320 +      avg_degree = parm[7];
 244.321 +      t_supply = parm[8];
 244.322 +      arc_costs.distribution = parm[9];
 244.323 +      if (parm[9] == 1)
 244.324 +      {  arc_costs.parameter[0] = parm[10];
 244.325 +         arc_costs.parameter[1] = parm[11];
 244.326 +      }
 244.327 +      else
 244.328 +      {  arc_costs.parameter[0] = (double)parm[10] / 100.0;
 244.329 +         arc_costs.parameter[1] = 0.0;
 244.330 +      }
 244.331 +      capacities.distribution = parm[12];
 244.332 +      if (parm[12] == 1)
 244.333 +      {  capacities.parameter[0] = parm[13];
 244.334 +         capacities.parameter[1] = parm[14];
 244.335 +      }
 244.336 +      else
 244.337 +      {  capacities.parameter[0] = (double)parm[13] / 100.0;
 244.338 +         capacities.parameter[1] = 0.0;
 244.339 +      }
 244.340 +      /* Calculate the edge lengths of the grid according to the
 244.341 +         input. */
 244.342 +      if (n * n >= n_node)
 244.343 +      {  n1 = n;
 244.344 +         n2 = (int)((double)n_node / (double)n + 0.5);
 244.345 +      }
 244.346 +      else
 244.347 +      {  n2 = n;
 244.348 +         n1 = (int)((double)n_node / (double)n + 0.5);
 244.349 +      }
 244.350 +      /* Recalculate the total number of nodes and plus 1 for the super
 244.351 +         node. */
 244.352 +      n_node = n1 * n2 + 1;
 244.353 +      n_arc = n_node * avg_degree;
 244.354 +      n_grid_arc = (two_way + 1) * ((n1 - 1) * n2 + (n2 - 1) * n1) +
 244.355 +         n_source + n_sink;
 244.356 +      if (n_grid_arc > n_arc) n_arc = n_grid_arc;
 244.357 +      arc_list = xcalloc(n_arc, sizeof(struct arcs));
 244.358 +      source_list = xcalloc(n_source, sizeof(struct imbalance));
 244.359 +      sink_list = xcalloc(n_sink, sizeof(struct imbalance));
 244.360 +      /* Generate a random network. */
 244.361 +      generate(csa);
 244.362 +      /* Output the network. */
 244.363 +      output(csa);
 244.364 +      /* Free all allocated memory. */
 244.365 +      xfree(arc_list);
 244.366 +      xfree(source_list);
 244.367 +      xfree(sink_list);
 244.368 +      /* The instance has been successfully generated. */
 244.369 +      ret = 0;
 244.370 +done: return ret;
 244.371 +}
 244.372 +
 244.373 +#undef random
 244.374 +
 244.375 +static void assign_capacities(struct csa *csa)
 244.376 +{     /* Assign a capacity to each arc. */
 244.377 +      struct arcs *arc_ptr = arc_list;
 244.378 +      int (*random)(struct csa *csa, double *);
 244.379 +      int i;
 244.380 +      /* Determine the random number generator to use. */
 244.381 +      switch (arc_costs.distribution)
 244.382 +      {  case UNIFORM:
 244.383 +            random = uniform;
 244.384 +            break;
 244.385 +         case EXPONENTIAL:
 244.386 +            random = exponential;
 244.387 +            break;
 244.388 +         default:
 244.389 +            xassert(csa != csa);
 244.390 +      }
 244.391 +      /* Assign capacities to grid arcs. */
 244.392 +      for (i = n_source + n_sink; i < n_grid_arc; i++, arc_ptr++)
 244.393 +         arc_ptr->u = random(csa, capacities.parameter);
 244.394 +      i = i - n_source - n_sink;
 244.395 +      /* Assign capacities to arcs to/from supernode. */
 244.396 +      for (; i < n_grid_arc; i++, arc_ptr++)
 244.397 +         arc_ptr->u = t_supply;
 244.398 +      /* Assign capacities to all other arcs. */
 244.399 +      for (; i < n_arc; i++, arc_ptr++)
 244.400 +         arc_ptr->u = random(csa, capacities.parameter);
 244.401 +      return;
 244.402 +}
 244.403 +
 244.404 +static void assign_costs(struct csa *csa)
 244.405 +{     /* Assign a cost to each arc. */
 244.406 +      struct arcs *arc_ptr = arc_list;
 244.407 +      int (*random)(struct csa *csa, double *);
 244.408 +      int i;
 244.409 +      /* A high cost assigned to arcs to/from the supernode. */
 244.410 +      int high_cost;
 244.411 +      /* The maximum cost assigned to arcs in the base grid. */
 244.412 +      int max_cost = 0;
 244.413 +      /* Determine the random number generator to use. */
 244.414 +      switch (arc_costs.distribution)
 244.415 +      {  case UNIFORM:
 244.416 +            random = uniform;
 244.417 +            break;
 244.418 +         case EXPONENTIAL:
 244.419 +            random = exponential;
 244.420 +            break;
 244.421 +         default:
 244.422 +            xassert(csa != csa);
 244.423 +      }
 244.424 +      /* Assign costs to arcs in the base grid. */
 244.425 +      for (i = n_source + n_sink; i < n_grid_arc; i++, arc_ptr++)
 244.426 +      {  arc_ptr->cost = random(csa, arc_costs.parameter);
 244.427 +         if (max_cost < arc_ptr->cost) max_cost = arc_ptr->cost;
 244.428 +      }
 244.429 +      i = i - n_source - n_sink;
 244.430 +      /* Assign costs to arcs to/from the super node. */
 244.431 +      high_cost = max_cost * 2;
 244.432 +      for (; i < n_grid_arc; i++, arc_ptr++)
 244.433 +         arc_ptr->cost = high_cost;
 244.434 +      /* Assign costs to all other arcs. */
 244.435 +      for (; i < n_arc; i++, arc_ptr++)
 244.436 +         arc_ptr->cost = random(csa, arc_costs.parameter);
 244.437 +      return;
 244.438 +}
 244.439 +
 244.440 +static void assign_imbalance(struct csa *csa)
 244.441 +{     /* Assign an imbalance to each node. */
 244.442 +      int total, i;
 244.443 +      double avg;
 244.444 +      struct imbalance *ptr;
 244.445 +      /* assign the supply nodes */
 244.446 +      avg = 2.0 * t_supply / n_source;
 244.447 +      do
 244.448 +      {  for (i = 1, total = t_supply, ptr = source_list + 1;
 244.449 +            i < n_source; i++, ptr++)
 244.450 +         {  ptr->supply = (int)(randy(csa) * avg + 0.5);
 244.451 +            total -= ptr->supply;
 244.452 +         }
 244.453 +         source_list->supply = total;
 244.454 +      }
 244.455 +      /* redo all if the assignment "overshooted" */
 244.456 +      while (total <= 0);
 244.457 +      /* assign the demand nodes */
 244.458 +      avg = -2.0 * t_supply / n_sink;
 244.459 +      do
 244.460 +      {  for (i = 1, total = t_supply, ptr = sink_list + 1;
 244.461 +            i < n_sink; i++, ptr++)
 244.462 +         {  ptr->supply = (int)(randy(csa) * avg - 0.5);
 244.463 +            total += ptr->supply;
 244.464 +         }
 244.465 +         sink_list->supply = - total;
 244.466 +      }
 244.467 +      while (total <= 0);
 244.468 +      return;
 244.469 +}
 244.470 +
 244.471 +static int exponential(struct csa *csa, double lambda[1])
 244.472 +{     /* Returns an "exponentially distributed" integer with parameter
 244.473 +         lambda. */
 244.474 +      return ((int)(- lambda[0] * log((double)randy(csa)) + 0.5));
 244.475 +}
 244.476 +
 244.477 +static struct arcs *gen_additional_arcs(struct csa *csa, struct arcs
 244.478 +      *arc_ptr)
 244.479 +{     /* Generate an arc from each source to the supernode and from
 244.480 +         supernode to each sink. */
 244.481 +      int i;
 244.482 +      for (i = 0; i < n_source; i++, arc_ptr++)
 244.483 +      {  arc_ptr->from = source_list[i].node;
 244.484 +         arc_ptr->to = n_node;
 244.485 +      }
 244.486 +      for (i = 0; i < n_sink; i++, arc_ptr++)
 244.487 +      {  arc_ptr->to = sink_list[i].node;
 244.488 +         arc_ptr->from = n_node;
 244.489 +      }
 244.490 +      return arc_ptr;
 244.491 +}
 244.492 +
 244.493 +static struct arcs *gen_basic_grid(struct csa *csa, struct arcs
 244.494 +      *arc_ptr)
 244.495 +{     /* Generate the basic grid. */
 244.496 +      int direction = 1, i, j, k;
 244.497 +      if (two_way)
 244.498 +      {  /* Generate an arc in each direction. */
 244.499 +         for (i = 1; i < n_node; i += n1)
 244.500 +         {  for (j = i, k = j + n1 - 1; j < k; j++)
 244.501 +            {  arc_ptr->from = j;
 244.502 +               arc_ptr->to = j + 1;
 244.503 +               arc_ptr++;
 244.504 +               arc_ptr->from = j + 1;
 244.505 +               arc_ptr->to = j;
 244.506 +               arc_ptr++;
 244.507 +            }
 244.508 +         }
 244.509 +         for (i = 1; i <= n1; i++)
 244.510 +         {  for (j = i + n1; j < n_node; j += n1)
 244.511 +            {  arc_ptr->from = j;
 244.512 +               arc_ptr->to = j - n1;
 244.513 +               arc_ptr++;
 244.514 +               arc_ptr->from = j - n1;
 244.515 +               arc_ptr->to = j;
 244.516 +               arc_ptr++;
 244.517 +            }
 244.518 +         }
 244.519 +      }
 244.520 +      else
 244.521 +      {  /* Generate one arc in each direction. */
 244.522 +         for (i = 1; i < n_node; i += n1)
 244.523 +         {  if (direction == 1)
 244.524 +               j = i;
 244.525 +            else
 244.526 +               j = i + 1;
 244.527 +            for (k = j + n1 - 1; j < k; j++)
 244.528 +            {  arc_ptr->from = j;
 244.529 +               arc_ptr->to = j + direction;
 244.530 +               arc_ptr++;
 244.531 +            }
 244.532 +            direction = - direction;
 244.533 +         }
 244.534 +         for (i = 1; i <= n1; i++)
 244.535 +         {  j = i + n1;
 244.536 +            if (direction == 1)
 244.537 +            {  for (; j < n_node; j += n1)
 244.538 +               {  arc_ptr->from = j - n1;
 244.539 +                  arc_ptr->to = j;
 244.540 +                  arc_ptr++;
 244.541 +               }
 244.542 +            }
 244.543 +            else
 244.544 +            {  for (; j < n_node; j += n1)
 244.545 +               {  arc_ptr->from = j - n1;
 244.546 +                  arc_ptr->to = j;
 244.547 +                  arc_ptr++;
 244.548 +               }
 244.549 +            }
 244.550 +            direction = - direction;
 244.551 +         }
 244.552 +      }
 244.553 +      return arc_ptr;
 244.554 +}
 244.555 +
 244.556 +static void gen_more_arcs(struct csa *csa, struct arcs *arc_ptr)
 244.557 +{     /* Generate random arcs to meet the specified density. */
 244.558 +      int i;
 244.559 +      double ab[2];
 244.560 +      ab[0] = 0.9;
 244.561 +      ab[1] = n_node - 0.99;  /* upper limit is n_node-1 because the
 244.562 +                                 supernode cannot be selected */
 244.563 +      for (i = n_grid_arc; i < n_arc; i++, arc_ptr++)
 244.564 +      {  arc_ptr->from = uniform(csa, ab);
 244.565 +         arc_ptr->to = uniform(csa, ab);
 244.566 +         if (arc_ptr->from == arc_ptr->to)
 244.567 +         {  arc_ptr--;
 244.568 +            i--;
 244.569 +         }
 244.570 +      }
 244.571 +      return;
 244.572 +}
 244.573 +
 244.574 +static void generate(struct csa *csa)
 244.575 +{     /* Generate a random network. */
 244.576 +      struct arcs *arc_ptr = arc_list;
 244.577 +      arc_ptr = gen_basic_grid(csa, arc_ptr);
 244.578 +      select_source_sinks(csa);
 244.579 +      arc_ptr = gen_additional_arcs(csa, arc_ptr);
 244.580 +      gen_more_arcs(csa, arc_ptr);
 244.581 +      assign_costs(csa);
 244.582 +      assign_capacities(csa);
 244.583 +      assign_imbalance(csa);
 244.584 +      return;
 244.585 +}
 244.586 +
 244.587 +static void output(struct csa *csa)
 244.588 +{     /* Output the network in DIMACS format. */
 244.589 +      struct arcs *arc_ptr;
 244.590 +      struct imbalance *imb_ptr;
 244.591 +      int i;
 244.592 +      if (G != NULL) goto skip;
 244.593 +      /* Output "c", "p" records. */
 244.594 +      xprintf("c generated by GRIDGEN\n");
 244.595 +      xprintf("c seed %d\n", seed_original);
 244.596 +      xprintf("c nodes %d\n", n_node);
 244.597 +      xprintf("c grid size %d X %d\n", n1, n2);
 244.598 +      xprintf("c sources %d sinks %d\n", n_source, n_sink);
 244.599 +      xprintf("c avg. degree %d\n", avg_degree);
 244.600 +      xprintf("c supply %d\n", t_supply);
 244.601 +      switch (arc_costs.distribution)
 244.602 +      {  case UNIFORM:
 244.603 +            xprintf("c arc costs: UNIFORM distr. min %d max %d\n",
 244.604 +               (int)arc_costs.parameter[0],
 244.605 +               (int)arc_costs.parameter[1]);
 244.606 +            break;
 244.607 +         case EXPONENTIAL:
 244.608 +            xprintf("c arc costs: EXPONENTIAL distr. lambda %d\n",
 244.609 +               (int)arc_costs.parameter[0]);
 244.610 +            break;
 244.611 +         default:
 244.612 +            xassert(csa != csa);
 244.613 +      }
 244.614 +      switch (capacities.distribution)
 244.615 +      {  case UNIFORM:
 244.616 +            xprintf("c arc caps :  UNIFORM distr. min %d max %d\n",
 244.617 +               (int)capacities.parameter[0],
 244.618 +               (int)capacities.parameter[1]);
 244.619 +            break;
 244.620 +         case EXPONENTIAL:
 244.621 +            xprintf("c arc caps :  EXPONENTIAL distr. %d lambda %d\n",
 244.622 +               (int)capacities.parameter[0]);
 244.623 +            break;
 244.624 +         default:
 244.625 +            xassert(csa != csa);
 244.626 +      }
 244.627 +skip: if (G == NULL)
 244.628 +         xprintf("p min %d %d\n", n_node, n_arc);
 244.629 +      else
 244.630 +      {  glp_add_vertices(G, n_node);
 244.631 +         if (v_rhs >= 0)
 244.632 +         {  double zero = 0.0;
 244.633 +            for (i = 1; i <= n_node; i++)
 244.634 +            {  glp_vertex *v = G->v[i];
 244.635 +               memcpy((char *)v->data + v_rhs, &zero, sizeof(double));
 244.636 +            }
 244.637 +         }
 244.638 +      }
 244.639 +      /* Output "n node supply". */
 244.640 +      for (i = 0, imb_ptr = source_list; i < n_source; i++, imb_ptr++)
 244.641 +      {  if (G == NULL)
 244.642 +            xprintf("n %d %d\n", imb_ptr->node, imb_ptr->supply);
 244.643 +         else
 244.644 +         {  if (v_rhs >= 0)
 244.645 +            {  double temp = (double)imb_ptr->supply;
 244.646 +               glp_vertex *v = G->v[imb_ptr->node];
 244.647 +               memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
 244.648 +            }
 244.649 +         }
 244.650 +      }
 244.651 +      for (i = 0, imb_ptr = sink_list; i < n_sink; i++, imb_ptr++)
 244.652 +      {  if (G == NULL)
 244.653 +            xprintf("n %d %d\n", imb_ptr->node, imb_ptr->supply);
 244.654 +         else
 244.655 +         {  if (v_rhs >= 0)
 244.656 +            {  double temp = (double)imb_ptr->supply;
 244.657 +               glp_vertex *v = G->v[imb_ptr->node];
 244.658 +               memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
 244.659 +            }
 244.660 +         }
 244.661 +      }
 244.662 +      /* Output "a from to lowcap=0 hicap cost". */
 244.663 +      for (i = 0, arc_ptr = arc_list; i < n_arc; i++, arc_ptr++)
 244.664 +      {  if (G == NULL)
 244.665 +            xprintf("a %d %d 0 %d %d\n", arc_ptr->from, arc_ptr->to,
 244.666 +               arc_ptr->u, arc_ptr->cost);
 244.667 +         else
 244.668 +         {  glp_arc *a = glp_add_arc(G, arc_ptr->from, arc_ptr->to);
 244.669 +            if (a_cap >= 0)
 244.670 +            {  double temp = (double)arc_ptr->u;
 244.671 +               memcpy((char *)a->data + a_cap, &temp, sizeof(double));
 244.672 +            }
 244.673 +            if (a_cost >= 0)
 244.674 +            {  double temp = (double)arc_ptr->cost;
 244.675 +               memcpy((char *)a->data + a_cost, &temp, sizeof(double));
 244.676 +            }
 244.677 +         }
 244.678 +      }
 244.679 +      return;
 244.680 +}
 244.681 +
 244.682 +static double randy(struct csa *csa)
 244.683 +{     /* Returns a random number between 0.0 and 1.0.
 244.684 +         See Ward Cheney & David Kincaid, "Numerical Mathematics and
 244.685 +         Computing," 2Ed, pp. 335. */
 244.686 +      seed = 16807 * seed % 2147483647;
 244.687 +      if (seed < 0) seed = - seed;
 244.688 +      return seed * 4.6566128752459e-10;
 244.689 +}
 244.690 +
 244.691 +static void select_source_sinks(struct csa *csa)
 244.692 +{     /* Randomly select the source nodes and sink nodes. */
 244.693 +      int i, *int_ptr;
 244.694 +      int *temp_list;   /* a temporary list of nodes */
 244.695 +      struct imbalance *ptr;
 244.696 +      double ab[2];     /* parameter for random number generator */
 244.697 +      ab[0] = 0.9;
 244.698 +      ab[1] = n_node - 0.99;  /* upper limit is n_node-1 because the
 244.699 +                                 supernode cannot be selected */
 244.700 +      temp_list = xcalloc(n_node, sizeof(int));
 244.701 +      for (i = 0, int_ptr = temp_list; i < n_node; i++, int_ptr++)
 244.702 +         *int_ptr = 0;
 244.703 +      /* Select the source nodes. */
 244.704 +      for (i = 0, ptr = source_list; i < n_source; i++, ptr++)
 244.705 +      {  ptr->node = uniform(csa, ab);
 244.706 +         if (temp_list[ptr->node] == 1) /* check for duplicates */
 244.707 +         {  ptr--;
 244.708 +            i--;
 244.709 +         }
 244.710 +         else
 244.711 +            temp_list[ptr->node] = 1;
 244.712 +      }
 244.713 +      /* Select the sink nodes. */
 244.714 +      for (i = 0, ptr = sink_list; i < n_sink; i++, ptr++)
 244.715 +      {  ptr->node = uniform(csa, ab);
 244.716 +         if (temp_list[ptr->node] == 1)
 244.717 +         {  ptr--;
 244.718 +            i--;
 244.719 +         }
 244.720 +         else
 244.721 +            temp_list[ptr->node] = 1;
 244.722 +      }
 244.723 +      xfree(temp_list);
 244.724 +      return;
 244.725 +}
 244.726 +
 244.727 +int uniform(struct csa *csa, double a[2])
 244.728 +{     /* Generates an integer uniformly selected from [a[0],a[1]]. */
 244.729 +      return (int)((a[1] - a[0]) * randy(csa) + a[0] + 0.5);
 244.730 +}
 244.731 +
 244.732 +/**********************************************************************/
 244.733 +
 244.734 +#if 0
 244.735 +int main(void)
 244.736 +{     int parm[1+14];
 244.737 +      double temp;
 244.738 +      scanf("%d", &parm[1]);
 244.739 +      scanf("%d", &parm[2]);
 244.740 +      scanf("%d", &parm[3]);
 244.741 +      scanf("%d", &parm[4]);
 244.742 +      scanf("%d", &parm[5]);
 244.743 +      scanf("%d", &parm[6]);
 244.744 +      scanf("%d", &parm[7]);
 244.745 +      scanf("%d", &parm[8]);
 244.746 +      scanf("%d", &parm[9]);
 244.747 +      if (parm[9] == 1)
 244.748 +      {  scanf("%d", &parm[10]);
 244.749 +         scanf("%d", &parm[11]);
 244.750 +      }
 244.751 +      else
 244.752 +      {  scanf("%le", &temp);
 244.753 +         parm[10] = (int)(100.0 * temp + .5);
 244.754 +         parm[11] = 0;
 244.755 +      }
 244.756 +      scanf("%d", &parm[12]);
 244.757 +      if (parm[12] == 1)
 244.758 +      {  scanf("%d", &parm[13]);
 244.759 +         scanf("%d", &parm[14]);
 244.760 +      }
 244.761 +      else
 244.762 +      {  scanf("%le", &temp);
 244.763 +         parm[13] = (int)(100.0 * temp + .5);
 244.764 +         parm[14] = 0;
 244.765 +      }
 244.766 +      glp_gridgen(NULL, 0, 0, 0, parm);
 244.767 +      return 0;
 244.768 +}
 244.769 +#endif
 244.770 +
 244.771 +/* eof */
   245.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   245.2 +++ b/src/glpnet05.c	Mon Dec 06 13:09:21 2010 +0100
   245.3 @@ -0,0 +1,367 @@
   245.4 +/* glpnet05.c (Goldfarb's maximum flow problem generator) */
   245.5 +
   245.6 +/***********************************************************************
   245.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   245.8 +*
   245.9 +*  This code is a modified version of the program RMFGEN, a maxflow
  245.10 +*  problem generator developed by D.Goldfarb and M.Grigoriadis, and
  245.11 +*  originally implemented by Tamas Badics <badics@rutcor.rutgers.edu>.
  245.12 +*  The original code is publically available on the DIMACS ftp site at:
  245.13 +*  <ftp://dimacs.rutgers.edu/pub/netflow/generators/network/genrmf>.
  245.14 +*
  245.15 +*  All changes concern only the program interface, so this modified
  245.16 +*  version produces exactly the same instances as the original version.
  245.17 +*
  245.18 +*  Changes were made by Andrew Makhorin <mao@gnu.org>.
  245.19 +*
  245.20 +*  GLPK is free software: you can redistribute it and/or modify it
  245.21 +*  under the terms of the GNU General Public License as published by
  245.22 +*  the Free Software Foundation, either version 3 of the License, or
  245.23 +*  (at your option) any later version.
  245.24 +*
  245.25 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  245.26 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  245.27 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  245.28 +*  License for more details.
  245.29 +*
  245.30 +*  You should have received a copy of the GNU General Public License
  245.31 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  245.32 +***********************************************************************/
  245.33 +
  245.34 +#include "glpapi.h"
  245.35 +#include "glprng.h"
  245.36 +
  245.37 +/***********************************************************************
  245.38 +*  NAME
  245.39 +*
  245.40 +*  glp_rmfgen - Goldfarb's maximum flow problem generator
  245.41 +*
  245.42 +*  SYNOPSIS
  245.43 +*
  245.44 +*  int glp_rmfgen(glp_graph *G, int *s, int *t, int a_cap,
  245.45 +*     const int parm[1+5]);
  245.46 +*
  245.47 +*  DESCRIPTION
  245.48 +*
  245.49 +*  The routine glp_rmfgen is a maximum flow problem generator developed
  245.50 +*  by D.Goldfarb and M.Grigoriadis.
  245.51 +*
  245.52 +*  The parameter G specifies the graph object, to which the generated
  245.53 +*  problem data have to be stored. Note that on entry the graph object
  245.54 +*  is erased with the routine glp_erase_graph.
  245.55 +*
  245.56 +*  The pointer s specifies a location, to which the routine stores the
  245.57 +*  source node number. If s is NULL, the node number is not stored.
  245.58 +*
  245.59 +*  The pointer t specifies a location, to which the routine stores the
  245.60 +*  sink node number. If t is NULL, the node number is not stored.
  245.61 +*
  245.62 +*  The parameter a_cap specifies an offset of the field of type double
  245.63 +*  in the arc data block, to which the routine stores the arc capacity.
  245.64 +*  If a_cap < 0, the capacity is not stored.
  245.65 +*
  245.66 +*  The array parm contains description of the network to be generated:
  245.67 +*
  245.68 +*  parm[0]  not used
  245.69 +*  parm[1]  (seed)   random number seed (a positive integer)
  245.70 +*  parm[2]  (a)      frame size
  245.71 +*  parm[3]  (b)      depth
  245.72 +*  parm[4]  (c1)     minimal arc capacity
  245.73 +*  parm[5]  (c2)     maximal arc capacity
  245.74 +*
  245.75 +*  RETURNS
  245.76 +*
  245.77 +*  If the instance was successfully generated, the routine glp_netgen
  245.78 +*  returns zero; otherwise, if specified parameters are inconsistent,
  245.79 +*  the routine returns a non-zero error code.
  245.80 +*
  245.81 +*  COMMENTS
  245.82 +*
  245.83 +*  The generated network is as follows. It has b pieces of frames of
  245.84 +*  size a * a. (So alltogether the number of vertices is a * a * b)
  245.85 +*
  245.86 +*  In each frame all the vertices are connected with their neighbours
  245.87 +*  (forth and back). In addition the vertices of a frame are connected
  245.88 +*  one to one with the vertices of next frame using a random permutation
  245.89 +*  of those vertices.
  245.90 +*
  245.91 +*  The source is the lower left vertex of the first frame, the sink is
  245.92 +*  the upper right vertex of the b'th frame.
  245.93 +*
  245.94 +*                    t
  245.95 +*           +-------+
  245.96 +*           |      .|
  245.97 +*           |     . |
  245.98 +*        /  |    /  |
  245.99 +*       +-------+/ -+ b
 245.100 +*       |    |  |/.
 245.101 +*     a |   -v- |/
 245.102 +*       |    |  |/
 245.103 +*       +-------+ 1
 245.104 +*      s    a
 245.105 +*
 245.106 +*  The capacities are randomly chosen integers from the range of [c1,c2]
 245.107 +*  in the case of interconnecting edges, and c2 * a * a for the in-frame
 245.108 +*  edges.
 245.109 +*
 245.110 +*  REFERENCES
 245.111 +*
 245.112 +*  D.Goldfarb and M.D.Grigoriadis, "A computational comparison of the
 245.113 +*  Dinic and network simplex methods for maximum flow." Annals of Op.
 245.114 +*  Res. 13 (1988), pp. 83-123.
 245.115 +*
 245.116 +*  U.Derigs and W.Meier, "Implementing Goldberg's max-flow algorithm:
 245.117 +*  A computational investigation." Zeitschrift fuer Operations Research
 245.118 +*  33 (1989), pp. 383-403. */
 245.119 +
 245.120 +typedef struct VERTEX
 245.121 +{     struct EDGE **edgelist;
 245.122 +      /* Pointer to the list of pointers to the adjacent edges.
 245.123 +         (No matter that to or from edges) */
 245.124 +      struct EDGE **current;
 245.125 +      /* Pointer to the current edge */
 245.126 +      int degree;
 245.127 +      /* Number of adjacent edges (both direction) */
 245.128 +      int index;
 245.129 +} vertex;
 245.130 +
 245.131 +typedef struct EDGE
 245.132 +{     int from;
 245.133 +      int to;
 245.134 +      int cap;
 245.135 +      /* Capacity */
 245.136 +} edge;
 245.137 +
 245.138 +typedef struct NETWORK
 245.139 +{     struct NETWORK *next, *prev;
 245.140 +      int vertnum;
 245.141 +      int edgenum;
 245.142 +      vertex *verts;
 245.143 +      /* Vertex array[1..vertnum] */
 245.144 +      edge *edges;
 245.145 +      /* Edge array[1..edgenum] */
 245.146 +      int source;
 245.147 +      /* Pointer to the source */
 245.148 +      int sink;
 245.149 +      /* Pointer to the sink */
 245.150 +} network;
 245.151 +
 245.152 +struct csa
 245.153 +{     /* common storage area */
 245.154 +      glp_graph *G;
 245.155 +      int *s, *t, a_cap;
 245.156 +      RNG *rand;
 245.157 +      network *N;
 245.158 +      int *Parr;
 245.159 +      int A, AA, C2AA, Ec;
 245.160 +};
 245.161 +
 245.162 +#define G      (csa->G)
 245.163 +#define s      (csa->s)
 245.164 +#define t      (csa->t)
 245.165 +#define a_cap  (csa->a_cap)
 245.166 +#define N      (csa->N)
 245.167 +#define Parr   (csa->Parr)
 245.168 +#define A      (csa->A)
 245.169 +#define AA     (csa->AA)
 245.170 +#define C2AA   (csa->C2AA)
 245.171 +#define Ec     (csa->Ec)
 245.172 +
 245.173 +#undef random
 245.174 +#define random(A) (int)(rng_unif_01(csa->rand) * (double)(A))
 245.175 +#define RANDOM(A, B) (int)(random((B) - (A) + 1) + (A))
 245.176 +#define sgn(A) (((A) > 0) ? 1 : ((A) == 0) ? 0 : -1)
 245.177 +
 245.178 +static void make_edge(struct csa *csa, int from, int to, int c1, int c2)
 245.179 +{     Ec++;
 245.180 +      N->edges[Ec].from = from;
 245.181 +      N->edges[Ec].to = to;
 245.182 +      N->edges[Ec].cap = RANDOM(c1, c2);
 245.183 +      return;
 245.184 +}
 245.185 +
 245.186 +static void permute(struct csa *csa)
 245.187 +{     int i, j, tmp;
 245.188 +      for (i = 1; i < AA; i++)
 245.189 +      {  j = RANDOM(i, AA);
 245.190 +         tmp = Parr[i];
 245.191 +         Parr[i] = Parr[j];
 245.192 +         Parr[j] = tmp;
 245.193 +      }
 245.194 +      return;
 245.195 +}
 245.196 +
 245.197 +static void connect(struct csa *csa, int offset, int cv, int x1, int y1)
 245.198 +{     int cv1;
 245.199 +      cv1 = offset + (x1 - 1) * A + y1;
 245.200 +      Ec++;
 245.201 +      N->edges[Ec].from = cv;
 245.202 +      N->edges[Ec].to = cv1;
 245.203 +      N->edges[Ec].cap = C2AA;
 245.204 +      return;
 245.205 +}
 245.206 +
 245.207 +static network *gen_rmf(struct csa *csa, int a, int b, int c1, int c2)
 245.208 +{     /* generates a network with a*a*b nodes and 6a*a*b-4ab-2a*a edges
 245.209 +         random_frame network:
 245.210 +         Derigs & Meier, Methods & Models of OR (1989), 33:383-403 */
 245.211 +      int x, y, z, offset, cv;
 245.212 +      A = a;
 245.213 +      AA = a * a;
 245.214 +      C2AA = c2 * AA;
 245.215 +      Ec = 0;
 245.216 +      N = (network *)xmalloc(sizeof(network));
 245.217 +      N->vertnum = AA * b;
 245.218 +      N->edgenum = 5 * AA * b - 4 * A * b - AA;
 245.219 +      N->edges = (edge *)xcalloc(N->edgenum + 1, sizeof(edge));
 245.220 +      N->source = 1;
 245.221 +      N->sink = N->vertnum;
 245.222 +      Parr = (int *)xcalloc(AA + 1, sizeof(int));
 245.223 +      for (x = 1; x <= AA; x++)
 245.224 +         Parr[x] = x;
 245.225 +      for (z = 1; z <= b; z++)
 245.226 +      {  offset = AA * (z - 1);
 245.227 +         if (z != b)
 245.228 +            permute(csa);
 245.229 +         for (x = 1; x <= A; x++)
 245.230 +         {  for (y = 1; y <= A; y++)
 245.231 +            {  cv = offset + (x - 1) * A + y;
 245.232 +               if (z != b)
 245.233 +                  make_edge(csa, cv, offset + AA + Parr[cv - offset],
 245.234 +                     c1, c2); /* the intermediate edges */
 245.235 +               if (y < A)
 245.236 +                  connect(csa, offset, cv, x, y + 1);
 245.237 +               if (y > 1)
 245.238 +                  connect(csa, offset, cv, x, y - 1);
 245.239 +               if (x < A)
 245.240 +                  connect(csa, offset, cv, x + 1, y);
 245.241 +               if (x > 1)
 245.242 +                  connect(csa, offset, cv, x - 1, y);
 245.243 +            }
 245.244 +         }
 245.245 +      }
 245.246 +      xfree(Parr);
 245.247 +      return N;
 245.248 +}
 245.249 +
 245.250 +static void print_max_format(struct csa *csa, network *n, char *comm[],
 245.251 +      int dim)
 245.252 +{     /* prints a network heading with dim lines of comments (no \n
 245.253 +         needs at the ends) */
 245.254 +      int i, vnum, e_num;
 245.255 +      edge *e;
 245.256 +      vnum = n->vertnum;
 245.257 +      e_num = n->edgenum;
 245.258 +      if (G == NULL)
 245.259 +      {  for (i = 0; i < dim; i++)
 245.260 +            xprintf("c %s\n", comm[i]);
 245.261 +         xprintf("p max %7d %10d\n", vnum, e_num);
 245.262 +         xprintf("n %7d s\n", n->source);
 245.263 +         xprintf("n %7d t\n", n->sink);
 245.264 +      }
 245.265 +      else
 245.266 +      {  glp_add_vertices(G, vnum);
 245.267 +         if (s != NULL) *s = n->source;
 245.268 +         if (t != NULL) *t = n->sink;
 245.269 +      }
 245.270 +      for (i = 1; i <= e_num; i++)
 245.271 +      {  e = &n->edges[i];
 245.272 +         if (G == NULL)
 245.273 +            xprintf("a %7d %7d %10d\n", e->from, e->to, (int)e->cap);
 245.274 +         else
 245.275 +         {  glp_arc *a = glp_add_arc(G, e->from, e->to);
 245.276 +            if (a_cap >= 0)
 245.277 +            {  double temp = (double)e->cap;
 245.278 +               memcpy((char *)a->data + a_cap, &temp, sizeof(double));
 245.279 +            }
 245.280 +         }
 245.281 +      }
 245.282 +      return;
 245.283 +}
 245.284 +
 245.285 +static void gen_free_net(network *n)
 245.286 +{     xfree(n->edges);
 245.287 +      xfree(n);
 245.288 +      return;
 245.289 +}
 245.290 +
 245.291 +int glp_rmfgen(glp_graph *G_, int *_s, int *_t, int _a_cap,
 245.292 +      const int parm[1+5])
 245.293 +{     struct csa _csa, *csa = &_csa;
 245.294 +      network *n;
 245.295 +      char comm[10][80], *com1[10];
 245.296 +      int seed, a, b, c1, c2, ret;
 245.297 +      G = G_;
 245.298 +      s = _s;
 245.299 +      t = _t;
 245.300 +      a_cap = _a_cap;
 245.301 +      if (G != NULL)
 245.302 +      {  if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
 245.303 +           xerror("glp_rmfgen: a_cap = %d; invalid offset\n", a_cap);
 245.304 +      }
 245.305 +      seed = parm[1];
 245.306 +      a = parm[2];
 245.307 +      b = parm[3];
 245.308 +      c1 = parm[4];
 245.309 +      c2 = parm[5];
 245.310 +      if (!(seed > 0 && 1 <= a && a <= 1000 && 1 <= b && b <= 1000 &&
 245.311 +            0 <= c1 && c1 <= c2 && c2 <= 1000))
 245.312 +      {  ret = 1;
 245.313 +         goto done;
 245.314 +      }
 245.315 +      if (G != NULL)
 245.316 +      {  glp_erase_graph(G, G->v_size, G->a_size);
 245.317 +         glp_set_graph_name(G, "RMFGEN");
 245.318 +      }
 245.319 +      csa->rand = rng_create_rand();
 245.320 +      rng_init_rand(csa->rand, seed);
 245.321 +      n = gen_rmf(csa, a, b, c1, c2);
 245.322 +      sprintf(comm[0], "This file was generated by genrmf.");
 245.323 +      sprintf(comm[1], "The parameters are: a: %d b: %d c1: %d c2: %d",
 245.324 +         a, b, c1, c2);
 245.325 +      com1[0] = comm[0];
 245.326 +      com1[1] = comm[1];
 245.327 +      print_max_format(csa, n, com1, 2);
 245.328 +      gen_free_net(n);
 245.329 +      rng_delete_rand(csa->rand);
 245.330 +      ret = 0;
 245.331 +done: return ret;
 245.332 +}
 245.333 +
 245.334 +/**********************************************************************/
 245.335 +
 245.336 +#if 0
 245.337 +int main(int argc, char *argv[])
 245.338 +{     int seed, a, b, c1, c2, i, parm[1+5];
 245.339 +      seed = 123;
 245.340 +      a = b = c1 = c2 = -1;
 245.341 +      for (i = 1; i < argc; i++)
 245.342 +      {  if (strcmp(argv[i], "-seed") == 0)
 245.343 +            seed = atoi(argv[++i]);
 245.344 +         else if (strcmp(argv[i], "-a") == 0)
 245.345 +            a = atoi(argv[++i]);
 245.346 +         else if (strcmp(argv[i], "-b") == 0)
 245.347 +            b = atoi(argv[++i]);
 245.348 +         else if (strcmp(argv[i], "-c1") == 0)
 245.349 +            c1 = atoi(argv[++i]);
 245.350 +         else if (strcmp(argv[i], "-c2") == 0)
 245.351 +            c2 = atoi(argv[++i]);
 245.352 +      }
 245.353 +      if (a < 0 || b < 0 || c1 < 0 || c2 < 0)
 245.354 +      {  xprintf("Usage:\n");
 245.355 +         xprintf("genrmf [-seed seed] -a frame_size -b depth\n");
 245.356 +         xprintf("        -c1 cap_range1 -c2 cap_range2\n");
 245.357 +      }
 245.358 +      else
 245.359 +      {  parm[1] = seed;
 245.360 +         parm[2] = a;
 245.361 +         parm[3] = b;
 245.362 +         parm[4] = c1;
 245.363 +         parm[5] = c2;
 245.364 +         glp_rmfgen(NULL, NULL, NULL, 0, parm);
 245.365 +      }
 245.366 +      return 0;
 245.367 +}
 245.368 +#endif
 245.369 +
 245.370 +/* eof */
   246.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   246.2 +++ b/src/glpnet06.c	Mon Dec 06 13:09:21 2010 +0100
   246.3 @@ -0,0 +1,383 @@
   246.4 +/* glpnet06.c (out-of-kilter algorithm) */
   246.5 +
   246.6 +/***********************************************************************
   246.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   246.8 +*
   246.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  246.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  246.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  246.12 +*  E-mail: <mao@gnu.org>.
  246.13 +*
  246.14 +*  GLPK is free software: you can redistribute it and/or modify it
  246.15 +*  under the terms of the GNU General Public License as published by
  246.16 +*  the Free Software Foundation, either version 3 of the License, or
  246.17 +*  (at your option) any later version.
  246.18 +*
  246.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  246.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  246.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  246.22 +*  License for more details.
  246.23 +*
  246.24 +*  You should have received a copy of the GNU General Public License
  246.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  246.26 +***********************************************************************/
  246.27 +
  246.28 +#include "glpenv.h"
  246.29 +#include "glpnet.h"
  246.30 +
  246.31 +/***********************************************************************
  246.32 +*  NAME
  246.33 +*
  246.34 +*  okalg - out-of-kilter algorithm
  246.35 +*
  246.36 +*  SYNOPSIS
  246.37 +*
  246.38 +*  #include "glpnet.h"
  246.39 +*  int okalg(int nv, int na, const int tail[], const int head[],
  246.40 +*     const int low[], const int cap[], const int cost[], int x[],
  246.41 +*     int pi[]);
  246.42 +*
  246.43 +*  DESCRIPTION
  246.44 +*
  246.45 +*  The routine okalg implements the out-of-kilter algorithm to find a
  246.46 +*  minimal-cost circulation in the specified flow network.
  246.47 +*
  246.48 +*  INPUT PARAMETERS
  246.49 +*
  246.50 +*  nv is the number of nodes, nv >= 0.
  246.51 +*
  246.52 +*  na is the number of arcs, na >= 0.
  246.53 +*
  246.54 +*  tail[a], a = 1,...,na, is the index of tail node of arc a.
  246.55 +*
  246.56 +*  head[a], a = 1,...,na, is the index of head node of arc a.
  246.57 +*
  246.58 +*  low[a], a = 1,...,na, is an lower bound to the flow through arc a.
  246.59 +*
  246.60 +*  cap[a], a = 1,...,na, is an upper bound to the flow through arc a,
  246.61 +*  which is the capacity of the arc.
  246.62 +*
  246.63 +*  cost[a], a = 1,...,na, is a per-unit cost of the flow through arc a.
  246.64 +*
  246.65 +*  NOTES
  246.66 +*
  246.67 +*  1. Multiple arcs are allowed, but self-loops are not allowed.
  246.68 +*
  246.69 +*  2. It is required that 0 <= low[a] <= cap[a] for all arcs.
  246.70 +*
  246.71 +*  3. Arc costs may have any sign.
  246.72 +*
  246.73 +*  OUTPUT PARAMETERS
  246.74 +*
  246.75 +*  x[a], a = 1,...,na, is optimal value of the flow through arc a.
  246.76 +*
  246.77 +*  pi[i], i = 1,...,nv, is Lagrange multiplier for flow conservation
  246.78 +*  equality constraint corresponding to node i (the node potential).
  246.79 +*
  246.80 +*  RETURNS
  246.81 +*
  246.82 +*  0  optimal circulation found;
  246.83 +*
  246.84 +*  1  there is no feasible circulation;
  246.85 +*
  246.86 +*  2  integer overflow occured;
  246.87 +*
  246.88 +*  3  optimality test failed (logic error).
  246.89 +*
  246.90 +*  REFERENCES
  246.91 +*
  246.92 +*  L.R.Ford, Jr., and D.R.Fulkerson, "Flows in Networks," The RAND
  246.93 +*  Corp., Report R-375-PR (August 1962), Chap. III "Minimal Cost Flow
  246.94 +*  Problems," pp.113-26. */
  246.95 +
  246.96 +static int overflow(int u, int v)
  246.97 +{     /* check for integer overflow on computing u + v */
  246.98 +      if (u > 0 && v > 0 && u + v < 0) return 1;
  246.99 +      if (u < 0 && v < 0 && u + v > 0) return 1;
 246.100 +      return 0;
 246.101 +}
 246.102 +
 246.103 +int okalg(int nv, int na, const int tail[], const int head[],
 246.104 +      const int low[], const int cap[], const int cost[], int x[],
 246.105 +      int pi[])
 246.106 +{     int a, aok, delta, i, j, k, lambda, pos1, pos2, s, t, temp, ret,
 246.107 +         *ptr, *arc, *link, *list;
 246.108 +      /* sanity checks */
 246.109 +      xassert(nv >= 0);
 246.110 +      xassert(na >= 0);
 246.111 +      for (a = 1; a <= na; a++)
 246.112 +      {  i = tail[a], j = head[a];
 246.113 +         xassert(1 <= i && i <= nv);
 246.114 +         xassert(1 <= j && j <= nv);
 246.115 +         xassert(i != j);
 246.116 +         xassert(0 <= low[a] && low[a] <= cap[a]);
 246.117 +      }
 246.118 +      /* allocate working arrays */
 246.119 +      ptr = xcalloc(1+nv+1, sizeof(int));
 246.120 +      arc = xcalloc(1+na+na, sizeof(int));
 246.121 +      link = xcalloc(1+nv, sizeof(int));
 246.122 +      list = xcalloc(1+nv, sizeof(int));
 246.123 +      /* ptr[i] := (degree of node i) */
 246.124 +      for (i = 1; i <= nv; i++)
 246.125 +         ptr[i] = 0;
 246.126 +      for (a = 1; a <= na; a++)
 246.127 +      {  ptr[tail[a]]++;
 246.128 +         ptr[head[a]]++;
 246.129 +      }
 246.130 +      /* initialize arc pointers */
 246.131 +      ptr[1]++;
 246.132 +      for (i = 1; i < nv; i++)
 246.133 +         ptr[i+1] += ptr[i];
 246.134 +      ptr[nv+1] = ptr[nv];
 246.135 +      /* build arc lists */
 246.136 +      for (a = 1; a <= na; a++)
 246.137 +      {  arc[--ptr[tail[a]]] = a;
 246.138 +         arc[--ptr[head[a]]] = a;
 246.139 +      }
 246.140 +      xassert(ptr[1] == 1);
 246.141 +      xassert(ptr[nv+1] == na+na+1);
 246.142 +      /* now the indices of arcs incident to node i are stored in
 246.143 +         locations arc[ptr[i]], arc[ptr[i]+1], ..., arc[ptr[i+1]-1] */
 246.144 +      /* initialize arc flows and node potentials */
 246.145 +      for (a = 1; a <= na; a++)
 246.146 +         x[a] = 0;
 246.147 +      for (i = 1; i <= nv; i++)
 246.148 +         pi[i] = 0;
 246.149 +loop: /* main loop starts here */
 246.150 +      /* find out-of-kilter arc */
 246.151 +      aok = 0;
 246.152 +      for (a = 1; a <= na; a++)
 246.153 +      {  i = tail[a], j = head[a];
 246.154 +         if (overflow(cost[a], pi[i] - pi[j]))
 246.155 +         {  ret = 2;
 246.156 +            goto done;
 246.157 +         }
 246.158 +         lambda = cost[a] + (pi[i] - pi[j]);
 246.159 +         if (x[a] < low[a] || lambda < 0 && x[a] < cap[a])
 246.160 +         {  /* arc a = i->j is out of kilter, and we need to increase
 246.161 +               the flow through this arc */
 246.162 +            aok = a, s = j, t = i;
 246.163 +            break;
 246.164 +         }
 246.165 +         if (x[a] > cap[a] || lambda > 0 && x[a] > low[a])
 246.166 +         {  /* arc a = i->j is out of kilter, and we need to decrease
 246.167 +               the flow through this arc */
 246.168 +            aok = a, s = i, t = j;
 246.169 +            break;
 246.170 +         }
 246.171 +      }
 246.172 +      if (aok == 0)
 246.173 +      {  /* all arcs are in kilter */
 246.174 +         /* check for feasibility */
 246.175 +         for (a = 1; a <= na; a++)
 246.176 +         {  if (!(low[a] <= x[a] && x[a] <= cap[a]))
 246.177 +            {  ret = 3;
 246.178 +               goto done;
 246.179 +            }
 246.180 +         }
 246.181 +         for (i = 1; i <= nv; i++)
 246.182 +         {  temp = 0;
 246.183 +            for (k = ptr[i]; k < ptr[i+1]; k++)
 246.184 +            {  a = arc[k];
 246.185 +               if (tail[a] == i)
 246.186 +               {  /* a is outgoing arc */
 246.187 +                  temp += x[a];
 246.188 +               }
 246.189 +               else if (head[a] == i)
 246.190 +               {  /* a is incoming arc */
 246.191 +                  temp -= x[a];
 246.192 +               }
 246.193 +               else
 246.194 +                  xassert(a != a);
 246.195 +            }
 246.196 +            if (temp != 0)
 246.197 +            {  ret = 3;
 246.198 +               goto done;
 246.199 +            }
 246.200 +         }
 246.201 +         /* check for optimality */
 246.202 +         for (a = 1; a <= na; a++)
 246.203 +         {  i = tail[a], j = head[a];
 246.204 +            lambda = cost[a] + (pi[i] - pi[j]);
 246.205 +            if (lambda > 0 && x[a] != low[a] ||
 246.206 +                lambda < 0 && x[a] != cap[a])
 246.207 +            {  ret = 3;
 246.208 +               goto done;
 246.209 +            }
 246.210 +         }
 246.211 +         /* current circulation is optimal */
 246.212 +         ret = 0;
 246.213 +         goto done;
 246.214 +      }
 246.215 +      /* now we need to find a cycle (t, a, s, ..., t), which allows
 246.216 +         increasing the flow along it, where a is the out-of-kilter arc
 246.217 +         just found */
 246.218 +      /* link[i] = 0 means that node i is not labelled yet;
 246.219 +         link[i] = a means that arc a immediately precedes node i */
 246.220 +      /* initially only node s is labelled */
 246.221 +      for (i = 1; i <= nv; i++)
 246.222 +         link[i] = 0;
 246.223 +      link[s] = aok, list[1] = s, pos1 = pos2 = 1;
 246.224 +      /* breadth first search */
 246.225 +      while (pos1 <= pos2)
 246.226 +      {  /* dequeue node i */
 246.227 +         i = list[pos1++];
 246.228 +         /* consider all arcs incident to node i */
 246.229 +         for (k = ptr[i]; k < ptr[i+1]; k++)
 246.230 +         {  a = arc[k];
 246.231 +            if (tail[a] == i)
 246.232 +            {  /* a = i->j is a forward arc from s to t */
 246.233 +               j = head[a];
 246.234 +               /* if node j has been labelled, skip the arc */
 246.235 +               if (link[j] != 0) continue;
 246.236 +               /* if the arc does not allow increasing the flow through
 246.237 +                  it, skip the arc */
 246.238 +               if (x[a] >= cap[a]) continue;
 246.239 +               if (overflow(cost[a], pi[i] - pi[j]))
 246.240 +               {  ret = 2;
 246.241 +                  goto done;
 246.242 +               }
 246.243 +               lambda = cost[a] + (pi[i] - pi[j]);
 246.244 +               if (lambda > 0 && x[a] >= low[a]) continue;
 246.245 +            }
 246.246 +            else if (head[a] == i)
 246.247 +            {  /* a = i<-j is a backward arc from s to t */
 246.248 +               j = tail[a];
 246.249 +               /* if node j has been labelled, skip the arc */
 246.250 +               if (link[j] != 0) continue;
 246.251 +               /* if the arc does not allow decreasing the flow through
 246.252 +                  it, skip the arc */
 246.253 +               if (x[a] <= low[a]) continue;
 246.254 +               if (overflow(cost[a], pi[j] - pi[i]))
 246.255 +               {  ret = 2;
 246.256 +                  goto done;
 246.257 +               }
 246.258 +               lambda = cost[a] + (pi[j] - pi[i]);
 246.259 +               if (lambda < 0 && x[a] <= cap[a]) continue;
 246.260 +            }
 246.261 +            else
 246.262 +               xassert(a != a);
 246.263 +            /* label node j and enqueue it */
 246.264 +            link[j] = a, list[++pos2] = j;
 246.265 +            /* check for breakthrough */
 246.266 +            if (j == t) goto brkt;
 246.267 +         }
 246.268 +      }
 246.269 +      /* NONBREAKTHROUGH */
 246.270 +      /* consider all arcs, whose one endpoint is labelled and other is
 246.271 +         not, and determine maximal change of node potentials */
 246.272 +      delta = 0;
 246.273 +      for (a = 1; a <= na; a++)
 246.274 +      {  i = tail[a], j = head[a];
 246.275 +         if (link[i] != 0 && link[j] == 0)
 246.276 +         {  /* a = i->j, where node i is labelled, node j is not */
 246.277 +            if (overflow(cost[a], pi[i] - pi[j]))
 246.278 +            {  ret = 2;
 246.279 +               goto done;
 246.280 +            }
 246.281 +            lambda = cost[a] + (pi[i] - pi[j]);
 246.282 +            if (x[a] <= cap[a] && lambda > 0)
 246.283 +               if (delta == 0 || delta > + lambda) delta = + lambda;
 246.284 +         }
 246.285 +         else if (link[i] == 0 && link[j] != 0)
 246.286 +         {  /* a = j<-i, where node j is labelled, node i is not */
 246.287 +            if (overflow(cost[a], pi[i] - pi[j]))
 246.288 +            {  ret = 2;
 246.289 +               goto done;
 246.290 +            }
 246.291 +            lambda = cost[a] + (pi[i] - pi[j]);
 246.292 +            if (x[a] >= low[a] && lambda < 0)
 246.293 +               if (delta == 0 || delta > - lambda) delta = - lambda;
 246.294 +         }
 246.295 +      }
 246.296 +      if (delta == 0)
 246.297 +      {  /* there is no feasible circulation */
 246.298 +         ret = 1;
 246.299 +         goto done;
 246.300 +      }
 246.301 +      /* increase potentials of all unlabelled nodes */
 246.302 +      for (i = 1; i <= nv; i++)
 246.303 +      {  if (link[i] == 0)
 246.304 +         {  if (overflow(pi[i], delta))
 246.305 +            {  ret = 2;
 246.306 +               goto done;
 246.307 +            }
 246.308 +            pi[i] += delta;
 246.309 +         }
 246.310 +      }
 246.311 +      goto loop;
 246.312 +brkt: /* BREAKTHROUGH */
 246.313 +      /* walk through arcs of the cycle (t, a, s, ..., t) found in the
 246.314 +         reverse order and determine maximal change of the flow */
 246.315 +      delta = 0;
 246.316 +      for (j = t;; j = i)
 246.317 +      {  /* arc a immediately precedes node j in the cycle */
 246.318 +         a = link[j];
 246.319 +         if (head[a] == j)
 246.320 +         {  /* a = i->j is a forward arc of the cycle */
 246.321 +            i = tail[a];
 246.322 +            lambda = cost[a] + (pi[i] - pi[j]);
 246.323 +            if (lambda > 0 && x[a] < low[a])
 246.324 +            {  /* x[a] may be increased until its lower bound */
 246.325 +               temp = low[a] - x[a];
 246.326 +            }
 246.327 +            else if (lambda <= 0 && x[a] < cap[a])
 246.328 +            {  /* x[a] may be increased until its upper bound */
 246.329 +               temp = cap[a] - x[a];
 246.330 +            }
 246.331 +            else
 246.332 +               xassert(a != a);
 246.333 +         }
 246.334 +         else if (tail[a] == j)
 246.335 +         {  /* a = i<-j is a backward arc of the cycle */
 246.336 +            i = head[a];
 246.337 +            lambda = cost[a] + (pi[j] - pi[i]);
 246.338 +            if (lambda < 0 && x[a] > cap[a])
 246.339 +            {  /* x[a] may be decreased until its upper bound */
 246.340 +               temp = x[a] - cap[a];
 246.341 +            }
 246.342 +            else if (lambda >= 0 && x[a] > low[a])
 246.343 +            {  /* x[a] may be decreased until its lower bound */
 246.344 +               temp = x[a] - low[a];
 246.345 +            }
 246.346 +            else
 246.347 +               xassert(a != a);
 246.348 +         }
 246.349 +         else
 246.350 +            xassert(a != a);
 246.351 +         if (delta == 0 || delta > temp) delta = temp;
 246.352 +         /* check for end of the cycle */
 246.353 +         if (i == t) break;
 246.354 +      }
 246.355 +      xassert(delta > 0);
 246.356 +      /* increase the flow along the cycle */
 246.357 +      for (j = t;; j = i)
 246.358 +      {  /* arc a immediately precedes node j in the cycle */
 246.359 +         a = link[j];
 246.360 +         if (head[a] == j)
 246.361 +         {  /* a = i->j is a forward arc of the cycle */
 246.362 +            i = tail[a];
 246.363 +            /* overflow cannot occur */
 246.364 +            x[a] += delta;
 246.365 +         }
 246.366 +         else if (tail[a] == j)
 246.367 +         {  /* a = i<-j is a backward arc of the cycle */
 246.368 +            i = head[a];
 246.369 +            /* overflow cannot occur */
 246.370 +            x[a] -= delta;
 246.371 +         }
 246.372 +         else
 246.373 +            xassert(a != a);
 246.374 +         /* check for end of the cycle */
 246.375 +         if (i == t) break;
 246.376 +      }
 246.377 +      goto loop;
 246.378 +done: /* free working arrays */
 246.379 +      xfree(ptr);
 246.380 +      xfree(arc);
 246.381 +      xfree(link);
 246.382 +      xfree(list);
 246.383 +      return ret;
 246.384 +}
 246.385 +
 246.386 +/* eof */
   247.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   247.2 +++ b/src/glpnet07.c	Mon Dec 06 13:09:21 2010 +0100
   247.3 @@ -0,0 +1,222 @@
   247.4 +/* glpnet07.c (Ford-Fulkerson algorithm) */
   247.5 +
   247.6 +/***********************************************************************
   247.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   247.8 +*
   247.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  247.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  247.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  247.12 +*  E-mail: <mao@gnu.org>.
  247.13 +*
  247.14 +*  GLPK is free software: you can redistribute it and/or modify it
  247.15 +*  under the terms of the GNU General Public License as published by
  247.16 +*  the Free Software Foundation, either version 3 of the License, or
  247.17 +*  (at your option) any later version.
  247.18 +*
  247.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  247.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  247.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  247.22 +*  License for more details.
  247.23 +*
  247.24 +*  You should have received a copy of the GNU General Public License
  247.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  247.26 +***********************************************************************/
  247.27 +
  247.28 +#include "glpenv.h"
  247.29 +#include "glpnet.h"
  247.30 +
  247.31 +/***********************************************************************
  247.32 +*  NAME
  247.33 +*
  247.34 +*  ffalg - Ford-Fulkerson algorithm
  247.35 +*
  247.36 +*  SYNOPSIS
  247.37 +*
  247.38 +*  #include "glpnet.h"
  247.39 +*  void ffalg(int nv, int na, const int tail[], const int head[],
  247.40 +*     int s, int t, const int cap[], int x[], char cut[]);
  247.41 +*
  247.42 +*  DESCRIPTION
  247.43 +*
  247.44 +*  The routine ffalg implements the Ford-Fulkerson algorithm to find a
  247.45 +*  maximal flow in the specified flow network.
  247.46 +*
  247.47 +*  INPUT PARAMETERS
  247.48 +*
  247.49 +*  nv is the number of nodes, nv >= 2.
  247.50 +*
  247.51 +*  na is the number of arcs, na >= 0.
  247.52 +*
  247.53 +*  tail[a], a = 1,...,na, is the index of tail node of arc a.
  247.54 +*
  247.55 +*  head[a], a = 1,...,na, is the index of head node of arc a.
  247.56 +*
  247.57 +*  s is the source node index, 1 <= s <= nv.
  247.58 +*
  247.59 +*  t is the sink node index, 1 <= t <= nv, t != s.
  247.60 +*
  247.61 +*  cap[a], a = 1,...,na, is the capacity of arc a, cap[a] >= 0.
  247.62 +*
  247.63 +*  NOTE: Multiple arcs are allowed, but self-loops are not allowed.
  247.64 +*
  247.65 +*  OUTPUT PARAMETERS
  247.66 +*
  247.67 +*  x[a], a = 1,...,na, is optimal value of the flow through arc a.
  247.68 +*
  247.69 +*  cut[i], i = 1,...,nv, is 1 if node i is labelled, and 0 otherwise.
  247.70 +*  The set of arcs, whose one endpoint is labelled and other is not,
  247.71 +*  defines the minimal cut corresponding to the maximal flow found.
  247.72 +*  If the parameter cut is NULL, the cut information are not stored.
  247.73 +*
  247.74 +*  REFERENCES
  247.75 +*
  247.76 +*  L.R.Ford, Jr., and D.R.Fulkerson, "Flows in Networks," The RAND
  247.77 +*  Corp., Report R-375-PR (August 1962), Chap. I "Static Maximal Flow,"
  247.78 +*  pp.30-33. */
  247.79 +
  247.80 +void ffalg(int nv, int na, const int tail[], const int head[],
  247.81 +      int s, int t, const int cap[], int x[], char cut[])
  247.82 +{     int a, delta, i, j, k, pos1, pos2, temp,
  247.83 +         *ptr, *arc, *link, *list;
  247.84 +      /* sanity checks */
  247.85 +      xassert(nv >= 2);
  247.86 +      xassert(na >= 0);
  247.87 +      xassert(1 <= s && s <= nv);
  247.88 +      xassert(1 <= t && t <= nv);
  247.89 +      xassert(s != t);
  247.90 +      for (a = 1; a <= na; a++)
  247.91 +      {  i = tail[a], j = head[a];
  247.92 +         xassert(1 <= i && i <= nv);
  247.93 +         xassert(1 <= j && j <= nv);
  247.94 +         xassert(i != j);
  247.95 +         xassert(cap[a] >= 0);
  247.96 +      }
  247.97 +      /* allocate working arrays */
  247.98 +      ptr = xcalloc(1+nv+1, sizeof(int));
  247.99 +      arc = xcalloc(1+na+na, sizeof(int));
 247.100 +      link = xcalloc(1+nv, sizeof(int));
 247.101 +      list = xcalloc(1+nv, sizeof(int));
 247.102 +      /* ptr[i] := (degree of node i) */
 247.103 +      for (i = 1; i <= nv; i++)
 247.104 +         ptr[i] = 0;
 247.105 +      for (a = 1; a <= na; a++)
 247.106 +      {  ptr[tail[a]]++;
 247.107 +         ptr[head[a]]++;
 247.108 +      }
 247.109 +      /* initialize arc pointers */
 247.110 +      ptr[1]++;
 247.111 +      for (i = 1; i < nv; i++)
 247.112 +         ptr[i+1] += ptr[i];
 247.113 +      ptr[nv+1] = ptr[nv];
 247.114 +      /* build arc lists */
 247.115 +      for (a = 1; a <= na; a++)
 247.116 +      {  arc[--ptr[tail[a]]] = a;
 247.117 +         arc[--ptr[head[a]]] = a;
 247.118 +      }
 247.119 +      xassert(ptr[1] == 1);
 247.120 +      xassert(ptr[nv+1] == na+na+1);
 247.121 +      /* now the indices of arcs incident to node i are stored in
 247.122 +         locations arc[ptr[i]], arc[ptr[i]+1], ..., arc[ptr[i+1]-1] */
 247.123 +      /* initialize arc flows */
 247.124 +      for (a = 1; a <= na; a++)
 247.125 +         x[a] = 0;
 247.126 +loop: /* main loop starts here */
 247.127 +      /* build augmenting tree rooted at s */
 247.128 +      /* link[i] = 0 means that node i is not labelled yet;
 247.129 +         link[i] = a means that arc a immediately precedes node i */
 247.130 +      /* initially node s is labelled as the root */
 247.131 +      for (i = 1; i <= nv; i++)
 247.132 +         link[i] = 0;
 247.133 +      link[s] = -1, list[1] = s, pos1 = pos2 = 1;
 247.134 +      /* breadth first search */
 247.135 +      while (pos1 <= pos2)
 247.136 +      {  /* dequeue node i */
 247.137 +         i = list[pos1++];
 247.138 +         /* consider all arcs incident to node i */
 247.139 +         for (k = ptr[i]; k < ptr[i+1]; k++)
 247.140 +         {  a = arc[k];
 247.141 +            if (tail[a] == i)
 247.142 +            {  /* a = i->j is a forward arc from s to t */
 247.143 +               j = head[a];
 247.144 +               /* if node j has been labelled, skip the arc */
 247.145 +               if (link[j] != 0) continue;
 247.146 +               /* if the arc does not allow increasing the flow through
 247.147 +                  it, skip the arc */
 247.148 +               if (x[a] == cap[a]) continue;
 247.149 +            }
 247.150 +            else if (head[a] == i)
 247.151 +            {  /* a = i<-j is a backward arc from s to t */
 247.152 +               j = tail[a];
 247.153 +               /* if node j has been labelled, skip the arc */
 247.154 +               if (link[j] != 0) continue;
 247.155 +               /* if the arc does not allow decreasing the flow through
 247.156 +                  it, skip the arc */
 247.157 +               if (x[a] == 0) continue;
 247.158 +            }
 247.159 +            else
 247.160 +               xassert(a != a);
 247.161 +            /* label node j and enqueue it */
 247.162 +            link[j] = a, list[++pos2] = j;
 247.163 +            /* check for breakthrough */
 247.164 +            if (j == t) goto brkt;
 247.165 +         }
 247.166 +      }
 247.167 +      /* NONBREAKTHROUGH */
 247.168 +      /* no augmenting path exists; current flow is maximal */
 247.169 +      /* store minimal cut information, if necessary */
 247.170 +      if (cut != NULL)
 247.171 +      {  for (i = 1; i <= nv; i++)
 247.172 +            cut[i] = (char)(link[i] != 0);
 247.173 +      }
 247.174 +      goto done;
 247.175 +brkt: /* BREAKTHROUGH */
 247.176 +      /* walk through arcs of the augmenting path (s, ..., t) found in
 247.177 +         the reverse order and determine maximal change of the flow */
 247.178 +      delta = 0;
 247.179 +      for (j = t; j != s; j = i)
 247.180 +      {  /* arc a immediately precedes node j in the path */
 247.181 +         a = link[j];
 247.182 +         if (head[a] == j)
 247.183 +         {  /* a = i->j is a forward arc of the cycle */
 247.184 +            i = tail[a];
 247.185 +            /* x[a] may be increased until its upper bound */
 247.186 +            temp = cap[a] - x[a];
 247.187 +         }
 247.188 +         else if (tail[a] == j)
 247.189 +         {  /* a = i<-j is a backward arc of the cycle */
 247.190 +            i = head[a];
 247.191 +            /* x[a] may be decreased until its lower bound */
 247.192 +            temp = x[a];
 247.193 +         }
 247.194 +         else
 247.195 +            xassert(a != a);
 247.196 +         if (delta == 0 || delta > temp) delta = temp;
 247.197 +      }
 247.198 +      xassert(delta > 0);
 247.199 +      /* increase the flow along the path */
 247.200 +      for (j = t; j != s; j = i)
 247.201 +      {  /* arc a immediately precedes node j in the path */
 247.202 +         a = link[j];
 247.203 +         if (head[a] == j)
 247.204 +         {  /* a = i->j is a forward arc of the cycle */
 247.205 +            i = tail[a];
 247.206 +            x[a] += delta;
 247.207 +         }
 247.208 +         else if (tail[a] == j)
 247.209 +         {  /* a = i<-j is a backward arc of the cycle */
 247.210 +            i = head[a];
 247.211 +            x[a] -= delta;
 247.212 +         }
 247.213 +         else
 247.214 +            xassert(a != a);
 247.215 +      }
 247.216 +      goto loop;
 247.217 +done: /* free working arrays */
 247.218 +      xfree(ptr);
 247.219 +      xfree(arc);
 247.220 +      xfree(link);
 247.221 +      xfree(list);
 247.222 +      return;
 247.223 +}
 247.224 +
 247.225 +/* eof */
   248.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   248.2 +++ b/src/glpnet08.c	Mon Dec 06 13:09:21 2010 +0100
   248.3 @@ -0,0 +1,241 @@
   248.4 +/* glpnet08.c */
   248.5 +
   248.6 +/***********************************************************************
   248.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   248.8 +*
   248.9 +*  Two subroutines sub() and wclique() below are intended to find a
  248.10 +*  maximum weight clique in a given undirected graph. These subroutines
  248.11 +*  are slightly modified version of the program WCLIQUE developed by
  248.12 +*  Patric Ostergard <http://www.tcs.hut.fi/~pat/wclique.html> and based
  248.13 +*  on ideas from the article "P. R. J. Ostergard, A new algorithm for
  248.14 +*  the maximum-weight clique problem, submitted for publication", which
  248.15 +*  in turn is a generalization of the algorithm for unweighted graphs
  248.16 +*  presented in "P. R. J. Ostergard, A fast algorithm for the maximum
  248.17 +*  clique problem, submitted for publication".
  248.18 +*
  248.19 +*  USED WITH PERMISSION OF THE AUTHOR OF THE ORIGINAL CODE.
  248.20 +*
  248.21 +*  Changes were made by Andrew Makhorin <mao@gnu.org>.
  248.22 +*
  248.23 +*  GLPK is free software: you can redistribute it and/or modify it
  248.24 +*  under the terms of the GNU General Public License as published by
  248.25 +*  the Free Software Foundation, either version 3 of the License, or
  248.26 +*  (at your option) any later version.
  248.27 +*
  248.28 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  248.29 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  248.30 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  248.31 +*  License for more details.
  248.32 +*
  248.33 +*  You should have received a copy of the GNU General Public License
  248.34 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  248.35 +***********************************************************************/
  248.36 +
  248.37 +#include "glpenv.h"
  248.38 +#include "glpnet.h"
  248.39 +
  248.40 +/***********************************************************************
  248.41 +*  NAME
  248.42 +*
  248.43 +*  wclique - find maximum weight clique with Ostergard's algorithm
  248.44 +*
  248.45 +*  SYNOPSIS
  248.46 +*
  248.47 +*  int wclique(int n, const int w[], const unsigned char a[],
  248.48 +*     int ind[]);
  248.49 +*
  248.50 +*  DESCRIPTION
  248.51 +*
  248.52 +*  The routine wclique finds a maximum weight clique in an undirected
  248.53 +*  graph with Ostergard's algorithm.
  248.54 +*
  248.55 +*  INPUT PARAMETERS
  248.56 +*
  248.57 +*  n is the number of vertices, n > 0.
  248.58 +*
  248.59 +*  w[i], i = 1,...,n, is a weight of vertex i.
  248.60 +*
  248.61 +*  a[*] is the strict (without main diagonal) lower triangle of the
  248.62 +*  graph adjacency matrix in packed format.
  248.63 +*
  248.64 +*  OUTPUT PARAMETER
  248.65 +*
  248.66 +*  ind[k], k = 1,...,size, is the number of a vertex included in the
  248.67 +*  clique found, 1 <= ind[k] <= n, where size is the number of vertices
  248.68 +*  in the clique returned on exit.
  248.69 +*
  248.70 +*  RETURNS
  248.71 +*
  248.72 +*  The routine returns the clique size, i.e. the number of vertices in
  248.73 +*  the clique. */
  248.74 +
  248.75 +struct csa
  248.76 +{     /* common storage area */
  248.77 +      int n;
  248.78 +      /* number of vertices */
  248.79 +      const int *wt; /* int wt[0:n-1]; */
  248.80 +      /* weights */
  248.81 +      const unsigned char *a;
  248.82 +      /* adjacency matrix (packed lower triangle without main diag.) */
  248.83 +      int record;
  248.84 +      /* weight of best clique */
  248.85 +      int rec_level;
  248.86 +      /* number of vertices in best clique */
  248.87 +      int *rec; /* int rec[0:n-1]; */
  248.88 +      /* best clique so far */
  248.89 +      int *clique; /* int clique[0:n-1]; */
  248.90 +      /* table for pruning */
  248.91 +      int *set; /* int set[0:n-1]; */
  248.92 +      /* current clique */
  248.93 +};
  248.94 +
  248.95 +#define n         (csa->n)
  248.96 +#define wt        (csa->wt)
  248.97 +#define a         (csa->a)
  248.98 +#define record    (csa->record)
  248.99 +#define rec_level (csa->rec_level)
 248.100 +#define rec       (csa->rec)
 248.101 +#define clique    (csa->clique)
 248.102 +#define set       (csa->set)
 248.103 +
 248.104 +#if 0
 248.105 +static int is_edge(struct csa *csa, int i, int j)
 248.106 +{     /* if there is arc (i,j), the routine returns true; otherwise
 248.107 +         false; 0 <= i, j < n */
 248.108 +      int k;
 248.109 +      xassert(0 <= i && i < n);
 248.110 +      xassert(0 <= j && j < n);
 248.111 +      if (i == j) return 0;
 248.112 +      if (i < j) k = i, i = j, j = k;
 248.113 +      k = (i * (i - 1)) / 2 + j;
 248.114 +      return a[k / CHAR_BIT] &
 248.115 +         (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT));
 248.116 +}
 248.117 +#else
 248.118 +#define is_edge(csa, i, j) ((i) == (j) ? 0 : \
 248.119 +      (i) > (j) ? is_edge1(i, j) : is_edge1(j, i))
 248.120 +#define is_edge1(i, j) is_edge2(((i) * ((i) - 1)) / 2 + (j))
 248.121 +#define is_edge2(k) (a[(k) / CHAR_BIT] & \
 248.122 +      (unsigned char)(1 << ((CHAR_BIT - 1) - (k) % CHAR_BIT)))
 248.123 +#endif
 248.124 +
 248.125 +static void sub(struct csa *csa, int ct, int table[], int level,
 248.126 +      int weight, int l_weight)
 248.127 +{     int i, j, k, curr_weight, left_weight, *p1, *p2, *newtable;
 248.128 +      newtable = xcalloc(n, sizeof(int));
 248.129 +      if (ct <= 0)
 248.130 +      {  /* 0 or 1 elements left; include these */
 248.131 +         if (ct == 0)
 248.132 +         {  set[level++] = table[0];
 248.133 +            weight += l_weight;
 248.134 +         }
 248.135 +         if (weight > record)
 248.136 +         {  record = weight;
 248.137 +            rec_level = level;
 248.138 +            for (i = 0; i < level; i++) rec[i] = set[i];
 248.139 +         }
 248.140 +         goto done;
 248.141 +      }
 248.142 +      for (i = ct; i >= 0; i--)
 248.143 +      {  if ((level == 0) && (i < ct)) goto done;
 248.144 +         k = table[i];
 248.145 +         if ((level > 0) && (clique[k] <= (record - weight)))
 248.146 +            goto done; /* prune */
 248.147 +         set[level] = k;
 248.148 +         curr_weight = weight + wt[k];
 248.149 +         l_weight -= wt[k];
 248.150 +         if (l_weight <= (record - curr_weight))
 248.151 +            goto done; /* prune */
 248.152 +         p1 = newtable;
 248.153 +         p2 = table;
 248.154 +         left_weight = 0;
 248.155 +         while (p2 < table + i)
 248.156 +         {  j = *p2++;
 248.157 +            if (is_edge(csa, j, k))
 248.158 +            {  *p1++ = j;
 248.159 +               left_weight += wt[j];
 248.160 +            }
 248.161 +         }
 248.162 +         if (left_weight <= (record - curr_weight)) continue;
 248.163 +         sub(csa, p1 - newtable - 1, newtable, level + 1, curr_weight,
 248.164 +            left_weight);
 248.165 +      }
 248.166 +done: xfree(newtable);
 248.167 +      return;
 248.168 +}
 248.169 +
 248.170 +int wclique(int _n, const int w[], const unsigned char _a[], int ind[])
 248.171 +{     struct csa _csa, *csa = &_csa;
 248.172 +      int i, j, p, max_wt, max_nwt, wth, *used, *nwt, *pos;
 248.173 +      glp_long timer;
 248.174 +      n = _n;
 248.175 +      xassert(n > 0);
 248.176 +      wt = &w[1];
 248.177 +      a = _a;
 248.178 +      record = 0;
 248.179 +      rec_level = 0;
 248.180 +      rec = &ind[1];
 248.181 +      clique = xcalloc(n, sizeof(int));
 248.182 +      set = xcalloc(n, sizeof(int));
 248.183 +      used = xcalloc(n, sizeof(int));
 248.184 +      nwt = xcalloc(n, sizeof(int));
 248.185 +      pos = xcalloc(n, sizeof(int));
 248.186 +      /* start timer */
 248.187 +      timer = xtime();
 248.188 +      /* order vertices */
 248.189 +      for (i = 0; i < n; i++)
 248.190 +      {  nwt[i] = 0;
 248.191 +         for (j = 0; j < n; j++)
 248.192 +            if (is_edge(csa, i, j)) nwt[i] += wt[j];
 248.193 +      }
 248.194 +      for (i = 0; i < n; i++)
 248.195 +         used[i] = 0;
 248.196 +      for (i = n-1; i >= 0; i--)
 248.197 +      {  max_wt = -1;
 248.198 +         max_nwt = -1;
 248.199 +         for (j = 0; j < n; j++)
 248.200 +         {  if ((!used[j]) && ((wt[j] > max_wt) || (wt[j] == max_wt
 248.201 +               && nwt[j] > max_nwt)))
 248.202 +            {  max_wt = wt[j];
 248.203 +               max_nwt = nwt[j];
 248.204 +               p = j;
 248.205 +            }
 248.206 +         }
 248.207 +         pos[i] = p;
 248.208 +         used[p] = 1;
 248.209 +         for (j = 0; j < n; j++)
 248.210 +            if ((!used[j]) && (j != p) && (is_edge(csa, p, j)))
 248.211 +               nwt[j] -= wt[p];
 248.212 +      }
 248.213 +      /* main routine */
 248.214 +      wth = 0;
 248.215 +      for (i = 0; i < n; i++)
 248.216 +      {  wth += wt[pos[i]];
 248.217 +         sub(csa, i, pos, 0, 0, wth);
 248.218 +         clique[pos[i]] = record;
 248.219 +         if (xdifftime(xtime(), timer) >= 5.0 - 0.001)
 248.220 +         {  /* print current record and reset timer */
 248.221 +            xprintf("level = %d (%d); best = %d\n", i+1, n, record);
 248.222 +            timer = xtime();
 248.223 +         }
 248.224 +      }
 248.225 +      xfree(clique);
 248.226 +      xfree(set);
 248.227 +      xfree(used);
 248.228 +      xfree(nwt);
 248.229 +      xfree(pos);
 248.230 +      /* return the solution found */
 248.231 +      for (i = 1; i <= rec_level; i++) ind[i]++;
 248.232 +      return rec_level;
 248.233 +}
 248.234 +
 248.235 +#undef n
 248.236 +#undef wt
 248.237 +#undef a
 248.238 +#undef record
 248.239 +#undef rec_level
 248.240 +#undef rec
 248.241 +#undef clique
 248.242 +#undef set
 248.243 +
 248.244 +/* eof */
   249.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   249.2 +++ b/src/glpnet09.c	Mon Dec 06 13:09:21 2010 +0100
   249.3 @@ -0,0 +1,235 @@
   249.4 +/* glpnet09.c */
   249.5 +
   249.6 +/***********************************************************************
   249.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   249.8 +*
   249.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  249.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  249.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  249.12 +*  E-mail: <mao@gnu.org>.
  249.13 +*
  249.14 +*  GLPK is free software: you can redistribute it and/or modify it
  249.15 +*  under the terms of the GNU General Public License as published by
  249.16 +*  the Free Software Foundation, either version 3 of the License, or
  249.17 +*  (at your option) any later version.
  249.18 +*
  249.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  249.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  249.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  249.22 +*  License for more details.
  249.23 +*
  249.24 +*  You should have received a copy of the GNU General Public License
  249.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  249.26 +***********************************************************************/
  249.27 +
  249.28 +#include "glpapi.h"
  249.29 +#include "glpnet.h"
  249.30 +
  249.31 +/***********************************************************************
  249.32 +*  NAME
  249.33 +*
  249.34 +*  kellerman - cover edges by cliques with Kellerman's heuristic
  249.35 +*
  249.36 +*  SYNOPSIS
  249.37 +*
  249.38 +*  #include "glpnet.h"
  249.39 +*  int kellerman(int n, int (*func)(void *info, int i, int ind[]),
  249.40 +*     void *info, glp_graph *H);
  249.41 +*
  249.42 +*  DESCRIPTION
  249.43 +*
  249.44 +*  The routine kellerman implements Kellerman's heuristic algorithm
  249.45 +*  to find a minimal set of cliques which cover all edges of specified
  249.46 +*  graph G = (V, E).
  249.47 +*
  249.48 +*  The parameter n specifies the number of vertices |V|, n >= 0.
  249.49 +*
  249.50 +*  Formal routine func specifies the set of edges E in the following
  249.51 +*  way. Running the routine kellerman calls the routine func and passes
  249.52 +*  to it parameter i, which is the number of some vertex, 1 <= i <= n.
  249.53 +*  In response the routine func should store numbers of all vertices
  249.54 +*  adjacent to vertex i to locations ind[1], ind[2], ..., ind[len] and
  249.55 +*  return the value of len, which is the number of adjacent vertices,
  249.56 +*  0 <= len <= n. Self-loops are allowed, but ignored. Multiple edges
  249.57 +*  are not allowed.
  249.58 +*
  249.59 +*  The parameter info is a transit pointer (magic cookie) passed to the
  249.60 +*  formal routine func as its first parameter.
  249.61 +*
  249.62 +*  The result provided by the routine kellerman is the bipartite graph
  249.63 +*  H = (V union C, F), which defines the covering found. (The program
  249.64 +*  object of type glp_graph specified by the parameter H should be
  249.65 +*  previously created with the routine glp_create_graph. On entry the
  249.66 +*  routine kellerman erases the content of this object with the routine
  249.67 +*  glp_erase_graph.) Vertices of first part V correspond to vertices of
  249.68 +*  the graph G and have the same ordinal numbers 1, 2, ..., n. Vertices
  249.69 +*  of second part C correspond to cliques and have ordinal numbers
  249.70 +*  n+1, n+2, ..., n+k, where k is the total number of cliques in the
  249.71 +*  edge covering found. Every edge f in F in the program object H is
  249.72 +*  represented as arc f = (i->j), where i in V and j in C, which means
  249.73 +*  that vertex i of the graph G is in clique C[j], 1 <= j <= k. (Thus,
  249.74 +*  if two vertices of the graph G are in the same clique, these vertices
  249.75 +*  are adjacent in G, and corresponding edge is covered by that clique.)
  249.76 +*
  249.77 +*  RETURNS
  249.78 +*
  249.79 +*  The routine Kellerman returns k, the total number of cliques in the
  249.80 +*  edge covering found.
  249.81 +*
  249.82 +*  REFERENCE
  249.83 +*
  249.84 +*  For more details see: glpk/doc/notes/keller.pdf (in Russian). */
  249.85 +
  249.86 +struct set
  249.87 +{     /* set of vertices */
  249.88 +      int size;
  249.89 +      /* size (cardinality) of the set, 0 <= card <= n */
  249.90 +      int *list; /* int list[1+n]; */
  249.91 +      /* the set contains vertices list[1,...,size] */
  249.92 +      int *pos; /* int pos[1+n]; */
  249.93 +      /* pos[i] > 0 means that vertex i is in the set and
  249.94 +         list[pos[i]] = i; pos[i] = 0 means that vertex i is not in
  249.95 +         the set */
  249.96 +};
  249.97 +
  249.98 +int kellerman(int n, int (*func)(void *info, int i, int ind[]),
  249.99 +      void *info, void /* glp_graph */ *H_)
 249.100 +{     glp_graph *H = H_;
 249.101 +      struct set W_, *W = &W_, V_, *V = &V_;
 249.102 +      glp_arc *a;
 249.103 +      int i, j, k, m, t, len, card, best;
 249.104 +      xassert(n >= 0);
 249.105 +      /* H := (V, 0; 0), where V is the set of vertices of graph G */
 249.106 +      glp_erase_graph(H, H->v_size, H->a_size);
 249.107 +      glp_add_vertices(H, n);
 249.108 +      /* W := 0 */
 249.109 +      W->size = 0;
 249.110 +      W->list = xcalloc(1+n, sizeof(int));
 249.111 +      W->pos = xcalloc(1+n, sizeof(int));
 249.112 +      memset(&W->pos[1], 0, sizeof(int) * n);
 249.113 +      /* V := 0 */
 249.114 +      V->size = 0;
 249.115 +      V->list = xcalloc(1+n, sizeof(int));
 249.116 +      V->pos = xcalloc(1+n, sizeof(int));
 249.117 +      memset(&V->pos[1], 0, sizeof(int) * n);
 249.118 +      /* main loop */
 249.119 +      for (i = 1; i <= n; i++)
 249.120 +      {  /* W must be empty */
 249.121 +         xassert(W->size == 0);
 249.122 +         /* W := { j : i > j and (i,j) in E } */
 249.123 +         len = func(info, i, W->list);
 249.124 +         xassert(0 <= len && len <= n);
 249.125 +         for (t = 1; t <= len; t++)
 249.126 +         {  j = W->list[t];
 249.127 +            xassert(1 <= j && j <= n);
 249.128 +            if (j >= i) continue;
 249.129 +            xassert(W->pos[j] == 0);
 249.130 +            W->list[++W->size] = j, W->pos[j] = W->size;
 249.131 +         }
 249.132 +         /* on i-th iteration we need to cover edges (i,j) for all
 249.133 +            j in W */
 249.134 +         /* if W is empty, it is a special case */
 249.135 +         if (W->size == 0)
 249.136 +         {  /* set k := k + 1 and create new clique C[k] = { i } */
 249.137 +            k = glp_add_vertices(H, 1) - n;
 249.138 +            glp_add_arc(H, i, n + k);
 249.139 +            continue;
 249.140 +         }
 249.141 +         /* try to include vertex i into existing cliques */
 249.142 +         /* V must be empty */
 249.143 +         xassert(V->size == 0);
 249.144 +         /* k is the number of cliques found so far */
 249.145 +         k = H->nv - n;
 249.146 +         for (m = 1; m <= k; m++)
 249.147 +         {  /* do while V != W; since here V is within W, we can use
 249.148 +               equivalent condition: do while |V| < |W| */
 249.149 +            if (V->size == W->size) break;
 249.150 +            /* check if C[m] is within W */
 249.151 +            for (a = H->v[n + m]->in; a != NULL; a = a->h_next)
 249.152 +            {  j = a->tail->i;
 249.153 +               if (W->pos[j] == 0) break;
 249.154 +            }
 249.155 +            if (a != NULL) continue;
 249.156 +            /* C[m] is within W, expand clique C[m] with vertex i */
 249.157 +            /* C[m] := C[m] union {i} */
 249.158 +            glp_add_arc(H, i, n + m);
 249.159 +            /* V is a set of vertices whose incident edges are already
 249.160 +               covered by existing cliques */
 249.161 +            /* V := V union C[m] */
 249.162 +            for (a = H->v[n + m]->in; a != NULL; a = a->h_next)
 249.163 +            {  j = a->tail->i;
 249.164 +               if (V->pos[j] == 0)
 249.165 +                  V->list[++V->size] = j, V->pos[j] = V->size;
 249.166 +            }
 249.167 +         }
 249.168 +         /* remove from set W the vertices whose incident edges are
 249.169 +            already covered by existing cliques */
 249.170 +         /* W := W \ V, V := 0 */
 249.171 +         for (t = 1; t <= V->size; t++)
 249.172 +         {  j = V->list[t], V->pos[j] = 0;
 249.173 +            if (W->pos[j] != 0)
 249.174 +            {  /* remove vertex j from W */
 249.175 +               if (W->pos[j] != W->size)
 249.176 +               {  int jj = W->list[W->size];
 249.177 +                  W->list[W->pos[j]] = jj;
 249.178 +                  W->pos[jj] = W->pos[j];
 249.179 +               }
 249.180 +               W->size--, W->pos[j] = 0;
 249.181 +            }
 249.182 +         }
 249.183 +         V->size = 0;
 249.184 +         /* now set W contains only vertices whose incident edges are
 249.185 +            still not covered by existing cliques; create new cliques
 249.186 +            to cover remaining edges until set W becomes empty */
 249.187 +         while (W->size > 0)
 249.188 +         {  /* find clique C[m], 1 <= m <= k, which shares maximal
 249.189 +               number of vertices with W; to break ties choose clique
 249.190 +               having smallest number m */
 249.191 +            m = 0, best = -1;
 249.192 +            k = H->nv - n;
 249.193 +            for (t = 1; t <= k; t++)
 249.194 +            {  /* compute cardinality of intersection of W and C[t] */
 249.195 +               card = 0;
 249.196 +               for (a = H->v[n + t]->in; a != NULL; a = a->h_next)
 249.197 +               {  j = a->tail->i;
 249.198 +                  if (W->pos[j] != 0) card++;
 249.199 +               }
 249.200 +               if (best < card)
 249.201 +                  m = t, best = card;
 249.202 +            }
 249.203 +            xassert(m > 0);
 249.204 +            /* set k := k + 1 and create new clique:
 249.205 +               C[k] := (W intersect C[m]) union { i }, which covers all
 249.206 +               edges incident to vertices from (W intersect C[m]) */
 249.207 +            k = glp_add_vertices(H, 1) - n;
 249.208 +            for (a = H->v[n + m]->in; a != NULL; a = a->h_next)
 249.209 +            {  j = a->tail->i;
 249.210 +               if (W->pos[j] != 0)
 249.211 +               {  /* vertex j is in both W and C[m]; include it in new
 249.212 +                     clique C[k] */
 249.213 +                  glp_add_arc(H, j, n + k);
 249.214 +                  /* remove vertex j from W, since edge (i,j) will be
 249.215 +                     covered by new clique C[k] */
 249.216 +                  if (W->pos[j] != W->size)
 249.217 +                  {  int jj = W->list[W->size];
 249.218 +                     W->list[W->pos[j]] = jj;
 249.219 +                     W->pos[jj] = W->pos[j];
 249.220 +                  }
 249.221 +                  W->size--, W->pos[j] = 0;
 249.222 +               }
 249.223 +            }
 249.224 +            /* include vertex i to new clique C[k] to cover edges (i,j)
 249.225 +               incident to all vertices j just removed from W */
 249.226 +            glp_add_arc(H, i, n + k);
 249.227 +         }
 249.228 +      }
 249.229 +      /* free working arrays */
 249.230 +      xfree(W->list);
 249.231 +      xfree(W->pos);
 249.232 +      xfree(V->list);
 249.233 +      xfree(V->pos);
 249.234 +      /* return the number of cliques in the edge covering found */
 249.235 +      return H->nv - n;
 249.236 +}
 249.237 +
 249.238 +/* eof */
   250.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   250.2 +++ b/src/glpnpp.h	Mon Dec 06 13:09:21 2010 +0100
   250.3 @@ -0,0 +1,520 @@
   250.4 +/* glpnpp.h (LP/MIP preprocessor) */
   250.5 +
   250.6 +/***********************************************************************
   250.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   250.8 +*
   250.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  250.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  250.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  250.12 +*  E-mail: <mao@gnu.org>.
  250.13 +*
  250.14 +*  GLPK is free software: you can redistribute it and/or modify it
  250.15 +*  under the terms of the GNU General Public License as published by
  250.16 +*  the Free Software Foundation, either version 3 of the License, or
  250.17 +*  (at your option) any later version.
  250.18 +*
  250.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  250.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  250.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  250.22 +*  License for more details.
  250.23 +*
  250.24 +*  You should have received a copy of the GNU General Public License
  250.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  250.26 +***********************************************************************/
  250.27 +
  250.28 +#ifndef GLPNPP_H
  250.29 +#define GLPNPP_H
  250.30 +
  250.31 +#include "glpapi.h"
  250.32 +
  250.33 +typedef struct NPP NPP;
  250.34 +typedef struct NPPROW NPPROW;
  250.35 +typedef struct NPPCOL NPPCOL;
  250.36 +typedef struct NPPAIJ NPPAIJ;
  250.37 +typedef struct NPPTSE NPPTSE;
  250.38 +typedef struct NPPLFE NPPLFE;
  250.39 +
  250.40 +struct NPP
  250.41 +{     /* LP/MIP preprocessor workspace */
  250.42 +      /*--------------------------------------------------------------*/
  250.43 +      /* original problem segment */
  250.44 +      int orig_dir;
  250.45 +      /* optimization direction flag:
  250.46 +         GLP_MIN - minimization
  250.47 +         GLP_MAX - maximization */
  250.48 +      int orig_m;
  250.49 +      /* number of rows */
  250.50 +      int orig_n;
  250.51 +      /* number of columns */
  250.52 +      int orig_nnz;
  250.53 +      /* number of non-zero constraint coefficients */
  250.54 +      /*--------------------------------------------------------------*/
  250.55 +      /* transformed problem segment (always minimization) */
  250.56 +      DMP *pool;
  250.57 +      /* memory pool to store problem components */
  250.58 +      char *name;
  250.59 +      /* problem name (1 to 255 chars); NULL means no name is assigned
  250.60 +         to the problem */
  250.61 +      char *obj;
  250.62 +      /* objective function name (1 to 255 chars); NULL means no name
  250.63 +         is assigned to the objective function */
  250.64 +      double c0;
  250.65 +      /* constant term of the objective function */
  250.66 +      int nrows;
  250.67 +      /* number of rows introduced into the problem; this count
  250.68 +         increases by one every time a new row is added and never
  250.69 +         decreases; thus, actual number of rows may be less than nrows
  250.70 +         due to row deletions */
  250.71 +      int ncols;
  250.72 +      /* number of columns introduced into the problem; this count
  250.73 +         increases by one every time a new column is added and never
  250.74 +         decreases; thus, actual number of column may be less than
  250.75 +         ncols due to column deletions */
  250.76 +      NPPROW *r_head;
  250.77 +      /* pointer to the beginning of the row list */
  250.78 +      NPPROW *r_tail;
  250.79 +      /* pointer to the end of the row list */
  250.80 +      NPPCOL *c_head;
  250.81 +      /* pointer to the beginning of the column list */
  250.82 +      NPPCOL *c_tail;
  250.83 +      /* pointer to the end of the column list */
  250.84 +      /*--------------------------------------------------------------*/
  250.85 +      /* transformation history */
  250.86 +      DMP *stack;
  250.87 +      /* memory pool to store transformation entries */
  250.88 +      NPPTSE *top;
  250.89 +      /* pointer to most recent transformation entry */
  250.90 +#if 0 /* 16/XII-2009 */
  250.91 +      int count[1+25];
  250.92 +      /* transformation statistics */
  250.93 +#endif
  250.94 +      /*--------------------------------------------------------------*/
  250.95 +      /* resultant (preprocessed) problem segment */
  250.96 +      int m;
  250.97 +      /* number of rows */
  250.98 +      int n;
  250.99 +      /* number of columns */
 250.100 +      int nnz;
 250.101 +      /* number of non-zero constraint coefficients */
 250.102 +      int *row_ref; /* int row_ref[1+m]; */
 250.103 +      /* row_ref[i], 1 <= i <= m, is the reference number assigned to
 250.104 +         a row, which is i-th row of the resultant problem */
 250.105 +      int *col_ref; /* int col_ref[1+n]; */
 250.106 +      /* col_ref[j], 1 <= j <= n, is the reference number assigned to
 250.107 +         a column, which is j-th column of the resultant problem */
 250.108 +      /*--------------------------------------------------------------*/
 250.109 +      /* recovered solution segment */
 250.110 +      int sol;
 250.111 +      /* solution indicator:
 250.112 +         GLP_SOL - basic solution
 250.113 +         GLP_IPT - interior-point solution
 250.114 +         GLP_MIP - mixed integer solution */
 250.115 +      int scaling;
 250.116 +      /* scaling option:
 250.117 +         GLP_OFF - scaling is disabled
 250.118 +         GLP_ON  - scaling is enabled */
 250.119 +      int p_stat;
 250.120 +      /* status of primal basic solution:
 250.121 +         GLP_UNDEF  - primal solution is undefined
 250.122 +         GLP_FEAS   - primal solution is feasible
 250.123 +         GLP_INFEAS - primal solution is infeasible
 250.124 +         GLP_NOFEAS - no primal feasible solution exists */
 250.125 +      int d_stat;
 250.126 +      /* status of dual basic solution:
 250.127 +         GLP_UNDEF  - dual solution is undefined
 250.128 +         GLP_FEAS   - dual solution is feasible
 250.129 +         GLP_INFEAS - dual solution is infeasible
 250.130 +         GLP_NOFEAS - no dual feasible solution exists */
 250.131 +      int t_stat;
 250.132 +      /* status of interior-point solution:
 250.133 +         GLP_UNDEF  - interior solution is undefined
 250.134 +         GLP_OPT    - interior solution is optimal */
 250.135 +      int i_stat;
 250.136 +      /* status of mixed integer solution:
 250.137 +         GLP_UNDEF  - integer solution is undefined
 250.138 +         GLP_OPT    - integer solution is optimal
 250.139 +         GLP_FEAS   - integer solution is feasible
 250.140 +         GLP_NOFEAS - no integer solution exists */
 250.141 +      char *r_stat; /* char r_stat[1+nrows]; */
 250.142 +      /* r_stat[i], 1 <= i <= nrows, is status of i-th row:
 250.143 +         GLP_BS - inactive constraint
 250.144 +         GLP_NL - active constraint on lower bound
 250.145 +         GLP_NU - active constraint on upper bound
 250.146 +         GLP_NF - active free row
 250.147 +         GLP_NS - active equality constraint */
 250.148 +      char *c_stat; /* char c_stat[1+nrows]; */
 250.149 +      /* c_stat[j], 1 <= j <= nrows, is status of j-th column:
 250.150 +         GLP_BS - basic variable
 250.151 +         GLP_NL - non-basic variable on lower bound
 250.152 +         GLP_NU - non-basic variable on upper bound
 250.153 +         GLP_NF - non-basic free variable
 250.154 +         GLP_NS - non-basic fixed variable */
 250.155 +      double *r_pi; /* double r_pi[1+nrows]; */
 250.156 +      /* r_pi[i], 1 <= i <= nrows, is Lagrange multiplier (dual value)
 250.157 +         for i-th row (constraint) */
 250.158 +      double *c_value; /* double c_value[1+ncols]; */
 250.159 +      /* c_value[j], 1 <= j <= ncols, is primal value of j-th column
 250.160 +         (structural variable) */
 250.161 +};
 250.162 +
 250.163 +struct NPPROW
 250.164 +{     /* row (constraint) */
 250.165 +      int i;
 250.166 +      /* reference number assigned to the row, 1 <= i <= nrows */
 250.167 +      char *name;
 250.168 +      /* row name (1 to 255 chars); NULL means no name is assigned to
 250.169 +         the row */
 250.170 +      double lb;
 250.171 +      /* lower bound; -DBL_MAX means the row has no lower bound */
 250.172 +      double ub;
 250.173 +      /* upper bound; +DBL_MAX means the row has no upper bound */
 250.174 +      NPPAIJ *ptr;
 250.175 +      /* pointer to the linked list of constraint coefficients */
 250.176 +      int temp;
 250.177 +      /* working field used by preprocessor routines */
 250.178 +      NPPROW *prev;
 250.179 +      /* pointer to previous row in the row list */
 250.180 +      NPPROW *next;
 250.181 +      /* pointer to next row in the row list */
 250.182 +};
 250.183 +
 250.184 +struct NPPCOL
 250.185 +{     /* column (variable) */
 250.186 +      int j;
 250.187 +      /* reference number assigned to the column, 1 <= j <= ncols */
 250.188 +      char *name;
 250.189 +      /* column name (1 to 255 chars); NULL means no name is assigned
 250.190 +         to the column */
 250.191 +      char is_int;
 250.192 +      /* 0 means continuous variable; 1 means integer variable */
 250.193 +      double lb;
 250.194 +      /* lower bound; -DBL_MAX means the column has no lower bound */
 250.195 +      double ub;
 250.196 +      /* upper bound; +DBL_MAX means the column has no upper bound */
 250.197 +      double coef;
 250.198 +      /* objective coefficient */
 250.199 +      NPPAIJ *ptr;
 250.200 +      /* pointer to the linked list of constraint coefficients */
 250.201 +      int temp;
 250.202 +      /* working field used by preprocessor routines */
 250.203 +#if 1 /* 28/XII-2009 */
 250.204 +      union
 250.205 +      {  double ll;
 250.206 +         /* implied column lower bound */
 250.207 +         int pos;
 250.208 +         /* vertex ordinal number corresponding to this binary column
 250.209 +            in the conflict graph (0, if the vertex does not exist) */
 250.210 +      }  ll;
 250.211 +      union
 250.212 +      {  double uu;
 250.213 +         /* implied column upper bound */
 250.214 +         int neg;
 250.215 +         /* vertex ordinal number corresponding to complement of this
 250.216 +            binary column in the conflict graph (0, if the vertex does
 250.217 +            not exist) */
 250.218 +      }  uu;
 250.219 +#endif
 250.220 +      NPPCOL *prev;
 250.221 +      /* pointer to previous column in the column list */
 250.222 +      NPPCOL *next;
 250.223 +      /* pointer to next column in the column list */
 250.224 +};
 250.225 +
 250.226 +struct NPPAIJ
 250.227 +{     /* constraint coefficient */
 250.228 +      NPPROW *row;
 250.229 +      /* pointer to corresponding row */
 250.230 +      NPPCOL *col;
 250.231 +      /* pointer to corresponding column */
 250.232 +      double val;
 250.233 +      /* (non-zero) coefficient value */
 250.234 +      NPPAIJ *r_prev;
 250.235 +      /* pointer to previous coefficient in the same row */
 250.236 +      NPPAIJ *r_next;
 250.237 +      /* pointer to next coefficient in the same row */
 250.238 +      NPPAIJ *c_prev;
 250.239 +      /* pointer to previous coefficient in the same column */
 250.240 +      NPPAIJ *c_next;
 250.241 +      /* pointer to next coefficient in the same column */
 250.242 +};
 250.243 +
 250.244 +struct NPPTSE
 250.245 +{     /* transformation stack entry */
 250.246 +      int (*func)(NPP *npp, void *info);
 250.247 +      /* pointer to routine performing back transformation */
 250.248 +      void *info;
 250.249 +      /* pointer to specific info (depends on the transformation) */
 250.250 +      NPPTSE *link;
 250.251 +      /* pointer to another entry created *before* this entry */
 250.252 +};
 250.253 +
 250.254 +struct NPPLFE
 250.255 +{     /* linear form element */
 250.256 +      int ref;
 250.257 +      /* row/column reference number */
 250.258 +      double val;
 250.259 +      /* (non-zero) coefficient value */
 250.260 +      NPPLFE *next;
 250.261 +      /* pointer to another element */
 250.262 +};
 250.263 +
 250.264 +#define npp_create_wksp _glp_npp_create_wksp
 250.265 +NPP *npp_create_wksp(void);
 250.266 +/* create LP/MIP preprocessor workspace */
 250.267 +
 250.268 +#define npp_insert_row _glp_npp_insert_row
 250.269 +void npp_insert_row(NPP *npp, NPPROW *row, int where);
 250.270 +/* insert row to the row list */
 250.271 +
 250.272 +#define npp_remove_row _glp_npp_remove_row
 250.273 +void npp_remove_row(NPP *npp, NPPROW *row);
 250.274 +/* remove row from the row list */
 250.275 +
 250.276 +#define npp_activate_row _glp_npp_activate_row
 250.277 +void npp_activate_row(NPP *npp, NPPROW *row);
 250.278 +/* make row active */
 250.279 +
 250.280 +#define npp_deactivate_row _glp_npp_deactivate_row
 250.281 +void npp_deactivate_row(NPP *npp, NPPROW *row);
 250.282 +/* make row inactive */
 250.283 +
 250.284 +#define npp_insert_col _glp_npp_insert_col
 250.285 +void npp_insert_col(NPP *npp, NPPCOL *col, int where);
 250.286 +/* insert column to the column list */
 250.287 +
 250.288 +#define npp_remove_col _glp_npp_remove_col
 250.289 +void npp_remove_col(NPP *npp, NPPCOL *col);
 250.290 +/* remove column from the column list */
 250.291 +
 250.292 +#define npp_activate_col _glp_npp_activate_col
 250.293 +void npp_activate_col(NPP *npp, NPPCOL *col);
 250.294 +/* make column active */
 250.295 +
 250.296 +#define npp_deactivate_col _glp_npp_deactivate_col
 250.297 +void npp_deactivate_col(NPP *npp, NPPCOL *col);
 250.298 +/* make column inactive */
 250.299 +
 250.300 +#define npp_add_row _glp_npp_add_row
 250.301 +NPPROW *npp_add_row(NPP *npp);
 250.302 +/* add new row to the current problem */
 250.303 +
 250.304 +#define npp_add_col _glp_npp_add_col
 250.305 +NPPCOL *npp_add_col(NPP *npp);
 250.306 +/* add new column to the current problem */
 250.307 +
 250.308 +#define npp_add_aij _glp_npp_add_aij
 250.309 +NPPAIJ *npp_add_aij(NPP *npp, NPPROW *row, NPPCOL *col, double val);
 250.310 +/* add new element to the constraint matrix */
 250.311 +
 250.312 +#define npp_row_nnz _glp_npp_row_nnz
 250.313 +int npp_row_nnz(NPP *npp, NPPROW *row);
 250.314 +/* count number of non-zero coefficients in row */
 250.315 +
 250.316 +#define npp_col_nnz _glp_npp_col_nnz
 250.317 +int npp_col_nnz(NPP *npp, NPPCOL *col);
 250.318 +/* count number of non-zero coefficients in column */
 250.319 +
 250.320 +#define npp_push_tse _glp_npp_push_tse
 250.321 +void *npp_push_tse(NPP *npp, int (*func)(NPP *npp, void *info),
 250.322 +      int size);
 250.323 +/* push new entry to the transformation stack */
 250.324 +
 250.325 +#define npp_erase_row _glp_npp_erase_row
 250.326 +void npp_erase_row(NPP *npp, NPPROW *row);
 250.327 +/* erase row content to make it empty */
 250.328 +
 250.329 +#define npp_del_row _glp_npp_del_row
 250.330 +void npp_del_row(NPP *npp, NPPROW *row);
 250.331 +/* remove row from the current problem */
 250.332 +
 250.333 +#define npp_del_col _glp_npp_del_col
 250.334 +void npp_del_col(NPP *npp, NPPCOL *col);
 250.335 +/* remove column from the current problem */
 250.336 +
 250.337 +#define npp_del_aij _glp_npp_del_aij
 250.338 +void npp_del_aij(NPP *npp, NPPAIJ *aij);
 250.339 +/* remove element from the constraint matrix */
 250.340 +
 250.341 +#define npp_load_prob _glp_npp_load_prob
 250.342 +void npp_load_prob(NPP *npp, glp_prob *orig, int names, int sol,
 250.343 +      int scaling);
 250.344 +/* load original problem into the preprocessor workspace */
 250.345 +
 250.346 +#define npp_build_prob _glp_npp_build_prob
 250.347 +void npp_build_prob(NPP *npp, glp_prob *prob);
 250.348 +/* build resultant (preprocessed) problem */
 250.349 +
 250.350 +#define npp_postprocess _glp_npp_postprocess
 250.351 +void npp_postprocess(NPP *npp, glp_prob *prob);
 250.352 +/* postprocess solution from the resultant problem */
 250.353 +
 250.354 +#define npp_unload_sol _glp_npp_unload_sol
 250.355 +void npp_unload_sol(NPP *npp, glp_prob *orig);
 250.356 +/* store solution to the original problem */
 250.357 +
 250.358 +#define npp_delete_wksp _glp_npp_delete_wksp
 250.359 +void npp_delete_wksp(NPP *npp);
 250.360 +/* delete LP/MIP preprocessor workspace */
 250.361 +
 250.362 +#define npp_error()
 250.363 +
 250.364 +#define npp_free_row _glp_npp_free_row
 250.365 +void npp_free_row(NPP *npp, NPPROW *p);
 250.366 +/* process free (unbounded) row */
 250.367 +
 250.368 +#define npp_geq_row _glp_npp_geq_row
 250.369 +void npp_geq_row(NPP *npp, NPPROW *p);
 250.370 +/* process row of 'not less than' type */
 250.371 +
 250.372 +#define npp_leq_row _glp_npp_leq_row
 250.373 +void npp_leq_row(NPP *npp, NPPROW *p);
 250.374 +/* process row of 'not greater than' type */
 250.375 +
 250.376 +#define npp_free_col _glp_npp_free_col
 250.377 +void npp_free_col(NPP *npp, NPPCOL *q);
 250.378 +/* process free (unbounded) column */
 250.379 +
 250.380 +#define npp_lbnd_col _glp_npp_lbnd_col
 250.381 +void npp_lbnd_col(NPP *npp, NPPCOL *q);
 250.382 +/* process column with (non-zero) lower bound */
 250.383 +
 250.384 +#define npp_ubnd_col _glp_npp_ubnd_col
 250.385 +void npp_ubnd_col(NPP *npp, NPPCOL *q);
 250.386 +/* process column with upper bound */
 250.387 +
 250.388 +#define npp_dbnd_col _glp_npp_dbnd_col
 250.389 +void npp_dbnd_col(NPP *npp, NPPCOL *q);
 250.390 +/* process non-negative column with upper bound */
 250.391 +
 250.392 +#define npp_fixed_col _glp_npp_fixed_col
 250.393 +void npp_fixed_col(NPP *npp, NPPCOL *q);
 250.394 +/* process fixed column */
 250.395 +
 250.396 +#define npp_make_equality _glp_npp_make_equality
 250.397 +int npp_make_equality(NPP *npp, NPPROW *p);
 250.398 +/* process row with almost identical bounds */
 250.399 +
 250.400 +#define npp_make_fixed _glp_npp_make_fixed
 250.401 +int npp_make_fixed(NPP *npp, NPPCOL *q);
 250.402 +/* process column with almost identical bounds */
 250.403 +
 250.404 +#define npp_empty_row _glp_npp_empty_row
 250.405 +int npp_empty_row(NPP *npp, NPPROW *p);
 250.406 +/* process empty row */
 250.407 +
 250.408 +#define npp_empty_col _glp_npp_empty_col
 250.409 +int npp_empty_col(NPP *npp, NPPCOL *q);
 250.410 +/* process empty column */
 250.411 +
 250.412 +#define npp_implied_value _glp_npp_implied_value
 250.413 +int npp_implied_value(NPP *npp, NPPCOL *q, double s);
 250.414 +/* process implied column value */
 250.415 +
 250.416 +#define npp_eq_singlet _glp_npp_eq_singlet
 250.417 +int npp_eq_singlet(NPP *npp, NPPROW *p);
 250.418 +/* process row singleton (equality constraint) */
 250.419 +
 250.420 +#define npp_implied_lower _glp_npp_implied_lower
 250.421 +int npp_implied_lower(NPP *npp, NPPCOL *q, double l);
 250.422 +/* process implied column lower bound */
 250.423 +
 250.424 +#define npp_implied_upper _glp_npp_implied_upper
 250.425 +int npp_implied_upper(NPP *npp, NPPCOL *q, double u);
 250.426 +/* process implied upper bound of column */
 250.427 +
 250.428 +#define npp_ineq_singlet _glp_npp_ineq_singlet
 250.429 +int npp_ineq_singlet(NPP *npp, NPPROW *p);
 250.430 +/* process row singleton (inequality constraint) */
 250.431 +
 250.432 +#define npp_implied_slack _glp_npp_implied_slack
 250.433 +void npp_implied_slack(NPP *npp, NPPCOL *q);
 250.434 +/* process column singleton (implied slack variable) */
 250.435 +
 250.436 +#define npp_implied_free _glp_npp_implied_free
 250.437 +int npp_implied_free(NPP *npp, NPPCOL *q);
 250.438 +/* process column singleton (implied free variable) */
 250.439 +
 250.440 +#define npp_eq_doublet _glp_npp_eq_doublet
 250.441 +NPPCOL *npp_eq_doublet(NPP *npp, NPPROW *p);
 250.442 +/* process row doubleton (equality constraint) */
 250.443 +
 250.444 +#define npp_forcing_row _glp_npp_forcing_row
 250.445 +int npp_forcing_row(NPP *npp, NPPROW *p, int at);
 250.446 +/* process forcing row */
 250.447 +
 250.448 +#define npp_analyze_row _glp_npp_analyze_row
 250.449 +int npp_analyze_row(NPP *npp, NPPROW *p);
 250.450 +/* perform general row analysis */
 250.451 +
 250.452 +#define npp_inactive_bound _glp_npp_inactive_bound
 250.453 +void npp_inactive_bound(NPP *npp, NPPROW *p, int which);
 250.454 +/* remove row lower/upper inactive bound */
 250.455 +
 250.456 +#define npp_implied_bounds _glp_npp_implied_bounds
 250.457 +void npp_implied_bounds(NPP *npp, NPPROW *p);
 250.458 +/* determine implied column bounds */
 250.459 +
 250.460 +#define npp_binarize_prob _glp_npp_binarize_prob
 250.461 +int npp_binarize_prob(NPP *npp);
 250.462 +/* binarize MIP problem */
 250.463 +
 250.464 +#define npp_is_packing _glp_npp_is_packing
 250.465 +int npp_is_packing(NPP *npp, NPPROW *row);
 250.466 +/* test if constraint is packing inequality */
 250.467 +
 250.468 +#define npp_hidden_packing _glp_npp_hidden_packing
 250.469 +int npp_hidden_packing(NPP *npp, NPPROW *row);
 250.470 +/* identify hidden packing inequality */
 250.471 +
 250.472 +#define npp_implied_packing _glp_npp_implied_packing
 250.473 +int npp_implied_packing(NPP *npp, NPPROW *row, int which,
 250.474 +      NPPCOL *var[], char set[]);
 250.475 +/* identify implied packing inequality */
 250.476 +
 250.477 +#define npp_is_covering _glp_npp_is_covering
 250.478 +int npp_is_covering(NPP *npp, NPPROW *row);
 250.479 +/* test if constraint is covering inequality */
 250.480 +
 250.481 +#define npp_hidden_covering _glp_npp_hidden_covering
 250.482 +int npp_hidden_covering(NPP *npp, NPPROW *row);
 250.483 +/* identify hidden covering inequality */
 250.484 +
 250.485 +#define npp_is_partitioning _glp_npp_is_partitioning
 250.486 +int npp_is_partitioning(NPP *npp, NPPROW *row);
 250.487 +/* test if constraint is partitioning equality */
 250.488 +
 250.489 +#define npp_reduce_ineq_coef _glp_npp_reduce_ineq_coef
 250.490 +int npp_reduce_ineq_coef(NPP *npp, NPPROW *row);
 250.491 +/* reduce inequality constraint coefficients */
 250.492 +
 250.493 +#define npp_clean_prob _glp_npp_clean_prob
 250.494 +void npp_clean_prob(NPP *npp);
 250.495 +/* perform initial LP/MIP processing */
 250.496 +
 250.497 +#define npp_process_row _glp_npp_process_row
 250.498 +int npp_process_row(NPP *npp, NPPROW *row, int hard);
 250.499 +/* perform basic row processing */
 250.500 +
 250.501 +#define npp_improve_bounds _glp_npp_improve_bounds
 250.502 +int npp_improve_bounds(NPP *npp, NPPROW *row, int flag);
 250.503 +/* improve current column bounds */
 250.504 +
 250.505 +#define npp_process_col _glp_npp_process_col
 250.506 +int npp_process_col(NPP *npp, NPPCOL *col);
 250.507 +/* perform basic column processing */
 250.508 +
 250.509 +#define npp_process_prob _glp_npp_process_prob
 250.510 +int npp_process_prob(NPP *npp, int hard);
 250.511 +/* perform basic LP/MIP processing */
 250.512 +
 250.513 +#define npp_simplex _glp_npp_simplex
 250.514 +int npp_simplex(NPP *npp, const glp_smcp *parm);
 250.515 +/* process LP prior to applying primal/dual simplex method */
 250.516 +
 250.517 +#define npp_integer _glp_npp_integer
 250.518 +int npp_integer(NPP *npp, const glp_iocp *parm);
 250.519 +/* process MIP prior to applying branch-and-bound method */
 250.520 +
 250.521 +#endif
 250.522 +
 250.523 +/* eof */
   251.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   251.2 +++ b/src/glpnpp01.c	Mon Dec 06 13:09:21 2010 +0100
   251.3 @@ -0,0 +1,927 @@
   251.4 +/* glpnpp01.c */
   251.5 +
   251.6 +/***********************************************************************
   251.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   251.8 +*
   251.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  251.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  251.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  251.12 +*  E-mail: <mao@gnu.org>.
  251.13 +*
  251.14 +*  GLPK is free software: you can redistribute it and/or modify it
  251.15 +*  under the terms of the GNU General Public License as published by
  251.16 +*  the Free Software Foundation, either version 3 of the License, or
  251.17 +*  (at your option) any later version.
  251.18 +*
  251.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  251.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  251.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  251.22 +*  License for more details.
  251.23 +*
  251.24 +*  You should have received a copy of the GNU General Public License
  251.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  251.26 +***********************************************************************/
  251.27 +
  251.28 +#include "glpnpp.h"
  251.29 +
  251.30 +NPP *npp_create_wksp(void)
  251.31 +{     /* create LP/MIP preprocessor workspace */
  251.32 +      NPP *npp;
  251.33 +      npp = xmalloc(sizeof(NPP));
  251.34 +      npp->orig_dir = 0;
  251.35 +      npp->orig_m = npp->orig_n = npp->orig_nnz = 0;
  251.36 +      npp->pool = dmp_create_pool();
  251.37 +      npp->name = npp->obj = NULL;
  251.38 +      npp->c0 = 0.0;
  251.39 +      npp->nrows = npp->ncols = 0;
  251.40 +      npp->r_head = npp->r_tail = NULL;
  251.41 +      npp->c_head = npp->c_tail = NULL;
  251.42 +      npp->stack = dmp_create_pool();
  251.43 +      npp->top = NULL;
  251.44 +#if 0 /* 16/XII-2009 */
  251.45 +      memset(&npp->count, 0, sizeof(npp->count));
  251.46 +#endif
  251.47 +      npp->m = npp->n = npp->nnz = 0;
  251.48 +      npp->row_ref = npp->col_ref = NULL;
  251.49 +      npp->sol = npp->scaling = 0;
  251.50 +      npp->p_stat = npp->d_stat = npp->t_stat = npp->i_stat = 0;
  251.51 +      npp->r_stat = NULL;
  251.52 +      /*npp->r_prim =*/ npp->r_pi = NULL;
  251.53 +      npp->c_stat = NULL;
  251.54 +      npp->c_value = /*npp->c_dual =*/ NULL;
  251.55 +      return npp;
  251.56 +}
  251.57 +
  251.58 +void npp_insert_row(NPP *npp, NPPROW *row, int where)
  251.59 +{     /* insert row to the row list */
  251.60 +      if (where == 0)
  251.61 +      {  /* insert row to the beginning of the row list */
  251.62 +         row->prev = NULL;
  251.63 +         row->next = npp->r_head;
  251.64 +         if (row->next == NULL)
  251.65 +            npp->r_tail = row;
  251.66 +         else
  251.67 +            row->next->prev = row;
  251.68 +         npp->r_head = row;
  251.69 +      }
  251.70 +      else
  251.71 +      {  /* insert row to the end of the row list */
  251.72 +         row->prev = npp->r_tail;
  251.73 +         row->next = NULL;
  251.74 +         if (row->prev == NULL)
  251.75 +            npp->r_head = row;
  251.76 +         else
  251.77 +            row->prev->next = row;
  251.78 +         npp->r_tail = row;
  251.79 +      }
  251.80 +      return;
  251.81 +}
  251.82 +
  251.83 +void npp_remove_row(NPP *npp, NPPROW *row)
  251.84 +{     /* remove row from the row list */
  251.85 +      if (row->prev == NULL)
  251.86 +         npp->r_head = row->next;
  251.87 +      else
  251.88 +         row->prev->next = row->next;
  251.89 +      if (row->next == NULL)
  251.90 +         npp->r_tail = row->prev;
  251.91 +      else
  251.92 +         row->next->prev = row->prev;
  251.93 +      return;
  251.94 +}
  251.95 +
  251.96 +void npp_activate_row(NPP *npp, NPPROW *row)
  251.97 +{     /* make row active */
  251.98 +      if (!row->temp)
  251.99 +      {  row->temp = 1;
 251.100 +         /* move the row to the beginning of the row list */
 251.101 +         npp_remove_row(npp, row);
 251.102 +         npp_insert_row(npp, row, 0);
 251.103 +      }
 251.104 +      return;
 251.105 +}
 251.106 +
 251.107 +void npp_deactivate_row(NPP *npp, NPPROW *row)
 251.108 +{     /* make row inactive */
 251.109 +      if (row->temp)
 251.110 +      {  row->temp = 0;
 251.111 +         /* move the row to the end of the row list */
 251.112 +         npp_remove_row(npp, row);
 251.113 +         npp_insert_row(npp, row, 1);
 251.114 +      }
 251.115 +      return;
 251.116 +}
 251.117 +
 251.118 +void npp_insert_col(NPP *npp, NPPCOL *col, int where)
 251.119 +{     /* insert column to the column list */
 251.120 +      if (where == 0)
 251.121 +      {  /* insert column to the beginning of the column list */
 251.122 +         col->prev = NULL;
 251.123 +         col->next = npp->c_head;
 251.124 +         if (col->next == NULL)
 251.125 +            npp->c_tail = col;
 251.126 +         else
 251.127 +            col->next->prev = col;
 251.128 +         npp->c_head = col;
 251.129 +      }
 251.130 +      else
 251.131 +      {  /* insert column to the end of the column list */
 251.132 +         col->prev = npp->c_tail;
 251.133 +         col->next = NULL;
 251.134 +         if (col->prev == NULL)
 251.135 +            npp->c_head = col;
 251.136 +         else
 251.137 +            col->prev->next = col;
 251.138 +         npp->c_tail = col;
 251.139 +      }
 251.140 +      return;
 251.141 +}
 251.142 +
 251.143 +void npp_remove_col(NPP *npp, NPPCOL *col)
 251.144 +{     /* remove column from the column list */
 251.145 +      if (col->prev == NULL)
 251.146 +         npp->c_head = col->next;
 251.147 +      else
 251.148 +         col->prev->next = col->next;
 251.149 +      if (col->next == NULL)
 251.150 +         npp->c_tail = col->prev;
 251.151 +      else
 251.152 +         col->next->prev = col->prev;
 251.153 +      return;
 251.154 +}
 251.155 +
 251.156 +void npp_activate_col(NPP *npp, NPPCOL *col)
 251.157 +{     /* make column active */
 251.158 +      if (!col->temp)
 251.159 +      {  col->temp = 1;
 251.160 +         /* move the column to the beginning of the column list */
 251.161 +         npp_remove_col(npp, col);
 251.162 +         npp_insert_col(npp, col, 0);
 251.163 +      }
 251.164 +      return;
 251.165 +}
 251.166 +
 251.167 +void npp_deactivate_col(NPP *npp, NPPCOL *col)
 251.168 +{     /* make column inactive */
 251.169 +      if (col->temp)
 251.170 +      {  col->temp = 0;
 251.171 +         /* move the column to the end of the column list */
 251.172 +         npp_remove_col(npp, col);
 251.173 +         npp_insert_col(npp, col, 1);
 251.174 +      }
 251.175 +      return;
 251.176 +}
 251.177 +
 251.178 +NPPROW *npp_add_row(NPP *npp)
 251.179 +{     /* add new row to the current problem */
 251.180 +      NPPROW *row;
 251.181 +      row = dmp_get_atom(npp->pool, sizeof(NPPROW));
 251.182 +      row->i = ++(npp->nrows);
 251.183 +      row->name = NULL;
 251.184 +      row->lb = -DBL_MAX, row->ub = +DBL_MAX;
 251.185 +      row->ptr = NULL;
 251.186 +      row->temp = 0;
 251.187 +      npp_insert_row(npp, row, 1);
 251.188 +      return row;
 251.189 +}
 251.190 +
 251.191 +NPPCOL *npp_add_col(NPP *npp)
 251.192 +{     /* add new column to the current problem */
 251.193 +      NPPCOL *col;
 251.194 +      col = dmp_get_atom(npp->pool, sizeof(NPPCOL));
 251.195 +      col->j = ++(npp->ncols);
 251.196 +      col->name = NULL;
 251.197 +#if 0
 251.198 +      col->kind = GLP_CV;
 251.199 +#else
 251.200 +      col->is_int = 0;
 251.201 +#endif
 251.202 +      col->lb = col->ub = col->coef = 0.0;
 251.203 +      col->ptr = NULL;
 251.204 +      col->temp = 0;
 251.205 +      npp_insert_col(npp, col, 1);
 251.206 +      return col;
 251.207 +}
 251.208 +
 251.209 +NPPAIJ *npp_add_aij(NPP *npp, NPPROW *row, NPPCOL *col, double val)
 251.210 +{     /* add new element to the constraint matrix */
 251.211 +      NPPAIJ *aij;
 251.212 +      aij = dmp_get_atom(npp->pool, sizeof(NPPAIJ));
 251.213 +      aij->row = row;
 251.214 +      aij->col = col;
 251.215 +      aij->val = val;
 251.216 +      aij->r_prev = NULL;
 251.217 +      aij->r_next = row->ptr;
 251.218 +      aij->c_prev = NULL;
 251.219 +      aij->c_next = col->ptr;
 251.220 +      if (aij->r_next != NULL)
 251.221 +         aij->r_next->r_prev = aij;
 251.222 +      if (aij->c_next != NULL)
 251.223 +         aij->c_next->c_prev = aij;
 251.224 +      row->ptr = col->ptr = aij;
 251.225 +      return aij;
 251.226 +}
 251.227 +
 251.228 +int npp_row_nnz(NPP *npp, NPPROW *row)
 251.229 +{     /* count number of non-zero coefficients in row */
 251.230 +      NPPAIJ *aij;
 251.231 +      int nnz;
 251.232 +      xassert(npp == npp);
 251.233 +      nnz = 0;
 251.234 +      for (aij = row->ptr; aij != NULL; aij = aij->r_next)
 251.235 +         nnz++;
 251.236 +      return nnz;
 251.237 +}
 251.238 +
 251.239 +int npp_col_nnz(NPP *npp, NPPCOL *col)
 251.240 +{     /* count number of non-zero coefficients in column */
 251.241 +      NPPAIJ *aij;
 251.242 +      int nnz;
 251.243 +      xassert(npp == npp);
 251.244 +      nnz = 0;
 251.245 +      for (aij = col->ptr; aij != NULL; aij = aij->c_next)
 251.246 +         nnz++;
 251.247 +      return nnz;
 251.248 +}
 251.249 +
 251.250 +void *npp_push_tse(NPP *npp, int (*func)(NPP *npp, void *info),
 251.251 +      int size)
 251.252 +{     /* push new entry to the transformation stack */
 251.253 +      NPPTSE *tse;
 251.254 +      tse = dmp_get_atom(npp->stack, sizeof(NPPTSE));
 251.255 +      tse->func = func;
 251.256 +      tse->info = dmp_get_atom(npp->stack, size);
 251.257 +      tse->link = npp->top;
 251.258 +      npp->top = tse;
 251.259 +      return tse->info;
 251.260 +}
 251.261 +
 251.262 +#if 1 /* 23/XII-2009 */
 251.263 +void npp_erase_row(NPP *npp, NPPROW *row)
 251.264 +{     /* erase row content to make it empty */
 251.265 +      NPPAIJ *aij;
 251.266 +      while (row->ptr != NULL)
 251.267 +      {  aij = row->ptr;
 251.268 +         row->ptr = aij->r_next;
 251.269 +         if (aij->c_prev == NULL)
 251.270 +            aij->col->ptr = aij->c_next;
 251.271 +         else
 251.272 +            aij->c_prev->c_next = aij->c_next;
 251.273 +         if (aij->c_next == NULL)
 251.274 +            ;
 251.275 +         else
 251.276 +            aij->c_next->c_prev = aij->c_prev;
 251.277 +         dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ));
 251.278 +      }
 251.279 +      return;
 251.280 +}
 251.281 +#endif
 251.282 +
 251.283 +void npp_del_row(NPP *npp, NPPROW *row)
 251.284 +{     /* remove row from the current problem */
 251.285 +#if 0 /* 23/XII-2009 */
 251.286 +      NPPAIJ *aij;
 251.287 +#endif
 251.288 +      if (row->name != NULL)
 251.289 +         dmp_free_atom(npp->pool, row->name, strlen(row->name)+1);
 251.290 +#if 0 /* 23/XII-2009 */
 251.291 +      while (row->ptr != NULL)
 251.292 +      {  aij = row->ptr;
 251.293 +         row->ptr = aij->r_next;
 251.294 +         if (aij->c_prev == NULL)
 251.295 +            aij->col->ptr = aij->c_next;
 251.296 +         else
 251.297 +            aij->c_prev->c_next = aij->c_next;
 251.298 +         if (aij->c_next == NULL)
 251.299 +            ;
 251.300 +         else
 251.301 +            aij->c_next->c_prev = aij->c_prev;
 251.302 +         dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ));
 251.303 +      }
 251.304 +#else
 251.305 +      npp_erase_row(npp, row);
 251.306 +#endif
 251.307 +      npp_remove_row(npp, row);
 251.308 +      dmp_free_atom(npp->pool, row, sizeof(NPPROW));
 251.309 +      return;
 251.310 +}
 251.311 +
 251.312 +void npp_del_col(NPP *npp, NPPCOL *col)
 251.313 +{     /* remove column from the current problem */
 251.314 +      NPPAIJ *aij;
 251.315 +      if (col->name != NULL)
 251.316 +         dmp_free_atom(npp->pool, col->name, strlen(col->name)+1);
 251.317 +      while (col->ptr != NULL)
 251.318 +      {  aij = col->ptr;
 251.319 +         col->ptr = aij->c_next;
 251.320 +         if (aij->r_prev == NULL)
 251.321 +            aij->row->ptr = aij->r_next;
 251.322 +         else
 251.323 +            aij->r_prev->r_next = aij->r_next;
 251.324 +         if (aij->r_next == NULL)
 251.325 +            ;
 251.326 +         else
 251.327 +            aij->r_next->r_prev = aij->r_prev;
 251.328 +         dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ));
 251.329 +      }
 251.330 +      npp_remove_col(npp, col);
 251.331 +      dmp_free_atom(npp->pool, col, sizeof(NPPCOL));
 251.332 +      return;
 251.333 +}
 251.334 +
 251.335 +void npp_del_aij(NPP *npp, NPPAIJ *aij)
 251.336 +{     /* remove element from the constraint matrix */
 251.337 +      if (aij->r_prev == NULL)
 251.338 +         aij->row->ptr = aij->r_next;
 251.339 +      else
 251.340 +         aij->r_prev->r_next = aij->r_next;
 251.341 +      if (aij->r_next == NULL)
 251.342 +         ;
 251.343 +      else
 251.344 +         aij->r_next->r_prev = aij->r_prev;
 251.345 +      if (aij->c_prev == NULL)
 251.346 +         aij->col->ptr = aij->c_next;
 251.347 +      else
 251.348 +         aij->c_prev->c_next = aij->c_next;
 251.349 +      if (aij->c_next == NULL)
 251.350 +         ;
 251.351 +      else
 251.352 +         aij->c_next->c_prev = aij->c_prev;
 251.353 +      dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ));
 251.354 +      return;
 251.355 +}
 251.356 +
 251.357 +void npp_load_prob(NPP *npp, glp_prob *orig, int names, int sol,
 251.358 +      int scaling)
 251.359 +{     /* load original problem into the preprocessor workspace */
 251.360 +      int m = orig->m;
 251.361 +      int n = orig->n;
 251.362 +      NPPROW **link;
 251.363 +      int i, j;
 251.364 +      double dir;
 251.365 +      xassert(names == GLP_OFF || names == GLP_ON);
 251.366 +      xassert(sol == GLP_SOL || sol == GLP_IPT || sol == GLP_MIP);
 251.367 +      xassert(scaling == GLP_OFF || scaling == GLP_ON);
 251.368 +      if (sol == GLP_MIP) xassert(!scaling);
 251.369 +      npp->orig_dir = orig->dir;
 251.370 +      if (npp->orig_dir == GLP_MIN)
 251.371 +         dir = +1.0;
 251.372 +      else if (npp->orig_dir == GLP_MAX)
 251.373 +         dir = -1.0;
 251.374 +      else
 251.375 +         xassert(npp != npp);
 251.376 +      npp->orig_m = m;
 251.377 +      npp->orig_n = n;
 251.378 +      npp->orig_nnz = orig->nnz;
 251.379 +      if (names && orig->name != NULL)
 251.380 +      {  npp->name = dmp_get_atom(npp->pool, strlen(orig->name)+1);
 251.381 +         strcpy(npp->name, orig->name);
 251.382 +      }
 251.383 +      if (names && orig->obj != NULL)
 251.384 +      {  npp->obj = dmp_get_atom(npp->pool, strlen(orig->obj)+1);
 251.385 +         strcpy(npp->obj, orig->obj);
 251.386 +      }
 251.387 +      npp->c0 = dir * orig->c0;
 251.388 +      /* load rows */
 251.389 +      link = xcalloc(1+m, sizeof(NPPROW *));
 251.390 +      for (i = 1; i <= m; i++)
 251.391 +      {  GLPROW *rrr = orig->row[i];
 251.392 +         NPPROW *row;
 251.393 +         link[i] = row = npp_add_row(npp);
 251.394 +         xassert(row->i == i);
 251.395 +         if (names && rrr->name != NULL)
 251.396 +         {  row->name = dmp_get_atom(npp->pool, strlen(rrr->name)+1);
 251.397 +            strcpy(row->name, rrr->name);
 251.398 +         }
 251.399 +         if (!scaling)
 251.400 +         {  if (rrr->type == GLP_FR)
 251.401 +               row->lb = -DBL_MAX, row->ub = +DBL_MAX;
 251.402 +            else if (rrr->type == GLP_LO)
 251.403 +               row->lb = rrr->lb, row->ub = +DBL_MAX;
 251.404 +            else if (rrr->type == GLP_UP)
 251.405 +               row->lb = -DBL_MAX, row->ub = rrr->ub;
 251.406 +            else if (rrr->type == GLP_DB)
 251.407 +               row->lb = rrr->lb, row->ub = rrr->ub;
 251.408 +            else if (rrr->type == GLP_FX)
 251.409 +               row->lb = row->ub = rrr->lb;
 251.410 +            else
 251.411 +               xassert(rrr != rrr);
 251.412 +         }
 251.413 +         else
 251.414 +         {  double rii = rrr->rii;
 251.415 +            if (rrr->type == GLP_FR)
 251.416 +               row->lb = -DBL_MAX, row->ub = +DBL_MAX;
 251.417 +            else if (rrr->type == GLP_LO)
 251.418 +               row->lb = rrr->lb * rii, row->ub = +DBL_MAX;
 251.419 +            else if (rrr->type == GLP_UP)
 251.420 +               row->lb = -DBL_MAX, row->ub = rrr->ub * rii;
 251.421 +            else if (rrr->type == GLP_DB)
 251.422 +               row->lb = rrr->lb * rii, row->ub = rrr->ub * rii;
 251.423 +            else if (rrr->type == GLP_FX)
 251.424 +               row->lb = row->ub = rrr->lb * rii;
 251.425 +            else
 251.426 +               xassert(rrr != rrr);
 251.427 +         }
 251.428 +      }
 251.429 +      /* load columns and constraint coefficients */
 251.430 +      for (j = 1; j <= n; j++)
 251.431 +      {  GLPCOL *ccc = orig->col[j];
 251.432 +         GLPAIJ *aaa;
 251.433 +         NPPCOL *col;
 251.434 +         col = npp_add_col(npp);
 251.435 +         xassert(col->j == j);
 251.436 +         if (names && ccc->name != NULL)
 251.437 +         {  col->name = dmp_get_atom(npp->pool, strlen(ccc->name)+1);
 251.438 +            strcpy(col->name, ccc->name);
 251.439 +         }
 251.440 +         if (sol == GLP_MIP)
 251.441 +#if 0
 251.442 +            col->kind = ccc->kind;
 251.443 +#else
 251.444 +            col->is_int = (char)(ccc->kind == GLP_IV);
 251.445 +#endif
 251.446 +         if (!scaling)
 251.447 +         {  if (ccc->type == GLP_FR)
 251.448 +               col->lb = -DBL_MAX, col->ub = +DBL_MAX;
 251.449 +            else if (ccc->type == GLP_LO)
 251.450 +               col->lb = ccc->lb, col->ub = +DBL_MAX;
 251.451 +            else if (ccc->type == GLP_UP)
 251.452 +               col->lb = -DBL_MAX, col->ub = ccc->ub;
 251.453 +            else if (ccc->type == GLP_DB)
 251.454 +               col->lb = ccc->lb, col->ub = ccc->ub;
 251.455 +            else if (ccc->type == GLP_FX)
 251.456 +               col->lb = col->ub = ccc->lb;
 251.457 +            else
 251.458 +               xassert(ccc != ccc);
 251.459 +            col->coef = dir * ccc->coef;
 251.460 +            for (aaa = ccc->ptr; aaa != NULL; aaa = aaa->c_next)
 251.461 +               npp_add_aij(npp, link[aaa->row->i], col, aaa->val);
 251.462 +         }
 251.463 +         else
 251.464 +         {  double sjj = ccc->sjj;
 251.465 +            if (ccc->type == GLP_FR)
 251.466 +               col->lb = -DBL_MAX, col->ub = +DBL_MAX;
 251.467 +            else if (ccc->type == GLP_LO)
 251.468 +               col->lb = ccc->lb / sjj, col->ub = +DBL_MAX;
 251.469 +            else if (ccc->type == GLP_UP)
 251.470 +               col->lb = -DBL_MAX, col->ub = ccc->ub / sjj;
 251.471 +            else if (ccc->type == GLP_DB)
 251.472 +               col->lb = ccc->lb / sjj, col->ub = ccc->ub / sjj;
 251.473 +            else if (ccc->type == GLP_FX)
 251.474 +               col->lb = col->ub = ccc->lb / sjj;
 251.475 +            else
 251.476 +               xassert(ccc != ccc);
 251.477 +            col->coef = dir * ccc->coef * sjj;
 251.478 +            for (aaa = ccc->ptr; aaa != NULL; aaa = aaa->c_next)
 251.479 +               npp_add_aij(npp, link[aaa->row->i], col,
 251.480 +                  aaa->row->rii * aaa->val * sjj);
 251.481 +         }
 251.482 +      }
 251.483 +      xfree(link);
 251.484 +      /* keep solution indicator and scaling option */
 251.485 +      npp->sol = sol;
 251.486 +      npp->scaling = scaling;
 251.487 +      return;
 251.488 +}
 251.489 +
 251.490 +void npp_build_prob(NPP *npp, glp_prob *prob)
 251.491 +{     /* build resultant (preprocessed) problem */
 251.492 +      NPPROW *row;
 251.493 +      NPPCOL *col;
 251.494 +      NPPAIJ *aij;
 251.495 +      int i, j, type, len, *ind;
 251.496 +      double dir, *val;
 251.497 +      glp_erase_prob(prob);
 251.498 +      glp_set_prob_name(prob, npp->name);
 251.499 +      glp_set_obj_name(prob, npp->obj);
 251.500 +      glp_set_obj_dir(prob, npp->orig_dir);
 251.501 +      if (npp->orig_dir == GLP_MIN)
 251.502 +         dir = +1.0;
 251.503 +      else if (npp->orig_dir == GLP_MAX)
 251.504 +         dir = -1.0;
 251.505 +      else
 251.506 +         xassert(npp != npp);
 251.507 +      glp_set_obj_coef(prob, 0, dir * npp->c0);
 251.508 +      /* build rows */
 251.509 +      for (row = npp->r_head; row != NULL; row = row->next)
 251.510 +      {  row->temp = i = glp_add_rows(prob, 1);
 251.511 +         glp_set_row_name(prob, i, row->name);
 251.512 +         if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
 251.513 +            type = GLP_FR;
 251.514 +         else if (row->ub == +DBL_MAX)
 251.515 +            type = GLP_LO;
 251.516 +         else if (row->lb == -DBL_MAX)
 251.517 +            type = GLP_UP;
 251.518 +         else if (row->lb != row->ub)
 251.519 +            type = GLP_DB;
 251.520 +         else
 251.521 +            type = GLP_FX;
 251.522 +         glp_set_row_bnds(prob, i, type, row->lb, row->ub);
 251.523 +      }
 251.524 +      /* build columns and the constraint matrix */
 251.525 +      ind = xcalloc(1+prob->m, sizeof(int));
 251.526 +      val = xcalloc(1+prob->m, sizeof(double));
 251.527 +      for (col = npp->c_head; col != NULL; col = col->next)
 251.528 +      {  j = glp_add_cols(prob, 1);
 251.529 +         glp_set_col_name(prob, j, col->name);
 251.530 +#if 0
 251.531 +         glp_set_col_kind(prob, j, col->kind);
 251.532 +#else
 251.533 +         glp_set_col_kind(prob, j, col->is_int ? GLP_IV : GLP_CV);
 251.534 +#endif
 251.535 +         if (col->lb == -DBL_MAX && col->ub == +DBL_MAX)
 251.536 +            type = GLP_FR;
 251.537 +         else if (col->ub == +DBL_MAX)
 251.538 +            type = GLP_LO;
 251.539 +         else if (col->lb == -DBL_MAX)
 251.540 +            type = GLP_UP;
 251.541 +         else if (col->lb != col->ub)
 251.542 +            type = GLP_DB;
 251.543 +         else
 251.544 +            type = GLP_FX;
 251.545 +         glp_set_col_bnds(prob, j, type, col->lb, col->ub);
 251.546 +         glp_set_obj_coef(prob, j, dir * col->coef);
 251.547 +         len = 0;
 251.548 +         for (aij = col->ptr; aij != NULL; aij = aij->c_next)
 251.549 +         {  len++;
 251.550 +            ind[len] = aij->row->temp;
 251.551 +            val[len] = aij->val;
 251.552 +         }
 251.553 +         glp_set_mat_col(prob, j, len, ind, val);
 251.554 +      }
 251.555 +      xfree(ind);
 251.556 +      xfree(val);
 251.557 +      /* resultant problem has been built */
 251.558 +      npp->m = prob->m;
 251.559 +      npp->n = prob->n;
 251.560 +      npp->nnz = prob->nnz;
 251.561 +      npp->row_ref = xcalloc(1+npp->m, sizeof(int));
 251.562 +      npp->col_ref = xcalloc(1+npp->n, sizeof(int));
 251.563 +      for (row = npp->r_head, i = 0; row != NULL; row = row->next)
 251.564 +         npp->row_ref[++i] = row->i;
 251.565 +      for (col = npp->c_head, j = 0; col != NULL; col = col->next)
 251.566 +         npp->col_ref[++j] = col->j;
 251.567 +      /* transformed problem segment is no longer needed */
 251.568 +      dmp_delete_pool(npp->pool), npp->pool = NULL;
 251.569 +      npp->name = npp->obj = NULL;
 251.570 +      npp->c0 = 0.0;
 251.571 +      npp->r_head = npp->r_tail = NULL;
 251.572 +      npp->c_head = npp->c_tail = NULL;
 251.573 +      return;
 251.574 +}
 251.575 +
 251.576 +void npp_postprocess(NPP *npp, glp_prob *prob)
 251.577 +{     /* postprocess solution from the resultant problem */
 251.578 +      GLPROW *row;
 251.579 +      GLPCOL *col;
 251.580 +      NPPTSE *tse;
 251.581 +      int i, j, k;
 251.582 +      double dir;
 251.583 +      xassert(npp->orig_dir == prob->dir);
 251.584 +      if (npp->orig_dir == GLP_MIN)
 251.585 +         dir = +1.0;
 251.586 +      else if (npp->orig_dir == GLP_MAX)
 251.587 +         dir = -1.0;
 251.588 +      else
 251.589 +         xassert(npp != npp);
 251.590 +      xassert(npp->m == prob->m);
 251.591 +      xassert(npp->n == prob->n);
 251.592 +      xassert(npp->nnz == prob->nnz);
 251.593 +      /* copy solution status */
 251.594 +      if (npp->sol == GLP_SOL)
 251.595 +      {  npp->p_stat = prob->pbs_stat;
 251.596 +         npp->d_stat = prob->dbs_stat;
 251.597 +      }
 251.598 +      else if (npp->sol == GLP_IPT)
 251.599 +         npp->t_stat = prob->ipt_stat;
 251.600 +      else if (npp->sol == GLP_MIP)
 251.601 +         npp->i_stat = prob->mip_stat;
 251.602 +      else
 251.603 +         xassert(npp != npp);
 251.604 +      /* allocate solution arrays */
 251.605 +      if (npp->sol == GLP_SOL)
 251.606 +      {  if (npp->r_stat == NULL)
 251.607 +            npp->r_stat = xcalloc(1+npp->nrows, sizeof(char));
 251.608 +         for (i = 1; i <= npp->nrows; i++)
 251.609 +            npp->r_stat[i] = 0;
 251.610 +         if (npp->c_stat == NULL)
 251.611 +            npp->c_stat = xcalloc(1+npp->ncols, sizeof(char));
 251.612 +         for (j = 1; j <= npp->ncols; j++)
 251.613 +            npp->c_stat[j] = 0;
 251.614 +      }
 251.615 +#if 0
 251.616 +      if (npp->r_prim == NULL)
 251.617 +         npp->r_prim = xcalloc(1+npp->nrows, sizeof(double));
 251.618 +      for (i = 1; i <= npp->nrows; i++)
 251.619 +         npp->r_prim[i] = DBL_MAX;
 251.620 +#endif
 251.621 +      if (npp->c_value == NULL)
 251.622 +         npp->c_value = xcalloc(1+npp->ncols, sizeof(double));
 251.623 +      for (j = 1; j <= npp->ncols; j++)
 251.624 +         npp->c_value[j] = DBL_MAX;
 251.625 +      if (npp->sol != GLP_MIP)
 251.626 +      {  if (npp->r_pi == NULL)
 251.627 +            npp->r_pi = xcalloc(1+npp->nrows, sizeof(double));
 251.628 +         for (i = 1; i <= npp->nrows; i++)
 251.629 +            npp->r_pi[i] = DBL_MAX;
 251.630 +#if 0
 251.631 +         if (npp->c_dual == NULL)
 251.632 +            npp->c_dual = xcalloc(1+npp->ncols, sizeof(double));
 251.633 +         for (j = 1; j <= npp->ncols; j++)
 251.634 +            npp->c_dual[j] = DBL_MAX;
 251.635 +#endif
 251.636 +      }
 251.637 +      /* copy solution components from the resultant problem */
 251.638 +      if (npp->sol == GLP_SOL)
 251.639 +      {  for (i = 1; i <= npp->m; i++)
 251.640 +         {  row = prob->row[i];
 251.641 +            k = npp->row_ref[i];
 251.642 +            npp->r_stat[k] = (char)row->stat;
 251.643 +            /*npp->r_prim[k] = row->prim;*/
 251.644 +            npp->r_pi[k] = dir * row->dual;
 251.645 +         }
 251.646 +         for (j = 1; j <= npp->n; j++)
 251.647 +         {  col = prob->col[j];
 251.648 +            k = npp->col_ref[j];
 251.649 +            npp->c_stat[k] = (char)col->stat;
 251.650 +            npp->c_value[k] = col->prim;
 251.651 +            /*npp->c_dual[k] = dir * col->dual;*/
 251.652 +         }
 251.653 +      }
 251.654 +      else if (npp->sol == GLP_IPT)
 251.655 +      {  for (i = 1; i <= npp->m; i++)
 251.656 +         {  row = prob->row[i];
 251.657 +            k = npp->row_ref[i];
 251.658 +            /*npp->r_prim[k] = row->pval;*/
 251.659 +            npp->r_pi[k] = dir * row->dval;
 251.660 +         }
 251.661 +         for (j = 1; j <= npp->n; j++)
 251.662 +         {  col = prob->col[j];
 251.663 +            k = npp->col_ref[j];
 251.664 +            npp->c_value[k] = col->pval;
 251.665 +            /*npp->c_dual[k] = dir * col->dval;*/
 251.666 +         }
 251.667 +      }
 251.668 +      else if (npp->sol == GLP_MIP)
 251.669 +      {
 251.670 +#if 0
 251.671 +         for (i = 1; i <= npp->m; i++)
 251.672 +         {  row = prob->row[i];
 251.673 +            k = npp->row_ref[i];
 251.674 +            /*npp->r_prim[k] = row->mipx;*/
 251.675 +         }
 251.676 +#endif
 251.677 +         for (j = 1; j <= npp->n; j++)
 251.678 +         {  col = prob->col[j];
 251.679 +            k = npp->col_ref[j];
 251.680 +            npp->c_value[k] = col->mipx;
 251.681 +         }
 251.682 +      }
 251.683 +      else
 251.684 +         xassert(npp != npp);
 251.685 +      /* perform postprocessing to construct solution to the original
 251.686 +         problem */
 251.687 +      for (tse = npp->top; tse != NULL; tse = tse->link)
 251.688 +      {  xassert(tse->func != NULL);
 251.689 +         xassert(tse->func(npp, tse->info) == 0);
 251.690 +      }
 251.691 +      return;
 251.692 +}
 251.693 +
 251.694 +void npp_unload_sol(NPP *npp, glp_prob *orig)
 251.695 +{     /* store solution to the original problem */
 251.696 +      GLPROW *row;
 251.697 +      GLPCOL *col;
 251.698 +      int i, j;
 251.699 +      double dir;
 251.700 +      xassert(npp->orig_dir == orig->dir);
 251.701 +      if (npp->orig_dir == GLP_MIN)
 251.702 +         dir = +1.0;
 251.703 +      else if (npp->orig_dir == GLP_MAX)
 251.704 +         dir = -1.0;
 251.705 +      else
 251.706 +         xassert(npp != npp);
 251.707 +      xassert(npp->orig_m == orig->m);
 251.708 +      xassert(npp->orig_n == orig->n);
 251.709 +      xassert(npp->orig_nnz == orig->nnz);
 251.710 +      if (npp->sol == GLP_SOL)
 251.711 +      {  /* store basic solution */
 251.712 +         orig->valid = 0;
 251.713 +         orig->pbs_stat = npp->p_stat;
 251.714 +         orig->dbs_stat = npp->d_stat;
 251.715 +         orig->obj_val = orig->c0;
 251.716 +         orig->some = 0;
 251.717 +         for (i = 1; i <= orig->m; i++)
 251.718 +         {  row = orig->row[i];
 251.719 +            row->stat = npp->r_stat[i];
 251.720 +            if (!npp->scaling)
 251.721 +            {  /*row->prim = npp->r_prim[i];*/
 251.722 +               row->dual = dir * npp->r_pi[i];
 251.723 +            }
 251.724 +            else
 251.725 +            {  /*row->prim = npp->r_prim[i] / row->rii;*/
 251.726 +               row->dual = dir * npp->r_pi[i] * row->rii;
 251.727 +            }
 251.728 +            if (row->stat == GLP_BS)
 251.729 +               row->dual = 0.0;
 251.730 +            else if (row->stat == GLP_NL)
 251.731 +            {  xassert(row->type == GLP_LO || row->type == GLP_DB);
 251.732 +               row->prim = row->lb;
 251.733 +            }
 251.734 +            else if (row->stat == GLP_NU)
 251.735 +            {  xassert(row->type == GLP_UP || row->type == GLP_DB);
 251.736 +               row->prim = row->ub;
 251.737 +            }
 251.738 +            else if (row->stat == GLP_NF)
 251.739 +            {  xassert(row->type == GLP_FR);
 251.740 +               row->prim = 0.0;
 251.741 +            }
 251.742 +            else if (row->stat == GLP_NS)
 251.743 +            {  xassert(row->type == GLP_FX);
 251.744 +               row->prim = row->lb;
 251.745 +            }
 251.746 +            else
 251.747 +               xassert(row != row);
 251.748 +         }
 251.749 +         for (j = 1; j <= orig->n; j++)
 251.750 +         {  col = orig->col[j];
 251.751 +            col->stat = npp->c_stat[j];
 251.752 +            if (!npp->scaling)
 251.753 +            {  col->prim = npp->c_value[j];
 251.754 +               /*col->dual = dir * npp->c_dual[j];*/
 251.755 +            }
 251.756 +            else
 251.757 +            {  col->prim = npp->c_value[j] * col->sjj;
 251.758 +               /*col->dual = dir * npp->c_dual[j] / col->sjj;*/
 251.759 +            }
 251.760 +            if (col->stat == GLP_BS)
 251.761 +               col->dual = 0.0;
 251.762 +#if 1
 251.763 +            else if (col->stat == GLP_NL)
 251.764 +            {  xassert(col->type == GLP_LO || col->type == GLP_DB);
 251.765 +               col->prim = col->lb;
 251.766 +            }
 251.767 +            else if (col->stat == GLP_NU)
 251.768 +            {  xassert(col->type == GLP_UP || col->type == GLP_DB);
 251.769 +               col->prim = col->ub;
 251.770 +            }
 251.771 +            else if (col->stat == GLP_NF)
 251.772 +            {  xassert(col->type == GLP_FR);
 251.773 +               col->prim = 0.0;
 251.774 +            }
 251.775 +            else if (col->stat == GLP_NS)
 251.776 +            {  xassert(col->type == GLP_FX);
 251.777 +               col->prim = col->lb;
 251.778 +            }
 251.779 +            else
 251.780 +               xassert(col != col);
 251.781 +#endif
 251.782 +            orig->obj_val += col->coef * col->prim;
 251.783 +         }
 251.784 +#if 1
 251.785 +         /* compute primal values of inactive rows */
 251.786 +         for (i = 1; i <= orig->m; i++)
 251.787 +         {  row = orig->row[i];
 251.788 +            if (row->stat == GLP_BS)
 251.789 +            {  GLPAIJ *aij;
 251.790 +               double temp;
 251.791 +               temp = 0.0;
 251.792 +               for (aij = row->ptr; aij != NULL; aij = aij->r_next)
 251.793 +                  temp += aij->val * aij->col->prim;
 251.794 +               row->prim = temp;
 251.795 +            }
 251.796 +         }
 251.797 +         /* compute reduced costs of active columns */
 251.798 +         for (j = 1; j <= orig->n; j++)
 251.799 +         {  col = orig->col[j];
 251.800 +            if (col->stat != GLP_BS)
 251.801 +            {  GLPAIJ *aij;
 251.802 +               double temp;
 251.803 +               temp = col->coef;
 251.804 +               for (aij = col->ptr; aij != NULL; aij = aij->c_next)
 251.805 +                  temp -= aij->val * aij->row->dual;
 251.806 +               col->dual = temp;
 251.807 +            }
 251.808 +         }
 251.809 +#endif
 251.810 +      }
 251.811 +      else if (npp->sol == GLP_IPT)
 251.812 +      {  /* store interior-point solution */
 251.813 +         orig->ipt_stat = npp->t_stat;
 251.814 +         orig->ipt_obj = orig->c0;
 251.815 +         for (i = 1; i <= orig->m; i++)
 251.816 +         {  row = orig->row[i];
 251.817 +            if (!npp->scaling)
 251.818 +            {  /*row->pval = npp->r_prim[i];*/
 251.819 +               row->dval = dir * npp->r_pi[i];
 251.820 +            }
 251.821 +            else
 251.822 +            {  /*row->pval = npp->r_prim[i] / row->rii;*/
 251.823 +               row->dval = dir * npp->r_pi[i] * row->rii;
 251.824 +            }
 251.825 +         }
 251.826 +         for (j = 1; j <= orig->n; j++)
 251.827 +         {  col = orig->col[j];
 251.828 +            if (!npp->scaling)
 251.829 +            {  col->pval = npp->c_value[j];
 251.830 +               /*col->dval = dir * npp->c_dual[j];*/
 251.831 +            }
 251.832 +            else
 251.833 +            {  col->pval = npp->c_value[j] * col->sjj;
 251.834 +               /*col->dval = dir * npp->c_dual[j] / col->sjj;*/
 251.835 +            }
 251.836 +            orig->ipt_obj += col->coef * col->pval;
 251.837 +         }
 251.838 +#if 1
 251.839 +         /* compute row primal values */
 251.840 +         for (i = 1; i <= orig->m; i++)
 251.841 +         {  row = orig->row[i];
 251.842 +            {  GLPAIJ *aij;
 251.843 +               double temp;
 251.844 +               temp = 0.0;
 251.845 +               for (aij = row->ptr; aij != NULL; aij = aij->r_next)
 251.846 +                  temp += aij->val * aij->col->pval;
 251.847 +               row->pval = temp;
 251.848 +            }
 251.849 +         }
 251.850 +         /* compute column dual values */
 251.851 +         for (j = 1; j <= orig->n; j++)
 251.852 +         {  col = orig->col[j];
 251.853 +            {  GLPAIJ *aij;
 251.854 +               double temp;
 251.855 +               temp = col->coef;
 251.856 +               for (aij = col->ptr; aij != NULL; aij = aij->c_next)
 251.857 +                  temp -= aij->val * aij->row->dval;
 251.858 +               col->dval = temp;
 251.859 +            }
 251.860 +         }
 251.861 +#endif
 251.862 +      }
 251.863 +      else if (npp->sol == GLP_MIP)
 251.864 +      {  /* store MIP solution */
 251.865 +         xassert(!npp->scaling);
 251.866 +         orig->mip_stat = npp->i_stat;
 251.867 +         orig->mip_obj = orig->c0;
 251.868 +#if 0
 251.869 +         for (i = 1; i <= orig->m; i++)
 251.870 +         {  row = orig->row[i];
 251.871 +            /*row->mipx = npp->r_prim[i];*/
 251.872 +         }
 251.873 +#endif
 251.874 +         for (j = 1; j <= orig->n; j++)
 251.875 +         {  col = orig->col[j];
 251.876 +            col->mipx = npp->c_value[j];
 251.877 +            if (col->kind == GLP_IV)
 251.878 +               xassert(col->mipx == floor(col->mipx));
 251.879 +            orig->mip_obj += col->coef * col->mipx;
 251.880 +         }
 251.881 +#if 1
 251.882 +         /* compute row primal values */
 251.883 +         for (i = 1; i <= orig->m; i++)
 251.884 +         {  row = orig->row[i];
 251.885 +            {  GLPAIJ *aij;
 251.886 +               double temp;
 251.887 +               temp = 0.0;
 251.888 +               for (aij = row->ptr; aij != NULL; aij = aij->r_next)
 251.889 +                  temp += aij->val * aij->col->mipx;
 251.890 +               row->mipx = temp;
 251.891 +            }
 251.892 +         }
 251.893 +#endif
 251.894 +      }
 251.895 +      else
 251.896 +         xassert(npp != npp);
 251.897 +      return;
 251.898 +}
 251.899 +
 251.900 +void npp_delete_wksp(NPP *npp)
 251.901 +{     /* delete LP/MIP preprocessor workspace */
 251.902 +      if (npp->pool != NULL)
 251.903 +         dmp_delete_pool(npp->pool);
 251.904 +      if (npp->stack != NULL)
 251.905 +         dmp_delete_pool(npp->stack);
 251.906 +      if (npp->row_ref != NULL)
 251.907 +         xfree(npp->row_ref);
 251.908 +      if (npp->col_ref != NULL)
 251.909 +         xfree(npp->col_ref);
 251.910 +      if (npp->r_stat != NULL)
 251.911 +         xfree(npp->r_stat);
 251.912 +#if 0
 251.913 +      if (npp->r_prim != NULL)
 251.914 +         xfree(npp->r_prim);
 251.915 +#endif
 251.916 +      if (npp->r_pi != NULL)
 251.917 +         xfree(npp->r_pi);
 251.918 +      if (npp->c_stat != NULL)
 251.919 +         xfree(npp->c_stat);
 251.920 +      if (npp->c_value != NULL)
 251.921 +         xfree(npp->c_value);
 251.922 +#if 0
 251.923 +      if (npp->c_dual != NULL)
 251.924 +         xfree(npp->c_dual);
 251.925 +#endif
 251.926 +      xfree(npp);
 251.927 +      return;
 251.928 +}
 251.929 +
 251.930 +/* eof */
   252.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   252.2 +++ b/src/glpnpp02.c	Mon Dec 06 13:09:21 2010 +0100
   252.3 @@ -0,0 +1,1433 @@
   252.4 +/* glpnpp02.c */
   252.5 +
   252.6 +/***********************************************************************
   252.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   252.8 +*
   252.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  252.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  252.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  252.12 +*  E-mail: <mao@gnu.org>.
  252.13 +*
  252.14 +*  GLPK is free software: you can redistribute it and/or modify it
  252.15 +*  under the terms of the GNU General Public License as published by
  252.16 +*  the Free Software Foundation, either version 3 of the License, or
  252.17 +*  (at your option) any later version.
  252.18 +*
  252.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  252.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  252.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  252.22 +*  License for more details.
  252.23 +*
  252.24 +*  You should have received a copy of the GNU General Public License
  252.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  252.26 +***********************************************************************/
  252.27 +
  252.28 +#include "glpnpp.h"
  252.29 +
  252.30 +/***********************************************************************
  252.31 +*  NAME
  252.32 +*
  252.33 +*  npp_free_row - process free (unbounded) row
  252.34 +*
  252.35 +*  SYNOPSIS
  252.36 +*
  252.37 +*  #include "glpnpp.h"
  252.38 +*  void npp_free_row(NPP *npp, NPPROW *p);
  252.39 +*
  252.40 +*  DESCRIPTION
  252.41 +*
  252.42 +*  The routine npp_free_row processes row p, which is free (i.e. has
  252.43 +*  no finite bounds):
  252.44 +*
  252.45 +*     -inf < sum a[p,j] x[j] < +inf.                                 (1)
  252.46 +*             j
  252.47 +*
  252.48 +*  PROBLEM TRANSFORMATION
  252.49 +*
  252.50 +*  Constraint (1) cannot be active, so it is redundant and can be
  252.51 +*  removed from the original problem.
  252.52 +*
  252.53 +*  Removing row p leads to removing a column of multiplier pi[p] for
  252.54 +*  this row in the dual system. Since row p has no bounds, pi[p] = 0,
  252.55 +*  so removing the column does not affect the dual solution.
  252.56 +*
  252.57 +*  RECOVERING BASIC SOLUTION
  252.58 +*
  252.59 +*  In solution to the original problem row p is inactive constraint,
  252.60 +*  so it is assigned status GLP_BS, and multiplier pi[p] is assigned
  252.61 +*  zero value.
  252.62 +*
  252.63 +*  RECOVERING INTERIOR-POINT SOLUTION
  252.64 +*
  252.65 +*  In solution to the original problem row p is inactive constraint,
  252.66 +*  so its multiplier pi[p] is assigned zero value.
  252.67 +*
  252.68 +*  RECOVERING MIP SOLUTION
  252.69 +*
  252.70 +*  None needed. */
  252.71 +
  252.72 +struct free_row
  252.73 +{     /* free (unbounded) row */
  252.74 +      int p;
  252.75 +      /* row reference number */
  252.76 +};
  252.77 +
  252.78 +static int rcv_free_row(NPP *npp, void *info);
  252.79 +
  252.80 +void npp_free_row(NPP *npp, NPPROW *p)
  252.81 +{     /* process free (unbounded) row */
  252.82 +      struct free_row *info;
  252.83 +      /* the row must be free */
  252.84 +      xassert(p->lb == -DBL_MAX && p->ub == +DBL_MAX);
  252.85 +      /* create transformation stack entry */
  252.86 +      info = npp_push_tse(npp,
  252.87 +         rcv_free_row, sizeof(struct free_row));
  252.88 +      info->p = p->i;
  252.89 +      /* remove the row from the problem */
  252.90 +      npp_del_row(npp, p);
  252.91 +      return;
  252.92 +}
  252.93 +
  252.94 +static int rcv_free_row(NPP *npp, void *_info)
  252.95 +{     /* recover free (unbounded) row */
  252.96 +      struct free_row *info = _info;
  252.97 +      if (npp->sol == GLP_SOL)
  252.98 +         npp->r_stat[info->p] = GLP_BS;
  252.99 +      if (npp->sol != GLP_MIP)
 252.100 +         npp->r_pi[info->p] = 0.0;
 252.101 +      return 0;
 252.102 +}
 252.103 +
 252.104 +/***********************************************************************
 252.105 +*  NAME
 252.106 +*
 252.107 +*  npp_geq_row - process row of 'not less than' type
 252.108 +*
 252.109 +*  SYNOPSIS
 252.110 +*
 252.111 +*  #include "glpnpp.h"
 252.112 +*  void npp_geq_row(NPP *npp, NPPROW *p);
 252.113 +*
 252.114 +*  DESCRIPTION
 252.115 +*
 252.116 +*  The routine npp_geq_row processes row p, which is 'not less than'
 252.117 +*  inequality constraint:
 252.118 +*
 252.119 +*     L[p] <= sum a[p,j] x[j] (<= U[p]),                             (1)
 252.120 +*              j
 252.121 +*
 252.122 +*  where L[p] < U[p], and upper bound may not exist (U[p] = +oo).
 252.123 +*
 252.124 +*  PROBLEM TRANSFORMATION
 252.125 +*
 252.126 +*  Constraint (1) can be replaced by equality constraint:
 252.127 +*
 252.128 +*     sum a[p,j] x[j] - s = L[p],                                    (2)
 252.129 +*      j
 252.130 +*
 252.131 +*  where
 252.132 +*
 252.133 +*     0 <= s (<= U[p] - L[p])                                        (3)
 252.134 +*
 252.135 +*  is a non-negative surplus variable.
 252.136 +*
 252.137 +*  Since in the primal system there appears column s having the only
 252.138 +*  non-zero coefficient in row p, in the dual system there appears a
 252.139 +*  new row:
 252.140 +*
 252.141 +*     (-1) pi[p] + lambda = 0,                                       (4)
 252.142 +*
 252.143 +*  where (-1) is coefficient of column s in row p, pi[p] is multiplier
 252.144 +*  of row p, lambda is multiplier of column q, 0 is coefficient of
 252.145 +*  column s in the objective row.
 252.146 +*
 252.147 +*  RECOVERING BASIC SOLUTION
 252.148 +*
 252.149 +*  Status of row p in solution to the original problem is determined
 252.150 +*  by its status and status of column q in solution to the transformed
 252.151 +*  problem as follows:
 252.152 +*
 252.153 +*     +--------------------------------------+------------------+
 252.154 +*     |         Transformed problem          | Original problem |
 252.155 +*     +-----------------+--------------------+------------------+
 252.156 +*     | Status of row p | Status of column s | Status of row p  |
 252.157 +*     +-----------------+--------------------+------------------+
 252.158 +*     |     GLP_BS      |       GLP_BS       |       N/A        |
 252.159 +*     |     GLP_BS      |       GLP_NL       |      GLP_BS      |
 252.160 +*     |     GLP_BS      |       GLP_NU       |      GLP_BS      |
 252.161 +*     |     GLP_NS      |       GLP_BS       |      GLP_BS      |
 252.162 +*     |     GLP_NS      |       GLP_NL       |      GLP_NL      |
 252.163 +*     |     GLP_NS      |       GLP_NU       |      GLP_NU      |
 252.164 +*     +-----------------+--------------------+------------------+
 252.165 +*
 252.166 +*  Value of row multiplier pi[p] in solution to the original problem
 252.167 +*  is the same as in solution to the transformed problem.
 252.168 +*
 252.169 +*  1. In solution to the transformed problem row p and column q cannot
 252.170 +*     be basic at the same time; otherwise the basis matrix would have
 252.171 +*     two linear dependent columns: unity column of auxiliary variable
 252.172 +*     of row p and unity column of variable s.
 252.173 +*
 252.174 +*  2. Though in the transformed problem row p is equality constraint,
 252.175 +*     it may be basic due to primal degenerate solution.
 252.176 +*
 252.177 +*  RECOVERING INTERIOR-POINT SOLUTION
 252.178 +*
 252.179 +*  Value of row multiplier pi[p] in solution to the original problem
 252.180 +*  is the same as in solution to the transformed problem.
 252.181 +*
 252.182 +*  RECOVERING MIP SOLUTION
 252.183 +*
 252.184 +*  None needed. */
 252.185 +
 252.186 +struct ineq_row
 252.187 +{     /* inequality constraint row */
 252.188 +      int p;
 252.189 +      /* row reference number */
 252.190 +      int s;
 252.191 +      /* column reference number for slack/surplus variable */
 252.192 +};
 252.193 +
 252.194 +static int rcv_geq_row(NPP *npp, void *info);
 252.195 +
 252.196 +void npp_geq_row(NPP *npp, NPPROW *p)
 252.197 +{     /* process row of 'not less than' type */
 252.198 +      struct ineq_row *info;
 252.199 +      NPPCOL *s;
 252.200 +      /* the row must have lower bound */
 252.201 +      xassert(p->lb != -DBL_MAX);
 252.202 +      xassert(p->lb < p->ub);
 252.203 +      /* create column for surplus variable */
 252.204 +      s = npp_add_col(npp);
 252.205 +      s->lb = 0.0;
 252.206 +      s->ub = (p->ub == +DBL_MAX ? +DBL_MAX : p->ub - p->lb);
 252.207 +      /* and add it to the transformed problem */
 252.208 +      npp_add_aij(npp, p, s, -1.0);
 252.209 +      /* create transformation stack entry */
 252.210 +      info = npp_push_tse(npp,
 252.211 +         rcv_geq_row, sizeof(struct ineq_row));
 252.212 +      info->p = p->i;
 252.213 +      info->s = s->j;
 252.214 +      /* replace the row by equality constraint */
 252.215 +      p->ub = p->lb;
 252.216 +      return;
 252.217 +}
 252.218 +
 252.219 +static int rcv_geq_row(NPP *npp, void *_info)
 252.220 +{     /* recover row of 'not less than' type */
 252.221 +      struct ineq_row *info = _info;
 252.222 +      if (npp->sol == GLP_SOL)
 252.223 +      {  if (npp->r_stat[info->p] == GLP_BS)
 252.224 +         {  if (npp->c_stat[info->s] == GLP_BS)
 252.225 +            {  npp_error();
 252.226 +               return 1;
 252.227 +            }
 252.228 +            else if (npp->c_stat[info->s] == GLP_NL ||
 252.229 +                     npp->c_stat[info->s] == GLP_NU)
 252.230 +               npp->r_stat[info->p] = GLP_BS;
 252.231 +            else
 252.232 +            {  npp_error();
 252.233 +               return 1;
 252.234 +            }
 252.235 +         }
 252.236 +         else if (npp->r_stat[info->p] == GLP_NS)
 252.237 +         {  if (npp->c_stat[info->s] == GLP_BS)
 252.238 +               npp->r_stat[info->p] = GLP_BS;
 252.239 +            else if (npp->c_stat[info->s] == GLP_NL)
 252.240 +               npp->r_stat[info->p] = GLP_NL;
 252.241 +            else if (npp->c_stat[info->s] == GLP_NU)
 252.242 +               npp->r_stat[info->p] = GLP_NU;
 252.243 +            else
 252.244 +            {  npp_error();
 252.245 +               return 1;
 252.246 +            }
 252.247 +         }
 252.248 +         else
 252.249 +         {  npp_error();
 252.250 +            return 1;
 252.251 +         }
 252.252 +      }
 252.253 +      return 0;
 252.254 +}
 252.255 +
 252.256 +/***********************************************************************
 252.257 +*  NAME
 252.258 +*
 252.259 +*  npp_leq_row - process row of 'not greater than' type
 252.260 +*
 252.261 +*  SYNOPSIS
 252.262 +*
 252.263 +*  #include "glpnpp.h"
 252.264 +*  void npp_leq_row(NPP *npp, NPPROW *p);
 252.265 +*
 252.266 +*  DESCRIPTION
 252.267 +*
 252.268 +*  The routine npp_leq_row processes row p, which is 'not greater than'
 252.269 +*  inequality constraint:
 252.270 +*
 252.271 +*     (L[p] <=) sum a[p,j] x[j] <= U[p],                             (1)
 252.272 +*                j
 252.273 +*
 252.274 +*  where L[p] < U[p], and lower bound may not exist (L[p] = +oo).
 252.275 +*
 252.276 +*  PROBLEM TRANSFORMATION
 252.277 +*
 252.278 +*  Constraint (1) can be replaced by equality constraint:
 252.279 +*
 252.280 +*     sum a[p,j] x[j] + s = L[p],                                    (2)
 252.281 +*      j
 252.282 +*
 252.283 +*  where
 252.284 +*
 252.285 +*     0 <= s (<= U[p] - L[p])                                        (3)
 252.286 +*
 252.287 +*  is a non-negative slack variable.
 252.288 +*
 252.289 +*  Since in the primal system there appears column s having the only
 252.290 +*  non-zero coefficient in row p, in the dual system there appears a
 252.291 +*  new row:
 252.292 +*
 252.293 +*     (+1) pi[p] + lambda = 0,                                       (4)
 252.294 +*
 252.295 +*  where (+1) is coefficient of column s in row p, pi[p] is multiplier
 252.296 +*  of row p, lambda is multiplier of column q, 0 is coefficient of
 252.297 +*  column s in the objective row.
 252.298 +*
 252.299 +*  RECOVERING BASIC SOLUTION
 252.300 +*
 252.301 +*  Status of row p in solution to the original problem is determined
 252.302 +*  by its status and status of column q in solution to the transformed
 252.303 +*  problem as follows:
 252.304 +*
 252.305 +*     +--------------------------------------+------------------+
 252.306 +*     |         Transformed problem          | Original problem |
 252.307 +*     +-----------------+--------------------+------------------+
 252.308 +*     | Status of row p | Status of column s | Status of row p  |
 252.309 +*     +-----------------+--------------------+------------------+
 252.310 +*     |     GLP_BS      |       GLP_BS       |       N/A        |
 252.311 +*     |     GLP_BS      |       GLP_NL       |      GLP_BS      |
 252.312 +*     |     GLP_BS      |       GLP_NU       |      GLP_BS      |
 252.313 +*     |     GLP_NS      |       GLP_BS       |      GLP_BS      |
 252.314 +*     |     GLP_NS      |       GLP_NL       |      GLP_NU      |
 252.315 +*     |     GLP_NS      |       GLP_NU       |      GLP_NL      |
 252.316 +*     +-----------------+--------------------+------------------+
 252.317 +*
 252.318 +*  Value of row multiplier pi[p] in solution to the original problem
 252.319 +*  is the same as in solution to the transformed problem.
 252.320 +*
 252.321 +*  1. In solution to the transformed problem row p and column q cannot
 252.322 +*     be basic at the same time; otherwise the basis matrix would have
 252.323 +*     two linear dependent columns: unity column of auxiliary variable
 252.324 +*     of row p and unity column of variable s.
 252.325 +*
 252.326 +*  2. Though in the transformed problem row p is equality constraint,
 252.327 +*     it may be basic due to primal degeneracy.
 252.328 +*
 252.329 +*  RECOVERING INTERIOR-POINT SOLUTION
 252.330 +*
 252.331 +*  Value of row multiplier pi[p] in solution to the original problem
 252.332 +*  is the same as in solution to the transformed problem.
 252.333 +*
 252.334 +*  RECOVERING MIP SOLUTION
 252.335 +*
 252.336 +*  None needed. */
 252.337 +
 252.338 +static int rcv_leq_row(NPP *npp, void *info);
 252.339 +
 252.340 +void npp_leq_row(NPP *npp, NPPROW *p)
 252.341 +{     /* process row of 'not greater than' type */
 252.342 +      struct ineq_row *info;
 252.343 +      NPPCOL *s;
 252.344 +      /* the row must have upper bound */
 252.345 +      xassert(p->ub != +DBL_MAX);
 252.346 +      xassert(p->lb < p->ub);
 252.347 +      /* create column for slack variable */
 252.348 +      s = npp_add_col(npp);
 252.349 +      s->lb = 0.0;
 252.350 +      s->ub = (p->lb == -DBL_MAX ? +DBL_MAX : p->ub - p->lb);
 252.351 +      /* and add it to the transformed problem */
 252.352 +      npp_add_aij(npp, p, s, +1.0);
 252.353 +      /* create transformation stack entry */
 252.354 +      info = npp_push_tse(npp,
 252.355 +         rcv_leq_row, sizeof(struct ineq_row));
 252.356 +      info->p = p->i;
 252.357 +      info->s = s->j;
 252.358 +      /* replace the row by equality constraint */
 252.359 +      p->lb = p->ub;
 252.360 +      return;
 252.361 +}
 252.362 +
 252.363 +static int rcv_leq_row(NPP *npp, void *_info)
 252.364 +{     /* recover row of 'not greater than' type */
 252.365 +      struct ineq_row *info = _info;
 252.366 +      if (npp->sol == GLP_SOL)
 252.367 +      {  if (npp->r_stat[info->p] == GLP_BS)
 252.368 +         {  if (npp->c_stat[info->s] == GLP_BS)
 252.369 +            {  npp_error();
 252.370 +               return 1;
 252.371 +            }
 252.372 +            else if (npp->c_stat[info->s] == GLP_NL ||
 252.373 +                     npp->c_stat[info->s] == GLP_NU)
 252.374 +               npp->r_stat[info->p] = GLP_BS;
 252.375 +            else
 252.376 +            {  npp_error();
 252.377 +               return 1;
 252.378 +            }
 252.379 +         }
 252.380 +         else if (npp->r_stat[info->p] == GLP_NS)
 252.381 +         {  if (npp->c_stat[info->s] == GLP_BS)
 252.382 +               npp->r_stat[info->p] = GLP_BS;
 252.383 +            else if (npp->c_stat[info->s] == GLP_NL)
 252.384 +               npp->r_stat[info->p] = GLP_NU;
 252.385 +            else if (npp->c_stat[info->s] == GLP_NU)
 252.386 +               npp->r_stat[info->p] = GLP_NL;
 252.387 +            else
 252.388 +            {  npp_error();
 252.389 +               return 1;
 252.390 +            }
 252.391 +         }
 252.392 +         else
 252.393 +         {  npp_error();
 252.394 +            return 1;
 252.395 +         }
 252.396 +      }
 252.397 +      return 0;
 252.398 +}
 252.399 +
 252.400 +/***********************************************************************
 252.401 +*  NAME
 252.402 +*
 252.403 +*  npp_free_col - process free (unbounded) column
 252.404 +*
 252.405 +*  SYNOPSIS
 252.406 +*
 252.407 +*  #include "glpnpp.h"
 252.408 +*  void npp_free_col(NPP *npp, NPPCOL *q);
 252.409 +*
 252.410 +*  DESCRIPTION
 252.411 +*
 252.412 +*  The routine npp_free_col processes column q, which is free (i.e. has
 252.413 +*  no finite bounds):
 252.414 +*
 252.415 +*     -oo < x[q] < +oo.                                              (1)
 252.416 +*
 252.417 +*  PROBLEM TRANSFORMATION
 252.418 +*
 252.419 +*  Free (unbounded) variable can be replaced by the difference of two
 252.420 +*  non-negative variables:
 252.421 +*
 252.422 +*     x[q] = s' - s'',   s', s'' >= 0.                               (2)
 252.423 +*
 252.424 +*  Assuming that in the transformed problem x[q] becomes s',
 252.425 +*  transformation (2) causes new column s'' to appear, which differs
 252.426 +*  from column s' only in the sign of coefficients in constraint and
 252.427 +*  objective rows. Thus, if in the dual system the following row
 252.428 +*  corresponds to column s':
 252.429 +*
 252.430 +*     sum a[i,q] pi[i] + lambda' = c[q],                             (3)
 252.431 +*      i
 252.432 +*
 252.433 +*  the row which corresponds to column s'' is the following:
 252.434 +*
 252.435 +*     sum (-a[i,q]) pi[i] + lambda'' = -c[q].                        (4)
 252.436 +*      i
 252.437 +*
 252.438 +*  Then from (3) and (4) it follows that:
 252.439 +*
 252.440 +*     lambda' + lambda'' = 0   =>   lambda' = lmabda'' = 0,          (5)
 252.441 +*
 252.442 +*  where lambda' and lambda'' are multipliers for columns s' and s'',
 252.443 +*  resp.
 252.444 +*
 252.445 +*  RECOVERING BASIC SOLUTION
 252.446 +*
 252.447 +*  With respect to (5) status of column q in solution to the original
 252.448 +*  problem is determined by statuses of columns s' and s'' in solution
 252.449 +*  to the transformed problem as follows:
 252.450 +*
 252.451 +*     +--------------------------------------+------------------+
 252.452 +*     |         Transformed problem          | Original problem |
 252.453 +*     +------------------+-------------------+------------------+
 252.454 +*     | Status of col s' | Status of col s'' | Status of col q  |
 252.455 +*     +------------------+-------------------+------------------+
 252.456 +*     |      GLP_BS      |      GLP_BS       |       N/A        |
 252.457 +*     |      GLP_BS      |      GLP_NL       |      GLP_BS      |
 252.458 +*     |      GLP_NL      |      GLP_BS       |      GLP_BS      |
 252.459 +*     |      GLP_NL      |      GLP_NL       |      GLP_NF      |
 252.460 +*     +------------------+-------------------+------------------+
 252.461 +*
 252.462 +*  Value of column q is computed with formula (2).
 252.463 +*
 252.464 +*  1. In solution to the transformed problem columns s' and s'' cannot
 252.465 +*     be basic at the same time, because they differ only in the sign,
 252.466 +*     hence, are linear dependent.
 252.467 +*
 252.468 +*  2. Though column q is free, it can be non-basic due to dual
 252.469 +*     degeneracy.
 252.470 +*
 252.471 +*  3. If column q is integral, columns s' and s'' are also integral.
 252.472 +*
 252.473 +*  RECOVERING INTERIOR-POINT SOLUTION
 252.474 +*
 252.475 +*  Value of column q is computed with formula (2).
 252.476 +*
 252.477 +*  RECOVERING MIP SOLUTION
 252.478 +*
 252.479 +*  Value of column q is computed with formula (2). */
 252.480 +
 252.481 +struct free_col
 252.482 +{     /* free (unbounded) column */
 252.483 +      int q;
 252.484 +      /* column reference number for variables x[q] and s' */
 252.485 +      int s;
 252.486 +      /* column reference number for variable s'' */
 252.487 +};
 252.488 +
 252.489 +static int rcv_free_col(NPP *npp, void *info);
 252.490 +
 252.491 +void npp_free_col(NPP *npp, NPPCOL *q)
 252.492 +{     /* process free (unbounded) column */
 252.493 +      struct free_col *info;
 252.494 +      NPPCOL *s;
 252.495 +      NPPAIJ *aij;
 252.496 +      /* the column must be free */
 252.497 +      xassert(q->lb == -DBL_MAX && q->ub == +DBL_MAX);
 252.498 +      /* variable x[q] becomes s' */
 252.499 +      q->lb = 0.0, q->ub = +DBL_MAX;
 252.500 +      /* create variable s'' */
 252.501 +      s = npp_add_col(npp);
 252.502 +      s->is_int = q->is_int;
 252.503 +      s->lb = 0.0, s->ub = +DBL_MAX;
 252.504 +      /* duplicate objective coefficient */
 252.505 +      s->coef = -q->coef;
 252.506 +      /* duplicate column of the constraint matrix */
 252.507 +      for (aij = q->ptr; aij != NULL; aij = aij->c_next)
 252.508 +         npp_add_aij(npp, aij->row, s, -aij->val);
 252.509 +      /* create transformation stack entry */
 252.510 +      info = npp_push_tse(npp,
 252.511 +         rcv_free_col, sizeof(struct free_col));
 252.512 +      info->q = q->j;
 252.513 +      info->s = s->j;
 252.514 +      return;
 252.515 +}
 252.516 +
 252.517 +static int rcv_free_col(NPP *npp, void *_info)
 252.518 +{     /* recover free (unbounded) column */
 252.519 +      struct free_col *info = _info;
 252.520 +      if (npp->sol == GLP_SOL)
 252.521 +      {  if (npp->c_stat[info->q] == GLP_BS)
 252.522 +         {  if (npp->c_stat[info->s] == GLP_BS)
 252.523 +            {  npp_error();
 252.524 +               return 1;
 252.525 +            }
 252.526 +            else if (npp->c_stat[info->s] == GLP_NL)
 252.527 +               npp->c_stat[info->q] = GLP_BS;
 252.528 +            else
 252.529 +            {  npp_error();
 252.530 +               return -1;
 252.531 +            }
 252.532 +         }
 252.533 +         else if (npp->c_stat[info->q] == GLP_NL)
 252.534 +         {  if (npp->c_stat[info->s] == GLP_BS)
 252.535 +               npp->c_stat[info->q] = GLP_BS;
 252.536 +            else if (npp->c_stat[info->s] == GLP_NL)
 252.537 +               npp->c_stat[info->q] = GLP_NF;
 252.538 +            else
 252.539 +            {  npp_error();
 252.540 +               return -1;
 252.541 +            }
 252.542 +         }
 252.543 +         else
 252.544 +         {  npp_error();
 252.545 +            return -1;
 252.546 +         }
 252.547 +      }
 252.548 +      /* compute value of x[q] with formula (2) */
 252.549 +      npp->c_value[info->q] -= npp->c_value[info->s];
 252.550 +      return 0;
 252.551 +}
 252.552 +
 252.553 +/***********************************************************************
 252.554 +*  NAME
 252.555 +*
 252.556 +*  npp_lbnd_col - process column with (non-zero) lower bound
 252.557 +*
 252.558 +*  SYNOPSIS
 252.559 +*
 252.560 +*  #include "glpnpp.h"
 252.561 +*  void npp_lbnd_col(NPP *npp, NPPCOL *q);
 252.562 +*
 252.563 +*  DESCRIPTION
 252.564 +*
 252.565 +*  The routine npp_lbnd_col processes column q, which has (non-zero)
 252.566 +*  lower bound:
 252.567 +*
 252.568 +*     l[q] <= x[q] (<= u[q]),                                        (1)
 252.569 +*
 252.570 +*  where l[q] < u[q], and upper bound may not exist (u[q] = +oo).
 252.571 +*
 252.572 +*  PROBLEM TRANSFORMATION
 252.573 +*
 252.574 +*  Column q can be replaced as follows:
 252.575 +*
 252.576 +*     x[q] = l[q] + s,                                               (2)
 252.577 +*
 252.578 +*  where
 252.579 +*
 252.580 +*     0 <= s (<= u[q] - l[q])                                        (3)
 252.581 +*
 252.582 +*  is a non-negative variable.
 252.583 +*
 252.584 +*  Substituting x[q] from (2) into the objective row, we have:
 252.585 +*
 252.586 +*     z = sum c[j] x[j] + c0 =
 252.587 +*          j
 252.588 +*
 252.589 +*       = sum c[j] x[j] + c[q] x[q] + c0 =
 252.590 +*         j!=q
 252.591 +*
 252.592 +*       = sum c[j] x[j] + c[q] (l[q] + s) + c0 =
 252.593 +*         j!=q
 252.594 +*
 252.595 +*       = sum c[j] x[j] + c[q] s + c~0,
 252.596 +*
 252.597 +*  where
 252.598 +*
 252.599 +*     c~0 = c0 + c[q] l[q]                                           (4)
 252.600 +*
 252.601 +*  is the constant term of the objective in the transformed problem.
 252.602 +*  Similarly, substituting x[q] into constraint row i, we have:
 252.603 +*
 252.604 +*     L[i] <= sum a[i,j] x[j] <= U[i]  ==>
 252.605 +*              j
 252.606 +*
 252.607 +*     L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i]  ==>
 252.608 +*             j!=q
 252.609 +*
 252.610 +*     L[i] <= sum a[i,j] x[j] + a[i,q] (l[q] + s) <= U[i]  ==>
 252.611 +*             j!=q
 252.612 +*
 252.613 +*     L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i],
 252.614 +*              j!=q
 252.615 +*
 252.616 +*  where
 252.617 +*
 252.618 +*     L~[i] = L[i] - a[i,q] l[q],  U~[i] = U[i] - a[i,q] l[q]        (5)
 252.619 +*
 252.620 +*  are lower and upper bounds of row i in the transformed problem,
 252.621 +*  resp.
 252.622 +*
 252.623 +*  Transformation (2) does not affect the dual system.
 252.624 +*
 252.625 +*  RECOVERING BASIC SOLUTION
 252.626 +*
 252.627 +*  Status of column q in solution to the original problem is the same
 252.628 +*  as in solution to the transformed problem (GLP_BS, GLP_NL or GLP_NU).
 252.629 +*  Value of column q is computed with formula (2).
 252.630 +*
 252.631 +*  RECOVERING INTERIOR-POINT SOLUTION
 252.632 +*
 252.633 +*  Value of column q is computed with formula (2).
 252.634 +*
 252.635 +*  RECOVERING MIP SOLUTION
 252.636 +*
 252.637 +*  Value of column q is computed with formula (2). */
 252.638 +
 252.639 +struct bnd_col
 252.640 +{     /* bounded column */
 252.641 +      int q;
 252.642 +      /* column reference number for variables x[q] and s */
 252.643 +      double bnd;
 252.644 +      /* lower/upper bound l[q] or u[q] */
 252.645 +};
 252.646 +
 252.647 +static int rcv_lbnd_col(NPP *npp, void *info);
 252.648 +
 252.649 +void npp_lbnd_col(NPP *npp, NPPCOL *q)
 252.650 +{     /* process column with (non-zero) lower bound */
 252.651 +      struct bnd_col *info;
 252.652 +      NPPROW *i;
 252.653 +      NPPAIJ *aij;
 252.654 +      /* the column must have non-zero lower bound */
 252.655 +      xassert(q->lb != 0.0);
 252.656 +      xassert(q->lb != -DBL_MAX);
 252.657 +      xassert(q->lb < q->ub);
 252.658 +      /* create transformation stack entry */
 252.659 +      info = npp_push_tse(npp,
 252.660 +         rcv_lbnd_col, sizeof(struct bnd_col));
 252.661 +      info->q = q->j;
 252.662 +      info->bnd = q->lb;
 252.663 +      /* substitute x[q] into objective row */
 252.664 +      npp->c0 += q->coef * q->lb;
 252.665 +      /* substitute x[q] into constraint rows */
 252.666 +      for (aij = q->ptr; aij != NULL; aij = aij->c_next)
 252.667 +      {  i = aij->row;
 252.668 +         if (i->lb == i->ub)
 252.669 +            i->ub = (i->lb -= aij->val * q->lb);
 252.670 +         else
 252.671 +         {  if (i->lb != -DBL_MAX)
 252.672 +               i->lb -= aij->val * q->lb;
 252.673 +            if (i->ub != +DBL_MAX)
 252.674 +               i->ub -= aij->val * q->lb;
 252.675 +         }
 252.676 +      }
 252.677 +      /* column x[q] becomes column s */
 252.678 +      if (q->ub != +DBL_MAX)
 252.679 +         q->ub -= q->lb;
 252.680 +      q->lb = 0.0;
 252.681 +      return;
 252.682 +}
 252.683 +
 252.684 +static int rcv_lbnd_col(NPP *npp, void *_info)
 252.685 +{     /* recover column with (non-zero) lower bound */
 252.686 +      struct bnd_col *info = _info;
 252.687 +      if (npp->sol == GLP_SOL)
 252.688 +      {  if (npp->c_stat[info->q] == GLP_BS ||
 252.689 +             npp->c_stat[info->q] == GLP_NL ||
 252.690 +             npp->c_stat[info->q] == GLP_NU)
 252.691 +            npp->c_stat[info->q] = npp->c_stat[info->q];
 252.692 +         else
 252.693 +         {  npp_error();
 252.694 +            return 1;
 252.695 +         }
 252.696 +      }
 252.697 +      /* compute value of x[q] with formula (2) */
 252.698 +      npp->c_value[info->q] = info->bnd + npp->c_value[info->q];
 252.699 +      return 0;
 252.700 +}
 252.701 +
 252.702 +/***********************************************************************
 252.703 +*  NAME
 252.704 +*
 252.705 +*  npp_ubnd_col - process column with upper bound
 252.706 +*
 252.707 +*  SYNOPSIS
 252.708 +*
 252.709 +*  #include "glpnpp.h"
 252.710 +*  void npp_ubnd_col(NPP *npp, NPPCOL *q);
 252.711 +*
 252.712 +*  DESCRIPTION
 252.713 +*
 252.714 +*  The routine npp_ubnd_col processes column q, which has upper bound:
 252.715 +*
 252.716 +*     (l[q] <=) x[q] <= u[q],                                        (1)
 252.717 +*
 252.718 +*  where l[q] < u[q], and lower bound may not exist (l[q] = -oo).
 252.719 +*
 252.720 +*  PROBLEM TRANSFORMATION
 252.721 +*
 252.722 +*  Column q can be replaced as follows:
 252.723 +*
 252.724 +*     x[q] = u[q] - s,                                               (2)
 252.725 +*
 252.726 +*  where
 252.727 +*
 252.728 +*     0 <= s (<= u[q] - l[q])                                        (3)
 252.729 +*
 252.730 +*  is a non-negative variable.
 252.731 +*
 252.732 +*  Substituting x[q] from (2) into the objective row, we have:
 252.733 +*
 252.734 +*     z = sum c[j] x[j] + c0 =
 252.735 +*          j
 252.736 +*
 252.737 +*       = sum c[j] x[j] + c[q] x[q] + c0 =
 252.738 +*         j!=q
 252.739 +*
 252.740 +*       = sum c[j] x[j] + c[q] (u[q] - s) + c0 =
 252.741 +*         j!=q
 252.742 +*
 252.743 +*       = sum c[j] x[j] - c[q] s + c~0,
 252.744 +*
 252.745 +*  where
 252.746 +*
 252.747 +*     c~0 = c0 + c[q] u[q]                                           (4)
 252.748 +*
 252.749 +*  is the constant term of the objective in the transformed problem.
 252.750 +*  Similarly, substituting x[q] into constraint row i, we have:
 252.751 +*
 252.752 +*     L[i] <= sum a[i,j] x[j] <= U[i]  ==>
 252.753 +*              j
 252.754 +*
 252.755 +*     L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i]  ==>
 252.756 +*             j!=q
 252.757 +*
 252.758 +*     L[i] <= sum a[i,j] x[j] + a[i,q] (u[q] - s) <= U[i]  ==>
 252.759 +*             j!=q
 252.760 +*
 252.761 +*     L~[i] <= sum a[i,j] x[j] - a[i,q] s <= U~[i],
 252.762 +*              j!=q
 252.763 +*
 252.764 +*  where
 252.765 +*
 252.766 +*     L~[i] = L[i] - a[i,q] u[q],  U~[i] = U[i] - a[i,q] u[q]        (5)
 252.767 +*
 252.768 +*  are lower and upper bounds of row i in the transformed problem,
 252.769 +*  resp.
 252.770 +*
 252.771 +*  Note that in the transformed problem coefficients c[q] and a[i,q]
 252.772 +*  change their sign. Thus, the row of the dual system corresponding to
 252.773 +*  column q:
 252.774 +*
 252.775 +*     sum a[i,q] pi[i] + lambda[q] = c[q]                            (6)
 252.776 +*      i
 252.777 +*
 252.778 +*  in the transformed problem becomes the following:
 252.779 +*
 252.780 +*     sum (-a[i,q]) pi[i] + lambda[s] = -c[q].                       (7)
 252.781 +*      i
 252.782 +*
 252.783 +*  Therefore:
 252.784 +*
 252.785 +*     lambda[q] = - lambda[s],                                       (8)
 252.786 +*
 252.787 +*  where lambda[q] is multiplier for column q, lambda[s] is multiplier
 252.788 +*  for column s.
 252.789 +*
 252.790 +*  RECOVERING BASIC SOLUTION
 252.791 +*
 252.792 +*  With respect to (8) status of column q in solution to the original
 252.793 +*  problem is determined by status of column s in solution to the
 252.794 +*  transformed problem as follows:
 252.795 +*
 252.796 +*     +-----------------------+--------------------+
 252.797 +*     |  Status of column s   | Status of column q |
 252.798 +*     | (transformed problem) | (original problem) |
 252.799 +*     +-----------------------+--------------------+
 252.800 +*     |        GLP_BS         |       GLP_BS       |
 252.801 +*     |        GLP_NL         |       GLP_NU       |
 252.802 +*     |        GLP_NU         |       GLP_NL       |
 252.803 +*     +-----------------------+--------------------+
 252.804 +*
 252.805 +*  Value of column q is computed with formula (2).
 252.806 +*
 252.807 +*  RECOVERING INTERIOR-POINT SOLUTION
 252.808 +*
 252.809 +*  Value of column q is computed with formula (2).
 252.810 +*
 252.811 +*  RECOVERING MIP SOLUTION
 252.812 +*
 252.813 +*  Value of column q is computed with formula (2). */
 252.814 +
 252.815 +static int rcv_ubnd_col(NPP *npp, void *info);
 252.816 +
 252.817 +void npp_ubnd_col(NPP *npp, NPPCOL *q)
 252.818 +{     /* process column with upper bound */
 252.819 +      struct bnd_col *info;
 252.820 +      NPPROW *i;
 252.821 +      NPPAIJ *aij;
 252.822 +      /* the column must have upper bound */
 252.823 +      xassert(q->ub != +DBL_MAX);
 252.824 +      xassert(q->lb < q->ub);
 252.825 +      /* create transformation stack entry */
 252.826 +      info = npp_push_tse(npp,
 252.827 +         rcv_ubnd_col, sizeof(struct bnd_col));
 252.828 +      info->q = q->j;
 252.829 +      info->bnd = q->ub;
 252.830 +      /* substitute x[q] into objective row */
 252.831 +      npp->c0 += q->coef * q->ub;
 252.832 +      q->coef = -q->coef;
 252.833 +      /* substitute x[q] into constraint rows */
 252.834 +      for (aij = q->ptr; aij != NULL; aij = aij->c_next)
 252.835 +      {  i = aij->row;
 252.836 +         if (i->lb == i->ub)
 252.837 +            i->ub = (i->lb -= aij->val * q->ub);
 252.838 +         else
 252.839 +         {  if (i->lb != -DBL_MAX)
 252.840 +               i->lb -= aij->val * q->ub;
 252.841 +            if (i->ub != +DBL_MAX)
 252.842 +               i->ub -= aij->val * q->ub;
 252.843 +         }
 252.844 +         aij->val = -aij->val;
 252.845 +      }
 252.846 +      /* column x[q] becomes column s */
 252.847 +      if (q->lb != -DBL_MAX)
 252.848 +         q->ub -= q->lb;
 252.849 +      else
 252.850 +         q->ub = +DBL_MAX;
 252.851 +      q->lb = 0.0;
 252.852 +      return;
 252.853 +}
 252.854 +
 252.855 +static int rcv_ubnd_col(NPP *npp, void *_info)
 252.856 +{     /* recover column with upper bound */
 252.857 +      struct bnd_col *info = _info;
 252.858 +      if (npp->sol == GLP_BS)
 252.859 +      {  if (npp->c_stat[info->q] == GLP_BS)
 252.860 +            npp->c_stat[info->q] = GLP_BS;
 252.861 +         else if (npp->c_stat[info->q] == GLP_NL)
 252.862 +            npp->c_stat[info->q] = GLP_NU;
 252.863 +         else if (npp->c_stat[info->q] == GLP_NU)
 252.864 +            npp->c_stat[info->q] = GLP_NL;
 252.865 +         else
 252.866 +         {  npp_error();
 252.867 +            return 1;
 252.868 +         }
 252.869 +      }
 252.870 +      /* compute value of x[q] with formula (2) */
 252.871 +      npp->c_value[info->q] = info->bnd - npp->c_value[info->q];
 252.872 +      return 0;
 252.873 +}
 252.874 +
 252.875 +/***********************************************************************
 252.876 +*  NAME
 252.877 +*
 252.878 +*  npp_dbnd_col - process non-negative column with upper bound
 252.879 +*
 252.880 +*  SYNOPSIS
 252.881 +*
 252.882 +*  #include "glpnpp.h"
 252.883 +*  void npp_dbnd_col(NPP *npp, NPPCOL *q);
 252.884 +*
 252.885 +*  DESCRIPTION
 252.886 +*
 252.887 +*  The routine npp_dbnd_col processes column q, which is non-negative
 252.888 +*  and has upper bound:
 252.889 +*
 252.890 +*     0 <= x[q] <= u[q],                                             (1)
 252.891 +*
 252.892 +*  where u[q] > 0.
 252.893 +*
 252.894 +*  PROBLEM TRANSFORMATION
 252.895 +*
 252.896 +*  Upper bound of column q can be replaced by the following equality
 252.897 +*  constraint:
 252.898 +*
 252.899 +*     x[q] + s = u[q],                                               (2)
 252.900 +*
 252.901 +*  where s >= 0 is a non-negative complement variable.
 252.902 +*
 252.903 +*  Since in the primal system along with new row (2) there appears a
 252.904 +*  new column s having the only non-zero coefficient in this row, in
 252.905 +*  the dual system there appears a new row:
 252.906 +*
 252.907 +*     (+1)pi + lambda[s] = 0,                                        (3)
 252.908 +*
 252.909 +*  where (+1) is coefficient at column s in row (2), pi is multiplier
 252.910 +*  for row (2), lambda[s] is multiplier for column s, 0 is coefficient
 252.911 +*  at column s in the objective row.
 252.912 +*
 252.913 +*  RECOVERING BASIC SOLUTION
 252.914 +*
 252.915 +*  Status of column q in solution to the original problem is determined
 252.916 +*  by its status and status of column s in solution to the transformed
 252.917 +*  problem as follows:
 252.918 +*
 252.919 +*     +-----------------------------------+------------------+
 252.920 +*     |         Transformed problem       | Original problem |
 252.921 +*     +-----------------+-----------------+------------------+
 252.922 +*     | Status of col q | Status of col s | Status of col q  |
 252.923 +*     +-----------------+-----------------+------------------+
 252.924 +*     |     GLP_BS      |     GLP_BS      |      GLP_BS      |
 252.925 +*     |     GLP_BS      |     GLP_NL      |      GLP_NU      |
 252.926 +*     |     GLP_NL      |     GLP_BS      |      GLP_NL      |
 252.927 +*     |     GLP_NL      |     GLP_NL      |      GLP_NL (*)  |
 252.928 +*     +-----------------+-----------------+------------------+
 252.929 +*
 252.930 +*  Value of column q in solution to the original problem is the same as
 252.931 +*  in solution to the transformed problem.
 252.932 +*
 252.933 +*  1. Formally, in solution to the transformed problem columns q and s
 252.934 +*     cannot be non-basic at the same time, since the constraint (2)
 252.935 +*     would be violated. However, if u[q] is close to zero, violation
 252.936 +*     may be less than a working precision even if both columns q and s
 252.937 +*     are non-basic. In this degenerate case row (2) can be only basic,
 252.938 +*     i.e. non-active constraint (otherwise corresponding row of the
 252.939 +*     basis matrix would be zero). This allows to pivot out auxiliary
 252.940 +*     variable and pivot in column s, in which case the row becomes
 252.941 +*     active while column s becomes basic.
 252.942 +*
 252.943 +*  2. If column q is integral, column s is also integral.
 252.944 +*
 252.945 +*  RECOVERING INTERIOR-POINT SOLUTION
 252.946 +*
 252.947 +*  Value of column q in solution to the original problem is the same as
 252.948 +*  in solution to the transformed problem.
 252.949 +*
 252.950 +*  RECOVERING MIP SOLUTION
 252.951 +*
 252.952 +*  Value of column q in solution to the original problem is the same as
 252.953 +*  in solution to the transformed problem. */
 252.954 +
 252.955 +struct dbnd_col
 252.956 +{     /* double-bounded column */
 252.957 +      int q;
 252.958 +      /* column reference number for variable x[q] */
 252.959 +      int s;
 252.960 +      /* column reference number for complement variable s */
 252.961 +};
 252.962 +
 252.963 +static int rcv_dbnd_col(NPP *npp, void *info);
 252.964 +
 252.965 +void npp_dbnd_col(NPP *npp, NPPCOL *q)
 252.966 +{     /* process non-negative column with upper bound */
 252.967 +      struct dbnd_col *info;
 252.968 +      NPPROW *p;
 252.969 +      NPPCOL *s;
 252.970 +      /* the column must be non-negative with upper bound */
 252.971 +      xassert(q->lb == 0.0);
 252.972 +      xassert(q->ub > 0.0);
 252.973 +      xassert(q->ub != +DBL_MAX);
 252.974 +      /* create variable s */
 252.975 +      s = npp_add_col(npp);
 252.976 +      s->is_int = q->is_int;
 252.977 +      s->lb = 0.0, s->ub = +DBL_MAX;
 252.978 +      /* create equality constraint (2) */
 252.979 +      p = npp_add_row(npp);
 252.980 +      p->lb = p->ub = q->ub;
 252.981 +      npp_add_aij(npp, p, q, +1.0);
 252.982 +      npp_add_aij(npp, p, s, +1.0);
 252.983 +      /* create transformation stack entry */
 252.984 +      info = npp_push_tse(npp,
 252.985 +         rcv_dbnd_col, sizeof(struct dbnd_col));
 252.986 +      info->q = q->j;
 252.987 +      info->s = s->j;
 252.988 +      /* remove upper bound of x[q] */
 252.989 +      q->ub = +DBL_MAX;
 252.990 +      return;
 252.991 +}
 252.992 +
 252.993 +static int rcv_dbnd_col(NPP *npp, void *_info)
 252.994 +{     /* recover non-negative column with upper bound */
 252.995 +      struct dbnd_col *info = _info;
 252.996 +      if (npp->sol == GLP_BS)
 252.997 +      {  if (npp->c_stat[info->q] == GLP_BS)
 252.998 +         {  if (npp->c_stat[info->s] == GLP_BS)
 252.999 +               npp->c_stat[info->q] = GLP_BS;
252.1000 +            else if (npp->c_stat[info->s] == GLP_NL)
252.1001 +               npp->c_stat[info->q] = GLP_NU;
252.1002 +            else
252.1003 +            {  npp_error();
252.1004 +               return 1;
252.1005 +            }
252.1006 +         }
252.1007 +         else if (npp->c_stat[info->q] == GLP_NL)
252.1008 +         {  if (npp->c_stat[info->s] == GLP_BS ||
252.1009 +                npp->c_stat[info->s] == GLP_NL)
252.1010 +               npp->c_stat[info->q] = GLP_NL;
252.1011 +            else
252.1012 +            {  npp_error();
252.1013 +               return 1;
252.1014 +            }
252.1015 +         }
252.1016 +         else
252.1017 +         {  npp_error();
252.1018 +            return 1;
252.1019 +         }
252.1020 +      }
252.1021 +      return 0;
252.1022 +}
252.1023 +
252.1024 +/***********************************************************************
252.1025 +*  NAME
252.1026 +*
252.1027 +*  npp_fixed_col - process fixed column
252.1028 +*
252.1029 +*  SYNOPSIS
252.1030 +*
252.1031 +*  #include "glpnpp.h"
252.1032 +*  void npp_fixed_col(NPP *npp, NPPCOL *q);
252.1033 +*
252.1034 +*  DESCRIPTION
252.1035 +*
252.1036 +*  The routine npp_fixed_col processes column q, which is fixed:
252.1037 +*
252.1038 +*     x[q] = s[q],                                                   (1)
252.1039 +*
252.1040 +*  where s[q] is a fixed column value.
252.1041 +*
252.1042 +*  PROBLEM TRANSFORMATION
252.1043 +*
252.1044 +*  The value of a fixed column can be substituted into the objective
252.1045 +*  and constraint rows that allows removing the column from the problem.
252.1046 +*
252.1047 +*  Substituting x[q] = s[q] into the objective row, we have:
252.1048 +*
252.1049 +*     z = sum c[j] x[j] + c0 =
252.1050 +*          j
252.1051 +*
252.1052 +*       = sum c[j] x[j] + c[q] x[q] + c0 =
252.1053 +*         j!=q
252.1054 +*
252.1055 +*       = sum c[j] x[j] + c[q] s[q] + c0 =
252.1056 +*         j!=q
252.1057 +*
252.1058 +*       = sum c[j] x[j] + c~0,
252.1059 +*         j!=q
252.1060 +*
252.1061 +*  where
252.1062 +*
252.1063 +*     c~0 = c0 + c[q] s[q]                                           (2)
252.1064 +*
252.1065 +*  is the constant term of the objective in the transformed problem.
252.1066 +*  Similarly, substituting x[q] = s[q] into constraint row i, we have:
252.1067 +*
252.1068 +*     L[i] <= sum a[i,j] x[j] <= U[i]  ==>
252.1069 +*              j
252.1070 +*
252.1071 +*     L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i]  ==>
252.1072 +*             j!=q
252.1073 +*
252.1074 +*     L[i] <= sum a[i,j] x[j] + a[i,q] s[q] <= U[i]  ==>
252.1075 +*             j!=q
252.1076 +*
252.1077 +*     L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i],
252.1078 +*              j!=q
252.1079 +*
252.1080 +*  where
252.1081 +*
252.1082 +*     L~[i] = L[i] - a[i,q] s[q],  U~[i] = U[i] - a[i,q] s[q]        (3)
252.1083 +*
252.1084 +*  are lower and upper bounds of row i in the transformed problem,
252.1085 +*  resp.
252.1086 +*
252.1087 +*  RECOVERING BASIC SOLUTION
252.1088 +*
252.1089 +*  Column q is assigned status GLP_NS and its value is assigned s[q].
252.1090 +*
252.1091 +*  RECOVERING INTERIOR-POINT SOLUTION
252.1092 +*
252.1093 +*  Value of column q is assigned s[q].
252.1094 +*
252.1095 +*  RECOVERING MIP SOLUTION
252.1096 +*
252.1097 +*  Value of column q is assigned s[q]. */
252.1098 +
252.1099 +struct fixed_col
252.1100 +{     /* fixed column */
252.1101 +      int q;
252.1102 +      /* column reference number for variable x[q] */
252.1103 +      double s;
252.1104 +      /* value, at which x[q] is fixed */
252.1105 +};
252.1106 +
252.1107 +static int rcv_fixed_col(NPP *npp, void *info);
252.1108 +
252.1109 +void npp_fixed_col(NPP *npp, NPPCOL *q)
252.1110 +{     /* process fixed column */
252.1111 +      struct fixed_col *info;
252.1112 +      NPPROW *i;
252.1113 +      NPPAIJ *aij;
252.1114 +      /* the column must be fixed */
252.1115 +      xassert(q->lb == q->ub);
252.1116 +      /* create transformation stack entry */
252.1117 +      info = npp_push_tse(npp,
252.1118 +         rcv_fixed_col, sizeof(struct fixed_col));
252.1119 +      info->q = q->j;
252.1120 +      info->s = q->lb;
252.1121 +      /* substitute x[q] = s[q] into objective row */
252.1122 +      npp->c0 += q->coef * q->lb;
252.1123 +      /* substitute x[q] = s[q] into constraint rows */
252.1124 +      for (aij = q->ptr; aij != NULL; aij = aij->c_next)
252.1125 +      {  i = aij->row;
252.1126 +         if (i->lb == i->ub)
252.1127 +            i->ub = (i->lb -= aij->val * q->lb);
252.1128 +         else
252.1129 +         {  if (i->lb != -DBL_MAX)
252.1130 +               i->lb -= aij->val * q->lb;
252.1131 +            if (i->ub != +DBL_MAX)
252.1132 +               i->ub -= aij->val * q->lb;
252.1133 +         }
252.1134 +      }
252.1135 +      /* remove the column from the problem */
252.1136 +      npp_del_col(npp, q);
252.1137 +      return;
252.1138 +}
252.1139 +
252.1140 +static int rcv_fixed_col(NPP *npp, void *_info)
252.1141 +{     /* recover fixed column */
252.1142 +      struct fixed_col *info = _info;
252.1143 +      if (npp->sol == GLP_SOL)
252.1144 +         npp->c_stat[info->q] = GLP_NS;
252.1145 +      npp->c_value[info->q] = info->s;
252.1146 +      return 0;
252.1147 +}
252.1148 +
252.1149 +/***********************************************************************
252.1150 +*  NAME
252.1151 +*
252.1152 +*  npp_make_equality - process row with almost identical bounds
252.1153 +*
252.1154 +*  SYNOPSIS
252.1155 +*
252.1156 +*  #include "glpnpp.h"
252.1157 +*  int npp_make_equality(NPP *npp, NPPROW *p);
252.1158 +*
252.1159 +*  DESCRIPTION
252.1160 +*
252.1161 +*  The routine npp_make_equality processes row p:
252.1162 +*
252.1163 +*     L[p] <= sum a[p,j] x[j] <= U[p],                               (1)
252.1164 +*              j
252.1165 +*
252.1166 +*  where -oo < L[p] < U[p] < +oo, i.e. which is double-sided inequality
252.1167 +*  constraint.
252.1168 +*
252.1169 +*  RETURNS
252.1170 +*
252.1171 +*  0 - row bounds have not been changed;
252.1172 +*
252.1173 +*  1 - row has been replaced by equality constraint.
252.1174 +*
252.1175 +*  PROBLEM TRANSFORMATION
252.1176 +*
252.1177 +*  If bounds of row (1) are very close to each other:
252.1178 +*
252.1179 +*     U[p] - L[p] <= eps,                                            (2)
252.1180 +*
252.1181 +*  where eps is an absolute tolerance for row value, the row can be
252.1182 +*  replaced by the following almost equivalent equiality constraint:
252.1183 +*
252.1184 +*     sum a[p,j] x[j] = b,                                           (3)
252.1185 +*      j
252.1186 +*
252.1187 +*  where b = (L[p] + U[p]) / 2. If the right-hand side in (3) happens
252.1188 +*  to be very close to its nearest integer:
252.1189 +*
252.1190 +*     |b - floor(b + 0.5)| <= eps,                                   (4)
252.1191 +*
252.1192 +*  it is reasonable to use this nearest integer as the right-hand side.
252.1193 +*
252.1194 +*  RECOVERING BASIC SOLUTION
252.1195 +*
252.1196 +*  Status of row p in solution to the original problem is determined
252.1197 +*  by its status and the sign of its multiplier pi[p] in solution to
252.1198 +*  the transformed problem as follows:
252.1199 +*
252.1200 +*     +-----------------------+---------+--------------------+
252.1201 +*     |    Status of row p    | Sign of |  Status of row p   |
252.1202 +*     | (transformed problem) |  pi[p]  | (original problem) |
252.1203 +*     +-----------------------+---------+--------------------+
252.1204 +*     |        GLP_BS         |  + / -  |       GLP_BS       |
252.1205 +*     |        GLP_NS         |    +    |       GLP_NL       |
252.1206 +*     |        GLP_NS         |    -    |       GLP_NU       |
252.1207 +*     +-----------------------+---------+--------------------+
252.1208 +*
252.1209 +*  Value of row multiplier pi[p] in solution to the original problem is
252.1210 +*  the same as in solution to the transformed problem.
252.1211 +*
252.1212 +*  RECOVERING INTERIOR POINT SOLUTION
252.1213 +*
252.1214 +*  Value of row multiplier pi[p] in solution to the original problem is
252.1215 +*  the same as in solution to the transformed problem.
252.1216 +*
252.1217 +*  RECOVERING MIP SOLUTION
252.1218 +*
252.1219 +*  None needed. */
252.1220 +
252.1221 +struct make_equality
252.1222 +{     /* row with almost identical bounds */
252.1223 +      int p;
252.1224 +      /* row reference number */
252.1225 +};
252.1226 +
252.1227 +static int rcv_make_equality(NPP *npp, void *info);
252.1228 +
252.1229 +int npp_make_equality(NPP *npp, NPPROW *p)
252.1230 +{     /* process row with almost identical bounds */
252.1231 +      struct make_equality *info;
252.1232 +      double b, eps, nint;
252.1233 +      /* the row must be double-sided inequality */
252.1234 +      xassert(p->lb != -DBL_MAX);
252.1235 +      xassert(p->ub != +DBL_MAX);
252.1236 +      xassert(p->lb < p->ub);
252.1237 +      /* check row bounds */
252.1238 +      eps = 1e-9 + 1e-12 * fabs(p->lb);
252.1239 +      if (p->ub - p->lb > eps) return 0;
252.1240 +      /* row bounds are very close to each other */
252.1241 +      /* create transformation stack entry */
252.1242 +      info = npp_push_tse(npp,
252.1243 +         rcv_make_equality, sizeof(struct make_equality));
252.1244 +      info->p = p->i;
252.1245 +      /* compute right-hand side */
252.1246 +      b = 0.5 * (p->ub + p->lb);
252.1247 +      nint = floor(b + 0.5);
252.1248 +      if (fabs(b - nint) <= eps) b = nint;
252.1249 +      /* replace row p by almost equivalent equality constraint */
252.1250 +      p->lb = p->ub = b;
252.1251 +      return 1;
252.1252 +}
252.1253 +
252.1254 +int rcv_make_equality(NPP *npp, void *_info)
252.1255 +{     /* recover row with almost identical bounds */
252.1256 +      struct make_equality *info = _info;
252.1257 +      if (npp->sol == GLP_SOL)
252.1258 +      {  if (npp->r_stat[info->p] == GLP_BS)
252.1259 +            npp->r_stat[info->p] = GLP_BS;
252.1260 +         else if (npp->r_stat[info->p] == GLP_NS)
252.1261 +         {  if (npp->r_pi[info->p] >= 0.0)
252.1262 +               npp->r_stat[info->p] = GLP_NL;
252.1263 +            else
252.1264 +               npp->r_stat[info->p] = GLP_NU;
252.1265 +         }
252.1266 +         else
252.1267 +         {  npp_error();
252.1268 +            return 1;
252.1269 +         }
252.1270 +      }
252.1271 +      return 0;
252.1272 +}
252.1273 +
252.1274 +/***********************************************************************
252.1275 +*  NAME
252.1276 +*
252.1277 +*  npp_make_fixed - process column with almost identical bounds
252.1278 +*
252.1279 +*  SYNOPSIS
252.1280 +*
252.1281 +*  #include "glpnpp.h"
252.1282 +*  int npp_make_fixed(NPP *npp, NPPCOL *q);
252.1283 +*
252.1284 +*  DESCRIPTION
252.1285 +*
252.1286 +*  The routine npp_make_fixed processes column q:
252.1287 +*
252.1288 +*     l[q] <= x[q] <= u[q],                                          (1)
252.1289 +*
252.1290 +*  where -oo < l[q] < u[q] < +oo, i.e. which has both lower and upper
252.1291 +*  bounds.
252.1292 +*
252.1293 +*  RETURNS
252.1294 +*
252.1295 +*  0 - column bounds have not been changed;
252.1296 +*
252.1297 +*  1 - column has been fixed.
252.1298 +*
252.1299 +*  PROBLEM TRANSFORMATION
252.1300 +*
252.1301 +*  If bounds of column (1) are very close to each other:
252.1302 +*
252.1303 +*     u[q] - l[q] <= eps,                                            (2)
252.1304 +*
252.1305 +*  where eps is an absolute tolerance for column value, the column can
252.1306 +*  be fixed:
252.1307 +*
252.1308 +*     x[q] = s[q],                                                   (3)
252.1309 +*
252.1310 +*  where s[q] = (l[q] + u[q]) / 2. And if the fixed column value s[q]
252.1311 +*  happens to be very close to its nearest integer:
252.1312 +*
252.1313 +*     |s[q] - floor(s[q] + 0.5)| <= eps,                             (4)
252.1314 +*
252.1315 +*  it is reasonable to use this nearest integer as the fixed value.
252.1316 +*
252.1317 +*  RECOVERING BASIC SOLUTION
252.1318 +*
252.1319 +*  In the dual system of the original (as well as transformed) problem
252.1320 +*  column q corresponds to the following row:
252.1321 +*
252.1322 +*     sum a[i,q] pi[i] + lambda[q] = c[q].                           (5)
252.1323 +*      i
252.1324 +*
252.1325 +*  Since multipliers pi[i] are known for all rows from solution to the
252.1326 +*  transformed problem, formula (5) allows computing value of multiplier
252.1327 +*  (reduced cost) for column q:
252.1328 +*
252.1329 +*     lambda[q] = c[q] - sum a[i,q] pi[i].                           (6)
252.1330 +*                         i
252.1331 +*
252.1332 +*  Status of column q in solution to the original problem is determined
252.1333 +*  by its status and the sign of its multiplier lambda[q] in solution to
252.1334 +*  the transformed problem as follows:
252.1335 +*
252.1336 +*     +-----------------------+-----------+--------------------+
252.1337 +*     |  Status of column q   |  Sign of  | Status of column q |
252.1338 +*     | (transformed problem) | lambda[q] | (original problem) |
252.1339 +*     +-----------------------+-----------+--------------------+
252.1340 +*     |        GLP_BS         |   + / -   |       GLP_BS       |
252.1341 +*     |        GLP_NS         |     +     |       GLP_NL       |
252.1342 +*     |        GLP_NS         |     -     |       GLP_NU       |
252.1343 +*     +-----------------------+-----------+--------------------+
252.1344 +*
252.1345 +*  Value of column q in solution to the original problem is the same as
252.1346 +*  in solution to the transformed problem.
252.1347 +*
252.1348 +*  RECOVERING INTERIOR POINT SOLUTION
252.1349 +*
252.1350 +*  Value of column q in solution to the original problem is the same as
252.1351 +*  in solution to the transformed problem.
252.1352 +*
252.1353 +*  RECOVERING MIP SOLUTION
252.1354 +*
252.1355 +*  None needed. */
252.1356 +
252.1357 +struct make_fixed
252.1358 +{     /* column with almost identical bounds */
252.1359 +      int q;
252.1360 +      /* column reference number */
252.1361 +      double c;
252.1362 +      /* objective coefficient at x[q] */
252.1363 +      NPPLFE *ptr;
252.1364 +      /* list of non-zero coefficients a[i,q] */
252.1365 +};
252.1366 +
252.1367 +static int rcv_make_fixed(NPP *npp, void *info);
252.1368 +
252.1369 +int npp_make_fixed(NPP *npp, NPPCOL *q)
252.1370 +{     /* process column with almost identical bounds */
252.1371 +      struct make_fixed *info;
252.1372 +      NPPAIJ *aij;
252.1373 +      NPPLFE *lfe;
252.1374 +      double s, eps, nint;
252.1375 +      /* the column must be double-bounded */
252.1376 +      xassert(q->lb != -DBL_MAX);
252.1377 +      xassert(q->ub != +DBL_MAX);
252.1378 +      xassert(q->lb < q->ub);
252.1379 +      /* check column bounds */
252.1380 +      eps = 1e-9 + 1e-12 * fabs(q->lb);
252.1381 +      if (q->ub - q->lb > eps) return 0;
252.1382 +      /* column bounds are very close to each other */
252.1383 +      /* create transformation stack entry */
252.1384 +      info = npp_push_tse(npp,
252.1385 +         rcv_make_fixed, sizeof(struct make_fixed));
252.1386 +      info->q = q->j;
252.1387 +      info->c = q->coef;
252.1388 +      info->ptr = NULL;
252.1389 +      /* save column coefficients a[i,q] (needed for basic solution
252.1390 +         only) */
252.1391 +      if (npp->sol == GLP_SOL)
252.1392 +      {  for (aij = q->ptr; aij != NULL; aij = aij->c_next)
252.1393 +         {  lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
252.1394 +            lfe->ref = aij->row->i;
252.1395 +            lfe->val = aij->val;
252.1396 +            lfe->next = info->ptr;
252.1397 +            info->ptr = lfe;
252.1398 +         }
252.1399 +      }
252.1400 +      /* compute column fixed value */
252.1401 +      s = 0.5 * (q->ub + q->lb);
252.1402 +      nint = floor(s + 0.5);
252.1403 +      if (fabs(s - nint) <= eps) s = nint;
252.1404 +      /* make column q fixed */
252.1405 +      q->lb = q->ub = s;
252.1406 +      return 1;
252.1407 +}
252.1408 +
252.1409 +static int rcv_make_fixed(NPP *npp, void *_info)
252.1410 +{     /* recover column with almost identical bounds */
252.1411 +      struct make_fixed *info = _info;
252.1412 +      NPPLFE *lfe;
252.1413 +      double lambda;
252.1414 +      if (npp->sol == GLP_SOL)
252.1415 +      {  if (npp->c_stat[info->q] == GLP_BS)
252.1416 +            npp->c_stat[info->q] = GLP_BS;
252.1417 +         else if (npp->c_stat[info->q] == GLP_NS)
252.1418 +         {  /* compute multiplier for column q with formula (6) */
252.1419 +            lambda = info->c;
252.1420 +            for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
252.1421 +               lambda -= lfe->val * npp->r_pi[lfe->ref];
252.1422 +            /* assign status to non-basic column */
252.1423 +            if (lambda >= 0.0)
252.1424 +               npp->c_stat[info->q] = GLP_NL;
252.1425 +            else
252.1426 +               npp->c_stat[info->q] = GLP_NU;
252.1427 +         }
252.1428 +         else
252.1429 +         {  npp_error();
252.1430 +            return 1;
252.1431 +         }
252.1432 +      }
252.1433 +      return 0;
252.1434 +}
252.1435 +
252.1436 +/* eof */
   253.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   253.2 +++ b/src/glpnpp03.c	Mon Dec 06 13:09:21 2010 +0100
   253.3 @@ -0,0 +1,2861 @@
   253.4 +/* glpnpp03.c */
   253.5 +
   253.6 +/***********************************************************************
   253.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   253.8 +*
   253.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  253.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  253.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  253.12 +*  E-mail: <mao@gnu.org>.
  253.13 +*
  253.14 +*  GLPK is free software: you can redistribute it and/or modify it
  253.15 +*  under the terms of the GNU General Public License as published by
  253.16 +*  the Free Software Foundation, either version 3 of the License, or
  253.17 +*  (at your option) any later version.
  253.18 +*
  253.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  253.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  253.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  253.22 +*  License for more details.
  253.23 +*
  253.24 +*  You should have received a copy of the GNU General Public License
  253.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  253.26 +***********************************************************************/
  253.27 +
  253.28 +#include "glpnpp.h"
  253.29 +
  253.30 +/***********************************************************************
  253.31 +*  NAME
  253.32 +*
  253.33 +*  npp_empty_row - process empty row
  253.34 +*
  253.35 +*  SYNOPSIS
  253.36 +*
  253.37 +*  #include "glpnpp.h"
  253.38 +*  int npp_empty_row(NPP *npp, NPPROW *p);
  253.39 +*
  253.40 +*  DESCRIPTION
  253.41 +*
  253.42 +*  The routine npp_empty_row processes row p, which is empty, i.e.
  253.43 +*  coefficients at all columns in this row are zero:
  253.44 +*
  253.45 +*     L[p] <= sum 0 x[j] <= U[p],                                    (1)
  253.46 +*
  253.47 +*  where L[p] <= U[p].
  253.48 +*
  253.49 +*  RETURNS
  253.50 +*
  253.51 +*  0 - success;
  253.52 +*
  253.53 +*  1 - problem has no primal feasible solution.
  253.54 +*
  253.55 +*  PROBLEM TRANSFORMATION
  253.56 +*
  253.57 +*  If the following conditions hold:
  253.58 +*
  253.59 +*     L[p] <= +eps,  U[p] >= -eps,                                   (2)
  253.60 +*
  253.61 +*  where eps is an absolute tolerance for row value, the row p is
  253.62 +*  redundant. In this case it can be replaced by equivalent redundant
  253.63 +*  row, which is free (unbounded), and then removed from the problem.
  253.64 +*  Otherwise, the row p is infeasible and, thus, the problem has no
  253.65 +*  primal feasible solution.
  253.66 +*
  253.67 +*  RECOVERING BASIC SOLUTION
  253.68 +*
  253.69 +*  See the routine npp_free_row.
  253.70 +*
  253.71 +*  RECOVERING INTERIOR-POINT SOLUTION
  253.72 +*
  253.73 +*  See the routine npp_free_row.
  253.74 +*
  253.75 +*  RECOVERING MIP SOLUTION
  253.76 +*
  253.77 +*  None needed. */
  253.78 +
  253.79 +int npp_empty_row(NPP *npp, NPPROW *p)
  253.80 +{     /* process empty row */
  253.81 +      double eps = 1e-3;
  253.82 +      /* the row must be empty */
  253.83 +      xassert(p->ptr == NULL);
  253.84 +      /* check primal feasibility */
  253.85 +      if (p->lb > +eps || p->ub < -eps)
  253.86 +         return 1;
  253.87 +      /* replace the row by equivalent free (unbounded) row */
  253.88 +      p->lb = -DBL_MAX, p->ub = +DBL_MAX;
  253.89 +      /* and process it */
  253.90 +      npp_free_row(npp, p);
  253.91 +      return 0;
  253.92 +}
  253.93 +
  253.94 +/***********************************************************************
  253.95 +*  NAME
  253.96 +*
  253.97 +*  npp_empty_col - process empty column
  253.98 +*
  253.99 +*  SYNOPSIS
 253.100 +*
 253.101 +*  #include "glpnpp.h"
 253.102 +*  int npp_empty_col(NPP *npp, NPPCOL *q);
 253.103 +*
 253.104 +*  DESCRIPTION
 253.105 +*
 253.106 +*  The routine npp_empty_col processes column q:
 253.107 +*
 253.108 +*     l[q] <= x[q] <= u[q],                                          (1)
 253.109 +*
 253.110 +*  where l[q] <= u[q], which is empty, i.e. has zero coefficients in
 253.111 +*  all constraint rows.
 253.112 +*
 253.113 +*  RETURNS
 253.114 +*
 253.115 +*  0 - success;
 253.116 +*
 253.117 +*  1 - problem has no dual feasible solution.
 253.118 +*
 253.119 +*  PROBLEM TRANSFORMATION
 253.120 +*
 253.121 +*  The row of the dual system corresponding to the empty column is the
 253.122 +*  following:
 253.123 +*
 253.124 +*     sum 0 pi[i] + lambda[q] = c[q],                                (2)
 253.125 +*      i
 253.126 +*
 253.127 +*  from which it follows that:
 253.128 +*
 253.129 +*     lambda[q] = c[q].                                              (3)
 253.130 +*
 253.131 +*  If the following condition holds:
 253.132 +*
 253.133 +*     c[q] < - eps,                                                  (4)
 253.134 +*
 253.135 +*  where eps is an absolute tolerance for column multiplier, the lower
 253.136 +*  column bound l[q] must be active to provide dual feasibility (note
 253.137 +*  that being preprocessed the problem is always minimization). In this
 253.138 +*  case the column can be fixed on its lower bound and removed from the
 253.139 +*  problem (if the column is integral, its bounds are also assumed to
 253.140 +*  be integral). And if the column has no lower bound (l[q] = -oo), the
 253.141 +*  problem has no dual feasible solution.
 253.142 +*
 253.143 +*  If the following condition holds:
 253.144 +*
 253.145 +*     c[q] > + eps,                                                  (5)
 253.146 +*
 253.147 +*  the upper column bound u[q] must be active to provide dual
 253.148 +*  feasibility. In this case the column can be fixed on its upper bound
 253.149 +*  and removed from the problem. And if the column has no upper bound
 253.150 +*  (u[q] = +oo), the problem has no dual feasible solution.
 253.151 +*
 253.152 +*  Finally, if the following condition holds:
 253.153 +*
 253.154 +*     - eps <= c[q] <= +eps,                                         (6)
 253.155 +*
 253.156 +*  dual feasibility does not depend on a particular value of column q.
 253.157 +*  In this case the column can be fixed either on its lower bound (if
 253.158 +*  l[q] > -oo) or on its upper bound (if u[q] < +oo) or at zero (if the
 253.159 +*  column is unbounded) and then removed from the problem.
 253.160 +*
 253.161 +*  RECOVERING BASIC SOLUTION
 253.162 +*
 253.163 +*  See the routine npp_fixed_col. Having been recovered the column
 253.164 +*  is assigned status GLP_NS. However, if actually it is not fixed
 253.165 +*  (l[q] < u[q]), its status should be changed to GLP_NL, GLP_NU, or
 253.166 +*  GLP_NF depending on which bound it was fixed on transformation stage.
 253.167 +*
 253.168 +*  RECOVERING INTERIOR-POINT SOLUTION
 253.169 +*
 253.170 +*  See the routine npp_fixed_col.
 253.171 +*
 253.172 +*  RECOVERING MIP SOLUTION
 253.173 +*
 253.174 +*  See the routine npp_fixed_col. */
 253.175 +
 253.176 +struct empty_col
 253.177 +{     /* empty column */
 253.178 +      int q;
 253.179 +      /* column reference number */
 253.180 +      char stat;
 253.181 +      /* status in basic solution */
 253.182 +};
 253.183 +
 253.184 +static int rcv_empty_col(NPP *npp, void *info);
 253.185 +
 253.186 +int npp_empty_col(NPP *npp, NPPCOL *q)
 253.187 +{     /* process empty column */
 253.188 +      struct empty_col *info;
 253.189 +      double eps = 1e-3;
 253.190 +      /* the column must be empty */
 253.191 +      xassert(q->ptr == NULL);
 253.192 +      /* check dual feasibility */
 253.193 +      if (q->coef > +eps && q->lb == -DBL_MAX)
 253.194 +         return 1;
 253.195 +      if (q->coef < -eps && q->ub == +DBL_MAX)
 253.196 +         return 1;
 253.197 +      /* create transformation stack entry */
 253.198 +      info = npp_push_tse(npp,
 253.199 +         rcv_empty_col, sizeof(struct empty_col));
 253.200 +      info->q = q->j;
 253.201 +      /* fix the column */
 253.202 +      if (q->lb == -DBL_MAX && q->ub == +DBL_MAX)
 253.203 +      {  /* free column */
 253.204 +         info->stat = GLP_NF;
 253.205 +         q->lb = q->ub = 0.0;
 253.206 +      }
 253.207 +      else if (q->ub == +DBL_MAX)
 253.208 +lo:   {  /* column with lower bound */
 253.209 +         info->stat = GLP_NL;
 253.210 +         q->ub = q->lb;
 253.211 +      }
 253.212 +      else if (q->lb == -DBL_MAX)
 253.213 +up:   {  /* column with upper bound */
 253.214 +         info->stat = GLP_NU;
 253.215 +         q->lb = q->ub;
 253.216 +      }
 253.217 +      else if (q->lb != q->ub)
 253.218 +      {  /* double-bounded column */
 253.219 +         if (q->coef >= +DBL_EPSILON) goto lo;
 253.220 +         if (q->coef <= -DBL_EPSILON) goto up;
 253.221 +         if (fabs(q->lb) <= fabs(q->ub)) goto lo; else goto up;
 253.222 +      }
 253.223 +      else
 253.224 +      {  /* fixed column */
 253.225 +         info->stat = GLP_NS;
 253.226 +      }
 253.227 +      /* process fixed column */
 253.228 +      npp_fixed_col(npp, q);
 253.229 +      return 0;
 253.230 +}
 253.231 +
 253.232 +static int rcv_empty_col(NPP *npp, void *_info)
 253.233 +{     /* recover empty column */
 253.234 +      struct empty_col *info = _info;
 253.235 +      if (npp->sol == GLP_SOL)
 253.236 +         npp->c_stat[info->q] = info->stat;
 253.237 +      return 0;
 253.238 +}
 253.239 +
 253.240 +/***********************************************************************
 253.241 +*  NAME
 253.242 +*
 253.243 +*  npp_implied_value - process implied column value
 253.244 +*
 253.245 +*  SYNOPSIS
 253.246 +*
 253.247 +*  #include "glpnpp.h"
 253.248 +*  int npp_implied_value(NPP *npp, NPPCOL *q, double s);
 253.249 +*
 253.250 +*  DESCRIPTION
 253.251 +*
 253.252 +*  For column q:
 253.253 +*
 253.254 +*     l[q] <= x[q] <= u[q],                                          (1)
 253.255 +*
 253.256 +*  where l[q] < u[q], the routine npp_implied_value processes its
 253.257 +*  implied value s[q]. If this implied value satisfies to the current
 253.258 +*  column bounds and integrality condition, the routine fixes column q
 253.259 +*  at the given point. Note that the column is kept in the problem in
 253.260 +*  any case.
 253.261 +*
 253.262 +*  RETURNS
 253.263 +*
 253.264 +*  0 - column has been fixed;
 253.265 +*
 253.266 +*  1 - implied value violates to current column bounds;
 253.267 +*
 253.268 +*  2 - implied value violates integrality condition.
 253.269 +*
 253.270 +*  ALGORITHM
 253.271 +*
 253.272 +*  Implied column value s[q] satisfies to the current column bounds if
 253.273 +*  the following condition holds:
 253.274 +*
 253.275 +*     l[q] - eps <= s[q] <= u[q] + eps,                              (2)
 253.276 +*
 253.277 +*  where eps is an absolute tolerance for column value. If the column
 253.278 +*  is integral, the following condition also must hold:
 253.279 +*
 253.280 +*     |s[q] - floor(s[q]+0.5)| <= eps,                               (3)
 253.281 +*
 253.282 +*  where floor(s[q]+0.5) is the nearest integer to s[q].
 253.283 +*
 253.284 +*  If both condition (2) and (3) are satisfied, the column can be fixed
 253.285 +*  at the value s[q], or, if it is integral, at floor(s[q]+0.5).
 253.286 +*  Otherwise, if s[q] violates (2) or (3), the problem has no feasible
 253.287 +*  solution.
 253.288 +*
 253.289 +*  Note: If s[q] is close to l[q] or u[q], it seems to be reasonable to
 253.290 +*  fix the column at its lower or upper bound, resp. rather than at the
 253.291 +*  implied value. */
 253.292 +
 253.293 +int npp_implied_value(NPP *npp, NPPCOL *q, double s)
 253.294 +{     /* process implied column value */
 253.295 +      double eps, nint;
 253.296 +      xassert(npp == npp);
 253.297 +      /* column must not be fixed */
 253.298 +      xassert(q->lb < q->ub);
 253.299 +      /* check integrality */
 253.300 +      if (q->is_int)
 253.301 +      {  nint = floor(s + 0.5);
 253.302 +         if (fabs(s - nint) <= 1e-5)
 253.303 +            s = nint;
 253.304 +         else
 253.305 +            return 2;
 253.306 +      }
 253.307 +      /* check current column lower bound */
 253.308 +      if (q->lb != -DBL_MAX)
 253.309 +      {  eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->lb));
 253.310 +         if (s < q->lb - eps) return 1;
 253.311 +         /* if s[q] is close to l[q], fix column at its lower bound
 253.312 +            rather than at the implied value */
 253.313 +         if (s < q->lb + 1e-3 * eps)
 253.314 +         {  q->ub = q->lb;
 253.315 +            return 0;
 253.316 +         }
 253.317 +      }
 253.318 +      /* check current column upper bound */
 253.319 +      if (q->ub != +DBL_MAX)
 253.320 +      {  eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->ub));
 253.321 +         if (s > q->ub + eps) return 1;
 253.322 +         /* if s[q] is close to u[q], fix column at its upper bound
 253.323 +            rather than at the implied value */
 253.324 +         if (s > q->ub - 1e-3 * eps)
 253.325 +         {  q->lb = q->ub;
 253.326 +            return 0;
 253.327 +         }
 253.328 +      }
 253.329 +      /* fix column at the implied value */
 253.330 +      q->lb = q->ub = s;
 253.331 +      return 0;
 253.332 +}
 253.333 +
 253.334 +/***********************************************************************
 253.335 +*  NAME
 253.336 +*
 253.337 +*  npp_eq_singlet - process row singleton (equality constraint)
 253.338 +*
 253.339 +*  SYNOPSIS
 253.340 +*
 253.341 +*  #include "glpnpp.h"
 253.342 +*  int npp_eq_singlet(NPP *npp, NPPROW *p);
 253.343 +*
 253.344 +*  DESCRIPTION
 253.345 +*
 253.346 +*  The routine npp_eq_singlet processes row p, which is equiality
 253.347 +*  constraint having the only non-zero coefficient:
 253.348 +*
 253.349 +*     a[p,q] x[q] = b.                                               (1)
 253.350 +*
 253.351 +*  RETURNS
 253.352 +*
 253.353 +*  0 - success;
 253.354 +*
 253.355 +*  1 - problem has no primal feasible solution;
 253.356 +*
 253.357 +*  2 - problem has no integer feasible solution.
 253.358 +*
 253.359 +*  PROBLEM TRANSFORMATION
 253.360 +*
 253.361 +*  The equality constraint defines implied value of column q:
 253.362 +*
 253.363 +*     x[q] = s[q] = b / a[p,q].                                      (2)
 253.364 +*
 253.365 +*  If the implied value s[q] satisfies to the column bounds (see the
 253.366 +*  routine npp_implied_value), the column can be fixed at s[q] and
 253.367 +*  removed from the problem. In this case row p becomes redundant, so
 253.368 +*  it can be replaced by equivalent free row and also removed from the
 253.369 +*  problem.
 253.370 +*
 253.371 +*  Note that the routine removes from the problem only row p. Column q
 253.372 +*  becomes fixed, however, it is kept in the problem.
 253.373 +*
 253.374 +*  RECOVERING BASIC SOLUTION
 253.375 +*
 253.376 +*  In solution to the original problem row p is assigned status GLP_NS
 253.377 +*  (active equality constraint), and column q is assigned status GLP_BS
 253.378 +*  (basic column).
 253.379 +*
 253.380 +*  Multiplier for row p can be computed as follows. In the dual system
 253.381 +*  of the original problem column q corresponds to the following row:
 253.382 +*
 253.383 +*     sum a[i,q] pi[i] + lambda[q] = c[q]  ==>
 253.384 +*      i
 253.385 +*
 253.386 +*     sum a[i,q] pi[i] + a[p,q] pi[p] + lambda[q] = c[q].
 253.387 +*     i!=p
 253.388 +*
 253.389 +*  Therefore:
 253.390 +*
 253.391 +*               1
 253.392 +*     pi[p] = ------ (c[q] - lambda[q] - sum a[i,q] pi[i]),          (3)
 253.393 +*             a[p,q]                     i!=q
 253.394 +*
 253.395 +*  where lambda[q] = 0 (since column[q] is basic), and pi[i] for all
 253.396 +*  i != p are known in solution to the transformed problem.
 253.397 +*
 253.398 +*  Value of column q in solution to the original problem is assigned
 253.399 +*  its implied value s[q].
 253.400 +*
 253.401 +*  RECOVERING INTERIOR-POINT SOLUTION
 253.402 +*
 253.403 +*  Multiplier for row p is computed with formula (3). Value of column
 253.404 +*  q is assigned its implied value s[q].
 253.405 +*
 253.406 +*  RECOVERING MIP SOLUTION
 253.407 +*
 253.408 +*  Value of column q is assigned its implied value s[q]. */
 253.409 +
 253.410 +struct eq_singlet
 253.411 +{     /* row singleton (equality constraint) */
 253.412 +      int p;
 253.413 +      /* row reference number */
 253.414 +      int q;
 253.415 +      /* column reference number */
 253.416 +      double apq;
 253.417 +      /* constraint coefficient a[p,q] */
 253.418 +      double c;
 253.419 +      /* objective coefficient at x[q] */
 253.420 +      NPPLFE *ptr;
 253.421 +      /* list of non-zero coefficients a[i,q], i != p */
 253.422 +};
 253.423 +
 253.424 +static int rcv_eq_singlet(NPP *npp, void *info);
 253.425 +
 253.426 +int npp_eq_singlet(NPP *npp, NPPROW *p)
 253.427 +{     /* process row singleton (equality constraint) */
 253.428 +      struct eq_singlet *info;
 253.429 +      NPPCOL *q;
 253.430 +      NPPAIJ *aij;
 253.431 +      NPPLFE *lfe;
 253.432 +      int ret;
 253.433 +      double s;
 253.434 +      /* the row must be singleton equality constraint */
 253.435 +      xassert(p->lb == p->ub);
 253.436 +      xassert(p->ptr != NULL && p->ptr->r_next == NULL);
 253.437 +      /* compute and process implied column value */
 253.438 +      aij = p->ptr;
 253.439 +      q = aij->col;
 253.440 +      s = p->lb / aij->val;
 253.441 +      ret = npp_implied_value(npp, q, s);
 253.442 +      xassert(0 <= ret && ret <= 2);
 253.443 +      if (ret != 0) return ret;
 253.444 +      /* create transformation stack entry */
 253.445 +      info = npp_push_tse(npp,
 253.446 +         rcv_eq_singlet, sizeof(struct eq_singlet));
 253.447 +      info->p = p->i;
 253.448 +      info->q = q->j;
 253.449 +      info->apq = aij->val;
 253.450 +      info->c = q->coef;
 253.451 +      info->ptr = NULL;
 253.452 +      /* save column coefficients a[i,q], i != p (not needed for MIP
 253.453 +         solution) */
 253.454 +      if (npp->sol != GLP_MIP)
 253.455 +      {  for (aij = q->ptr; aij != NULL; aij = aij->c_next)
 253.456 +         {  if (aij->row == p) continue; /* skip a[p,q] */
 253.457 +            lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
 253.458 +            lfe->ref = aij->row->i;
 253.459 +            lfe->val = aij->val;
 253.460 +            lfe->next = info->ptr;
 253.461 +            info->ptr = lfe;
 253.462 +         }
 253.463 +      }
 253.464 +      /* remove the row from the problem */
 253.465 +      npp_del_row(npp, p);
 253.466 +      return 0;
 253.467 +}
 253.468 +
 253.469 +static int rcv_eq_singlet(NPP *npp, void *_info)
 253.470 +{     /* recover row singleton (equality constraint) */
 253.471 +      struct eq_singlet *info = _info;
 253.472 +      NPPLFE *lfe;
 253.473 +      double temp;
 253.474 +      if (npp->sol == GLP_SOL)
 253.475 +      {  /* column q must be already recovered as GLP_NS */
 253.476 +         if (npp->c_stat[info->q] != GLP_NS)
 253.477 +         {  npp_error();
 253.478 +            return 1;
 253.479 +         }
 253.480 +         npp->r_stat[info->p] = GLP_NS;
 253.481 +         npp->c_stat[info->q] = GLP_BS;
 253.482 +      }
 253.483 +      if (npp->sol != GLP_MIP)
 253.484 +      {  /* compute multiplier for row p with formula (3) */
 253.485 +         temp = info->c;
 253.486 +         for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
 253.487 +            temp -= lfe->val * npp->r_pi[lfe->ref];
 253.488 +         npp->r_pi[info->p] = temp / info->apq;
 253.489 +      }
 253.490 +      return 0;
 253.491 +}
 253.492 +
 253.493 +/***********************************************************************
 253.494 +*  NAME
 253.495 +*
 253.496 +*  npp_implied_lower - process implied column lower bound
 253.497 +*
 253.498 +*  SYNOPSIS
 253.499 +*
 253.500 +*  #include "glpnpp.h"
 253.501 +*  int npp_implied_lower(NPP *npp, NPPCOL *q, double l);
 253.502 +*
 253.503 +*  DESCRIPTION
 253.504 +*
 253.505 +*  For column q:
 253.506 +*
 253.507 +*     l[q] <= x[q] <= u[q],                                          (1)
 253.508 +*
 253.509 +*  where l[q] < u[q], the routine npp_implied_lower processes its
 253.510 +*  implied lower bound l'[q]. As the result the current column lower
 253.511 +*  bound may increase. Note that the column is kept in the problem in
 253.512 +*  any case.
 253.513 +*
 253.514 +*  RETURNS
 253.515 +*
 253.516 +*  0 - current column lower bound has not changed;
 253.517 +*
 253.518 +*  1 - current column lower bound has changed, but not significantly;
 253.519 +*
 253.520 +*  2 - current column lower bound has significantly changed;
 253.521 +*
 253.522 +*  3 - column has been fixed on its upper bound;
 253.523 +*
 253.524 +*  4 - implied lower bound violates current column upper bound.
 253.525 +*
 253.526 +*  ALGORITHM
 253.527 +*
 253.528 +*  If column q is integral, before processing its implied lower bound
 253.529 +*  should be rounded up:
 253.530 +*
 253.531 +*              ( floor(l'[q]+0.5), if |l'[q] - floor(l'[q]+0.5)| <= eps
 253.532 +*     l'[q] := <                                                     (2)
 253.533 +*              ( ceil(l'[q]),      otherwise
 253.534 +*
 253.535 +*  where floor(l'[q]+0.5) is the nearest integer to l'[q], ceil(l'[q])
 253.536 +*  is smallest integer not less than l'[q], and eps is an absolute
 253.537 +*  tolerance for column value.
 253.538 +*
 253.539 +*  Processing implied column lower bound l'[q] includes the following
 253.540 +*  cases:
 253.541 +*
 253.542 +*  1) if l'[q] < l[q] + eps, implied lower bound is redundant;
 253.543 +*
 253.544 +*  2) if l[q] + eps <= l[q] <= u[q] + eps, current column lower bound
 253.545 +*     l[q] can be strengthened by replacing it with l'[q]. If in this
 253.546 +*     case new column lower bound becomes close to current column upper
 253.547 +*     bound u[q], the column can be fixed on its upper bound;
 253.548 +*
 253.549 +*  3) if l'[q] > u[q] + eps, implied lower bound violates current
 253.550 +*     column upper bound u[q], in which case the problem has no primal
 253.551 +*     feasible solution. */
 253.552 +
 253.553 +int npp_implied_lower(NPP *npp, NPPCOL *q, double l)
 253.554 +{     /* process implied column lower bound */
 253.555 +      int ret;
 253.556 +      double eps, nint;
 253.557 +      xassert(npp == npp);
 253.558 +      /* column must not be fixed */
 253.559 +      xassert(q->lb < q->ub);
 253.560 +      /* implied lower bound must be finite */
 253.561 +      xassert(l != -DBL_MAX);
 253.562 +      /* if column is integral, round up l'[q] */
 253.563 +      if (q->is_int)
 253.564 +      {  nint = floor(l + 0.5);
 253.565 +         if (fabs(l - nint) <= 1e-5)
 253.566 +            l = nint;
 253.567 +         else
 253.568 +            l = ceil(l);
 253.569 +      }
 253.570 +      /* check current column lower bound */
 253.571 +      if (q->lb != -DBL_MAX)
 253.572 +      {  eps = (q->is_int ? 1e-3 : 1e-3 + 1e-6 * fabs(q->lb));
 253.573 +         if (l < q->lb + eps)
 253.574 +         {  ret = 0; /* redundant */
 253.575 +            goto done;
 253.576 +         }
 253.577 +      }
 253.578 +      /* check current column upper bound */
 253.579 +      if (q->ub != +DBL_MAX)
 253.580 +      {  eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->ub));
 253.581 +         if (l > q->ub + eps)
 253.582 +         {  ret = 4; /* infeasible */
 253.583 +            goto done;
 253.584 +         }
 253.585 +         /* if l'[q] is close to u[q], fix column at its upper bound */
 253.586 +         if (l > q->ub - 1e-3 * eps)
 253.587 +         {  q->lb = q->ub;
 253.588 +            ret = 3; /* fixed */
 253.589 +            goto done;
 253.590 +         }
 253.591 +      }
 253.592 +      /* check if column lower bound changes significantly */
 253.593 +      if (q->lb == -DBL_MAX)
 253.594 +         ret = 2; /* significantly */
 253.595 +      else if (q->is_int && l > q->lb + 0.5)
 253.596 +         ret = 2; /* significantly */
 253.597 +      else if (l > q->lb + 0.30 * (1.0 + fabs(q->lb)))
 253.598 +         ret = 2; /* significantly */
 253.599 +      else
 253.600 +         ret = 1; /* not significantly */
 253.601 +      /* set new column lower bound */
 253.602 +      q->lb = l;
 253.603 +done: return ret;
 253.604 +}
 253.605 +
 253.606 +/***********************************************************************
 253.607 +*  NAME
 253.608 +*
 253.609 +*  npp_implied_upper - process implied column upper bound
 253.610 +*
 253.611 +*  SYNOPSIS
 253.612 +*
 253.613 +*  #include "glpnpp.h"
 253.614 +*  int npp_implied_upper(NPP *npp, NPPCOL *q, double u);
 253.615 +*
 253.616 +*  DESCRIPTION
 253.617 +*
 253.618 +*  For column q:
 253.619 +*
 253.620 +*     l[q] <= x[q] <= u[q],                                          (1)
 253.621 +*
 253.622 +*  where l[q] < u[q], the routine npp_implied_upper processes its
 253.623 +*  implied upper bound u'[q]. As the result the current column upper
 253.624 +*  bound may decrease. Note that the column is kept in the problem in
 253.625 +*  any case.
 253.626 +*
 253.627 +*  RETURNS
 253.628 +*
 253.629 +*  0 - current column upper bound has not changed;
 253.630 +*
 253.631 +*  1 - current column upper bound has changed, but not significantly;
 253.632 +*
 253.633 +*  2 - current column upper bound has significantly changed;
 253.634 +*
 253.635 +*  3 - column has been fixed on its lower bound;
 253.636 +*
 253.637 +*  4 - implied upper bound violates current column lower bound.
 253.638 +*
 253.639 +*  ALGORITHM
 253.640 +*
 253.641 +*  If column q is integral, before processing its implied upper bound
 253.642 +*  should be rounded down:
 253.643 +*
 253.644 +*              ( floor(u'[q]+0.5), if |u'[q] - floor(l'[q]+0.5)| <= eps
 253.645 +*     u'[q] := <                                                     (2)
 253.646 +*              ( floor(l'[q]),     otherwise
 253.647 +*
 253.648 +*  where floor(u'[q]+0.5) is the nearest integer to u'[q],
 253.649 +*  floor(u'[q]) is largest integer not greater than u'[q], and eps is
 253.650 +*  an absolute tolerance for column value.
 253.651 +*
 253.652 +*  Processing implied column upper bound u'[q] includes the following
 253.653 +*  cases:
 253.654 +*
 253.655 +*  1) if u'[q] > u[q] - eps, implied upper bound is redundant;
 253.656 +*
 253.657 +*  2) if l[q] - eps <= u[q] <= u[q] - eps, current column upper bound
 253.658 +*     u[q] can be strengthened by replacing it with u'[q]. If in this
 253.659 +*     case new column upper bound becomes close to current column lower
 253.660 +*     bound, the column can be fixed on its lower bound;
 253.661 +*
 253.662 +*  3) if u'[q] < l[q] - eps, implied upper bound violates current
 253.663 +*     column lower bound l[q], in which case the problem has no primal
 253.664 +*     feasible solution. */
 253.665 +
 253.666 +int npp_implied_upper(NPP *npp, NPPCOL *q, double u)
 253.667 +{     int ret;
 253.668 +      double eps, nint;
 253.669 +      xassert(npp == npp);
 253.670 +      /* column must not be fixed */
 253.671 +      xassert(q->lb < q->ub);
 253.672 +      /* implied upper bound must be finite */
 253.673 +      xassert(u != +DBL_MAX);
 253.674 +      /* if column is integral, round down u'[q] */
 253.675 +      if (q->is_int)
 253.676 +      {  nint = floor(u + 0.5);
 253.677 +         if (fabs(u - nint) <= 1e-5)
 253.678 +            u = nint;
 253.679 +         else
 253.680 +            u = floor(u);
 253.681 +      }
 253.682 +      /* check current column upper bound */
 253.683 +      if (q->ub != +DBL_MAX)
 253.684 +      {  eps = (q->is_int ? 1e-3 : 1e-3 + 1e-6 * fabs(q->ub));
 253.685 +         if (u > q->ub - eps)
 253.686 +         {  ret = 0; /* redundant */
 253.687 +            goto done;
 253.688 +         }
 253.689 +      }
 253.690 +      /* check current column lower bound */
 253.691 +      if (q->lb != -DBL_MAX)
 253.692 +      {  eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->lb));
 253.693 +         if (u < q->lb - eps)
 253.694 +         {  ret = 4; /* infeasible */
 253.695 +            goto done;
 253.696 +         }
 253.697 +         /* if u'[q] is close to l[q], fix column at its lower bound */
 253.698 +         if (u < q->lb + 1e-3 * eps)
 253.699 +         {  q->ub = q->lb;
 253.700 +            ret = 3; /* fixed */
 253.701 +            goto done;
 253.702 +         }
 253.703 +      }
 253.704 +      /* check if column upper bound changes significantly */
 253.705 +      if (q->ub == +DBL_MAX)
 253.706 +         ret = 2; /* significantly */
 253.707 +      else if (q->is_int && u < q->ub - 0.5)
 253.708 +         ret = 2; /* significantly */
 253.709 +      else if (u < q->ub - 0.30 * (1.0 + fabs(q->ub)))
 253.710 +         ret = 2; /* significantly */
 253.711 +      else
 253.712 +         ret = 1; /* not significantly */
 253.713 +      /* set new column upper bound */
 253.714 +      q->ub = u;
 253.715 +done: return ret;
 253.716 +}
 253.717 +
 253.718 +/***********************************************************************
 253.719 +*  NAME
 253.720 +*
 253.721 +*  npp_ineq_singlet - process row singleton (inequality constraint)
 253.722 +*
 253.723 +*  SYNOPSIS
 253.724 +*
 253.725 +*  #include "glpnpp.h"
 253.726 +*  int npp_ineq_singlet(NPP *npp, NPPROW *p);
 253.727 +*
 253.728 +*  DESCRIPTION
 253.729 +*
 253.730 +*  The routine npp_ineq_singlet processes row p, which is inequality
 253.731 +*  constraint having the only non-zero coefficient:
 253.732 +*
 253.733 +*     L[p] <= a[p,q] * x[q] <= U[p],                                 (1)
 253.734 +*
 253.735 +*  where L[p] < U[p], L[p] > -oo and/or U[p] < +oo.
 253.736 +*
 253.737 +*  RETURNS
 253.738 +*
 253.739 +*  0 - current column bounds have not changed;
 253.740 +*
 253.741 +*  1 - current column bounds have changed, but not significantly;
 253.742 +*
 253.743 +*  2 - current column bounds have significantly changed;
 253.744 +*
 253.745 +*  3 - column has been fixed on its lower or upper bound;
 253.746 +*
 253.747 +*  4 - problem has no primal feasible solution.
 253.748 +*
 253.749 +*  PROBLEM TRANSFORMATION
 253.750 +*
 253.751 +*  Inequality constraint (1) defines implied bounds of column q:
 253.752 +*
 253.753 +*             (  L[p] / a[p,q],  if a[p,q] > 0
 253.754 +*     l'[q] = <                                                      (2)
 253.755 +*             (  U[p] / a[p,q],  if a[p,q] < 0
 253.756 +*
 253.757 +*             (  U[p] / a[p,q],  if a[p,q] > 0
 253.758 +*     u'[q] = <                                                      (3)
 253.759 +*             (  L[p] / a[p,q],  if a[p,q] < 0
 253.760 +*
 253.761 +*  If these implied bounds do not violate current bounds of column q:
 253.762 +*
 253.763 +*     l[q] <= x[q] <= u[q],                                          (4)
 253.764 +*
 253.765 +*  they can be used to strengthen the current column bounds:
 253.766 +*
 253.767 +*     l[q] := max(l[q], l'[q]),                                      (5)
 253.768 +*
 253.769 +*     u[q] := min(u[q], u'[q]).                                      (6)
 253.770 +*
 253.771 +*  (See the routines npp_implied_lower and npp_implied_upper.)
 253.772 +*
 253.773 +*  Once bounds of row p (1) have been carried over column q, the row
 253.774 +*  becomes redundant, so it can be replaced by equivalent free row and
 253.775 +*  removed from the problem.
 253.776 +*
 253.777 +*  Note that the routine removes from the problem only row p. Column q,
 253.778 +*  even it has been fixed, is kept in the problem.
 253.779 +*
 253.780 +*  RECOVERING BASIC SOLUTION
 253.781 +*
 253.782 +*  Note that the row in the dual system corresponding to column q is
 253.783 +*  the following:
 253.784 +*
 253.785 +*     sum a[i,q] pi[i] + lambda[q] = c[q]  ==>
 253.786 +*      i
 253.787 +*                                                                    (7)
 253.788 +*     sum a[i,q] pi[i] + a[p,q] pi[p] + lambda[q] = c[q],
 253.789 +*     i!=p
 253.790 +*
 253.791 +*  where pi[i] for all i != p are known in solution to the transformed
 253.792 +*  problem. Row p does not exist in the transformed problem, so it has
 253.793 +*  zero multiplier there. This allows computing multiplier for column q
 253.794 +*  in solution to the transformed problem:
 253.795 +*
 253.796 +*     lambda~[q] = c[q] - sum a[i,q] pi[i].                          (8)
 253.797 +*                         i!=p
 253.798 +*
 253.799 +*  Let in solution to the transformed problem column q be non-basic
 253.800 +*  with lower bound active (GLP_NL, lambda~[q] >= 0), and this lower
 253.801 +*  bound be implied one l'[q]. From the original problem's standpoint
 253.802 +*  this then means that actually the original column lower bound l[q]
 253.803 +*  is inactive, and active is that row bound L[p] or U[p] that defines
 253.804 +*  the implied bound l'[q] (2). In this case in solution to the
 253.805 +*  original problem column q is assigned status GLP_BS while row p is
 253.806 +*  assigned status GLP_NL (if a[p,q] > 0) or GLP_NU (if a[p,q] < 0).
 253.807 +*  Since now column q is basic, its multiplier lambda[q] is zero. This
 253.808 +*  allows using (7) and (8) to find multiplier for row p in solution to
 253.809 +*  the original problem:
 253.810 +*
 253.811 +*               1
 253.812 +*     pi[p] = ------ (c[q] - sum a[i,q] pi[i]) = lambda~[q] / a[p,q] (9)
 253.813 +*             a[p,q]         i!=p
 253.814 +*
 253.815 +*  Now let in solution to the transformed problem column q be non-basic
 253.816 +*  with upper bound active (GLP_NU, lambda~[q] <= 0), and this upper
 253.817 +*  bound be implied one u'[q]. As in the previous case this then means
 253.818 +*  that from the original problem's standpoint actually the original
 253.819 +*  column upper bound u[q] is inactive, and active is that row bound
 253.820 +*  L[p] or U[p] that defines the implied bound u'[q] (3). In this case
 253.821 +*  in solution to the original problem column q is assigned status
 253.822 +*  GLP_BS, row p is assigned status GLP_NU (if a[p,q] > 0) or GLP_NL
 253.823 +*  (if a[p,q] < 0), and its multiplier is computed with formula (9).
 253.824 +*
 253.825 +*  Strengthening bounds of column q according to (5) and (6) may make
 253.826 +*  it fixed. Thus, if in solution to the transformed problem column q is
 253.827 +*  non-basic and fixed (GLP_NS), we can suppose that if lambda~[q] > 0,
 253.828 +*  column q has active lower bound (GLP_NL), and if lambda~[q] < 0,
 253.829 +*  column q has active upper bound (GLP_NU), reducing this case to two
 253.830 +*  previous ones. If, however, lambda~[q] is close to zero or
 253.831 +*  corresponding bound of row p does not exist (this may happen if
 253.832 +*  lambda~[q] has wrong sign due to round-off errors, in which case it
 253.833 +*  is expected to be close to zero, since solution is assumed to be dual
 253.834 +*  feasible), column q can be assigned status GLP_BS (basic), and row p
 253.835 +*  can be made active on its existing bound. In the latter case row
 253.836 +*  multiplier pi[p] computed with formula (9) will be also close to
 253.837 +*  zero, and dual feasibility will be kept.
 253.838 +*
 253.839 +*  In all other cases, namely, if in solution to the transformed
 253.840 +*  problem column q is basic (GLP_BS), or non-basic with original lower
 253.841 +*  bound l[q] active (GLP_NL), or non-basic with original upper bound
 253.842 +*  u[q] active (GLP_NU), constraint (1) is inactive. So in solution to
 253.843 +*  the original problem status of column q remains unchanged, row p is
 253.844 +*  assigned status GLP_BS, and its multiplier pi[p] is assigned zero
 253.845 +*  value.
 253.846 +*
 253.847 +*  RECOVERING INTERIOR-POINT SOLUTION
 253.848 +*
 253.849 +*  First, value of multiplier for column q in solution to the original
 253.850 +*  problem is computed with formula (8). If lambda~[q] > 0 and column q
 253.851 +*  has implied lower bound, or if lambda~[q] < 0 and column q has
 253.852 +*  implied upper bound, this means that from the original problem's
 253.853 +*  standpoint actually row p has corresponding active bound, in which
 253.854 +*  case its multiplier pi[p] is computed with formula (9). In other
 253.855 +*  cases, when the sign of lambda~[q] corresponds to original bound of
 253.856 +*  column q, or when lambda~[q] =~ 0, value of row multiplier pi[p] is
 253.857 +*  assigned zero value.
 253.858 +*
 253.859 +*  RECOVERING MIP SOLUTION
 253.860 +*
 253.861 +*  None needed. */
 253.862 +
 253.863 +struct ineq_singlet
 253.864 +{     /* row singleton (inequality constraint) */
 253.865 +      int p;
 253.866 +      /* row reference number */
 253.867 +      int q;
 253.868 +      /* column reference number */
 253.869 +      double apq;
 253.870 +      /* constraint coefficient a[p,q] */
 253.871 +      double c;
 253.872 +      /* objective coefficient at x[q] */
 253.873 +      double lb;
 253.874 +      /* row lower bound */
 253.875 +      double ub;
 253.876 +      /* row upper bound */
 253.877 +      char lb_changed;
 253.878 +      /* this flag is set if column lower bound was changed */
 253.879 +      char ub_changed;
 253.880 +      /* this flag is set if column upper bound was changed */
 253.881 +      NPPLFE *ptr;
 253.882 +      /* list of non-zero coefficients a[i,q], i != p */
 253.883 +};
 253.884 +
 253.885 +static int rcv_ineq_singlet(NPP *npp, void *info);
 253.886 +
 253.887 +int npp_ineq_singlet(NPP *npp, NPPROW *p)
 253.888 +{     /* process row singleton (inequality constraint) */
 253.889 +      struct ineq_singlet *info;
 253.890 +      NPPCOL *q;
 253.891 +      NPPAIJ *apq, *aij;
 253.892 +      NPPLFE *lfe;
 253.893 +      int lb_changed, ub_changed;
 253.894 +      double ll, uu;
 253.895 +      /* the row must be singleton inequality constraint */
 253.896 +      xassert(p->lb != -DBL_MAX || p->ub != +DBL_MAX);
 253.897 +      xassert(p->lb < p->ub);
 253.898 +      xassert(p->ptr != NULL && p->ptr->r_next == NULL);
 253.899 +      /* compute implied column bounds */
 253.900 +      apq = p->ptr;
 253.901 +      q = apq->col;
 253.902 +      xassert(q->lb < q->ub);
 253.903 +      if (apq->val > 0.0)
 253.904 +      {  ll = (p->lb == -DBL_MAX ? -DBL_MAX : p->lb / apq->val);
 253.905 +         uu = (p->ub == +DBL_MAX ? +DBL_MAX : p->ub / apq->val);
 253.906 +      }
 253.907 +      else
 253.908 +      {  ll = (p->ub == +DBL_MAX ? -DBL_MAX : p->ub / apq->val);
 253.909 +         uu = (p->lb == -DBL_MAX ? +DBL_MAX : p->lb / apq->val);
 253.910 +      }
 253.911 +      /* process implied column lower bound */
 253.912 +      if (ll == -DBL_MAX)
 253.913 +         lb_changed = 0;
 253.914 +      else
 253.915 +      {  lb_changed = npp_implied_lower(npp, q, ll);
 253.916 +         xassert(0 <= lb_changed && lb_changed <= 4);
 253.917 +         if (lb_changed == 4) return 4; /* infeasible */
 253.918 +      }
 253.919 +      /* process implied column upper bound */
 253.920 +      if (uu == +DBL_MAX)
 253.921 +         ub_changed = 0;
 253.922 +      else if (lb_changed == 3)
 253.923 +      {  /* column was fixed on its upper bound due to l'[q] = u[q] */
 253.924 +         /* note that L[p] < U[p], so l'[q] = u[q] < u'[q] */
 253.925 +         ub_changed = 0;
 253.926 +      }
 253.927 +      else
 253.928 +      {  ub_changed = npp_implied_upper(npp, q, uu);
 253.929 +         xassert(0 <= ub_changed && ub_changed <= 4);
 253.930 +         if (ub_changed == 4) return 4; /* infeasible */
 253.931 +      }
 253.932 +      /* if neither lower nor upper column bound was changed, the row
 253.933 +         is originally redundant and can be replaced by free row */
 253.934 +      if (!lb_changed && !ub_changed)
 253.935 +      {  p->lb = -DBL_MAX, p->ub = +DBL_MAX;
 253.936 +         npp_free_row(npp, p);
 253.937 +         return 0;
 253.938 +      }
 253.939 +      /* create transformation stack entry */
 253.940 +      info = npp_push_tse(npp,
 253.941 +         rcv_ineq_singlet, sizeof(struct ineq_singlet));
 253.942 +      info->p = p->i;
 253.943 +      info->q = q->j;
 253.944 +      info->apq = apq->val;
 253.945 +      info->c = q->coef;
 253.946 +      info->lb = p->lb;
 253.947 +      info->ub = p->ub;
 253.948 +      info->lb_changed = (char)lb_changed;
 253.949 +      info->ub_changed = (char)ub_changed;
 253.950 +      info->ptr = NULL;
 253.951 +      /* save column coefficients a[i,q], i != p (not needed for MIP
 253.952 +         solution) */
 253.953 +      if (npp->sol != GLP_MIP)
 253.954 +      {  for (aij = q->ptr; aij != NULL; aij = aij->c_next)
 253.955 +         {  if (aij == apq) continue; /* skip a[p,q] */
 253.956 +            lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
 253.957 +            lfe->ref = aij->row->i;
 253.958 +            lfe->val = aij->val;
 253.959 +            lfe->next = info->ptr;
 253.960 +            info->ptr = lfe;
 253.961 +         }
 253.962 +      }
 253.963 +      /* remove the row from the problem */
 253.964 +      npp_del_row(npp, p);
 253.965 +      return lb_changed >= ub_changed ? lb_changed : ub_changed;
 253.966 +}
 253.967 +
 253.968 +static int rcv_ineq_singlet(NPP *npp, void *_info)
 253.969 +{     /* recover row singleton (inequality constraint) */
 253.970 +      struct ineq_singlet *info = _info;
 253.971 +      NPPLFE *lfe;
 253.972 +      double lambda;
 253.973 +      if (npp->sol == GLP_MIP) goto done;
 253.974 +      /* compute lambda~[q] in solution to the transformed problem
 253.975 +         with formula (8) */
 253.976 +      lambda = info->c;
 253.977 +      for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
 253.978 +         lambda -= lfe->val * npp->r_pi[lfe->ref];
 253.979 +      if (npp->sol == GLP_SOL)
 253.980 +      {  /* recover basic solution */
 253.981 +         if (npp->c_stat[info->q] == GLP_BS)
 253.982 +         {  /* column q is basic, so row p is inactive */
 253.983 +            npp->r_stat[info->p] = GLP_BS;
 253.984 +            npp->r_pi[info->p] = 0.0;
 253.985 +         }
 253.986 +         else if (npp->c_stat[info->q] == GLP_NL)
 253.987 +nl:      {  /* column q is non-basic with lower bound active */
 253.988 +            if (info->lb_changed)
 253.989 +            {  /* it is implied bound, so actually row p is active
 253.990 +                  while column q is basic */
 253.991 +               npp->r_stat[info->p] =
 253.992 +                  (char)(info->apq > 0.0 ? GLP_NL : GLP_NU);
 253.993 +               npp->c_stat[info->q] = GLP_BS;
 253.994 +               npp->r_pi[info->p] = lambda / info->apq;
 253.995 +            }
 253.996 +            else
 253.997 +            {  /* it is original bound, so row p is inactive */
 253.998 +               npp->r_stat[info->p] = GLP_BS;
 253.999 +               npp->r_pi[info->p] = 0.0;
253.1000 +            }
253.1001 +         }
253.1002 +         else if (npp->c_stat[info->q] == GLP_NU)
253.1003 +nu:      {  /* column q is non-basic with upper bound active */
253.1004 +            if (info->ub_changed)
253.1005 +            {  /* it is implied bound, so actually row p is active
253.1006 +                  while column q is basic */
253.1007 +               npp->r_stat[info->p] =
253.1008 +                  (char)(info->apq > 0.0 ? GLP_NU : GLP_NL);
253.1009 +               npp->c_stat[info->q] = GLP_BS;
253.1010 +               npp->r_pi[info->p] = lambda / info->apq;
253.1011 +            }
253.1012 +            else
253.1013 +            {  /* it is original bound, so row p is inactive */
253.1014 +               npp->r_stat[info->p] = GLP_BS;
253.1015 +               npp->r_pi[info->p] = 0.0;
253.1016 +            }
253.1017 +         }
253.1018 +         else if (npp->c_stat[info->q] == GLP_NS)
253.1019 +         {  /* column q is non-basic and fixed; note, however, that in
253.1020 +               in the original problem it is non-fixed */
253.1021 +            if (lambda > +1e-7)
253.1022 +            {  if (info->apq > 0.0 && info->lb != -DBL_MAX ||
253.1023 +                   info->apq < 0.0 && info->ub != +DBL_MAX ||
253.1024 +                  !info->lb_changed)
253.1025 +               {  /* either corresponding bound of row p exists or
253.1026 +                     column q remains non-basic with its original lower
253.1027 +                     bound active */
253.1028 +                  npp->c_stat[info->q] = GLP_NL;
253.1029 +                  goto nl;
253.1030 +               }
253.1031 +            }
253.1032 +            if (lambda < -1e-7)
253.1033 +            {  if (info->apq > 0.0 && info->ub != +DBL_MAX ||
253.1034 +                   info->apq < 0.0 && info->lb != -DBL_MAX ||
253.1035 +                  !info->ub_changed)
253.1036 +               {  /* either corresponding bound of row p exists or
253.1037 +                     column q remains non-basic with its original upper
253.1038 +                     bound active */
253.1039 +                  npp->c_stat[info->q] = GLP_NU;
253.1040 +                  goto nu;
253.1041 +               }
253.1042 +            }
253.1043 +            /* either lambda~[q] is close to zero, or corresponding
253.1044 +               bound of row p does not exist, because lambda~[q] has
253.1045 +               wrong sign due to round-off errors; in the latter case
253.1046 +               lambda~[q] is also assumed to be close to zero; so, we
253.1047 +               can make row p active on its existing bound and column q
253.1048 +               basic; pi[p] will have wrong sign, but it also will be
253.1049 +               close to zero (rarus casus of dual degeneracy) */
253.1050 +            if (info->lb != -DBL_MAX && info->ub == +DBL_MAX)
253.1051 +            {  /* row lower bound exists, but upper bound doesn't */
253.1052 +               npp->r_stat[info->p] = GLP_NL;
253.1053 +            }
253.1054 +            else if (info->lb == -DBL_MAX && info->ub != +DBL_MAX)
253.1055 +            {  /* row upper bound exists, but lower bound doesn't */
253.1056 +               npp->r_stat[info->p] = GLP_NU;
253.1057 +            }
253.1058 +            else if (info->lb != -DBL_MAX && info->ub != +DBL_MAX)
253.1059 +            {  /* both row lower and upper bounds exist */
253.1060 +               /* to choose proper active row bound we should not use
253.1061 +                  lambda~[q], because its value being close to zero is
253.1062 +                  unreliable; so we choose that bound which provides
253.1063 +                  primal feasibility for original constraint (1) */
253.1064 +               if (info->apq * npp->c_value[info->q] <=
253.1065 +                   0.5 * (info->lb + info->ub))
253.1066 +                  npp->r_stat[info->p] = GLP_NL;
253.1067 +               else
253.1068 +                  npp->r_stat[info->p] = GLP_NU;
253.1069 +            }
253.1070 +            else
253.1071 +            {  npp_error();
253.1072 +               return 1;
253.1073 +            }
253.1074 +            npp->c_stat[info->q] = GLP_BS;
253.1075 +            npp->r_pi[info->p] = lambda / info->apq;
253.1076 +         }
253.1077 +         else
253.1078 +         {  npp_error();
253.1079 +            return 1;
253.1080 +         }
253.1081 +      }
253.1082 +      if (npp->sol == GLP_IPT)
253.1083 +      {  /* recover interior-point solution */
253.1084 +         if (lambda > +DBL_EPSILON && info->lb_changed ||
253.1085 +             lambda < -DBL_EPSILON && info->ub_changed)
253.1086 +         {  /* actually row p has corresponding active bound */
253.1087 +            npp->r_pi[info->p] = lambda / info->apq;
253.1088 +         }
253.1089 +         else
253.1090 +         {  /* either bounds of column q are both inactive or its
253.1091 +               original bound is active */
253.1092 +            npp->r_pi[info->p] = 0.0;
253.1093 +         }
253.1094 +      }
253.1095 +done: return 0;
253.1096 +}
253.1097 +
253.1098 +/***********************************************************************
253.1099 +*  NAME
253.1100 +*
253.1101 +*  npp_implied_slack - process column singleton (implied slack variable)
253.1102 +*
253.1103 +*  SYNOPSIS
253.1104 +*
253.1105 +*  #include "glpnpp.h"
253.1106 +*  void npp_implied_slack(NPP *npp, NPPCOL *q);
253.1107 +*
253.1108 +*  DESCRIPTION
253.1109 +*
253.1110 +*  The routine npp_implied_slack processes column q:
253.1111 +*
253.1112 +*     l[q] <= x[q] <= u[q],                                          (1)
253.1113 +*
253.1114 +*  where l[q] < u[q], having the only non-zero coefficient in row p,
253.1115 +*  which is equality constraint:
253.1116 +*
253.1117 +*     sum a[p,j] x[j] + a[p,q] x[q] = b.                             (2)
253.1118 +*     j!=q
253.1119 +*
253.1120 +*  PROBLEM TRANSFORMATION
253.1121 +*
253.1122 +*  (If x[q] is integral, this transformation must not be used.)
253.1123 +*
253.1124 +*  The term a[p,q] x[q] in constraint (2) can be considered as a slack
253.1125 +*  variable that allows to carry bounds of column q over row p and then
253.1126 +*  remove column q from the problem.
253.1127 +*
253.1128 +*  Constraint (2) can be written as follows:
253.1129 +*
253.1130 +*     sum a[p,j] x[j] = b - a[p,q] x[q].                             (3)
253.1131 +*     j!=q
253.1132 +*
253.1133 +*  According to (1) constraint (3) is equivalent to the following
253.1134 +*  inequality constraint:
253.1135 +*
253.1136 +*     L[p] <= sum a[p,j] x[j] <= U[p],                               (4)
253.1137 +*             j!=q
253.1138 +*
253.1139 +*  where
253.1140 +*
253.1141 +*            ( b - a[p,q] u[q],  if a[p,q] > 0
253.1142 +*     L[p] = <                                                       (5)
253.1143 +*            ( b - a[p,q] l[q],  if a[p,q] < 0
253.1144 +*
253.1145 +*            ( b - a[p,q] l[q],  if a[p,q] > 0
253.1146 +*     U[p] = <                                                       (6)
253.1147 +*            ( b - a[p,q] u[q],  if a[p,q] < 0
253.1148 +*
253.1149 +*  From (2) it follows that:
253.1150 +*
253.1151 +*              1
253.1152 +*     x[q] = ------ (b - sum a[p,j] x[j]).                           (7)
253.1153 +*            a[p,q]      j!=q
253.1154 +*
253.1155 +*  In order to eliminate x[q] from the objective row we substitute it
253.1156 +*  from (6) to that row:
253.1157 +*
253.1158 +*     z = sum c[j] x[j] + c[q] x[q] + c[0] =
253.1159 +*         j!=q
253.1160 +*                                 1
253.1161 +*       = sum c[j] x[j] + c[q] [------ (b - sum a[p,j] x[j])] + c0 =
253.1162 +*         j!=q                  a[p,q]      j!=q
253.1163 +*
253.1164 +*       = sum c~[j] x[j] + c~[0],
253.1165 +*         j!=q
253.1166 +*                         a[p,j]                     b
253.1167 +*     c~[j] = c[j] - c[q] ------,  c~0 = c0 - c[q] ------            (8)
253.1168 +*                         a[p,q]                   a[p,q]
253.1169 +*
253.1170 +*  are values of objective coefficients and constant term, resp., in
253.1171 +*  the transformed problem.
253.1172 +*
253.1173 +*  Note that column q is column singleton, so in the dual system of the
253.1174 +*  original problem it corresponds to the following row singleton:
253.1175 +*
253.1176 +*     a[p,q] pi[p] + lambda[q] = c[q].                               (9)
253.1177 +*
253.1178 +*  In the transformed problem row (9) would be the following:
253.1179 +*
253.1180 +*     a[p,q] pi~[p] + lambda[q] = c~[q] = 0.                        (10)
253.1181 +*
253.1182 +*  Subtracting (10) from (9) we have:
253.1183 +*
253.1184 +*     a[p,q] (pi[p] - pi~[p]) = c[q]
253.1185 +*
253.1186 +*  that gives the following formula to compute multiplier for row p in
253.1187 +*  solution to the original problem using its value in solution to the
253.1188 +*  transformed problem:
253.1189 +*
253.1190 +*     pi[p] = pi~[p] + c[q] / a[p,q].                               (11)
253.1191 +*
253.1192 +*  RECOVERING BASIC SOLUTION
253.1193 +*
253.1194 +*  Status of column q in solution to the original problem is defined
253.1195 +*  by status of row p in solution to the transformed problem and the
253.1196 +*  sign of coefficient a[p,q] in the original inequality constraint (2)
253.1197 +*  as follows:
253.1198 +*
253.1199 +*     +-----------------------+---------+--------------------+
253.1200 +*     |    Status of row p    | Sign of | Status of column q |
253.1201 +*     | (transformed problem) | a[p,q]  | (original problem) |
253.1202 +*     +-----------------------+---------+--------------------+
253.1203 +*     |        GLP_BS         |  + / -  |       GLP_BS       |
253.1204 +*     |        GLP_NL         |    +    |       GLP_NU       |
253.1205 +*     |        GLP_NL         |    -    |       GLP_NL       |
253.1206 +*     |        GLP_NU         |    +    |       GLP_NL       |
253.1207 +*     |        GLP_NU         |    -    |       GLP_NU       |
253.1208 +*     |        GLP_NF         |  + / -  |       GLP_NF       |
253.1209 +*     +-----------------------+---------+--------------------+
253.1210 +*
253.1211 +*  Value of column q is computed with formula (7). Since originally row
253.1212 +*  p is equality constraint, its status is assigned GLP_NS, and value of
253.1213 +*  its multiplier pi[p] is computed with formula (11).
253.1214 +*
253.1215 +*  RECOVERING INTERIOR-POINT SOLUTION
253.1216 +*
253.1217 +*  Value of column q is computed with formula (7). Row multiplier value
253.1218 +*  pi[p] is computed with formula (11).
253.1219 +*
253.1220 +*  RECOVERING MIP SOLUTION
253.1221 +*
253.1222 +*  Value of column q is computed with formula (7). */
253.1223 +
253.1224 +struct implied_slack
253.1225 +{     /* column singleton (implied slack variable) */
253.1226 +      int p;
253.1227 +      /* row reference number */
253.1228 +      int q;
253.1229 +      /* column reference number */
253.1230 +      double apq;
253.1231 +      /* constraint coefficient a[p,q] */
253.1232 +      double b;
253.1233 +      /* right-hand side of original equality constraint */
253.1234 +      double c;
253.1235 +      /* original objective coefficient at x[q] */
253.1236 +      NPPLFE *ptr;
253.1237 +      /* list of non-zero coefficients a[p,j], j != q */
253.1238 +};
253.1239 +
253.1240 +static int rcv_implied_slack(NPP *npp, void *info);
253.1241 +
253.1242 +void npp_implied_slack(NPP *npp, NPPCOL *q)
253.1243 +{     /* process column singleton (implied slack variable) */
253.1244 +      struct implied_slack *info;
253.1245 +      NPPROW *p;
253.1246 +      NPPAIJ *aij;
253.1247 +      NPPLFE *lfe;
253.1248 +      /* the column must be non-integral non-fixed singleton */
253.1249 +      xassert(!q->is_int);
253.1250 +      xassert(q->lb < q->ub);
253.1251 +      xassert(q->ptr != NULL && q->ptr->c_next == NULL);
253.1252 +      /* corresponding row must be equality constraint */
253.1253 +      aij = q->ptr;
253.1254 +      p = aij->row;
253.1255 +      xassert(p->lb == p->ub);
253.1256 +      /* create transformation stack entry */
253.1257 +      info = npp_push_tse(npp,
253.1258 +         rcv_implied_slack, sizeof(struct implied_slack));
253.1259 +      info->p = p->i;
253.1260 +      info->q = q->j;
253.1261 +      info->apq = aij->val;
253.1262 +      info->b = p->lb;
253.1263 +      info->c = q->coef;
253.1264 +      info->ptr = NULL;
253.1265 +      /* save row coefficients a[p,j], j != q, and substitute x[q]
253.1266 +         into the objective row */
253.1267 +      for (aij = p->ptr; aij != NULL; aij = aij->r_next)
253.1268 +      {  if (aij->col == q) continue; /* skip a[p,q] */
253.1269 +         lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
253.1270 +         lfe->ref = aij->col->j;
253.1271 +         lfe->val = aij->val;
253.1272 +         lfe->next = info->ptr;
253.1273 +         info->ptr = lfe;
253.1274 +         aij->col->coef -= info->c * (aij->val / info->apq);
253.1275 +      }
253.1276 +      npp->c0 += info->c * (info->b / info->apq);
253.1277 +      /* compute new row bounds */
253.1278 +      if (info->apq > 0.0)
253.1279 +      {  p->lb = (q->ub == +DBL_MAX ?
253.1280 +            -DBL_MAX : info->b - info->apq * q->ub);
253.1281 +         p->ub = (q->lb == -DBL_MAX ?
253.1282 +            +DBL_MAX : info->b - info->apq * q->lb);
253.1283 +      }
253.1284 +      else
253.1285 +      {  p->lb = (q->lb == -DBL_MAX ?
253.1286 +            -DBL_MAX : info->b - info->apq * q->lb);
253.1287 +         p->ub = (q->ub == +DBL_MAX ?
253.1288 +            +DBL_MAX : info->b - info->apq * q->ub);
253.1289 +      }
253.1290 +      /* remove the column from the problem */
253.1291 +      npp_del_col(npp, q);
253.1292 +      return;
253.1293 +}
253.1294 +
253.1295 +static int rcv_implied_slack(NPP *npp, void *_info)
253.1296 +{     /* recover column singleton (implied slack variable) */
253.1297 +      struct implied_slack *info = _info;
253.1298 +      NPPLFE *lfe;
253.1299 +      double temp;
253.1300 +      if (npp->sol == GLP_SOL)
253.1301 +      {  /* assign statuses to row p and column q */
253.1302 +         if (npp->r_stat[info->p] == GLP_BS ||
253.1303 +             npp->r_stat[info->p] == GLP_NF)
253.1304 +            npp->c_stat[info->q] = npp->r_stat[info->p];
253.1305 +         else if (npp->r_stat[info->p] == GLP_NL)
253.1306 +            npp->c_stat[info->q] =
253.1307 +               (char)(info->apq > 0.0 ? GLP_NU : GLP_NL);
253.1308 +         else if (npp->r_stat[info->p] == GLP_NU)
253.1309 +            npp->c_stat[info->q] =
253.1310 +               (char)(info->apq > 0.0 ? GLP_NL : GLP_NU);
253.1311 +         else
253.1312 +         {  npp_error();
253.1313 +            return 1;
253.1314 +         }
253.1315 +         npp->r_stat[info->p] = GLP_NS;
253.1316 +      }
253.1317 +      if (npp->sol != GLP_MIP)
253.1318 +      {  /* compute multiplier for row p */
253.1319 +         npp->r_pi[info->p] += info->c / info->apq;
253.1320 +      }
253.1321 +      /* compute value of column q */
253.1322 +      temp = info->b;
253.1323 +      for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
253.1324 +         temp -= lfe->val * npp->c_value[lfe->ref];
253.1325 +      npp->c_value[info->q] = temp / info->apq;
253.1326 +      return 0;
253.1327 +}
253.1328 +
253.1329 +/***********************************************************************
253.1330 +*  NAME
253.1331 +*
253.1332 +*  npp_implied_free - process column singleton (implied free variable)
253.1333 +*
253.1334 +*  SYNOPSIS
253.1335 +*
253.1336 +*  #include "glpnpp.h"
253.1337 +*  int npp_implied_free(NPP *npp, NPPCOL *q);
253.1338 +*
253.1339 +*  DESCRIPTION
253.1340 +*
253.1341 +*  The routine npp_implied_free processes column q:
253.1342 +*
253.1343 +*     l[q] <= x[q] <= u[q],                                          (1)
253.1344 +*
253.1345 +*  having non-zero coefficient in the only row p, which is inequality
253.1346 +*  constraint:
253.1347 +*
253.1348 +*     L[p] <= sum a[p,j] x[j] + a[p,q] x[q] <= U[p],                 (2)
253.1349 +*             j!=q
253.1350 +*
253.1351 +*  where l[q] < u[q], L[p] < U[p], L[p] > -oo and/or U[p] < +oo.
253.1352 +*
253.1353 +*  RETURNS
253.1354 +*
253.1355 +*  0 - success;
253.1356 +*
253.1357 +*  1 - column lower and/or upper bound(s) can be active;
253.1358 +*
253.1359 +*  2 - problem has no dual feasible solution.
253.1360 +*
253.1361 +*  PROBLEM TRANSFORMATION
253.1362 +*
253.1363 +*  Constraint (2) can be written as follows:
253.1364 +*
253.1365 +*     L[p] - sum a[p,j] x[j] <= a[p,q] x[q] <= U[p] - sum a[p,j] x[j],
253.1366 +*            j!=q                                     j!=q
253.1367 +*
253.1368 +*  from which it follows that:
253.1369 +*
253.1370 +*     alfa <= a[p,q] x[q] <= beta,                                   (3)
253.1371 +*
253.1372 +*  where
253.1373 +*
253.1374 +*     alfa = inf(L[p] - sum a[p,j] x[j]) =
253.1375 +*                       j!=q
253.1376 +*
253.1377 +*          = L[p] - sup sum a[p,j] x[j] =                            (4)
253.1378 +*                       j!=q
253.1379 +*
253.1380 +*          = L[p] -  sum  a[p,j] u[j] -  sum  a[p,j] l[j],
253.1381 +*                  j in Jp             j in Jn
253.1382 +*
253.1383 +*     beta = sup(L[p] - sum a[p,j] x[j]) =
253.1384 +*                       j!=q
253.1385 +*
253.1386 +*          = L[p] - inf sum a[p,j] x[j] =                            (5)
253.1387 +*                       j!=q
253.1388 +*
253.1389 +*          = L[p] -  sum  a[p,j] l[j] -  sum  a[p,j] u[j],
253.1390 +*                  j in Jp             j in Jn
253.1391 +*
253.1392 +*     Jp = {j != q: a[p,j] > 0},  Jn = {j != q: a[p,j] < 0}.         (6)
253.1393 +*
253.1394 +*  Inequality (3) defines implied bounds of variable x[q]:
253.1395 +*
253.1396 +*     l'[q] <= x[q] <= u'[q],                                        (7)
253.1397 +*
253.1398 +*  where
253.1399 +*
253.1400 +*             ( alfa / a[p,q], if a[p,q] > 0
253.1401 +*     l'[q] = <                                                     (8a)
253.1402 +*             ( beta / a[p,q], if a[p,q] < 0
253.1403 +*
253.1404 +*             ( beta / a[p,q], if a[p,q] > 0
253.1405 +*     u'[q] = <                                                     (8b)
253.1406 +*             ( alfa / a[p,q], if a[p,q] < 0
253.1407 +*
253.1408 +*  Thus, if l'[q] > l[q] - eps and u'[q] < u[q] + eps, where eps is
253.1409 +*  an absolute tolerance for column value, column bounds (1) cannot be
253.1410 +*  active, in which case column q can be replaced by equivalent free
253.1411 +*  (unbounded) column.
253.1412 +*
253.1413 +*  Note that column q is column singleton, so in the dual system of the
253.1414 +*  original problem it corresponds to the following row singleton:
253.1415 +*
253.1416 +*     a[p,q] pi[p] + lambda[q] = c[q],                               (9)
253.1417 +*
253.1418 +*  from which it follows that:
253.1419 +*
253.1420 +*     pi[p] = (c[q] - lambda[q]) / a[p,q].                          (10)
253.1421 +*
253.1422 +*  Let x[q] be implied free (unbounded) variable. Then column q can be
253.1423 +*  only basic, so its multiplier lambda[q] is equal to zero, and from
253.1424 +*  (10) we have:
253.1425 +*
253.1426 +*     pi[p] = c[q] / a[p,q].                                        (11)
253.1427 +*
253.1428 +*  There are possible three cases:
253.1429 +*
253.1430 +*  1) pi[p] < -eps, where eps is an absolute tolerance for row
253.1431 +*     multiplier. In this case, to provide dual feasibility of the
253.1432 +*     original problem, row p must be active on its lower bound, and
253.1433 +*     if its lower bound does not exist (L[p] = -oo), the problem has
253.1434 +*     no dual feasible solution;
253.1435 +*
253.1436 +*  2) pi[p] > +eps. In this case row p must be active on its upper
253.1437 +*     bound, and if its upper bound does not exist (U[p] = +oo), the
253.1438 +*     problem has no dual feasible solution;
253.1439 +*
253.1440 +*  3) -eps <= pi[p] <= +eps. In this case any (either lower or upper)
253.1441 +*     bound of row p can be active, because this does not affect dual
253.1442 +*     feasibility.
253.1443 +*
253.1444 +*  Thus, in all three cases original inequality constraint (2) can be
253.1445 +*  replaced by equality constraint, where the right-hand side is either
253.1446 +*  lower or upper bound of row p, and bounds of column q can be removed
253.1447 +*  that makes it free (unbounded). (May note that this transformation
253.1448 +*  can be followed by transformation "Column singleton (implied slack
253.1449 +*  variable)" performed by the routine npp_implied_slack.)
253.1450 +*
253.1451 +*  RECOVERING BASIC SOLUTION
253.1452 +*
253.1453 +*  Status of row p in solution to the original problem is determined
253.1454 +*  by its status in solution to the transformed problem and its bound,
253.1455 +*  which was choosen to be active:
253.1456 +*
253.1457 +*     +-----------------------+--------+--------------------+
253.1458 +*     |    Status of row p    | Active | Status of row p    |
253.1459 +*     | (transformed problem) | bound  | (original problem) |
253.1460 +*     +-----------------------+--------+--------------------+
253.1461 +*     |        GLP_BS         |  L[p]  |       GLP_BS       |
253.1462 +*     |        GLP_BS         |  U[p]  |       GLP_BS       |
253.1463 +*     |        GLP_NS         |  L[p]  |       GLP_NL       |
253.1464 +*     |        GLP_NS         |  U[p]  |       GLP_NU       |
253.1465 +*     +-----------------------+--------+--------------------+
253.1466 +*
253.1467 +*  Value of row multiplier pi[p] (as well as value of column q) in
253.1468 +*  solution to the original problem is the same as in solution to the
253.1469 +*  transformed problem.
253.1470 +*
253.1471 +*  RECOVERING INTERIOR-POINT SOLUTION
253.1472 +*
253.1473 +*  Value of row multiplier pi[p] in solution to the original problem is
253.1474 +*  the same as in solution to the transformed problem.
253.1475 +*
253.1476 +*  RECOVERING MIP SOLUTION
253.1477 +*
253.1478 +*  None needed. */
253.1479 +
253.1480 +struct implied_free
253.1481 +{     /* column singleton (implied free variable) */
253.1482 +      int p;
253.1483 +      /* row reference number */
253.1484 +      char stat;
253.1485 +      /* row status:
253.1486 +         GLP_NL - active constraint on lower bound
253.1487 +         GLP_NU - active constraint on upper bound */
253.1488 +};
253.1489 +
253.1490 +static int rcv_implied_free(NPP *npp, void *info);
253.1491 +
253.1492 +int npp_implied_free(NPP *npp, NPPCOL *q)
253.1493 +{     /* process column singleton (implied free variable) */
253.1494 +      struct implied_free *info;
253.1495 +      NPPROW *p;
253.1496 +      NPPAIJ *apq, *aij;
253.1497 +      double alfa, beta, l, u, pi, eps;
253.1498 +      /* the column must be non-fixed singleton */
253.1499 +      xassert(q->lb < q->ub);
253.1500 +      xassert(q->ptr != NULL && q->ptr->c_next == NULL);
253.1501 +      /* corresponding row must be inequality constraint */
253.1502 +      apq = q->ptr;
253.1503 +      p = apq->row;
253.1504 +      xassert(p->lb != -DBL_MAX || p->ub != +DBL_MAX);
253.1505 +      xassert(p->lb < p->ub);
253.1506 +      /* compute alfa */
253.1507 +      alfa = p->lb;
253.1508 +      if (alfa != -DBL_MAX)
253.1509 +      {  for (aij = p->ptr; aij != NULL; aij = aij->r_next)
253.1510 +         {  if (aij == apq) continue; /* skip a[p,q] */
253.1511 +            if (aij->val > 0.0)
253.1512 +            {  if (aij->col->ub == +DBL_MAX)
253.1513 +               {  alfa = -DBL_MAX;
253.1514 +                  break;
253.1515 +               }
253.1516 +               alfa -= aij->val * aij->col->ub;
253.1517 +            }
253.1518 +            else /* < 0.0 */
253.1519 +            {  if (aij->col->lb == -DBL_MAX)
253.1520 +               {  alfa = -DBL_MAX;
253.1521 +                  break;
253.1522 +               }
253.1523 +               alfa -= aij->val * aij->col->lb;
253.1524 +            }
253.1525 +         }
253.1526 +      }
253.1527 +      /* compute beta */
253.1528 +      beta = p->ub;
253.1529 +      if (beta != +DBL_MAX)
253.1530 +      {  for (aij = p->ptr; aij != NULL; aij = aij->r_next)
253.1531 +         {  if (aij == apq) continue; /* skip a[p,q] */
253.1532 +            if (aij->val > 0.0)
253.1533 +            {  if (aij->col->lb == -DBL_MAX)
253.1534 +               {  beta = +DBL_MAX;
253.1535 +                  break;
253.1536 +               }
253.1537 +               beta -= aij->val * aij->col->lb;
253.1538 +            }
253.1539 +            else /* < 0.0 */
253.1540 +            {  if (aij->col->ub == +DBL_MAX)
253.1541 +               {  beta = +DBL_MAX;
253.1542 +                  break;
253.1543 +               }
253.1544 +               beta -= aij->val * aij->col->ub;
253.1545 +            }
253.1546 +         }
253.1547 +      }
253.1548 +      /* compute implied column lower bound l'[q] */
253.1549 +      if (apq->val > 0.0)
253.1550 +         l = (alfa == -DBL_MAX ? -DBL_MAX : alfa / apq->val);
253.1551 +      else /* < 0.0 */
253.1552 +         l = (beta == +DBL_MAX ? -DBL_MAX : beta / apq->val);
253.1553 +      /* compute implied column upper bound u'[q] */
253.1554 +      if (apq->val > 0.0)
253.1555 +         u = (beta == +DBL_MAX ? +DBL_MAX : beta / apq->val);
253.1556 +      else
253.1557 +         u = (alfa == -DBL_MAX ? +DBL_MAX : alfa / apq->val);
253.1558 +      /* check if column lower bound l[q] can be active */
253.1559 +      if (q->lb != -DBL_MAX)
253.1560 +      {  eps = 1e-9 + 1e-12 * fabs(q->lb);
253.1561 +         if (l < q->lb - eps) return 1; /* yes, it can */
253.1562 +      }
253.1563 +      /* check if column upper bound u[q] can be active */
253.1564 +      if (q->ub != +DBL_MAX)
253.1565 +      {  eps = 1e-9 + 1e-12 * fabs(q->ub);
253.1566 +         if (u > q->ub + eps) return 1; /* yes, it can */
253.1567 +      }
253.1568 +      /* okay; make column q free (unbounded) */
253.1569 +      q->lb = -DBL_MAX, q->ub = +DBL_MAX;
253.1570 +      /* create transformation stack entry */
253.1571 +      info = npp_push_tse(npp,
253.1572 +         rcv_implied_free, sizeof(struct implied_free));
253.1573 +      info->p = p->i;
253.1574 +      info->stat = -1;
253.1575 +      /* compute row multiplier pi[p] */
253.1576 +      pi = q->coef / apq->val;
253.1577 +      /* check dual feasibility for row p */
253.1578 +      if (pi > +DBL_EPSILON)
253.1579 +      {  /* lower bound L[p] must be active */
253.1580 +         if (p->lb != -DBL_MAX)
253.1581 +nl:      {  info->stat = GLP_NL;
253.1582 +            p->ub = p->lb;
253.1583 +         }
253.1584 +         else
253.1585 +         {  if (pi > +1e-5) return 2; /* dual infeasibility */
253.1586 +            /* take a chance on U[p] */
253.1587 +            xassert(p->ub != +DBL_MAX);
253.1588 +            goto nu;
253.1589 +         }
253.1590 +      }
253.1591 +      else if (pi < -DBL_EPSILON)
253.1592 +      {  /* upper bound U[p] must be active */
253.1593 +         if (p->ub != +DBL_MAX)
253.1594 +nu:      {  info->stat = GLP_NU;
253.1595 +            p->lb = p->ub;
253.1596 +         }
253.1597 +         else
253.1598 +         {  if (pi < -1e-5) return 2; /* dual infeasibility */
253.1599 +            /* take a chance on L[p] */
253.1600 +            xassert(p->lb != -DBL_MAX);
253.1601 +            goto nl;
253.1602 +         }
253.1603 +      }
253.1604 +      else
253.1605 +      {  /* any bound (either L[p] or U[p]) can be made active  */
253.1606 +         if (p->ub == +DBL_MAX)
253.1607 +         {  xassert(p->lb != -DBL_MAX);
253.1608 +            goto nl;
253.1609 +         }
253.1610 +         if (p->lb == -DBL_MAX)
253.1611 +         {  xassert(p->ub != +DBL_MAX);
253.1612 +            goto nu;
253.1613 +         }
253.1614 +         if (fabs(p->lb) <= fabs(p->ub)) goto nl; else goto nu;
253.1615 +      }
253.1616 +      return 0;
253.1617 +}
253.1618 +
253.1619 +static int rcv_implied_free(NPP *npp, void *_info)
253.1620 +{     /* recover column singleton (implied free variable) */
253.1621 +      struct implied_free *info = _info;
253.1622 +      if (npp->sol == GLP_SOL)
253.1623 +      {  if (npp->r_stat[info->p] == GLP_BS)
253.1624 +            npp->r_stat[info->p] = GLP_BS;
253.1625 +         else if (npp->r_stat[info->p] == GLP_NS)
253.1626 +         {  xassert(info->stat == GLP_NL || info->stat == GLP_NU);
253.1627 +            npp->r_stat[info->p] = info->stat;
253.1628 +         }
253.1629 +         else
253.1630 +         {  npp_error();
253.1631 +            return 1;
253.1632 +         }
253.1633 +      }
253.1634 +      return 0;
253.1635 +}
253.1636 +
253.1637 +/***********************************************************************
253.1638 +*  NAME
253.1639 +*
253.1640 +*  npp_eq_doublet - process row doubleton (equality constraint)
253.1641 +*
253.1642 +*  SYNOPSIS
253.1643 +*
253.1644 +*  #include "glpnpp.h"
253.1645 +*  NPPCOL *npp_eq_doublet(NPP *npp, NPPROW *p);
253.1646 +*
253.1647 +*  DESCRIPTION
253.1648 +*
253.1649 +*  The routine npp_eq_doublet processes row p, which is equality
253.1650 +*  constraint having exactly two non-zero coefficients:
253.1651 +*
253.1652 +*     a[p,q] x[q] + a[p,r] x[r] = b.                                 (1)
253.1653 +*
253.1654 +*  As the result of processing one of columns q or r is eliminated from
253.1655 +*  all other rows and, thus, becomes column singleton of type "implied
253.1656 +*  slack variable". Row p is not changed and along with column q and r
253.1657 +*  remains in the problem.
253.1658 +*
253.1659 +*  RETURNS
253.1660 +*
253.1661 +*  The routine npp_eq_doublet returns pointer to the descriptor of that
253.1662 +*  column q or r which has been eliminated. If, due to some reason, the
253.1663 +*  elimination was not performed, the routine returns NULL.
253.1664 +*
253.1665 +*  PROBLEM TRANSFORMATION
253.1666 +*
253.1667 +*  First, we decide which column q or r will be eliminated. Let it be
253.1668 +*  column q. Consider i-th constraint row, where column q has non-zero
253.1669 +*  coefficient a[i,q] != 0:
253.1670 +*
253.1671 +*     L[i] <= sum a[i,j] x[j] <= U[i].                               (2)
253.1672 +*              j
253.1673 +*
253.1674 +*  In order to eliminate column q from row (2) we subtract from it row
253.1675 +*  (1) multiplied by gamma[i] = a[i,q] / a[p,q], i.e. we replace in the
253.1676 +*  transformed problem row (2) by its linear combination with row (1).
253.1677 +*  This transformation changes only coefficients in columns q and r,
253.1678 +*  and bounds of row i as follows:
253.1679 +*
253.1680 +*     a~[i,q] = a[i,q] - gamma[i] a[p,q] = 0,                        (3)
253.1681 +*
253.1682 +*     a~[i,r] = a[i,r] - gamma[i] a[p,r],                            (4)
253.1683 +*
253.1684 +*       L~[i] = L[i] - gamma[i] b,                                   (5)
253.1685 +*
253.1686 +*       U~[i] = U[i] - gamma[i] b.                                   (6)
253.1687 +*
253.1688 +*  RECOVERING BASIC SOLUTION
253.1689 +*
253.1690 +*  The transformation of the primal system of the original problem:
253.1691 +*
253.1692 +*     L <= A x <= U                                                  (7)
253.1693 +*
253.1694 +*  is equivalent to multiplying from the left a transformation matrix F
253.1695 +*  by components of this primal system, which in the transformed problem
253.1696 +*  becomes the following:
253.1697 +*
253.1698 +*     F L <= F A x <= F U  ==>  L~ <= A~x <= U~.                     (8)
253.1699 +*
253.1700 +*  The matrix F has the following structure:
253.1701 +*
253.1702 +*         ( 1           -gamma[1]            )
253.1703 +*         (                                  )
253.1704 +*         (    1        -gamma[2]            )
253.1705 +*         (                                  )
253.1706 +*         (      ...       ...               )
253.1707 +*         (                                  )
253.1708 +*     F = (          1  -gamma[p-1]          )                       (9)
253.1709 +*         (                                  )
253.1710 +*         (                 1                )
253.1711 +*         (                                  )
253.1712 +*         (             -gamma[p+1]  1       )
253.1713 +*         (                                  )
253.1714 +*         (                ...          ...  )
253.1715 +*
253.1716 +*  where its column containing elements -gamma[i] corresponds to row p
253.1717 +*  of the primal system.
253.1718 +*
253.1719 +*  From (8) it follows that the dual system of the original problem:
253.1720 +*
253.1721 +*     A'pi + lambda = c,                                            (10)
253.1722 +*
253.1723 +*  in the transformed problem becomes the following:
253.1724 +*
253.1725 +*     A'F'inv(F')pi + lambda = c  ==>  (A~)'pi~ + lambda = c,       (11)
253.1726 +*
253.1727 +*  where:
253.1728 +*
253.1729 +*     pi~ = inv(F')pi                                               (12)
253.1730 +*
253.1731 +*  is the vector of row multipliers in the transformed problem. Thus:
253.1732 +*
253.1733 +*     pi = F'pi~.                                                   (13)
253.1734 +*
253.1735 +*  Therefore, as it follows from (13), value of multiplier for row p in
253.1736 +*  solution to the original problem can be computed as follows:
253.1737 +*
253.1738 +*     pi[p] = pi~[p] - sum gamma[i] pi~[i],                         (14)
253.1739 +*                       i
253.1740 +*
253.1741 +*  where pi~[i] = pi[i] is multiplier for row i (i != p).
253.1742 +*
253.1743 +*  Note that the statuses of all rows and columns are not changed.
253.1744 +*
253.1745 +*  RECOVERING INTERIOR-POINT SOLUTION
253.1746 +*
253.1747 +*  Multiplier for row p in solution to the original problem is computed
253.1748 +*  with formula (14).
253.1749 +*
253.1750 +*  RECOVERING MIP SOLUTION
253.1751 +*
253.1752 +*  None needed. */
253.1753 +
253.1754 +struct eq_doublet
253.1755 +{     /* row doubleton (equality constraint) */
253.1756 +      int p;
253.1757 +      /* row reference number */
253.1758 +      double apq;
253.1759 +      /* constraint coefficient a[p,q] */
253.1760 +      NPPLFE *ptr;
253.1761 +      /* list of non-zero coefficients a[i,q], i != p */
253.1762 +};
253.1763 +
253.1764 +static int rcv_eq_doublet(NPP *npp, void *info);
253.1765 +
253.1766 +NPPCOL *npp_eq_doublet(NPP *npp, NPPROW *p)
253.1767 +{     /* process row doubleton (equality constraint) */
253.1768 +      struct eq_doublet *info;
253.1769 +      NPPROW *i;
253.1770 +      NPPCOL *q, *r;
253.1771 +      NPPAIJ *apq, *apr, *aiq, *air, *next;
253.1772 +      NPPLFE *lfe;
253.1773 +      double gamma;
253.1774 +      /* the row must be doubleton equality constraint */
253.1775 +      xassert(p->lb == p->ub);
253.1776 +      xassert(p->ptr != NULL && p->ptr->r_next != NULL &&
253.1777 +              p->ptr->r_next->r_next == NULL);
253.1778 +      /* choose column to be eliminated */
253.1779 +      {  NPPAIJ *a1, *a2;
253.1780 +         a1 = p->ptr, a2 = a1->r_next;
253.1781 +         if (fabs(a2->val) < 0.001 * fabs(a1->val))
253.1782 +         {  /* only first column can be eliminated, because second one
253.1783 +               has too small constraint coefficient */
253.1784 +            apq = a1, apr = a2;
253.1785 +         }
253.1786 +         else if (fabs(a1->val) < 0.001 * fabs(a2->val))
253.1787 +         {  /* only second column can be eliminated, because first one
253.1788 +               has too small constraint coefficient */
253.1789 +            apq = a2, apr = a1;
253.1790 +         }
253.1791 +         else
253.1792 +         {  /* both columns are appropriate; choose that one which is
253.1793 +               shorter to minimize fill-in */
253.1794 +            if (npp_col_nnz(npp, a1->col) <= npp_col_nnz(npp, a2->col))
253.1795 +            {  /* first column is shorter */
253.1796 +               apq = a1, apr = a2;
253.1797 +            }
253.1798 +            else
253.1799 +            {  /* second column is shorter */
253.1800 +               apq = a2, apr = a1;
253.1801 +            }
253.1802 +         }
253.1803 +      }
253.1804 +      /* now columns q and r have been chosen */
253.1805 +      q = apq->col, r = apr->col;
253.1806 +      /* create transformation stack entry */
253.1807 +      info = npp_push_tse(npp,
253.1808 +         rcv_eq_doublet, sizeof(struct eq_doublet));
253.1809 +      info->p = p->i;
253.1810 +      info->apq = apq->val;
253.1811 +      info->ptr = NULL;
253.1812 +      /* transform each row i (i != p), where a[i,q] != 0, to eliminate
253.1813 +         column q */
253.1814 +      for (aiq = q->ptr; aiq != NULL; aiq = next)
253.1815 +      {  next = aiq->c_next;
253.1816 +         if (aiq == apq) continue; /* skip row p */
253.1817 +         i = aiq->row; /* row i to be transformed */
253.1818 +         /* save constraint coefficient a[i,q] */
253.1819 +         if (npp->sol != GLP_MIP)
253.1820 +         {  lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
253.1821 +            lfe->ref = i->i;
253.1822 +            lfe->val = aiq->val;
253.1823 +            lfe->next = info->ptr;
253.1824 +            info->ptr = lfe;
253.1825 +         }
253.1826 +         /* find coefficient a[i,r] in row i */
253.1827 +         for (air = i->ptr; air != NULL; air = air->r_next)
253.1828 +            if (air->col == r) break;
253.1829 +         /* if a[i,r] does not exist, create a[i,r] = 0 */
253.1830 +         if (air == NULL)
253.1831 +            air = npp_add_aij(npp, i, r, 0.0);
253.1832 +         /* compute gamma[i] = a[i,q] / a[p,q] */
253.1833 +         gamma = aiq->val / apq->val;
253.1834 +         /* (row i) := (row i) - gamma[i] * (row p); see (3)-(6) */
253.1835 +         /* new a[i,q] is exact zero due to elimnation; remove it from
253.1836 +            row i */
253.1837 +         npp_del_aij(npp, aiq);
253.1838 +         /* compute new a[i,r] */
253.1839 +         air->val -= gamma * apr->val;
253.1840 +         /* if new a[i,r] is close to zero due to numeric cancelation,
253.1841 +            remove it from row i */
253.1842 +         if (fabs(air->val) <= 1e-10)
253.1843 +            npp_del_aij(npp, air);
253.1844 +         /* compute new lower and upper bounds of row i */
253.1845 +         if (i->lb == i->ub)
253.1846 +            i->lb = i->ub = (i->lb - gamma * p->lb);
253.1847 +         else
253.1848 +         {  if (i->lb != -DBL_MAX)
253.1849 +               i->lb -= gamma * p->lb;
253.1850 +            if (i->ub != +DBL_MAX)
253.1851 +               i->ub -= gamma * p->lb;
253.1852 +         }
253.1853 +      }
253.1854 +      return q;
253.1855 +}
253.1856 +
253.1857 +static int rcv_eq_doublet(NPP *npp, void *_info)
253.1858 +{     /* recover row doubleton (equality constraint) */
253.1859 +      struct eq_doublet *info = _info;
253.1860 +      NPPLFE *lfe;
253.1861 +      double gamma, temp;
253.1862 +      /* we assume that processing row p is followed by processing
253.1863 +         column q as singleton of type "implied slack variable", in
253.1864 +         which case row p must always be active equality constraint */
253.1865 +      if (npp->sol == GLP_SOL)
253.1866 +      {  if (npp->r_stat[info->p] != GLP_NS)
253.1867 +         {  npp_error();
253.1868 +            return 1;
253.1869 +         }
253.1870 +      }
253.1871 +      if (npp->sol != GLP_MIP)
253.1872 +      {  /* compute value of multiplier for row p; see (14) */
253.1873 +         temp = npp->r_pi[info->p];
253.1874 +         for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
253.1875 +         {  gamma = lfe->val / info->apq; /* a[i,q] / a[p,q] */
253.1876 +            temp -= gamma * npp->r_pi[lfe->ref];
253.1877 +         }
253.1878 +         npp->r_pi[info->p] = temp;
253.1879 +      }
253.1880 +      return 0;
253.1881 +}
253.1882 +
253.1883 +/***********************************************************************
253.1884 +*  NAME
253.1885 +*
253.1886 +*  npp_forcing_row - process forcing row
253.1887 +*
253.1888 +*  SYNOPSIS
253.1889 +*
253.1890 +*  #include "glpnpp.h"
253.1891 +*  int npp_forcing_row(NPP *npp, NPPROW *p, int at);
253.1892 +*
253.1893 +*  DESCRIPTION
253.1894 +*
253.1895 +*  The routine npp_forcing row processes row p of general format:
253.1896 +*
253.1897 +*     L[p] <= sum a[p,j] x[j] <= U[p],                               (1)
253.1898 +*              j
253.1899 +*
253.1900 +*     l[j] <= x[j] <= u[j],                                          (2)
253.1901 +*
253.1902 +*  where L[p] <= U[p] and l[j] < u[j] for all a[p,j] != 0. It is also
253.1903 +*  assumed that:
253.1904 +*
253.1905 +*  1) if at = 0 then |L[p] - U'[p]| <= eps, where U'[p] is implied
253.1906 +*     row upper bound (see below), eps is an absolute tolerance for row
253.1907 +*     value;
253.1908 +*
253.1909 +*  2) if at = 1 then |U[p] - L'[p]| <= eps, where L'[p] is implied
253.1910 +*     row lower bound (see below).
253.1911 +*
253.1912 +*  RETURNS
253.1913 +*
253.1914 +*  0 - success;
253.1915 +*
253.1916 +*  1 - cannot fix columns due to too small constraint coefficients.
253.1917 +*
253.1918 +*  PROBLEM TRANSFORMATION
253.1919 +*
253.1920 +*  Implied lower and upper bounds of row (1) are determined by bounds
253.1921 +*  of corresponding columns (variables) as follows:
253.1922 +*
253.1923 +*     L'[p] = inf sum a[p,j] x[j] =
253.1924 +*                  j
253.1925 +*                                                                    (3)
253.1926 +*           =  sum  a[p,j] l[j] +  sum  a[p,j] u[j],
253.1927 +*            j in Jp             j in Jn
253.1928 +*
253.1929 +*     U'[p] = sup sum a[p,j] x[j] =
253.1930 +*                                                                    (4)
253.1931 +*           =  sum  a[p,j] u[j] +  sum  a[p,j] l[j],
253.1932 +*            j in Jp             j in Jn
253.1933 +*
253.1934 +*     Jp = {j: a[p,j] > 0},  Jn = {j: a[p,j] < 0}.                   (5)
253.1935 +*
253.1936 +*  If L[p] =~ U'[p] (at = 0), solution can be primal feasible only when
253.1937 +*  all variables take their boundary values as defined by (4):
253.1938 +*
253.1939 +*            ( u[j], if j in Jp
253.1940 +*     x[j] = <                                                       (6)
253.1941 +*            ( l[j], if j in Jn
253.1942 +*
253.1943 +*  Similarly, if U[p] =~ L'[p] (at = 1), solution can be primal feasible
253.1944 +*  only when all variables take their boundary values as defined by (3):
253.1945 +*
253.1946 +*            ( l[j], if j in Jp
253.1947 +*     x[j] = <                                                       (7)
253.1948 +*            ( u[j], if j in Jn
253.1949 +*
253.1950 +*  Condition (6) or (7) allows fixing all columns (variables x[j])
253.1951 +*  in row (1) on their bounds and then removing them from the problem
253.1952 +*  (see the routine npp_fixed_col). Due to this row p becomes redundant,
253.1953 +*  so it can be replaced by equivalent free (unbounded) row and also
253.1954 +*  removed from the problem (see the routine npp_free_row).
253.1955 +*
253.1956 +*  1. To apply this transformation row (1) should not have coefficients
253.1957 +*     whose magnitude is too small, i.e. all a[p,j] should satisfy to
253.1958 +*     the following condition:
253.1959 +*
253.1960 +*        |a[p,j]| >= eps * max(1, |a[p,k]|),                         (8)
253.1961 +*                           k
253.1962 +*     where eps is a relative tolerance for constraint coefficients.
253.1963 +*     Otherwise, fixing columns may be numerically unreliable and may
253.1964 +*     lead to wrong solution.
253.1965 +*
253.1966 +*  2. The routine fixes columns and remove bounds of row p, however,
253.1967 +*     it does not remove the row and columns from the problem.
253.1968 +*
253.1969 +*  RECOVERING BASIC SOLUTION
253.1970 +*
253.1971 +*  In the transformed problem row p being inactive constraint is
253.1972 +*  assigned status GLP_BS (as the result of transformation of free
253.1973 +*  row), and all columns in this row are assigned status GLP_NS (as the
253.1974 +*  result of transformation of fixed columns).
253.1975 +*
253.1976 +*  Note that in the dual system of the transformed (as well as original)
253.1977 +*  problem every column j in row p corresponds to the following row:
253.1978 +*
253.1979 +*     sum  a[i,j] pi[i] + a[p,j] pi[p] + lambda[j] = c[j],           (9)
253.1980 +*     i!=p
253.1981 +*
253.1982 +*  from which it follows that:
253.1983 +*
253.1984 +*     lambda[j] = c[j] - sum a[i,j] pi[i] - a[p,j] pi[p].           (10)
253.1985 +*                        i!=p
253.1986 +*
253.1987 +*  In the transformed problem values of all multipliers pi[i] are known
253.1988 +*  (including pi[i], whose value is zero, since row p is inactive).
253.1989 +*  Thus, using formula (10) it is possible to compute values of
253.1990 +*  multipliers lambda[j] for all columns in row p.
253.1991 +*
253.1992 +*  Note also that in the original problem all columns in row p are
253.1993 +*  bounded, not fixed. So status GLP_NS assigned to every such column
253.1994 +*  must be changed to GLP_NL or GLP_NU depending on which bound the
253.1995 +*  corresponding column has been fixed. This status change may lead to
253.1996 +*  dual feasibility violation for solution of the original problem,
253.1997 +*  because now column multipliers must satisfy to the following
253.1998 +*  condition:
253.1999 +*
253.2000 +*               ( >= 0, if status of column j is GLP_NL,
253.2001 +*     lambda[j] <                                                   (11)
253.2002 +*               ( <= 0, if status of column j is GLP_NU.
253.2003 +*
253.2004 +*  If this condition holds, solution to the original problem is the
253.2005 +*  same as to the transformed problem. Otherwise, we have to perform
253.2006 +*  one degenerate pivoting step of the primal simplex method to obtain
253.2007 +*  dual feasible (hence, optimal) solution to the original problem as
253.2008 +*  follows. If, on problem transformation, row p was made active on its
253.2009 +*  lower bound (case at = 0), we change its status to GLP_NL (or GLP_NS)
253.2010 +*  and start increasing its multiplier pi[p]. Otherwise, if row p was
253.2011 +*  made active on its upper bound (case at = 1), we change its status
253.2012 +*  to GLP_NU (or GLP_NS) and start decreasing pi[p]. From (10) it
253.2013 +*  follows that:
253.2014 +*
253.2015 +*     delta lambda[j] = - a[p,j] * delta pi[p] = - a[p,j] pi[p].    (12)
253.2016 +*
253.2017 +*  Simple analysis of formulae (3)-(5) shows that changing pi[p] in the
253.2018 +*  specified direction causes increasing lambda[j] for every column j
253.2019 +*  assigned status GLP_NL (delta lambda[j] > 0) and decreasing lambda[j]
253.2020 +*  for every column j assigned status GLP_NU (delta lambda[j] < 0). It
253.2021 +*  is understood that once the last lambda[q], which violates condition
253.2022 +*  (11), has reached zero, multipliers lambda[j] for all columns get
253.2023 +*  valid signs. Such column q can be determined as follows. Let d[j] be
253.2024 +*  initial value of lambda[j] (i.e. reduced cost of column j) in the
253.2025 +*  transformed problem computed with formula (10) when pi[p] = 0. Then
253.2026 +*  lambda[j] = d[j] + delta lambda[j], and from (12) it follows that
253.2027 +*  lambda[j] becomes zero if:
253.2028 +*
253.2029 +*     delta lambda[j] = - a[p,j] pi[p] = - d[j]  ==>
253.2030 +*                                                                   (13)
253.2031 +*     pi[p] = d[j] / a[p,j].
253.2032 +*
253.2033 +*  Therefore, the last column q, for which lambda[q] becomes zero, can
253.2034 +*  be determined from the following condition:
253.2035 +*
253.2036 +*     |d[q] / a[p,q]| = max  |pi[p]| = max  |d[j] / a[p,j]|,        (14)
253.2037 +*                      j in D         j in D
253.2038 +*
253.2039 +*  where D is a set of columns j whose, reduced costs d[j] have invalid
253.2040 +*  signs, i.e. violate condition (11). (Thus, if D is empty, solution
253.2041 +*  to the original problem is the same as solution to the transformed
253.2042 +*  problem, and no correction is needed as was noticed above.) In
253.2043 +*  solution to the original problem column q is assigned status GLP_BS,
253.2044 +*  since it replaces column of auxiliary variable of row p (becoming
253.2045 +*  active) in the basis, and multiplier for row p is assigned its new
253.2046 +*  value, which is pi[p] = d[q] / a[p,q]. Note that due to primal
253.2047 +*  degeneracy values of all columns having non-zero coefficients in row
253.2048 +*  p remain unchanged.
253.2049 +*
253.2050 +*  RECOVERING INTERIOR-POINT SOLUTION
253.2051 +*
253.2052 +*  Value of multiplier pi[p] in solution to the original problem is
253.2053 +*  corrected in the same way as for basic solution. Values of all
253.2054 +*  columns having non-zero coefficients in row p remain unchanged.
253.2055 +*
253.2056 +*  RECOVERING MIP SOLUTION
253.2057 +*
253.2058 +*  None needed. */
253.2059 +
253.2060 +struct forcing_col
253.2061 +{     /* column fixed on its bound by forcing row */
253.2062 +      int j;
253.2063 +      /* column reference number */
253.2064 +      char stat;
253.2065 +      /* original column status:
253.2066 +         GLP_NL - fixed on lower bound
253.2067 +         GLP_NU - fixed on upper bound */
253.2068 +      double a;
253.2069 +      /* constraint coefficient a[p,j] */
253.2070 +      double c;
253.2071 +      /* objective coefficient c[j] */
253.2072 +      NPPLFE *ptr;
253.2073 +      /* list of non-zero coefficients a[i,j], i != p */
253.2074 +      struct forcing_col *next;
253.2075 +      /* pointer to another column fixed by forcing row */
253.2076 +};
253.2077 +
253.2078 +struct forcing_row
253.2079 +{     /* forcing row */
253.2080 +      int p;
253.2081 +      /* row reference number */
253.2082 +      char stat;
253.2083 +      /* status assigned to the row if it becomes active:
253.2084 +         GLP_NS - active equality constraint
253.2085 +         GLP_NL - inequality constraint with lower bound active
253.2086 +         GLP_NU - inequality constraint with upper bound active */
253.2087 +      struct forcing_col *ptr;
253.2088 +      /* list of all columns having non-zero constraint coefficient
253.2089 +         a[p,j] in the forcing row */
253.2090 +};
253.2091 +
253.2092 +static int rcv_forcing_row(NPP *npp, void *info);
253.2093 +
253.2094 +int npp_forcing_row(NPP *npp, NPPROW *p, int at)
253.2095 +{     /* process forcing row */
253.2096 +      struct forcing_row *info;
253.2097 +      struct forcing_col *col = NULL;
253.2098 +      NPPCOL *j;
253.2099 +      NPPAIJ *apj, *aij;
253.2100 +      NPPLFE *lfe;
253.2101 +      double big;
253.2102 +      xassert(at == 0 || at == 1);
253.2103 +      /* determine maximal magnitude of the row coefficients */
253.2104 +      big = 1.0;
253.2105 +      for (apj = p->ptr; apj != NULL; apj = apj->r_next)
253.2106 +         if (big < fabs(apj->val)) big = fabs(apj->val);
253.2107 +      /* if there are too small coefficients in the row, transformation
253.2108 +         should not be applied */
253.2109 +      for (apj = p->ptr; apj != NULL; apj = apj->r_next)
253.2110 +         if (fabs(apj->val) < 1e-7 * big) return 1;
253.2111 +      /* create transformation stack entry */
253.2112 +      info = npp_push_tse(npp,
253.2113 +         rcv_forcing_row, sizeof(struct forcing_row));
253.2114 +      info->p = p->i;
253.2115 +      if (p->lb == p->ub)
253.2116 +      {  /* equality constraint */
253.2117 +         info->stat = GLP_NS;
253.2118 +      }
253.2119 +      else if (at == 0)
253.2120 +      {  /* inequality constraint; case L[p] = U'[p] */
253.2121 +         info->stat = GLP_NL;
253.2122 +         xassert(p->lb != -DBL_MAX);
253.2123 +      }
253.2124 +      else /* at == 1 */
253.2125 +      {  /* inequality constraint; case U[p] = L'[p] */
253.2126 +         info->stat = GLP_NU;
253.2127 +         xassert(p->ub != +DBL_MAX);
253.2128 +      }
253.2129 +      info->ptr = NULL;
253.2130 +      /* scan the forcing row, fix columns at corresponding bounds, and
253.2131 +         save column information (the latter is not needed for MIP) */
253.2132 +      for (apj = p->ptr; apj != NULL; apj = apj->r_next)
253.2133 +      {  /* column j has non-zero coefficient in the forcing row */
253.2134 +         j = apj->col;
253.2135 +         /* it must be non-fixed */
253.2136 +         xassert(j->lb < j->ub);
253.2137 +         /* allocate stack entry to save column information */
253.2138 +         if (npp->sol != GLP_MIP)
253.2139 +         {  col = dmp_get_atom(npp->stack, sizeof(struct forcing_col));
253.2140 +            col->j = j->j;
253.2141 +            col->stat = -1; /* will be set below */
253.2142 +            col->a = apj->val;
253.2143 +            col->c = j->coef;
253.2144 +            col->ptr = NULL;
253.2145 +            col->next = info->ptr;
253.2146 +            info->ptr = col;
253.2147 +         }
253.2148 +         /* fix column j */
253.2149 +         if (at == 0 && apj->val < 0.0 || at != 0 && apj->val > 0.0)
253.2150 +         {  /* at its lower bound */
253.2151 +            if (npp->sol != GLP_MIP)
253.2152 +               col->stat = GLP_NL;
253.2153 +            xassert(j->lb != -DBL_MAX);
253.2154 +            j->ub = j->lb;
253.2155 +         }
253.2156 +         else
253.2157 +         {  /* at its upper bound */
253.2158 +            if (npp->sol != GLP_MIP)
253.2159 +               col->stat = GLP_NU;
253.2160 +            xassert(j->ub != +DBL_MAX);
253.2161 +            j->lb = j->ub;
253.2162 +         }
253.2163 +         /* save column coefficients a[i,j], i != p */
253.2164 +         if (npp->sol != GLP_MIP)
253.2165 +         {  for (aij = j->ptr; aij != NULL; aij = aij->c_next)
253.2166 +            {  if (aij == apj) continue; /* skip a[p,j] */
253.2167 +               lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
253.2168 +               lfe->ref = aij->row->i;
253.2169 +               lfe->val = aij->val;
253.2170 +               lfe->next = col->ptr;
253.2171 +               col->ptr = lfe;
253.2172 +            }
253.2173 +         }
253.2174 +      }
253.2175 +      /* make the row free (unbounded) */
253.2176 +      p->lb = -DBL_MAX, p->ub = +DBL_MAX;
253.2177 +      return 0;
253.2178 +}
253.2179 +
253.2180 +static int rcv_forcing_row(NPP *npp, void *_info)
253.2181 +{     /* recover forcing row */
253.2182 +      struct forcing_row *info = _info;
253.2183 +      struct forcing_col *col, *piv;
253.2184 +      NPPLFE *lfe;
253.2185 +      double d, big, temp;
253.2186 +      if (npp->sol == GLP_MIP) goto done;
253.2187 +      /* initially solution to the original problem is the same as
253.2188 +         to the transformed problem, where row p is inactive constraint
253.2189 +         with pi[p] = 0, and all columns are non-basic */
253.2190 +      if (npp->sol == GLP_SOL)
253.2191 +      {  if (npp->r_stat[info->p] != GLP_BS)
253.2192 +         {  npp_error();
253.2193 +            return 1;
253.2194 +         }
253.2195 +         for (col = info->ptr; col != NULL; col = col->next)
253.2196 +         {  if (npp->c_stat[col->j] != GLP_NS)
253.2197 +            {  npp_error();
253.2198 +               return 1;
253.2199 +            }
253.2200 +            npp->c_stat[col->j] = col->stat; /* original status */
253.2201 +         }
253.2202 +      }
253.2203 +      /* compute reduced costs d[j] for all columns with formula (10)
253.2204 +         and store them in col.c instead objective coefficients */
253.2205 +      for (col = info->ptr; col != NULL; col = col->next)
253.2206 +      {  d = col->c;
253.2207 +         for (lfe = col->ptr; lfe != NULL; lfe = lfe->next)
253.2208 +            d -= lfe->val * npp->r_pi[lfe->ref];
253.2209 +         col->c = d;
253.2210 +      }
253.2211 +      /* consider columns j, whose multipliers lambda[j] has wrong
253.2212 +         sign in solution to the transformed problem (where lambda[j] =
253.2213 +         d[j]), and choose column q, whose multipler lambda[q] reaches
253.2214 +         zero last on changing row multiplier pi[p]; see (14) */
253.2215 +      piv = NULL, big = 0.0;
253.2216 +      for (col = info->ptr; col != NULL; col = col->next)
253.2217 +      {  d = col->c; /* d[j] */
253.2218 +         temp = fabs(d / col->a);
253.2219 +         if (col->stat == GLP_NL)
253.2220 +         {  /* column j has active lower bound */
253.2221 +            if (d < 0.0 && big < temp)
253.2222 +               piv = col, big = temp;
253.2223 +         }
253.2224 +         else if (col->stat == GLP_NU)
253.2225 +         {  /* column j has active upper bound */
253.2226 +            if (d > 0.0 && big < temp)
253.2227 +               piv = col, big = temp;
253.2228 +         }
253.2229 +         else
253.2230 +         {  npp_error();
253.2231 +            return 1;
253.2232 +         }
253.2233 +      }
253.2234 +      /* if column q does not exist, no correction is needed */
253.2235 +      if (piv != NULL)
253.2236 +      {  /* correct solution; row p becomes active constraint while
253.2237 +            column q becomes basic */
253.2238 +         if (npp->sol == GLP_SOL)
253.2239 +         {  npp->r_stat[info->p] = info->stat;
253.2240 +            npp->c_stat[piv->j] = GLP_BS;
253.2241 +         }
253.2242 +         /* assign new value to row multiplier pi[p] = d[p] / a[p,q] */
253.2243 +         npp->r_pi[info->p] = piv->c / piv->a;
253.2244 +      }
253.2245 +done: return 0;
253.2246 +}
253.2247 +
253.2248 +/***********************************************************************
253.2249 +*  NAME
253.2250 +*
253.2251 +*  npp_analyze_row - perform general row analysis
253.2252 +*
253.2253 +*  SYNOPSIS
253.2254 +*
253.2255 +*  #include "glpnpp.h"
253.2256 +*  int npp_analyze_row(NPP *npp, NPPROW *p);
253.2257 +*
253.2258 +*  DESCRIPTION
253.2259 +*
253.2260 +*  The routine npp_analyze_row performs analysis of row p of general
253.2261 +*  format:
253.2262 +*
253.2263 +*     L[p] <= sum a[p,j] x[j] <= U[p],                               (1)
253.2264 +*              j
253.2265 +*
253.2266 +*     l[j] <= x[j] <= u[j],                                          (2)
253.2267 +*
253.2268 +*  where L[p] <= U[p] and l[j] <= u[j] for all a[p,j] != 0.
253.2269 +*
253.2270 +*  RETURNS
253.2271 +*
253.2272 +*  0x?0 - row lower bound does not exist or is redundant;
253.2273 +*
253.2274 +*  0x?1 - row lower bound can be active;
253.2275 +*
253.2276 +*  0x?2 - row lower bound is a forcing bound;
253.2277 +*
253.2278 +*  0x0? - row upper bound does not exist or is redundant;
253.2279 +*
253.2280 +*  0x1? - row upper bound can be active;
253.2281 +*
253.2282 +*  0x2? - row upper bound is a forcing bound;
253.2283 +*
253.2284 +*  0x33 - row bounds are inconsistent with column bounds.
253.2285 +*
253.2286 +*  ALGORITHM
253.2287 +*
253.2288 +*  Analysis of row (1) is based on analysis of its implied lower and
253.2289 +*  upper bounds, which are determined by bounds of corresponding columns
253.2290 +*  (variables) as follows:
253.2291 +*
253.2292 +*     L'[p] = inf sum a[p,j] x[j] =
253.2293 +*                  j
253.2294 +*                                                                    (3)
253.2295 +*           =  sum  a[p,j] l[j] +  sum  a[p,j] u[j],
253.2296 +*            j in Jp             j in Jn
253.2297 +*
253.2298 +*     U'[p] = sup sum a[p,j] x[j] =
253.2299 +*                                                                    (4)
253.2300 +*           =  sum  a[p,j] u[j] +  sum  a[p,j] l[j],
253.2301 +*            j in Jp             j in Jn
253.2302 +*
253.2303 +*     Jp = {j: a[p,j] > 0},  Jn = {j: a[p,j] < 0}.                   (5)
253.2304 +*
253.2305 +*  (Note that bounds of all columns in row p are assumed to be correct,
253.2306 +*  so L'[p] <= U'[p].)
253.2307 +*
253.2308 +*  Analysis of row lower bound L[p] includes the following cases:
253.2309 +*
253.2310 +*  1) if L[p] > U'[p] + eps, where eps is an absolute tolerance for row
253.2311 +*     value, row lower bound L[p] and implied row upper bound U'[p] are
253.2312 +*     inconsistent, ergo, the problem has no primal feasible solution;
253.2313 +*
253.2314 +*  2) if U'[p] - eps <= L[p] <= U'[p] + eps, i.e. if L[p] =~ U'[p],
253.2315 +*     the row is a forcing row on its lower bound (see description of
253.2316 +*     the routine npp_forcing_row);
253.2317 +*
253.2318 +*  3) if L[p] > L'[p] + eps, row lower bound L[p] can be active (this
253.2319 +*     conclusion does not account other rows in the problem);
253.2320 +*
253.2321 +*  4) if L[p] <= L'[p] + eps, row lower bound L[p] cannot be active, so
253.2322 +*     it is redundant and can be removed (replaced by -oo).
253.2323 +*
253.2324 +*  Analysis of row upper bound U[p] is performed in a similar way and
253.2325 +*  includes the following cases:
253.2326 +*
253.2327 +*  1) if U[p] < L'[p] - eps, row upper bound U[p] and implied row lower
253.2328 +*     bound L'[p] are inconsistent, ergo the problem has no primal
253.2329 +*     feasible solution;
253.2330 +*
253.2331 +*  2) if L'[p] - eps <= U[p] <= L'[p] + eps, i.e. if U[p] =~ L'[p],
253.2332 +*     the row is a forcing row on its upper bound (see description of
253.2333 +*     the routine npp_forcing_row);
253.2334 +*
253.2335 +*  3) if U[p] < U'[p] - eps, row upper bound U[p] can be active (this
253.2336 +*     conclusion does not account other rows in the problem);
253.2337 +*
253.2338 +*  4) if U[p] >= U'[p] - eps, row upper bound U[p] cannot be active, so
253.2339 +*     it is redundant and can be removed (replaced by +oo). */
253.2340 +
253.2341 +int npp_analyze_row(NPP *npp, NPPROW *p)
253.2342 +{     /* perform general row analysis */
253.2343 +      NPPAIJ *aij;
253.2344 +      int ret = 0x00;
253.2345 +      double l, u, eps;
253.2346 +      xassert(npp == npp);
253.2347 +      /* compute implied lower bound L'[p]; see (3) */
253.2348 +      l = 0.0;
253.2349 +      for (aij = p->ptr; aij != NULL; aij = aij->r_next)
253.2350 +      {  if (aij->val > 0.0)
253.2351 +         {  if (aij->col->lb == -DBL_MAX)
253.2352 +            {  l = -DBL_MAX;
253.2353 +               break;
253.2354 +            }
253.2355 +            l += aij->val * aij->col->lb;
253.2356 +         }
253.2357 +         else /* aij->val < 0.0 */
253.2358 +         {  if (aij->col->ub == +DBL_MAX)
253.2359 +            {  l = -DBL_MAX;
253.2360 +               break;
253.2361 +            }
253.2362 +            l += aij->val * aij->col->ub;
253.2363 +         }
253.2364 +      }
253.2365 +      /* compute implied upper bound U'[p]; see (4) */
253.2366 +      u = 0.0;
253.2367 +      for (aij = p->ptr; aij != NULL; aij = aij->r_next)
253.2368 +      {  if (aij->val > 0.0)
253.2369 +         {  if (aij->col->ub == +DBL_MAX)
253.2370 +            {  u = +DBL_MAX;
253.2371 +               break;
253.2372 +            }
253.2373 +            u += aij->val * aij->col->ub;
253.2374 +         }
253.2375 +         else /* aij->val < 0.0 */
253.2376 +         {  if (aij->col->lb == -DBL_MAX)
253.2377 +            {  u = +DBL_MAX;
253.2378 +               break;
253.2379 +            }
253.2380 +            u += aij->val * aij->col->lb;
253.2381 +         }
253.2382 +      }
253.2383 +      /* column bounds are assumed correct, so L'[p] <= U'[p] */
253.2384 +      /* check if row lower bound is consistent */
253.2385 +      if (p->lb != -DBL_MAX)
253.2386 +      {  eps = 1e-3 + 1e-6 * fabs(p->lb);
253.2387 +         if (p->lb - eps > u)
253.2388 +         {  ret = 0x33;
253.2389 +            goto done;
253.2390 +         }
253.2391 +      }
253.2392 +      /* check if row upper bound is consistent */
253.2393 +      if (p->ub != +DBL_MAX)
253.2394 +      {  eps = 1e-3 + 1e-6 * fabs(p->ub);
253.2395 +         if (p->ub + eps < l)
253.2396 +         {  ret = 0x33;
253.2397 +            goto done;
253.2398 +         }
253.2399 +      }
253.2400 +      /* check if row lower bound can be active/forcing */
253.2401 +      if (p->lb != -DBL_MAX)
253.2402 +      {  eps = 1e-9 + 1e-12 * fabs(p->lb);
253.2403 +         if (p->lb - eps > l)
253.2404 +         {  if (p->lb + eps <= u)
253.2405 +               ret |= 0x01;
253.2406 +            else
253.2407 +               ret |= 0x02;
253.2408 +         }
253.2409 +      }
253.2410 +      /* check if row upper bound can be active/forcing */
253.2411 +      if (p->ub != +DBL_MAX)
253.2412 +      {  eps = 1e-9 + 1e-12 * fabs(p->ub);
253.2413 +         if (p->ub + eps < u)
253.2414 +         {  /* check if the upper bound is forcing */
253.2415 +            if (p->ub - eps >= l)
253.2416 +               ret |= 0x10;
253.2417 +            else
253.2418 +               ret |= 0x20;
253.2419 +         }
253.2420 +      }
253.2421 +done: return ret;
253.2422 +}
253.2423 +
253.2424 +/***********************************************************************
253.2425 +*  NAME
253.2426 +*
253.2427 +*  npp_inactive_bound - remove row lower/upper inactive bound
253.2428 +*
253.2429 +*  SYNOPSIS
253.2430 +*
253.2431 +*  #include "glpnpp.h"
253.2432 +*  void npp_inactive_bound(NPP *npp, NPPROW *p, int which);
253.2433 +*
253.2434 +*  DESCRIPTION
253.2435 +*
253.2436 +*  The routine npp_inactive_bound removes lower (if which = 0) or upper
253.2437 +*  (if which = 1) bound of row p:
253.2438 +*
253.2439 +*     L[p] <= sum a[p,j] x[j] <= U[p],
253.2440 +*
253.2441 +*  which (bound) is assumed to be redundant.
253.2442 +*
253.2443 +*  PROBLEM TRANSFORMATION
253.2444 +*
253.2445 +*  If which = 0, current lower bound L[p] of row p is assigned -oo.
253.2446 +*  If which = 1, current upper bound U[p] of row p is assigned +oo.
253.2447 +*
253.2448 +*  RECOVERING BASIC SOLUTION
253.2449 +*
253.2450 +*  If in solution to the transformed problem row p is inactive
253.2451 +*  constraint (GLP_BS), its status is not changed in solution to the
253.2452 +*  original problem. Otherwise, status of row p in solution to the
253.2453 +*  original problem is defined by its type before transformation and
253.2454 +*  its status in solution to the transformed problem as follows:
253.2455 +*
253.2456 +*     +---------------------+-------+---------------+---------------+
253.2457 +*     |        Row          | Flag  | Row status in | Row status in |
253.2458 +*     |        type         | which | transfmd soln | original soln |
253.2459 +*     +---------------------+-------+---------------+---------------+
253.2460 +*     |     sum >= L[p]     |   0   |    GLP_NF     |    GLP_NL     |
253.2461 +*     |     sum <= U[p]     |   1   |    GLP_NF     |    GLP_NU     |
253.2462 +*     | L[p] <= sum <= U[p] |   0   |    GLP_NU     |    GLP_NU     |
253.2463 +*     | L[p] <= sum <= U[p] |   1   |    GLP_NL     |    GLP_NL     |
253.2464 +*     |  sum = L[p] = U[p]  |   0   |    GLP_NU     |    GLP_NS     |
253.2465 +*     |  sum = L[p] = U[p]  |   1   |    GLP_NL     |    GLP_NS     |
253.2466 +*     +---------------------+-------+---------------+---------------+
253.2467 +*
253.2468 +*  RECOVERING INTERIOR-POINT SOLUTION
253.2469 +*
253.2470 +*  None needed.
253.2471 +*
253.2472 +*  RECOVERING MIP SOLUTION
253.2473 +*
253.2474 +*  None needed. */
253.2475 +
253.2476 +struct inactive_bound
253.2477 +{     /* row inactive bound */
253.2478 +      int p;
253.2479 +      /* row reference number */
253.2480 +      char stat;
253.2481 +      /* row status (if active constraint) */
253.2482 +};
253.2483 +
253.2484 +static int rcv_inactive_bound(NPP *npp, void *info);
253.2485 +
253.2486 +void npp_inactive_bound(NPP *npp, NPPROW *p, int which)
253.2487 +{     /* remove row lower/upper inactive bound */
253.2488 +      struct inactive_bound *info;
253.2489 +      if (npp->sol == GLP_SOL)
253.2490 +      {  /* create transformation stack entry */
253.2491 +         info = npp_push_tse(npp,
253.2492 +            rcv_inactive_bound, sizeof(struct inactive_bound));
253.2493 +         info->p = p->i;
253.2494 +         if (p->ub == +DBL_MAX)
253.2495 +            info->stat = GLP_NL;
253.2496 +         else if (p->lb == -DBL_MAX)
253.2497 +            info->stat = GLP_NU;
253.2498 +         else if (p->lb != p->ub)
253.2499 +            info->stat = (char)(which == 0 ? GLP_NU : GLP_NL);
253.2500 +         else
253.2501 +            info->stat = GLP_NS;
253.2502 +      }
253.2503 +      /* remove row inactive bound */
253.2504 +      if (which == 0)
253.2505 +      {  xassert(p->lb != -DBL_MAX);
253.2506 +         p->lb = -DBL_MAX;
253.2507 +      }
253.2508 +      else if (which == 1)
253.2509 +      {  xassert(p->ub != +DBL_MAX);
253.2510 +         p->ub = +DBL_MAX;
253.2511 +      }
253.2512 +      else
253.2513 +         xassert(which != which);
253.2514 +      return;
253.2515 +}
253.2516 +
253.2517 +static int rcv_inactive_bound(NPP *npp, void *_info)
253.2518 +{     /* recover row status */
253.2519 +      struct inactive_bound *info = _info;
253.2520 +      if (npp->sol != GLP_SOL)
253.2521 +      {  npp_error();
253.2522 +         return 1;
253.2523 +      }
253.2524 +      if (npp->r_stat[info->p] == GLP_BS)
253.2525 +         npp->r_stat[info->p] = GLP_BS;
253.2526 +      else
253.2527 +         npp->r_stat[info->p] = info->stat;
253.2528 +      return 0;
253.2529 +}
253.2530 +
253.2531 +/***********************************************************************
253.2532 +*  NAME
253.2533 +*
253.2534 +*  npp_implied_bounds - determine implied column bounds
253.2535 +*
253.2536 +*  SYNOPSIS
253.2537 +*
253.2538 +*  #include "glpnpp.h"
253.2539 +*  void npp_implied_bounds(NPP *npp, NPPROW *p);
253.2540 +*
253.2541 +*  DESCRIPTION
253.2542 +*
253.2543 +*  The routine npp_implied_bounds inspects general row (constraint) p:
253.2544 +*
253.2545 +*     L[p] <= sum a[p,j] x[j] <= U[p],                               (1)
253.2546 +*
253.2547 +*     l[j] <= x[j] <= u[j],                                          (2)
253.2548 +*
253.2549 +*  where L[p] <= U[p] and l[j] <= u[j] for all a[p,j] != 0, to compute
253.2550 +*  implied bounds of columns (variables x[j]) in this row.
253.2551 +*
253.2552 +*  The routine stores implied column bounds l'[j] and u'[j] in column
253.2553 +*  descriptors (NPPCOL); it does not change current column bounds l[j]
253.2554 +*  and u[j]. (Implied column bounds can be then used to strengthen the
253.2555 +*  current column bounds; see the routines npp_implied_lower and
253.2556 +*  npp_implied_upper).
253.2557 +*
253.2558 +*  ALGORITHM
253.2559 +*
253.2560 +*  Current column bounds (2) define implied lower and upper bounds of
253.2561 +*  row (1) as follows:
253.2562 +*
253.2563 +*     L'[p] = inf sum a[p,j] x[j] =
253.2564 +*                  j
253.2565 +*                                                                    (3)
253.2566 +*           =  sum  a[p,j] l[j] +  sum  a[p,j] u[j],
253.2567 +*            j in Jp             j in Jn
253.2568 +*
253.2569 +*     U'[p] = sup sum a[p,j] x[j] =
253.2570 +*                                                                    (4)
253.2571 +*           =  sum  a[p,j] u[j] +  sum  a[p,j] l[j],
253.2572 +*            j in Jp             j in Jn
253.2573 +*
253.2574 +*     Jp = {j: a[p,j] > 0},  Jn = {j: a[p,j] < 0}.                   (5)
253.2575 +*
253.2576 +*  (Note that bounds of all columns in row p are assumed to be correct,
253.2577 +*  so L'[p] <= U'[p].)
253.2578 +*
253.2579 +*  If L[p] > L'[p] and/or U[p] < U'[p], the lower and/or upper bound of
253.2580 +*  row (1) can be active, in which case such row defines implied bounds
253.2581 +*  of its variables.
253.2582 +*
253.2583 +*  Let x[k] be some variable having in row (1) coefficient a[p,k] != 0.
253.2584 +*  Consider a case when row lower bound can be active (L[p] > L'[p]):
253.2585 +*
253.2586 +*     sum a[p,j] x[j] >= L[p]  ==>
253.2587 +*      j
253.2588 +*
253.2589 +*     sum a[p,j] x[j] + a[p,k] x[k] >= L[p]  ==>
253.2590 +*     j!=k
253.2591 +*                                                                    (6)
253.2592 +*     a[p,k] x[k] >= L[p] - sum a[p,j] x[j]  ==>
253.2593 +*                           j!=k
253.2594 +*
253.2595 +*     a[p,k] x[k] >= L[p,k],
253.2596 +*
253.2597 +*  where
253.2598 +*
253.2599 +*     L[p,k] = inf(L[p] - sum a[p,j] x[j]) =
253.2600 +*                         j!=k
253.2601 +*
253.2602 +*            = L[p] - sup sum a[p,j] x[j] =                          (7)
253.2603 +*                         j!=k
253.2604 +*
253.2605 +*            = L[p] - sum a[p,j] u[j] - sum a[p,j] l[j].
253.2606 +*                    j in Jp\{k}       j in Jn\{k}
253.2607 +*
253.2608 +*  Thus:
253.2609 +*
253.2610 +*     x[k] >= l'[k] = L[p,k] / a[p,k],  if a[p,k] > 0,               (8)
253.2611 +*
253.2612 +*     x[k] <= u'[k] = L[p,k] / a[p,k],  if a[p,k] < 0.               (9)
253.2613 +*
253.2614 +*  where l'[k] and u'[k] are implied lower and upper bounds of variable
253.2615 +*  x[k], resp.
253.2616 +*
253.2617 +*  Now consider a similar case when row upper bound can be active
253.2618 +*  (U[p] < U'[p]):
253.2619 +*
253.2620 +*     sum a[p,j] x[j] <= U[p]  ==>
253.2621 +*      j
253.2622 +*
253.2623 +*     sum a[p,j] x[j] + a[p,k] x[k] <= U[p]  ==>
253.2624 +*     j!=k
253.2625 +*                                                                   (10)
253.2626 +*     a[p,k] x[k] <= U[p] - sum a[p,j] x[j]  ==>
253.2627 +*                           j!=k
253.2628 +*
253.2629 +*     a[p,k] x[k] <= U[p,k],
253.2630 +*
253.2631 +*  where:
253.2632 +*
253.2633 +*     U[p,k] = sup(U[p] - sum a[p,j] x[j]) =
253.2634 +*                         j!=k
253.2635 +*
253.2636 +*            = U[p] - inf sum a[p,j] x[j] =                         (11)
253.2637 +*                         j!=k
253.2638 +*
253.2639 +*            = U[p] - sum a[p,j] l[j] - sum a[p,j] u[j].
253.2640 +*                    j in Jp\{k}       j in Jn\{k}
253.2641 +*
253.2642 +*  Thus:
253.2643 +*
253.2644 +*     x[k] <= u'[k] = U[p,k] / a[p,k],  if a[p,k] > 0,              (12)
253.2645 +*
253.2646 +*     x[k] >= l'[k] = U[p,k] / a[p,k],  if a[p,k] < 0.              (13)
253.2647 +*
253.2648 +*  Note that in formulae (8), (9), (12), and (13) coefficient a[p,k]
253.2649 +*  must not be too small in magnitude relatively to other non-zero
253.2650 +*  coefficients in row (1), i.e. the following condition must hold:
253.2651 +*
253.2652 +*     |a[p,k]| >= eps * max(1, |a[p,j]|),                           (14)
253.2653 +*                        j
253.2654 +*
253.2655 +*  where eps is a relative tolerance for constraint coefficients.
253.2656 +*  Otherwise the implied column bounds can be numerical inreliable. For
253.2657 +*  example, using formula (8) for the following inequality constraint:
253.2658 +*
253.2659 +*     1e-12 x1 - x2 - x3 >= 0,
253.2660 +*
253.2661 +*  where x1 >= -1, x2, x3, >= 0, may lead to numerically unreliable
253.2662 +*  conclusion that x1 >= 0.
253.2663 +*
253.2664 +*  Using formulae (8), (9), (12), and (13) to compute implied bounds
253.2665 +*  for one variable requires |J| operations, where J = {j: a[p,j] != 0},
253.2666 +*  because this needs computing L[p,k] and U[p,k]. Thus, computing
253.2667 +*  implied bounds for all variables in row (1) would require |J|^2
253.2668 +*  operations, that is not a good technique. However, the total number
253.2669 +*  of operations can be reduced to |J| as follows.
253.2670 +*
253.2671 +*  Let a[p,k] > 0. Then from (7) and (11) we have:
253.2672 +*
253.2673 +*     L[p,k] = L[p] - (U'[p] - a[p,k] u[k]) =
253.2674 +*
253.2675 +*            = L[p] - U'[p] + a[p,k] u[k],
253.2676 +*
253.2677 +*     U[p,k] = U[p] - (L'[p] - a[p,k] l[k]) =
253.2678 +*
253.2679 +*            = U[p] - L'[p] + a[p,k] l[k],
253.2680 +*
253.2681 +*  where L'[p] and U'[p] are implied row lower and upper bounds defined
253.2682 +*  by formulae (3) and (4). Substituting these expressions into (8) and
253.2683 +*  (12) gives:
253.2684 +*
253.2685 +*     l'[k] = L[p,k] / a[p,k] = u[k] + (L[p] - U'[p]) / a[p,k],     (15)
253.2686 +*
253.2687 +*     u'[k] = U[p,k] / a[p,k] = l[k] + (U[p] - L'[p]) / a[p,k].     (16)
253.2688 +*
253.2689 +*  Similarly, if a[p,k] < 0, according to (7) and (11) we have:
253.2690 +*
253.2691 +*     L[p,k] = L[p] - (U'[p] - a[p,k] l[k]) =
253.2692 +*
253.2693 +*            = L[p] - U'[p] + a[p,k] l[k],
253.2694 +*
253.2695 +*     U[p,k] = U[p] - (L'[p] - a[p,k] u[k]) =
253.2696 +*
253.2697 +*            = U[p] - L'[p] + a[p,k] u[k],
253.2698 +*
253.2699 +*  and substituting these expressions into (8) and (12) gives:
253.2700 +*
253.2701 +*     l'[k] = U[p,k] / a[p,k] = u[k] + (U[p] - L'[p]) / a[p,k],     (17)
253.2702 +*
253.2703 +*     u'[k] = L[p,k] / a[p,k] = l[k] + (L[p] - U'[p]) / a[p,k].     (18)
253.2704 +*
253.2705 +*  Note that formulae (15)-(18) can be used only if L'[p] and U'[p]
253.2706 +*  exist. However, if for some variable x[j] it happens that l[j] = -oo
253.2707 +*  and/or u[j] = +oo, values of L'[p] (if a[p,j] > 0) and/or U'[p] (if
253.2708 +*  a[p,j] < 0) are undefined. Consider, therefore, the most general
253.2709 +*  situation, when some column bounds (2) may not exist.
253.2710 +*
253.2711 +*  Let:
253.2712 +*
253.2713 +*     J' = {j : (a[p,j] > 0 and l[j] = -oo) or
253.2714 +*                                                                   (19)
253.2715 +*               (a[p,j] < 0 and u[j] = +oo)}.
253.2716 +*
253.2717 +*  Then (assuming that row upper bound U[p] can be active) the following
253.2718 +*  three cases are possible:
253.2719 +*
253.2720 +*  1) |J'| = 0. In this case L'[p] exists, thus, for all variables x[j]
253.2721 +*     in row (1) we can use formulae (16) and (17);
253.2722 +*
253.2723 +*  2) J' = {k}. In this case L'[p] = -oo, however, U[p,k] (11) exists,
253.2724 +*     so for variable x[k] we can use formulae (12) and (13). Note that
253.2725 +*     for all other variables x[j] (j != k) l'[j] = -oo (if a[p,j] < 0)
253.2726 +*     or u'[j] = +oo (if a[p,j] > 0);
253.2727 +*
253.2728 +*  3) |J'| > 1. In this case for all variables x[j] in row [1] we have
253.2729 +*     l'[j] = -oo (if a[p,j] < 0) or u'[j] = +oo (if a[p,j] > 0).
253.2730 +*
253.2731 +*  Similarly, let:
253.2732 +*
253.2733 +*     J'' = {j : (a[p,j] > 0 and u[j] = +oo) or
253.2734 +*                                                                   (20)
253.2735 +*                (a[p,j] < 0 and l[j] = -oo)}.
253.2736 +*
253.2737 +*  Then (assuming that row lower bound L[p] can be active) the following
253.2738 +*  three cases are possible:
253.2739 +*
253.2740 +*  1) |J''| = 0. In this case U'[p] exists, thus, for all variables x[j]
253.2741 +*     in row (1) we can use formulae (15) and (18);
253.2742 +*
253.2743 +*  2) J'' = {k}. In this case U'[p] = +oo, however, L[p,k] (7) exists,
253.2744 +*     so for variable x[k] we can use formulae (8) and (9). Note that
253.2745 +*     for all other variables x[j] (j != k) l'[j] = -oo (if a[p,j] > 0)
253.2746 +*     or u'[j] = +oo (if a[p,j] < 0);
253.2747 +*
253.2748 +*  3) |J''| > 1. In this case for all variables x[j] in row (1) we have
253.2749 +*     l'[j] = -oo (if a[p,j] > 0) or u'[j] = +oo (if a[p,j] < 0). */
253.2750 +
253.2751 +void npp_implied_bounds(NPP *npp, NPPROW *p)
253.2752 +{     NPPAIJ *apj, *apk;
253.2753 +      double big, eps, temp;
253.2754 +      xassert(npp == npp);
253.2755 +      /* initialize implied bounds for all variables and determine
253.2756 +         maximal magnitude of row coefficients a[p,j] */
253.2757 +      big = 1.0;
253.2758 +      for (apj = p->ptr; apj != NULL; apj = apj->r_next)
253.2759 +      {  apj->col->ll.ll = -DBL_MAX, apj->col->uu.uu = +DBL_MAX;
253.2760 +         if (big < fabs(apj->val)) big = fabs(apj->val);
253.2761 +      }
253.2762 +      eps = 1e-6 * big;
253.2763 +      /* process row lower bound (assuming that it can be active) */
253.2764 +      if (p->lb != -DBL_MAX)
253.2765 +      {  apk = NULL;
253.2766 +         for (apj = p->ptr; apj != NULL; apj = apj->r_next)
253.2767 +         {  if (apj->val > 0.0 && apj->col->ub == +DBL_MAX ||
253.2768 +                apj->val < 0.0 && apj->col->lb == -DBL_MAX)
253.2769 +            {  if (apk == NULL)
253.2770 +                  apk = apj;
253.2771 +               else
253.2772 +                  goto skip1;
253.2773 +            }
253.2774 +         }
253.2775 +         /* if a[p,k] = NULL then |J'| = 0 else J' = { k } */
253.2776 +         temp = p->lb;
253.2777 +         for (apj = p->ptr; apj != NULL; apj = apj->r_next)
253.2778 +         {  if (apj == apk)
253.2779 +               /* skip a[p,k] */;
253.2780 +            else if (apj->val > 0.0)
253.2781 +               temp -= apj->val * apj->col->ub;
253.2782 +            else /* apj->val < 0.0 */
253.2783 +               temp -= apj->val * apj->col->lb;
253.2784 +         }
253.2785 +         /* compute column implied bounds */
253.2786 +         if (apk == NULL)
253.2787 +         {  /* temp = L[p] - U'[p] */
253.2788 +            for (apj = p->ptr; apj != NULL; apj = apj->r_next)
253.2789 +            {  if (apj->val >= +eps)
253.2790 +               {  /* l'[j] := u[j] + (L[p] - U'[p]) / a[p,j] */
253.2791 +                  apj->col->ll.ll = apj->col->ub + temp / apj->val;
253.2792 +               }
253.2793 +               else if (apj->val <= -eps)
253.2794 +               {  /* u'[j] := l[j] + (L[p] - U'[p]) / a[p,j] */
253.2795 +                  apj->col->uu.uu = apj->col->lb + temp / apj->val;
253.2796 +               }
253.2797 +            }
253.2798 +         }
253.2799 +         else
253.2800 +         {  /* temp = L[p,k] */
253.2801 +            if (apk->val >= +eps)
253.2802 +            {  /* l'[k] := L[p,k] / a[p,k] */
253.2803 +               apk->col->ll.ll = temp / apk->val;
253.2804 +            }
253.2805 +            else if (apk->val <= -eps)
253.2806 +            {  /* u'[k] := L[p,k] / a[p,k] */
253.2807 +               apk->col->uu.uu = temp / apk->val;
253.2808 +            }
253.2809 +         }
253.2810 +skip1:   ;
253.2811 +      }
253.2812 +      /* process row upper bound (assuming that it can be active) */
253.2813 +      if (p->ub != +DBL_MAX)
253.2814 +      {  apk = NULL;
253.2815 +         for (apj = p->ptr; apj != NULL; apj = apj->r_next)
253.2816 +         {  if (apj->val > 0.0 && apj->col->lb == -DBL_MAX ||
253.2817 +                apj->val < 0.0 && apj->col->ub == +DBL_MAX)
253.2818 +            {  if (apk == NULL)
253.2819 +                  apk = apj;
253.2820 +               else
253.2821 +                  goto skip2;
253.2822 +            }
253.2823 +         }
253.2824 +         /* if a[p,k] = NULL then |J''| = 0 else J'' = { k } */
253.2825 +         temp = p->ub;
253.2826 +         for (apj = p->ptr; apj != NULL; apj = apj->r_next)
253.2827 +         {  if (apj == apk)
253.2828 +               /* skip a[p,k] */;
253.2829 +            else if (apj->val > 0.0)
253.2830 +               temp -= apj->val * apj->col->lb;
253.2831 +            else /* apj->val < 0.0 */
253.2832 +               temp -= apj->val * apj->col->ub;
253.2833 +         }
253.2834 +         /* compute column implied bounds */
253.2835 +         if (apk == NULL)
253.2836 +         {  /* temp = U[p] - L'[p] */
253.2837 +            for (apj = p->ptr; apj != NULL; apj = apj->r_next)
253.2838 +            {  if (apj->val >= +eps)
253.2839 +               {  /* u'[j] := l[j] + (U[p] - L'[p]) / a[p,j] */
253.2840 +                  apj->col->uu.uu = apj->col->lb + temp / apj->val;
253.2841 +               }
253.2842 +               else if (apj->val <= -eps)
253.2843 +               {  /* l'[j] := u[j] + (U[p] - L'[p]) / a[p,j] */
253.2844 +                  apj->col->ll.ll = apj->col->ub + temp / apj->val;
253.2845 +               }
253.2846 +            }
253.2847 +         }
253.2848 +         else
253.2849 +         {  /* temp = U[p,k] */
253.2850 +            if (apk->val >= +eps)
253.2851 +            {  /* u'[k] := U[p,k] / a[p,k] */
253.2852 +               apk->col->uu.uu = temp / apk->val;
253.2853 +            }
253.2854 +            else if (apk->val <= -eps)
253.2855 +            {  /* l'[k] := U[p,k] / a[p,k] */
253.2856 +               apk->col->ll.ll = temp / apk->val;
253.2857 +            }
253.2858 +         }
253.2859 +skip2:   ;
253.2860 +      }
253.2861 +      return;
253.2862 +}
253.2863 +
253.2864 +/* eof */
   254.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   254.2 +++ b/src/glpnpp04.c	Mon Dec 06 13:09:21 2010 +0100
   254.3 @@ -0,0 +1,1414 @@
   254.4 +/* glpnpp04.c */
   254.5 +
   254.6 +/***********************************************************************
   254.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   254.8 +*
   254.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  254.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  254.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  254.12 +*  E-mail: <mao@gnu.org>.
  254.13 +*
  254.14 +*  GLPK is free software: you can redistribute it and/or modify it
  254.15 +*  under the terms of the GNU General Public License as published by
  254.16 +*  the Free Software Foundation, either version 3 of the License, or
  254.17 +*  (at your option) any later version.
  254.18 +*
  254.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  254.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  254.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  254.22 +*  License for more details.
  254.23 +*
  254.24 +*  You should have received a copy of the GNU General Public License
  254.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  254.26 +***********************************************************************/
  254.27 +
  254.28 +#include "glpnpp.h"
  254.29 +
  254.30 +/***********************************************************************
  254.31 +*  NAME
  254.32 +*
  254.33 +*  npp_binarize_prob - binarize MIP problem
  254.34 +*
  254.35 +*  SYNOPSIS
  254.36 +*
  254.37 +*  #include "glpnpp.h"
  254.38 +*  int npp_binarize_prob(NPP *npp);
  254.39 +*
  254.40 +*  DESCRIPTION
  254.41 +*
  254.42 +*  The routine npp_binarize_prob replaces in the original MIP problem
  254.43 +*  every integer variable:
  254.44 +*
  254.45 +*     l[q] <= x[q] <= u[q],                                          (1)
  254.46 +*
  254.47 +*  where l[q] < u[q], by an equivalent sum of binary variables.
  254.48 +*
  254.49 +*  RETURNS
  254.50 +*
  254.51 +*  The routine returns the number of integer variables for which the
  254.52 +*  transformation failed, because u[q] - l[q] > d_max.
  254.53 +*
  254.54 +*  PROBLEM TRANSFORMATION
  254.55 +*
  254.56 +*  If variable x[q] has non-zero lower bound, it is first processed
  254.57 +*  with the routine npp_lbnd_col. Thus, we can assume that:
  254.58 +*
  254.59 +*     0 <= x[q] <= u[q].                                             (2)
  254.60 +*
  254.61 +*  If u[q] = 1, variable x[q] is already binary, so further processing
  254.62 +*  is not needed. Let, therefore, that 2 <= u[q] <= d_max, and n be a
  254.63 +*  smallest integer such that u[q] <= 2^n - 1 (n >= 2, since u[q] >= 2).
  254.64 +*  Then variable x[q] can be replaced by the following sum:
  254.65 +*
  254.66 +*            n-1
  254.67 +*     x[q] = sum 2^k x[k],                                           (3)
  254.68 +*            k=0
  254.69 +*
  254.70 +*  where x[k] are binary columns (variables). If u[q] < 2^n - 1, the
  254.71 +*  following additional inequality constraint must be also included in
  254.72 +*  the transformed problem:
  254.73 +*
  254.74 +*     n-1
  254.75 +*     sum 2^k x[k] <= u[q].                                          (4)
  254.76 +*     k=0
  254.77 +*
  254.78 +*  Note: Assuming that in the transformed problem x[q] becomes binary
  254.79 +*  variable x[0], this transformation causes new n-1 binary variables
  254.80 +*  to appear.
  254.81 +*
  254.82 +*  Substituting x[q] from (3) to the objective row gives:
  254.83 +*
  254.84 +*     z = sum c[j] x[j] + c[0] =
  254.85 +*          j
  254.86 +*
  254.87 +*       = sum c[j] x[j] + c[q] x[q] + c[0] =
  254.88 +*         j!=q
  254.89 +*                              n-1
  254.90 +*       = sum c[j] x[j] + c[q] sum 2^k x[k] + c[0] =
  254.91 +*         j!=q                 k=0
  254.92 +*                         n-1
  254.93 +*       = sum c[j] x[j] + sum c[k] x[k] + c[0],
  254.94 +*         j!=q            k=0
  254.95 +*
  254.96 +*  where:
  254.97 +*
  254.98 +*     c[k] = 2^k c[q],  k = 0, ..., n-1.                             (5)
  254.99 +*
 254.100 +*  And substituting x[q] from (3) to i-th constraint row i gives:
 254.101 +*
 254.102 +*     L[i] <= sum a[i,j] x[j] <= U[i]  ==>
 254.103 +*              j
 254.104 +*
 254.105 +*     L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i]  ==>
 254.106 +*             j!=q
 254.107 +*                                      n-1
 254.108 +*     L[i] <= sum a[i,j] x[j] + a[i,q] sum 2^k x[k] <= U[i]  ==>
 254.109 +*             j!=q                     k=0
 254.110 +*                               n-1
 254.111 +*     L[i] <= sum a[i,j] x[j] + sum a[i,k] x[k] <= U[i],
 254.112 +*             j!=q              k=0
 254.113 +*
 254.114 +*  where:
 254.115 +*
 254.116 +*     a[i,k] = 2^k a[i,q],  k = 0, ..., n-1.                         (6)
 254.117 +*
 254.118 +*  RECOVERING SOLUTION
 254.119 +*
 254.120 +*  Value of variable x[q] is computed with formula (3). */
 254.121 +
 254.122 +struct binarize
 254.123 +{     int q;
 254.124 +      /* column reference number for x[q] = x[0] */
 254.125 +      int j;
 254.126 +      /* column reference number for x[1]; x[2] has reference number
 254.127 +         j+1, x[3] - j+2, etc. */
 254.128 +      int n;
 254.129 +      /* total number of binary variables, n >= 2 */
 254.130 +};
 254.131 +
 254.132 +static int rcv_binarize_prob(NPP *npp, void *info);
 254.133 +
 254.134 +int npp_binarize_prob(NPP *npp)
 254.135 +{     /* binarize MIP problem */
 254.136 +      struct binarize *info;
 254.137 +      NPPROW *row;
 254.138 +      NPPCOL *col, *bin;
 254.139 +      NPPAIJ *aij;
 254.140 +      int u, n, k, temp, nfails, nvars, nbins, nrows;
 254.141 +      /* new variables will be added to the end of the column list, so
 254.142 +         we go from the end to beginning of the column list */
 254.143 +      nfails = nvars = nbins = nrows = 0;
 254.144 +      for (col = npp->c_tail; col != NULL; col = col->prev)
 254.145 +      {  /* skip continuous variable */
 254.146 +         if (!col->is_int) continue;
 254.147 +         /* skip fixed variable */
 254.148 +         if (col->lb == col->ub) continue;
 254.149 +         /* skip binary variable */
 254.150 +         if (col->lb == 0.0 && col->ub == 1.0) continue;
 254.151 +         /* check if the transformation is applicable */
 254.152 +         if (col->lb < -1e6 || col->ub > +1e6 ||
 254.153 +             col->ub - col->lb > 4095.0)
 254.154 +         {  /* unfortunately, not */
 254.155 +            nfails++;
 254.156 +            continue;
 254.157 +         }
 254.158 +         /* process integer non-binary variable x[q] */
 254.159 +         nvars++;
 254.160 +         /* make x[q] non-negative, if its lower bound is non-zero */
 254.161 +         if (col->lb != 0.0)
 254.162 +            npp_lbnd_col(npp, col);
 254.163 +         /* now 0 <= x[q] <= u[q] */
 254.164 +         xassert(col->lb == 0.0);
 254.165 +         u = (int)col->ub;
 254.166 +         xassert(col->ub == (double)u);
 254.167 +         /* if x[q] is binary, further processing is not needed */
 254.168 +         if (u == 1) continue;
 254.169 +         /* determine smallest n such that u <= 2^n - 1 (thus, n is the
 254.170 +            number of binary variables needed) */
 254.171 +         n = 2, temp = 4;
 254.172 +         while (u >= temp)
 254.173 +            n++, temp += temp;
 254.174 +         nbins += n;
 254.175 +         /* create transformation stack entry */
 254.176 +         info = npp_push_tse(npp,
 254.177 +            rcv_binarize_prob, sizeof(struct binarize));
 254.178 +         info->q = col->j;
 254.179 +         info->j = 0; /* will be set below */
 254.180 +         info->n = n;
 254.181 +         /* if u < 2^n - 1, we need one additional row for (4) */
 254.182 +         if (u < temp - 1)
 254.183 +         {  row = npp_add_row(npp), nrows++;
 254.184 +            row->lb = -DBL_MAX, row->ub = u;
 254.185 +         }
 254.186 +         else
 254.187 +            row = NULL;
 254.188 +         /* in the transformed problem variable x[q] becomes binary
 254.189 +            variable x[0], so its objective and constraint coefficients
 254.190 +            are not changed */
 254.191 +         col->ub = 1.0;
 254.192 +         /* include x[0] into constraint (4) */
 254.193 +         if (row != NULL)
 254.194 +            npp_add_aij(npp, row, col, 1.0);
 254.195 +         /* add other binary variables x[1], ..., x[n-1] */
 254.196 +         for (k = 1, temp = 2; k < n; k++, temp += temp)
 254.197 +         {  /* add new binary variable x[k] */
 254.198 +            bin = npp_add_col(npp);
 254.199 +            bin->is_int = 1;
 254.200 +            bin->lb = 0.0, bin->ub = 1.0;
 254.201 +            bin->coef = (double)temp * col->coef;
 254.202 +            /* store column reference number for x[1] */
 254.203 +            if (info->j == 0)
 254.204 +               info->j = bin->j;
 254.205 +            else
 254.206 +               xassert(info->j + (k-1) == bin->j);
 254.207 +            /* duplicate constraint coefficients for x[k]; this also
 254.208 +               automatically includes x[k] into constraint (4) */
 254.209 +            for (aij = col->ptr; aij != NULL; aij = aij->c_next)
 254.210 +               npp_add_aij(npp, aij->row, bin, (double)temp * aij->val);
 254.211 +         }
 254.212 +      }
 254.213 +      if (nvars > 0)
 254.214 +         xprintf("%d integer variable(s) were replaced by %d binary one"
 254.215 +            "s\n", nvars, nbins);
 254.216 +      if (nrows > 0)
 254.217 +         xprintf("%d row(s) were added due to binarization\n", nrows);
 254.218 +      if (nfails > 0)
 254.219 +         xprintf("Binarization failed for %d integer variable(s)\n",
 254.220 +            nfails);
 254.221 +      return nfails;
 254.222 +}
 254.223 +
 254.224 +static int rcv_binarize_prob(NPP *npp, void *_info)
 254.225 +{     /* recovery binarized variable */
 254.226 +      struct binarize *info = _info;
 254.227 +      int k, temp;
 254.228 +      double sum;
 254.229 +      /* compute value of x[q]; see formula (3) */
 254.230 +      sum = npp->c_value[info->q];
 254.231 +      for (k = 1, temp = 2; k < info->n; k++, temp += temp)
 254.232 +         sum += (double)temp * npp->c_value[info->j + (k-1)];
 254.233 +      npp->c_value[info->q] = sum;
 254.234 +      return 0;
 254.235 +}
 254.236 +
 254.237 +/**********************************************************************/
 254.238 +
 254.239 +struct elem
 254.240 +{     /* linear form element a[j] x[j] */
 254.241 +      double aj;
 254.242 +      /* non-zero coefficient value */
 254.243 +      NPPCOL *xj;
 254.244 +      /* pointer to variable (column) */
 254.245 +      struct elem *next;
 254.246 +      /* pointer to another term */
 254.247 +};
 254.248 +
 254.249 +static struct elem *copy_form(NPP *npp, NPPROW *row, double s)
 254.250 +{     /* copy linear form */
 254.251 +      NPPAIJ *aij;
 254.252 +      struct elem *ptr, *e;
 254.253 +      ptr = NULL;
 254.254 +      for (aij = row->ptr; aij != NULL; aij = aij->r_next)
 254.255 +      {  e = dmp_get_atom(npp->pool, sizeof(struct elem));
 254.256 +         e->aj = s * aij->val;
 254.257 +         e->xj = aij->col;
 254.258 +         e->next = ptr;
 254.259 +         ptr = e;
 254.260 +      }
 254.261 +      return ptr;
 254.262 +}
 254.263 +
 254.264 +static void drop_form(NPP *npp, struct elem *ptr)
 254.265 +{     /* drop linear form */
 254.266 +      struct elem *e;
 254.267 +      while (ptr != NULL)
 254.268 +      {  e = ptr;
 254.269 +         ptr = e->next;
 254.270 +         dmp_free_atom(npp->pool, e, sizeof(struct elem));
 254.271 +      }
 254.272 +      return;
 254.273 +}
 254.274 +
 254.275 +/***********************************************************************
 254.276 +*  NAME
 254.277 +*
 254.278 +*  npp_is_packing - test if constraint is packing inequality
 254.279 +*
 254.280 +*  SYNOPSIS
 254.281 +*
 254.282 +*  #include "glpnpp.h"
 254.283 +*  int npp_is_packing(NPP *npp, NPPROW *row);
 254.284 +*
 254.285 +*  RETURNS
 254.286 +*
 254.287 +*  If the specified row (constraint) is packing inequality (see below),
 254.288 +*  the routine npp_is_packing returns non-zero. Otherwise, it returns
 254.289 +*  zero.
 254.290 +*
 254.291 +*  PACKING INEQUALITIES
 254.292 +*
 254.293 +*  In canonical format the packing inequality is the following:
 254.294 +*
 254.295 +*     sum  x[j] <= 1,                                                (1)
 254.296 +*    j in J
 254.297 +*
 254.298 +*  where all variables x[j] are binary. This inequality expresses the
 254.299 +*  condition that in any integer feasible solution at most one variable
 254.300 +*  from set J can take non-zero (unity) value while other variables
 254.301 +*  must be equal to zero. W.l.o.g. it is assumed that |J| >= 2, because
 254.302 +*  if J is empty or |J| = 1, the inequality (1) is redundant.
 254.303 +*
 254.304 +*  In general case the packing inequality may include original variables
 254.305 +*  x[j] as well as their complements x~[j]:
 254.306 +*
 254.307 +*     sum   x[j] + sum   x~[j] <= 1,                                 (2)
 254.308 +*    j in Jp      j in Jn
 254.309 +*
 254.310 +*  where Jp and Jn are not intersected. Therefore, using substitution
 254.311 +*  x~[j] = 1 - x[j] gives the packing inequality in generalized format:
 254.312 +*
 254.313 +*     sum   x[j] - sum   x[j] <= 1 - |Jn|.                           (3)
 254.314 +*    j in Jp      j in Jn */
 254.315 +
 254.316 +int npp_is_packing(NPP *npp, NPPROW *row)
 254.317 +{     /* test if constraint is packing inequality */
 254.318 +      NPPCOL *col;
 254.319 +      NPPAIJ *aij;
 254.320 +      int b;
 254.321 +      xassert(npp == npp);
 254.322 +      if (!(row->lb == -DBL_MAX && row->ub != +DBL_MAX))
 254.323 +         return 0;
 254.324 +      b = 1;
 254.325 +      for (aij = row->ptr; aij != NULL; aij = aij->r_next)
 254.326 +      {  col = aij->col;
 254.327 +         if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
 254.328 +            return 0;
 254.329 +         if (aij->val == +1.0)
 254.330 +            ;
 254.331 +         else if (aij->val == -1.0)
 254.332 +            b--;
 254.333 +         else
 254.334 +            return 0;
 254.335 +      }
 254.336 +      if (row->ub != (double)b) return 0;
 254.337 +      return 1;
 254.338 +}
 254.339 +
 254.340 +/***********************************************************************
 254.341 +*  NAME
 254.342 +*
 254.343 +*  npp_hidden_packing - identify hidden packing inequality
 254.344 +*
 254.345 +*  SYNOPSIS
 254.346 +*
 254.347 +*  #include "glpnpp.h"
 254.348 +*  int npp_hidden_packing(NPP *npp, NPPROW *row);
 254.349 +*
 254.350 +*  DESCRIPTION
 254.351 +*
 254.352 +*  The routine npp_hidden_packing processes specified inequality
 254.353 +*  constraint, which includes only binary variables, and the number of
 254.354 +*  the variables is not less than two. If the original inequality is
 254.355 +*  equivalent to a packing inequality, the routine replaces it by this
 254.356 +*  equivalent inequality. If the original constraint is double-sided
 254.357 +*  inequality, it is replaced by a pair of single-sided inequalities,
 254.358 +*  if necessary.
 254.359 +*
 254.360 +*  RETURNS
 254.361 +*
 254.362 +*  If the original inequality constraint was replaced by equivalent
 254.363 +*  packing inequality, the routine npp_hidden_packing returns non-zero.
 254.364 +*  Otherwise, it returns zero.
 254.365 +*
 254.366 +*  PROBLEM TRANSFORMATION
 254.367 +*
 254.368 +*  Consider an inequality constraint:
 254.369 +*
 254.370 +*     sum  a[j] x[j] <= b,                                           (1)
 254.371 +*    j in J
 254.372 +*
 254.373 +*  where all variables x[j] are binary, and |J| >= 2. (In case of '>='
 254.374 +*  inequality it can be transformed to '<=' format by multiplying both
 254.375 +*  its sides by -1.)
 254.376 +*
 254.377 +*  Let Jp = {j: a[j] > 0}, Jn = {j: a[j] < 0}. Performing substitution
 254.378 +*  x[j] = 1 - x~[j] for all j in Jn, we have:
 254.379 +*
 254.380 +*     sum   a[j] x[j] <= b  ==>
 254.381 +*    j in J
 254.382 +*
 254.383 +*     sum   a[j] x[j] + sum   a[j] x[j] <= b  ==>
 254.384 +*    j in Jp           j in Jn
 254.385 +*
 254.386 +*     sum   a[j] x[j] + sum   a[j] (1 - x~[j]) <= b  ==>
 254.387 +*    j in Jp           j in Jn
 254.388 +*
 254.389 +*     sum   a[j] x[j] - sum   a[j] x~[j] <= b - sum   a[j].
 254.390 +*    j in Jp           j in Jn                 j in Jn
 254.391 +*
 254.392 +*  Thus, meaning the transformation above, we can assume that in
 254.393 +*  inequality (1) all coefficients a[j] are positive. Moreover, we can
 254.394 +*  assume that a[j] <= b. In fact, let a[j] > b; then the following
 254.395 +*  three cases are possible:
 254.396 +*
 254.397 +*  1) b < 0. In this case inequality (1) is infeasible, so the problem
 254.398 +*     has no feasible solution (see the routine npp_analyze_row);
 254.399 +*
 254.400 +*  2) b = 0. In this case inequality (1) is a forcing inequality on its
 254.401 +*     upper bound (see the routine npp_forcing row), from which it
 254.402 +*     follows that all variables x[j] should be fixed at zero;
 254.403 +*
 254.404 +*  3) b > 0. In this case inequality (1) defines an implied zero upper
 254.405 +*     bound for variable x[j] (see the routine npp_implied_bounds), from
 254.406 +*     which it follows that x[j] should be fixed at zero.
 254.407 +*
 254.408 +*  It is assumed that all three cases listed above have been recognized
 254.409 +*  by the routine npp_process_prob, which performs basic MIP processing
 254.410 +*  prior to a call the routine npp_hidden_packing. So, if one of these
 254.411 +*  cases occurs, we should just skip processing such constraint.
 254.412 +*
 254.413 +*  Thus, let 0 < a[j] <= b. Then it is obvious that constraint (1) is
 254.414 +*  equivalent to packing inquality only if:
 254.415 +*
 254.416 +*     a[j] + a[k] > b + eps                                          (2)
 254.417 +*
 254.418 +*  for all j, k in J, j != k, where eps is an absolute tolerance for
 254.419 +*  row (linear form) value. Checking the condition (2) for all j and k,
 254.420 +*  j != k, requires time O(|J|^2). However, this time can be reduced to
 254.421 +*  O(|J|), if use minimal a[j] and a[k], in which case it is sufficient
 254.422 +*  to check the condition (2) only once.
 254.423 +*
 254.424 +*  Once the original inequality (1) is replaced by equivalent packing
 254.425 +*  inequality, we need to perform back substitution x~[j] = 1 - x[j] for
 254.426 +*  all j in Jn (see above).
 254.427 +*
 254.428 +*  RECOVERING SOLUTION
 254.429 +*
 254.430 +*  None needed. */
 254.431 +
 254.432 +static int hidden_packing(NPP *npp, struct elem *ptr, double *_b)
 254.433 +{     /* process inequality constraint: sum a[j] x[j] <= b;
 254.434 +         0 - specified row is NOT hidden packing inequality;
 254.435 +         1 - specified row is packing inequality;
 254.436 +         2 - specified row is hidden packing inequality. */
 254.437 +      struct elem *e, *ej, *ek;
 254.438 +      int neg;
 254.439 +      double b = *_b, eps;
 254.440 +      xassert(npp == npp);
 254.441 +      /* a[j] must be non-zero, x[j] must be binary, for all j in J */
 254.442 +      for (e = ptr; e != NULL; e = e->next)
 254.443 +      {  xassert(e->aj != 0.0);
 254.444 +         xassert(e->xj->is_int);
 254.445 +         xassert(e->xj->lb == 0.0 && e->xj->ub == 1.0);
 254.446 +      }
 254.447 +      /* check if the specified inequality constraint already has the
 254.448 +         form of packing inequality */
 254.449 +      neg = 0; /* neg is |Jn| */
 254.450 +      for (e = ptr; e != NULL; e = e->next)
 254.451 +      {  if (e->aj == +1.0)
 254.452 +            ;
 254.453 +         else if (e->aj == -1.0)
 254.454 +            neg++;
 254.455 +         else
 254.456 +            break;
 254.457 +      }
 254.458 +      if (e == NULL)
 254.459 +      {  /* all coefficients a[j] are +1 or -1; check rhs b */
 254.460 +         if (b == (double)(1 - neg))
 254.461 +         {  /* it is packing inequality; no processing is needed */
 254.462 +            return 1;
 254.463 +         }
 254.464 +      }
 254.465 +      /* substitute x[j] = 1 - x~[j] for all j in Jn to make all a[j]
 254.466 +         positive; the result is a~[j] = |a[j]| and new rhs b */
 254.467 +      for (e = ptr; e != NULL; e = e->next)
 254.468 +         if (e->aj < 0) b -= e->aj;
 254.469 +      /* now a[j] > 0 for all j in J (actually |a[j]| are used) */
 254.470 +      /* if a[j] > b, skip processing--this case must not appear */
 254.471 +      for (e = ptr; e != NULL; e = e->next)
 254.472 +         if (fabs(e->aj) > b) return 0;
 254.473 +      /* now 0 < a[j] <= b for all j in J */
 254.474 +      /* find two minimal coefficients a[j] and a[k], j != k */
 254.475 +      ej = NULL;
 254.476 +      for (e = ptr; e != NULL; e = e->next)
 254.477 +         if (ej == NULL || fabs(ej->aj) > fabs(e->aj)) ej = e;
 254.478 +      xassert(ej != NULL);
 254.479 +      ek = NULL;
 254.480 +      for (e = ptr; e != NULL; e = e->next)
 254.481 +         if (e != ej)
 254.482 +            if (ek == NULL || fabs(ek->aj) > fabs(e->aj)) ek = e;
 254.483 +      xassert(ek != NULL);
 254.484 +      /* the specified constraint is equivalent to packing inequality
 254.485 +         iff a[j] + a[k] > b + eps */
 254.486 +      eps = 1e-3 + 1e-6 * fabs(b);
 254.487 +      if (fabs(ej->aj) + fabs(ek->aj) <= b + eps) return 0;
 254.488 +      /* perform back substitution x~[j] = 1 - x[j] and construct the
 254.489 +         final equivalent packing inequality in generalized format */
 254.490 +      b = 1.0;
 254.491 +      for (e = ptr; e != NULL; e = e->next)
 254.492 +      {  if (e->aj > 0.0)
 254.493 +            e->aj = +1.0;
 254.494 +         else /* e->aj < 0.0 */
 254.495 +            e->aj = -1.0, b -= 1.0;
 254.496 +      }
 254.497 +      *_b = b;
 254.498 +      return 2;
 254.499 +}
 254.500 +
 254.501 +int npp_hidden_packing(NPP *npp, NPPROW *row)
 254.502 +{     /* identify hidden packing inequality */
 254.503 +      NPPROW *copy;
 254.504 +      NPPAIJ *aij;
 254.505 +      struct elem *ptr, *e;
 254.506 +      int kase, ret, count = 0;
 254.507 +      double b;
 254.508 +      /* the row must be inequality constraint */
 254.509 +      xassert(row->lb < row->ub);
 254.510 +      for (kase = 0; kase <= 1; kase++)
 254.511 +      {  if (kase == 0)
 254.512 +         {  /* process row upper bound */
 254.513 +            if (row->ub == +DBL_MAX) continue;
 254.514 +            ptr = copy_form(npp, row, +1.0);
 254.515 +            b = + row->ub;
 254.516 +         }
 254.517 +         else
 254.518 +         {  /* process row lower bound */
 254.519 +            if (row->lb == -DBL_MAX) continue;
 254.520 +            ptr = copy_form(npp, row, -1.0);
 254.521 +            b = - row->lb;
 254.522 +         }
 254.523 +         /* now the inequality has the form "sum a[j] x[j] <= b" */
 254.524 +         ret = hidden_packing(npp, ptr, &b);
 254.525 +         xassert(0 <= ret && ret <= 2);
 254.526 +         if (kase == 1 && ret == 1 || ret == 2)
 254.527 +         {  /* the original inequality has been identified as hidden
 254.528 +               packing inequality */
 254.529 +            count++;
 254.530 +#ifdef GLP_DEBUG
 254.531 +            xprintf("Original constraint:\n");
 254.532 +            for (aij = row->ptr; aij != NULL; aij = aij->r_next)
 254.533 +               xprintf(" %+g x%d", aij->val, aij->col->j);
 254.534 +            if (row->lb != -DBL_MAX) xprintf(", >= %g", row->lb);
 254.535 +            if (row->ub != +DBL_MAX) xprintf(", <= %g", row->ub);
 254.536 +            xprintf("\n");
 254.537 +            xprintf("Equivalent packing inequality:\n");
 254.538 +            for (e = ptr; e != NULL; e = e->next)
 254.539 +               xprintf(" %sx%d", e->aj > 0.0 ? "+" : "-", e->xj->j);
 254.540 +            xprintf(", <= %g\n", b);
 254.541 +#endif
 254.542 +            if (row->lb == -DBL_MAX || row->ub == +DBL_MAX)
 254.543 +            {  /* the original row is single-sided inequality; no copy
 254.544 +                  is needed */
 254.545 +               copy = NULL;
 254.546 +            }
 254.547 +            else
 254.548 +            {  /* the original row is double-sided inequality; we need
 254.549 +                  to create its copy for other bound before replacing it
 254.550 +                  with the equivalent inequality */
 254.551 +               copy = npp_add_row(npp);
 254.552 +               if (kase == 0)
 254.553 +               {  /* the copy is for lower bound */
 254.554 +                  copy->lb = row->lb, copy->ub = +DBL_MAX;
 254.555 +               }
 254.556 +               else
 254.557 +               {  /* the copy is for upper bound */
 254.558 +                  copy->lb = -DBL_MAX, copy->ub = row->ub;
 254.559 +               }
 254.560 +               /* copy original row coefficients */
 254.561 +               for (aij = row->ptr; aij != NULL; aij = aij->r_next)
 254.562 +                  npp_add_aij(npp, copy, aij->col, aij->val);
 254.563 +            }
 254.564 +            /* replace the original inequality by equivalent one */
 254.565 +            npp_erase_row(npp, row);
 254.566 +            row->lb = -DBL_MAX, row->ub = b;
 254.567 +            for (e = ptr; e != NULL; e = e->next)
 254.568 +               npp_add_aij(npp, row, e->xj, e->aj);
 254.569 +            /* continue processing lower bound for the copy */
 254.570 +            if (copy != NULL) row = copy;
 254.571 +         }
 254.572 +         drop_form(npp, ptr);
 254.573 +      }
 254.574 +      return count;
 254.575 +}
 254.576 +
 254.577 +/***********************************************************************
 254.578 +*  NAME
 254.579 +*
 254.580 +*  npp_implied_packing - identify implied packing inequality
 254.581 +*
 254.582 +*  SYNOPSIS
 254.583 +*
 254.584 +*  #include "glpnpp.h"
 254.585 +*  int npp_implied_packing(NPP *npp, NPPROW *row, int which,
 254.586 +*     NPPCOL *var[], char set[]);
 254.587 +*
 254.588 +*  DESCRIPTION
 254.589 +*
 254.590 +*  The routine npp_implied_packing processes specified row (constraint)
 254.591 +*  of general format:
 254.592 +*
 254.593 +*     L <= sum a[j] x[j] <= U.                                       (1)
 254.594 +*           j
 254.595 +*
 254.596 +*  If which = 0, only lower bound L, which must exist, is considered,
 254.597 +*  while upper bound U is ignored. Similarly, if which = 1, only upper
 254.598 +*  bound U, which must exist, is considered, while lower bound L is
 254.599 +*  ignored. Thus, if the specified row is a double-sided inequality or
 254.600 +*  equality constraint, this routine should be called twice for both
 254.601 +*  lower and upper bounds.
 254.602 +*
 254.603 +*  The routine npp_implied_packing attempts to find a non-trivial (i.e.
 254.604 +*  having not less than two binary variables) packing inequality:
 254.605 +*
 254.606 +*     sum   x[j] - sum   x[j] <= 1 - |Jn|,                           (2)
 254.607 +*    j in Jp      j in Jn
 254.608 +*
 254.609 +*  which is relaxation of the constraint (1) in the sense that any
 254.610 +*  solution satisfying to that constraint also satisfies to the packing
 254.611 +*  inequality (2). If such relaxation exists, the routine stores
 254.612 +*  pointers to descriptors of corresponding binary variables and their
 254.613 +*  flags, resp., to locations var[1], var[2], ..., var[len] and set[1],
 254.614 +*  set[2], ..., set[len], where set[j] = 0 means that j in Jp and
 254.615 +*  set[j] = 1 means that j in Jn.
 254.616 +*
 254.617 +*  RETURNS
 254.618 +*
 254.619 +*  The routine npp_implied_packing returns len, which is the total
 254.620 +*  number of binary variables in the packing inequality found, len >= 2.
 254.621 +*  However, if the relaxation does not exist, the routine returns zero.
 254.622 +*
 254.623 +*  ALGORITHM
 254.624 +*
 254.625 +*  If which = 0, the constraint coefficients (1) are multiplied by -1
 254.626 +*  and b is assigned -L; if which = 1, the constraint coefficients (1)
 254.627 +*  are not changed and b is assigned +U. In both cases the specified
 254.628 +*  constraint gets the following format:
 254.629 +*
 254.630 +*     sum a[j] x[j] <= b.                                            (3)
 254.631 +*      j
 254.632 +*
 254.633 +*  (Note that (3) is a relaxation of (1), because one of bounds L or U
 254.634 +*  is ignored.)
 254.635 +*
 254.636 +*  Let J be set of binary variables, Kp be set of non-binary (integer
 254.637 +*  or continuous) variables with a[j] > 0, and Kn be set of non-binary
 254.638 +*  variables with a[j] < 0. Then the inequality (3) can be written as
 254.639 +*  follows:
 254.640 +*
 254.641 +*     sum  a[j] x[j] <= b - sum   a[j] x[j] - sum   a[j] x[j].       (4)
 254.642 +*    j in J                j in Kp           j in Kn
 254.643 +*
 254.644 +*  To get rid of non-binary variables we can replace the inequality (4)
 254.645 +*  by the following relaxed inequality:
 254.646 +*
 254.647 +*     sum  a[j] x[j] <= b~,                                          (5)
 254.648 +*    j in J
 254.649 +*
 254.650 +*  where:
 254.651 +*
 254.652 +*     b~ = sup(b - sum   a[j] x[j] - sum   a[j] x[j]) =
 254.653 +*                 j in Kp           j in Kn
 254.654 +*
 254.655 +*        = b - inf sum   a[j] x[j] - inf sum   a[j] x[j] =           (6)
 254.656 +*                 j in Kp               j in Kn
 254.657 +*
 254.658 +*        = b - sum   a[j] l[j] - sum   a[j] u[j].
 254.659 +*             j in Kp           j in Kn
 254.660 +*
 254.661 +*  Note that if lower bound l[j] (if j in Kp) or upper bound u[j]
 254.662 +*  (if j in Kn) of some non-binary variable x[j] does not exist, then
 254.663 +*  formally b = +oo, in which case further analysis is not performed.
 254.664 +*
 254.665 +*  Let Bp = {j in J: a[j] > 0}, Bn = {j in J: a[j] < 0}. To make all
 254.666 +*  the inequality coefficients in (5) positive, we replace all x[j] in
 254.667 +*  Bn by their complementaries, substituting x[j] = 1 - x~[j] for all
 254.668 +*  j in Bn, that gives:
 254.669 +*
 254.670 +*     sum   a[j] x[j] - sum   a[j] x~[j] <= b~ - sum   a[j].         (7)
 254.671 +*    j in Bp           j in Bn                  j in Bn
 254.672 +*
 254.673 +*  This inequality is a relaxation of the original constraint (1), and
 254.674 +*  it is a binary knapsack inequality. Writing it in the standard format
 254.675 +*  we have:
 254.676 +*
 254.677 +*     sum  alfa[j] z[j] <= beta,                                     (8)
 254.678 +*    j in J
 254.679 +*
 254.680 +*  where:
 254.681 +*               ( + a[j],   if j in Bp,
 254.682 +*     alfa[j] = <                                                    (9)
 254.683 +*               ( - a[j],   if j in Bn,
 254.684 +*
 254.685 +*               ( x[j],     if j in Bp,
 254.686 +*        z[j] = <                                                   (10)
 254.687 +*               ( 1 - x[j], if j in Bn,
 254.688 +*
 254.689 +*        beta = b~ - sum   a[j].                                    (11)
 254.690 +*                   j in Bn
 254.691 +*
 254.692 +*  In the inequality (8) all coefficients are positive, therefore, the
 254.693 +*  packing relaxation to be found for this inequality is the following:
 254.694 +*
 254.695 +*     sum  z[j] <= 1.                                               (12)
 254.696 +*    j in P
 254.697 +*
 254.698 +*  It is obvious that set P within J, which we would like to find, must
 254.699 +*  satisfy to the following condition:
 254.700 +*
 254.701 +*     alfa[j] + alfa[k] > beta + eps  for all j, k in P, j != k,    (13)
 254.702 +*
 254.703 +*  where eps is an absolute tolerance for value of the linear form.
 254.704 +*  Thus, it is natural to take P = {j: alpha[j] > (beta + eps) / 2}.
 254.705 +*  Moreover, if in the equality (8) there exist coefficients alfa[k],
 254.706 +*  for which alfa[k] <= (beta + eps) / 2, but which, nevertheless,
 254.707 +*  satisfies to the condition (13) for all j in P, *one* corresponding
 254.708 +*  variable z[k] (having, for example, maximal coefficient alfa[k]) can
 254.709 +*  be included in set P, that allows increasing the number of binary
 254.710 +*  variables in (12) by one.
 254.711 +*
 254.712 +*  Once the set P has been built, for the inequality (12) we need to
 254.713 +*  perform back substitution according to (10) in order to express it
 254.714 +*  through the original binary variables. As the result of such back
 254.715 +*  substitution the relaxed packing inequality get its final format (2),
 254.716 +*  where Jp = J intersect Bp, and Jn = J intersect Bn. */
 254.717 +
 254.718 +int npp_implied_packing(NPP *npp, NPPROW *row, int which,
 254.719 +      NPPCOL *var[], char set[])
 254.720 +{     struct elem *ptr, *e, *i, *k;
 254.721 +      int len = 0;
 254.722 +      double b, eps;
 254.723 +      /* build inequality (3) */
 254.724 +      if (which == 0)
 254.725 +      {  ptr = copy_form(npp, row, -1.0);
 254.726 +         xassert(row->lb != -DBL_MAX);
 254.727 +         b = - row->lb;
 254.728 +      }
 254.729 +      else if (which == 1)
 254.730 +      {  ptr = copy_form(npp, row, +1.0);
 254.731 +         xassert(row->ub != +DBL_MAX);
 254.732 +         b = + row->ub;
 254.733 +      }
 254.734 +      /* remove non-binary variables to build relaxed inequality (5);
 254.735 +         compute its right-hand side b~ with formula (6) */
 254.736 +      for (e = ptr; e != NULL; e = e->next)
 254.737 +      {  if (!(e->xj->is_int && e->xj->lb == 0.0 && e->xj->ub == 1.0))
 254.738 +         {  /* x[j] is non-binary variable */
 254.739 +            if (e->aj > 0.0)
 254.740 +            {  if (e->xj->lb == -DBL_MAX) goto done;
 254.741 +               b -= e->aj * e->xj->lb;
 254.742 +            }
 254.743 +            else /* e->aj < 0.0 */
 254.744 +            {  if (e->xj->ub == +DBL_MAX) goto done;
 254.745 +               b -= e->aj * e->xj->ub;
 254.746 +            }
 254.747 +            /* a[j] = 0 means that variable x[j] is removed */
 254.748 +            e->aj = 0.0;
 254.749 +         }
 254.750 +      }
 254.751 +      /* substitute x[j] = 1 - x~[j] to build knapsack inequality (8);
 254.752 +         compute its right-hand side beta with formula (11) */
 254.753 +      for (e = ptr; e != NULL; e = e->next)
 254.754 +         if (e->aj < 0.0) b -= e->aj;
 254.755 +      /* if beta is close to zero, the knapsack inequality is either
 254.756 +         infeasible or forcing inequality; this must never happen, so
 254.757 +         we skip further analysis */
 254.758 +      if (b < 1e-3) goto done;
 254.759 +      /* build set P as well as sets Jp and Jn, and determine x[k] as
 254.760 +         explained above in comments to the routine */
 254.761 +      eps = 1e-3 + 1e-6 * b;
 254.762 +      i = k = NULL;
 254.763 +      for (e = ptr; e != NULL; e = e->next)
 254.764 +      {  /* note that alfa[j] = |a[j]| */
 254.765 +         if (fabs(e->aj) > 0.5 * (b + eps))
 254.766 +         {  /* alfa[j] > (b + eps) / 2; include x[j] in set P, i.e. in
 254.767 +               set Jp or Jn */
 254.768 +            var[++len] = e->xj;
 254.769 +            set[len] = (char)(e->aj > 0.0 ? 0 : 1);
 254.770 +            /* alfa[i] = min alfa[j] over all j included in set P */
 254.771 +            if (i == NULL || fabs(i->aj) > fabs(e->aj)) i = e;
 254.772 +         }
 254.773 +         else if (fabs(e->aj) >= 1e-3)
 254.774 +         {  /* alfa[k] = max alfa[j] over all j not included in set P;
 254.775 +               we skip coefficient a[j] if it is close to zero to avoid
 254.776 +               numerically unreliable results */
 254.777 +            if (k == NULL || fabs(k->aj) < fabs(e->aj)) k = e;
 254.778 +         }
 254.779 +      }
 254.780 +      /* if alfa[k] satisfies to condition (13) for all j in P, include
 254.781 +         x[k] in P */
 254.782 +      if (i != NULL && k != NULL && fabs(i->aj) + fabs(k->aj) > b + eps)
 254.783 +      {  var[++len] = k->xj;
 254.784 +         set[len] = (char)(k->aj > 0.0 ? 0 : 1);
 254.785 +      }
 254.786 +      /* trivial packing inequality being redundant must never appear,
 254.787 +         so we just ignore it */
 254.788 +      if (len < 2) len = 0;
 254.789 +done: drop_form(npp, ptr);
 254.790 +      return len;
 254.791 +}
 254.792 +
 254.793 +/***********************************************************************
 254.794 +*  NAME
 254.795 +*
 254.796 +*  npp_is_covering - test if constraint is covering inequality
 254.797 +*
 254.798 +*  SYNOPSIS
 254.799 +*
 254.800 +*  #include "glpnpp.h"
 254.801 +*  int npp_is_covering(NPP *npp, NPPROW *row);
 254.802 +*
 254.803 +*  RETURNS
 254.804 +*
 254.805 +*  If the specified row (constraint) is covering inequality (see below),
 254.806 +*  the routine npp_is_covering returns non-zero. Otherwise, it returns
 254.807 +*  zero.
 254.808 +*
 254.809 +*  COVERING INEQUALITIES
 254.810 +*
 254.811 +*  In canonical format the covering inequality is the following:
 254.812 +*
 254.813 +*     sum  x[j] >= 1,                                                (1)
 254.814 +*    j in J
 254.815 +*
 254.816 +*  where all variables x[j] are binary. This inequality expresses the
 254.817 +*  condition that in any integer feasible solution variables in set J
 254.818 +*  cannot be all equal to zero at the same time, i.e. at least one
 254.819 +*  variable must take non-zero (unity) value. W.l.o.g. it is assumed
 254.820 +*  that |J| >= 2, because if J is empty, the inequality (1) is
 254.821 +*  infeasible, and if |J| = 1, the inequality (1) is a forcing row.
 254.822 +*
 254.823 +*  In general case the covering inequality may include original
 254.824 +*  variables x[j] as well as their complements x~[j]:
 254.825 +*
 254.826 +*     sum   x[j] + sum   x~[j] >= 1,                                 (2)
 254.827 +*    j in Jp      j in Jn
 254.828 +*
 254.829 +*  where Jp and Jn are not intersected. Therefore, using substitution
 254.830 +*  x~[j] = 1 - x[j] gives the packing inequality in generalized format:
 254.831 +*
 254.832 +*     sum   x[j] - sum   x[j] >= 1 - |Jn|.                           (3)
 254.833 +*    j in Jp      j in Jn
 254.834 +*
 254.835 +*  (May note that the inequality (3) cuts off infeasible solutions,
 254.836 +*  where x[j] = 0 for all j in Jp and x[j] = 1 for all j in Jn.)
 254.837 +*
 254.838 +*  NOTE: If |J| = 2, the inequality (3) is equivalent to packing
 254.839 +*        inequality (see the routine npp_is_packing). */
 254.840 +
 254.841 +int npp_is_covering(NPP *npp, NPPROW *row)
 254.842 +{     /* test if constraint is covering inequality */
 254.843 +      NPPCOL *col;
 254.844 +      NPPAIJ *aij;
 254.845 +      int b;
 254.846 +      xassert(npp == npp);
 254.847 +      if (!(row->lb != -DBL_MAX && row->ub == +DBL_MAX))
 254.848 +         return 0;
 254.849 +      b = 1;
 254.850 +      for (aij = row->ptr; aij != NULL; aij = aij->r_next)
 254.851 +      {  col = aij->col;
 254.852 +         if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
 254.853 +            return 0;
 254.854 +         if (aij->val == +1.0)
 254.855 +            ;
 254.856 +         else if (aij->val == -1.0)
 254.857 +            b--;
 254.858 +         else
 254.859 +            return 0;
 254.860 +      }
 254.861 +      if (row->lb != (double)b) return 0;
 254.862 +      return 1;
 254.863 +}
 254.864 +
 254.865 +/***********************************************************************
 254.866 +*  NAME
 254.867 +*
 254.868 +*  npp_hidden_covering - identify hidden covering inequality
 254.869 +*
 254.870 +*  SYNOPSIS
 254.871 +*
 254.872 +*  #include "glpnpp.h"
 254.873 +*  int npp_hidden_covering(NPP *npp, NPPROW *row);
 254.874 +*
 254.875 +*  DESCRIPTION
 254.876 +*
 254.877 +*  The routine npp_hidden_covering processes specified inequality
 254.878 +*  constraint, which includes only binary variables, and the number of
 254.879 +*  the variables is not less than three. If the original inequality is
 254.880 +*  equivalent to a covering inequality (see below), the routine
 254.881 +*  replaces it by the equivalent inequality. If the original constraint
 254.882 +*  is double-sided inequality, it is replaced by a pair of single-sided
 254.883 +*  inequalities, if necessary.
 254.884 +*
 254.885 +*  RETURNS
 254.886 +*
 254.887 +*  If the original inequality constraint was replaced by equivalent
 254.888 +*  covering inequality, the routine npp_hidden_covering returns
 254.889 +*  non-zero. Otherwise, it returns zero.
 254.890 +*
 254.891 +*  PROBLEM TRANSFORMATION
 254.892 +*
 254.893 +*  Consider an inequality constraint:
 254.894 +*
 254.895 +*     sum  a[j] x[j] >= b,                                           (1)
 254.896 +*    j in J
 254.897 +*
 254.898 +*  where all variables x[j] are binary, and |J| >= 3. (In case of '<='
 254.899 +*  inequality it can be transformed to '>=' format by multiplying both
 254.900 +*  its sides by -1.)
 254.901 +*
 254.902 +*  Let Jp = {j: a[j] > 0}, Jn = {j: a[j] < 0}. Performing substitution
 254.903 +*  x[j] = 1 - x~[j] for all j in Jn, we have:
 254.904 +*
 254.905 +*     sum   a[j] x[j] >= b  ==>
 254.906 +*    j in J
 254.907 +*
 254.908 +*     sum   a[j] x[j] + sum   a[j] x[j] >= b  ==>
 254.909 +*    j in Jp           j in Jn
 254.910 +*
 254.911 +*     sum   a[j] x[j] + sum   a[j] (1 - x~[j]) >= b  ==>
 254.912 +*    j in Jp           j in Jn
 254.913 +*
 254.914 +*     sum  m   a[j] x[j] - sum   a[j] x~[j] >= b - sum   a[j].
 254.915 +*    j in Jp              j in Jn                 j in Jn
 254.916 +*
 254.917 +*  Thus, meaning the transformation above, we can assume that in
 254.918 +*  inequality (1) all coefficients a[j] are positive. Moreover, we can
 254.919 +*  assume that b > 0, because otherwise the inequality (1) would be
 254.920 +*  redundant (see the routine npp_analyze_row). It is then obvious that
 254.921 +*  constraint (1) is equivalent to covering inequality only if:
 254.922 +*
 254.923 +*     a[j] >= b,                                                     (2)
 254.924 +*
 254.925 +*  for all j in J.
 254.926 +*
 254.927 +*  Once the original inequality (1) is replaced by equivalent covering
 254.928 +*  inequality, we need to perform back substitution x~[j] = 1 - x[j] for
 254.929 +*  all j in Jn (see above).
 254.930 +*
 254.931 +*  RECOVERING SOLUTION
 254.932 +*
 254.933 +*  None needed. */
 254.934 +
 254.935 +static int hidden_covering(NPP *npp, struct elem *ptr, double *_b)
 254.936 +{     /* process inequality constraint: sum a[j] x[j] >= b;
 254.937 +         0 - specified row is NOT hidden covering inequality;
 254.938 +         1 - specified row is covering inequality;
 254.939 +         2 - specified row is hidden covering inequality. */
 254.940 +      struct elem *e;
 254.941 +      int neg;
 254.942 +      double b = *_b, eps;
 254.943 +      xassert(npp == npp);
 254.944 +      /* a[j] must be non-zero, x[j] must be binary, for all j in J */
 254.945 +      for (e = ptr; e != NULL; e = e->next)
 254.946 +      {  xassert(e->aj != 0.0);
 254.947 +         xassert(e->xj->is_int);
 254.948 +         xassert(e->xj->lb == 0.0 && e->xj->ub == 1.0);
 254.949 +      }
 254.950 +      /* check if the specified inequality constraint already has the
 254.951 +         form of covering inequality */
 254.952 +      neg = 0; /* neg is |Jn| */
 254.953 +      for (e = ptr; e != NULL; e = e->next)
 254.954 +      {  if (e->aj == +1.0)
 254.955 +            ;
 254.956 +         else if (e->aj == -1.0)
 254.957 +            neg++;
 254.958 +         else
 254.959 +            break;
 254.960 +      }
 254.961 +      if (e == NULL)
 254.962 +      {  /* all coefficients a[j] are +1 or -1; check rhs b */
 254.963 +         if (b == (double)(1 - neg))
 254.964 +         {  /* it is covering inequality; no processing is needed */
 254.965 +            return 1;
 254.966 +         }
 254.967 +      }
 254.968 +      /* substitute x[j] = 1 - x~[j] for all j in Jn to make all a[j]
 254.969 +         positive; the result is a~[j] = |a[j]| and new rhs b */
 254.970 +      for (e = ptr; e != NULL; e = e->next)
 254.971 +         if (e->aj < 0) b -= e->aj;
 254.972 +      /* now a[j] > 0 for all j in J (actually |a[j]| are used) */
 254.973 +      /* if b <= 0, skip processing--this case must not appear */
 254.974 +      if (b < 1e-3) return 0;
 254.975 +      /* now a[j] > 0 for all j in J, and b > 0 */
 254.976 +      /* the specified constraint is equivalent to covering inequality
 254.977 +         iff a[j] >= b for all j in J */
 254.978 +      eps = 1e-9 + 1e-12 * fabs(b);
 254.979 +      for (e = ptr; e != NULL; e = e->next)
 254.980 +         if (fabs(e->aj) < b - eps) return 0;
 254.981 +      /* perform back substitution x~[j] = 1 - x[j] and construct the
 254.982 +         final equivalent covering inequality in generalized format */
 254.983 +      b = 1.0;
 254.984 +      for (e = ptr; e != NULL; e = e->next)
 254.985 +      {  if (e->aj > 0.0)
 254.986 +            e->aj = +1.0;
 254.987 +         else /* e->aj < 0.0 */
 254.988 +            e->aj = -1.0, b -= 1.0;
 254.989 +      }
 254.990 +      *_b = b;
 254.991 +      return 2;
 254.992 +}
 254.993 +
 254.994 +int npp_hidden_covering(NPP *npp, NPPROW *row)
 254.995 +{     /* identify hidden covering inequality */
 254.996 +      NPPROW *copy;
 254.997 +      NPPAIJ *aij;
 254.998 +      struct elem *ptr, *e;
 254.999 +      int kase, ret, count = 0;
254.1000 +      double b;
254.1001 +      /* the row must be inequality constraint */
254.1002 +      xassert(row->lb < row->ub);
254.1003 +      for (kase = 0; kase <= 1; kase++)
254.1004 +      {  if (kase == 0)
254.1005 +         {  /* process row lower bound */
254.1006 +            if (row->lb == -DBL_MAX) continue;
254.1007 +            ptr = copy_form(npp, row, +1.0);
254.1008 +            b = + row->lb;
254.1009 +         }
254.1010 +         else
254.1011 +         {  /* process row upper bound */
254.1012 +            if (row->ub == +DBL_MAX) continue;
254.1013 +            ptr = copy_form(npp, row, -1.0);
254.1014 +            b = - row->ub;
254.1015 +         }
254.1016 +         /* now the inequality has the form "sum a[j] x[j] >= b" */
254.1017 +         ret = hidden_covering(npp, ptr, &b);
254.1018 +         xassert(0 <= ret && ret <= 2);
254.1019 +         if (kase == 1 && ret == 1 || ret == 2)
254.1020 +         {  /* the original inequality has been identified as hidden
254.1021 +               covering inequality */
254.1022 +            count++;
254.1023 +#ifdef GLP_DEBUG
254.1024 +            xprintf("Original constraint:\n");
254.1025 +            for (aij = row->ptr; aij != NULL; aij = aij->r_next)
254.1026 +               xprintf(" %+g x%d", aij->val, aij->col->j);
254.1027 +            if (row->lb != -DBL_MAX) xprintf(", >= %g", row->lb);
254.1028 +            if (row->ub != +DBL_MAX) xprintf(", <= %g", row->ub);
254.1029 +            xprintf("\n");
254.1030 +            xprintf("Equivalent covering inequality:\n");
254.1031 +            for (e = ptr; e != NULL; e = e->next)
254.1032 +               xprintf(" %sx%d", e->aj > 0.0 ? "+" : "-", e->xj->j);
254.1033 +            xprintf(", >= %g\n", b);
254.1034 +#endif
254.1035 +            if (row->lb == -DBL_MAX || row->ub == +DBL_MAX)
254.1036 +            {  /* the original row is single-sided inequality; no copy
254.1037 +                  is needed */
254.1038 +               copy = NULL;
254.1039 +            }
254.1040 +            else
254.1041 +            {  /* the original row is double-sided inequality; we need
254.1042 +                  to create its copy for other bound before replacing it
254.1043 +                  with the equivalent inequality */
254.1044 +               copy = npp_add_row(npp);
254.1045 +               if (kase == 0)
254.1046 +               {  /* the copy is for upper bound */
254.1047 +                  copy->lb = -DBL_MAX, copy->ub = row->ub;
254.1048 +               }
254.1049 +               else
254.1050 +               {  /* the copy is for lower bound */
254.1051 +                  copy->lb = row->lb, copy->ub = +DBL_MAX;
254.1052 +               }
254.1053 +               /* copy original row coefficients */
254.1054 +               for (aij = row->ptr; aij != NULL; aij = aij->r_next)
254.1055 +                  npp_add_aij(npp, copy, aij->col, aij->val);
254.1056 +            }
254.1057 +            /* replace the original inequality by equivalent one */
254.1058 +            npp_erase_row(npp, row);
254.1059 +            row->lb = b, row->ub = +DBL_MAX;
254.1060 +            for (e = ptr; e != NULL; e = e->next)
254.1061 +               npp_add_aij(npp, row, e->xj, e->aj);
254.1062 +            /* continue processing upper bound for the copy */
254.1063 +            if (copy != NULL) row = copy;
254.1064 +         }
254.1065 +         drop_form(npp, ptr);
254.1066 +      }
254.1067 +      return count;
254.1068 +}
254.1069 +
254.1070 +/***********************************************************************
254.1071 +*  NAME
254.1072 +*
254.1073 +*  npp_is_partitioning - test if constraint is partitioning equality
254.1074 +*
254.1075 +*  SYNOPSIS
254.1076 +*
254.1077 +*  #include "glpnpp.h"
254.1078 +*  int npp_is_partitioning(NPP *npp, NPPROW *row);
254.1079 +*
254.1080 +*  RETURNS
254.1081 +*
254.1082 +*  If the specified row (constraint) is partitioning equality (see
254.1083 +*  below), the routine npp_is_partitioning returns non-zero. Otherwise,
254.1084 +*  it returns zero.
254.1085 +*
254.1086 +*  PARTITIONING EQUALITIES
254.1087 +*
254.1088 +*  In canonical format the partitioning equality is the following:
254.1089 +*
254.1090 +*     sum  x[j] = 1,                                                 (1)
254.1091 +*    j in J
254.1092 +*
254.1093 +*  where all variables x[j] are binary. This equality expresses the
254.1094 +*  condition that in any integer feasible solution exactly one variable
254.1095 +*  in set J must take non-zero (unity) value while other variables must
254.1096 +*  be equal to zero. W.l.o.g. it is assumed that |J| >= 2, because if
254.1097 +*  J is empty, the inequality (1) is infeasible, and if |J| = 1, the
254.1098 +*  inequality (1) is a fixing row.
254.1099 +*
254.1100 +*  In general case the partitioning equality may include original
254.1101 +*  variables x[j] as well as their complements x~[j]:
254.1102 +*
254.1103 +*     sum   x[j] + sum   x~[j] = 1,                                  (2)
254.1104 +*    j in Jp      j in Jn
254.1105 +*
254.1106 +*  where Jp and Jn are not intersected. Therefore, using substitution
254.1107 +*  x~[j] = 1 - x[j] leads to the partitioning equality in generalized
254.1108 +*  format:
254.1109 +*
254.1110 +*     sum   x[j] - sum   x[j] = 1 - |Jn|.                            (3)
254.1111 +*    j in Jp      j in Jn */
254.1112 +
254.1113 +int npp_is_partitioning(NPP *npp, NPPROW *row)
254.1114 +{     /* test if constraint is partitioning equality */
254.1115 +      NPPCOL *col;
254.1116 +      NPPAIJ *aij;
254.1117 +      int b;
254.1118 +      xassert(npp == npp);
254.1119 +      if (row->lb != row->ub) return 0;
254.1120 +      b = 1;
254.1121 +      for (aij = row->ptr; aij != NULL; aij = aij->r_next)
254.1122 +      {  col = aij->col;
254.1123 +         if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
254.1124 +            return 0;
254.1125 +         if (aij->val == +1.0)
254.1126 +            ;
254.1127 +         else if (aij->val == -1.0)
254.1128 +            b--;
254.1129 +         else
254.1130 +            return 0;
254.1131 +      }
254.1132 +      if (row->lb != (double)b) return 0;
254.1133 +      return 1;
254.1134 +}
254.1135 +
254.1136 +/***********************************************************************
254.1137 +*  NAME
254.1138 +*
254.1139 +*  npp_reduce_ineq_coef - reduce inequality constraint coefficients
254.1140 +*
254.1141 +*  SYNOPSIS
254.1142 +*
254.1143 +*  #include "glpnpp.h"
254.1144 +*  int npp_reduce_ineq_coef(NPP *npp, NPPROW *row);
254.1145 +*
254.1146 +*  DESCRIPTION
254.1147 +*
254.1148 +*  The routine npp_reduce_ineq_coef processes specified inequality
254.1149 +*  constraint attempting to replace it by an equivalent constraint,
254.1150 +*  where magnitude of coefficients at binary variables is smaller than
254.1151 +*  in the original constraint. If the inequality is double-sided, it is
254.1152 +*  replaced by a pair of single-sided inequalities, if necessary.
254.1153 +*
254.1154 +*  RETURNS
254.1155 +*
254.1156 +*  The routine npp_reduce_ineq_coef returns the number of coefficients
254.1157 +*  reduced.
254.1158 +*
254.1159 +*  BACKGROUND
254.1160 +*
254.1161 +*  Consider an inequality constraint:
254.1162 +*
254.1163 +*     sum  a[j] x[j] >= b.                                           (1)
254.1164 +*    j in J
254.1165 +*
254.1166 +*  (In case of '<=' inequality it can be transformed to '>=' format by
254.1167 +*  multiplying both its sides by -1.) Let x[k] be a binary variable;
254.1168 +*  other variables can be integer as well as continuous. We can write
254.1169 +*  constraint (1) as follows:
254.1170 +*
254.1171 +*     a[k] x[k] + t[k] >= b,                                         (2)
254.1172 +*
254.1173 +*  where:
254.1174 +*
254.1175 +*     t[k] = sum      a[j] x[j].                                     (3)
254.1176 +*           j in J\{k}
254.1177 +*
254.1178 +*  Since x[k] is binary, constraint (2) is equivalent to disjunction of
254.1179 +*  the following two constraints:
254.1180 +*
254.1181 +*     x[k] = 0,  t[k] >= b                                           (4)
254.1182 +*
254.1183 +*        OR
254.1184 +*
254.1185 +*     x[k] = 1,  t[k] >= b - a[k].                                   (5)
254.1186 +*
254.1187 +*  Let also that for the partial sum t[k] be known some its implied
254.1188 +*  lower bound inf t[k].
254.1189 +*
254.1190 +*  Case a[k] > 0. Let inf t[k] < b, since otherwise both constraints
254.1191 +*  (4) and (5) and therefore constraint (2) are redundant.
254.1192 +*  If inf t[k] > b - a[k], only constraint (5) is redundant, in which
254.1193 +*  case it can be replaced with the following redundant and therefore
254.1194 +*  equivalent constraint:
254.1195 +*
254.1196 +*     t[k] >= b - a'[k] = inf t[k],                                  (6)
254.1197 +*
254.1198 +*  where:
254.1199 +*
254.1200 +*     a'[k] = b - inf t[k].                                          (7)
254.1201 +*
254.1202 +*  Thus, the original constraint (2) is equivalent to the following
254.1203 +*  constraint with coefficient at variable x[k] changed:
254.1204 +*
254.1205 +*     a'[k] x[k] + t[k] >= b.                                        (8)
254.1206 +*
254.1207 +*  From inf t[k] < b it follows that a'[k] > 0, i.e. the coefficient
254.1208 +*  at x[k] keeps its sign. And from inf t[k] > b - a[k] it follows that
254.1209 +*  a'[k] < a[k], i.e. the coefficient reduces in magnitude.
254.1210 +*
254.1211 +*  Case a[k] < 0. Let inf t[k] < b - a[k], since otherwise both
254.1212 +*  constraints (4) and (5) and therefore constraint (2) are redundant.
254.1213 +*  If inf t[k] > b, only constraint (4) is redundant, in which case it
254.1214 +*  can be replaced with the following redundant and therefore equivalent
254.1215 +*  constraint:
254.1216 +*
254.1217 +*     t[k] >= b' = inf t[k].                                         (9)
254.1218 +*
254.1219 +*  Rewriting constraint (5) as follows:
254.1220 +*
254.1221 +*     t[k] >= b - a[k] = b' - a'[k],                                (10)
254.1222 +*
254.1223 +*  where:
254.1224 +*
254.1225 +*     a'[k] = a[k] + b' - b = a[k] + inf t[k] - b,                  (11)
254.1226 +*
254.1227 +*  we can see that disjunction of constraint (9) and (10) is equivalent
254.1228 +*  to disjunction of constraint (4) and (5), from which it follows that
254.1229 +*  the original constraint (2) is equivalent to the following constraint
254.1230 +*  with both coefficient at variable x[k] and right-hand side changed:
254.1231 +*
254.1232 +*     a'[k] x[k] + t[k] >= b'.                                      (12)
254.1233 +*
254.1234 +*  From inf t[k] < b - a[k] it follows that a'[k] < 0, i.e. the
254.1235 +*  coefficient at x[k] keeps its sign. And from inf t[k] > b it follows
254.1236 +*  that a'[k] > a[k], i.e. the coefficient reduces in magnitude.
254.1237 +*
254.1238 +*  PROBLEM TRANSFORMATION
254.1239 +*
254.1240 +*  In the routine npp_reduce_ineq_coef the following implied lower
254.1241 +*  bound of the partial sum (3) is used:
254.1242 +*
254.1243 +*     inf t[k] = sum       a[j] l[j] + sum       a[j] u[j],         (13)
254.1244 +*               j in Jp\{k}           k in Jn\{k}
254.1245 +*
254.1246 +*  where Jp = {j : a[j] > 0}, Jn = {j : a[j] < 0}, l[j] and u[j] are
254.1247 +*  lower and upper bounds, resp., of variable x[j].
254.1248 +*
254.1249 +*  In order to compute inf t[k] more efficiently, the following formula,
254.1250 +*  which is equivalent to (13), is actually used:
254.1251 +*
254.1252 +*                ( h - a[k] l[k] = h,        if a[k] > 0,
254.1253 +*     inf t[k] = <                                                  (14)
254.1254 +*                ( h - a[k] u[k] = h - a[k], if a[k] < 0,
254.1255 +*
254.1256 +*  where:
254.1257 +*
254.1258 +*     h = sum   a[j] l[j] + sum   a[j] u[j]                         (15)
254.1259 +*        j in Jp           j in Jn
254.1260 +*
254.1261 +*  is the implied lower bound of row (1).
254.1262 +*
254.1263 +*  Reduction of positive coefficient (a[k] > 0) does not change value
254.1264 +*  of h, since l[k] = 0. In case of reduction of negative coefficient
254.1265 +*  (a[k] < 0) from (11) it follows that:
254.1266 +*
254.1267 +*     delta a[k] = a'[k] - a[k] = inf t[k] - b  (> 0),              (16)
254.1268 +*
254.1269 +*  so new value of h (accounting that u[k] = 1) can be computed as
254.1270 +*  follows:
254.1271 +*
254.1272 +*     h := h + delta a[k] = h + (inf t[k] - b).                     (17)
254.1273 +*
254.1274 +*  RECOVERING SOLUTION
254.1275 +*
254.1276 +*  None needed. */
254.1277 +
254.1278 +static int reduce_ineq_coef(NPP *npp, struct elem *ptr, double *_b)
254.1279 +{     /* process inequality constraint: sum a[j] x[j] >= b */
254.1280 +      /* returns: the number of coefficients reduced */
254.1281 +      struct elem *e;
254.1282 +      int count = 0;
254.1283 +      double h, inf_t, new_a, b = *_b;
254.1284 +      xassert(npp == npp);
254.1285 +      /* compute h; see (15) */
254.1286 +      h = 0.0;
254.1287 +      for (e = ptr; e != NULL; e = e->next)
254.1288 +      {  if (e->aj > 0.0)
254.1289 +         {  if (e->xj->lb == -DBL_MAX) goto done;
254.1290 +            h += e->aj * e->xj->lb;
254.1291 +         }
254.1292 +         else /* e->aj < 0.0 */
254.1293 +         {  if (e->xj->ub == +DBL_MAX) goto done;
254.1294 +            h += e->aj * e->xj->ub;
254.1295 +         }
254.1296 +      }
254.1297 +      /* perform reduction of coefficients at binary variables */
254.1298 +      for (e = ptr; e != NULL; e = e->next)
254.1299 +      {  /* skip non-binary variable */
254.1300 +         if (!(e->xj->is_int && e->xj->lb == 0.0 && e->xj->ub == 1.0))
254.1301 +            continue;
254.1302 +         if (e->aj > 0.0)
254.1303 +         {  /* compute inf t[k]; see (14) */
254.1304 +            inf_t = h;
254.1305 +            if (b - e->aj < inf_t && inf_t < b)
254.1306 +            {  /* compute reduced coefficient a'[k]; see (7) */
254.1307 +               new_a = b - inf_t;
254.1308 +               if (new_a >= +1e-3 &&
254.1309 +                   e->aj - new_a >= 0.01 * (1.0 + e->aj))
254.1310 +               {  /* accept a'[k] */
254.1311 +#ifdef GLP_DEBUG
254.1312 +                  xprintf("+");
254.1313 +#endif
254.1314 +                  e->aj = new_a;
254.1315 +                  count++;
254.1316 +               }
254.1317 +            }
254.1318 +         }
254.1319 +         else /* e->aj < 0.0 */
254.1320 +         {  /* compute inf t[k]; see (14) */
254.1321 +            inf_t = h - e->aj;
254.1322 +            if (b < inf_t && inf_t < b - e->aj)
254.1323 +            {  /* compute reduced coefficient a'[k]; see (11) */
254.1324 +               new_a = e->aj + (inf_t - b);
254.1325 +               if (new_a <= -1e-3 &&
254.1326 +                   new_a - e->aj >= 0.01 * (1.0 - e->aj))
254.1327 +               {  /* accept a'[k] */
254.1328 +#ifdef GLP_DEBUG
254.1329 +                  xprintf("-");
254.1330 +#endif
254.1331 +                  e->aj = new_a;
254.1332 +                  /* update h; see (17) */
254.1333 +                  h += (inf_t - b);
254.1334 +                  /* compute b'; see (9) */
254.1335 +                  b = inf_t;
254.1336 +                  count++;
254.1337 +               }
254.1338 +            }
254.1339 +         }
254.1340 +      }
254.1341 +      *_b = b;
254.1342 +done: return count;
254.1343 +}
254.1344 +
254.1345 +int npp_reduce_ineq_coef(NPP *npp, NPPROW *row)
254.1346 +{     /* reduce inequality constraint coefficients */
254.1347 +      NPPROW *copy;
254.1348 +      NPPAIJ *aij;
254.1349 +      struct elem *ptr, *e;
254.1350 +      int kase, count[2];
254.1351 +      double b;
254.1352 +      /* the row must be inequality constraint */
254.1353 +      xassert(row->lb < row->ub);
254.1354 +      count[0] = count[1] = 0;
254.1355 +      for (kase = 0; kase <= 1; kase++)
254.1356 +      {  if (kase == 0)
254.1357 +         {  /* process row lower bound */
254.1358 +            if (row->lb == -DBL_MAX) continue;
254.1359 +#ifdef GLP_DEBUG
254.1360 +            xprintf("L");
254.1361 +#endif
254.1362 +            ptr = copy_form(npp, row, +1.0);
254.1363 +            b = + row->lb;
254.1364 +         }
254.1365 +         else
254.1366 +         {  /* process row upper bound */
254.1367 +            if (row->ub == +DBL_MAX) continue;
254.1368 +#ifdef GLP_DEBUG
254.1369 +            xprintf("U");
254.1370 +#endif
254.1371 +            ptr = copy_form(npp, row, -1.0);
254.1372 +            b = - row->ub;
254.1373 +         }
254.1374 +         /* now the inequality has the form "sum a[j] x[j] >= b" */
254.1375 +         count[kase] = reduce_ineq_coef(npp, ptr, &b);
254.1376 +         if (count[kase] > 0)
254.1377 +         {  /* the original inequality has been replaced by equivalent
254.1378 +               one with coefficients reduced */
254.1379 +            if (row->lb == -DBL_MAX || row->ub == +DBL_MAX)
254.1380 +            {  /* the original row is single-sided inequality; no copy
254.1381 +                  is needed */
254.1382 +               copy = NULL;
254.1383 +            }
254.1384 +            else
254.1385 +            {  /* the original row is double-sided inequality; we need
254.1386 +                  to create its copy for other bound before replacing it
254.1387 +                  with the equivalent inequality */
254.1388 +#ifdef GLP_DEBUG
254.1389 +               xprintf("*");
254.1390 +#endif
254.1391 +               copy = npp_add_row(npp);
254.1392 +               if (kase == 0)
254.1393 +               {  /* the copy is for upper bound */
254.1394 +                  copy->lb = -DBL_MAX, copy->ub = row->ub;
254.1395 +               }
254.1396 +               else
254.1397 +               {  /* the copy is for lower bound */
254.1398 +                  copy->lb = row->lb, copy->ub = +DBL_MAX;
254.1399 +               }
254.1400 +               /* copy original row coefficients */
254.1401 +               for (aij = row->ptr; aij != NULL; aij = aij->r_next)
254.1402 +                  npp_add_aij(npp, copy, aij->col, aij->val);
254.1403 +            }
254.1404 +            /* replace the original inequality by equivalent one */
254.1405 +            npp_erase_row(npp, row);
254.1406 +            row->lb = b, row->ub = +DBL_MAX;
254.1407 +            for (e = ptr; e != NULL; e = e->next)
254.1408 +               npp_add_aij(npp, row, e->xj, e->aj);
254.1409 +            /* continue processing upper bound for the copy */
254.1410 +            if (copy != NULL) row = copy;
254.1411 +         }
254.1412 +         drop_form(npp, ptr);
254.1413 +      }
254.1414 +      return count[0] + count[1];
254.1415 +}
254.1416 +
254.1417 +/* eof */
   255.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   255.2 +++ b/src/glpnpp05.c	Mon Dec 06 13:09:21 2010 +0100
   255.3 @@ -0,0 +1,809 @@
   255.4 +/* glpnpp05.c */
   255.5 +
   255.6 +/***********************************************************************
   255.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   255.8 +*
   255.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  255.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  255.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  255.12 +*  E-mail: <mao@gnu.org>.
  255.13 +*
  255.14 +*  GLPK is free software: you can redistribute it and/or modify it
  255.15 +*  under the terms of the GNU General Public License as published by
  255.16 +*  the Free Software Foundation, either version 3 of the License, or
  255.17 +*  (at your option) any later version.
  255.18 +*
  255.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  255.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  255.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  255.22 +*  License for more details.
  255.23 +*
  255.24 +*  You should have received a copy of the GNU General Public License
  255.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  255.26 +***********************************************************************/
  255.27 +
  255.28 +#include "glpnpp.h"
  255.29 +
  255.30 +/***********************************************************************
  255.31 +*  NAME
  255.32 +*
  255.33 +*  npp_clean_prob - perform initial LP/MIP processing
  255.34 +*
  255.35 +*  SYNOPSIS
  255.36 +*
  255.37 +*  #include "glpnpp.h"
  255.38 +*  void npp_clean_prob(NPP *npp);
  255.39 +*
  255.40 +*  DESCRIPTION
  255.41 +*
  255.42 +*  The routine npp_clean_prob performs initial LP/MIP processing that
  255.43 +*  currently includes:
  255.44 +*
  255.45 +*  1) removing free rows;
  255.46 +*
  255.47 +*  2) replacing double-sided constraint rows with almost identical
  255.48 +*     bounds, by equality constraint rows;
  255.49 +*
  255.50 +*  3) removing fixed columns;
  255.51 +*
  255.52 +*  4) replacing double-bounded columns with almost identical bounds by
  255.53 +*     fixed columns and removing those columns;
  255.54 +*
  255.55 +*  5) initial processing constraint coefficients (not implemented);
  255.56 +*
  255.57 +*  6) initial processing objective coefficients (not implemented). */
  255.58 +
  255.59 +void npp_clean_prob(NPP *npp)
  255.60 +{     /* perform initial LP/MIP processing */
  255.61 +      NPPROW *row, *next_row;
  255.62 +      NPPCOL *col, *next_col;
  255.63 +      int ret;
  255.64 +      xassert(npp == npp);
  255.65 +      /* process rows which originally are free */
  255.66 +      for (row = npp->r_head; row != NULL; row = next_row)
  255.67 +      {  next_row = row->next;
  255.68 +         if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
  255.69 +         {  /* process free row */
  255.70 +#ifdef GLP_DEBUG
  255.71 +            xprintf("1");
  255.72 +#endif
  255.73 +            npp_free_row(npp, row);
  255.74 +            /* row was deleted */
  255.75 +         }
  255.76 +      }
  255.77 +      /* process rows which originally are double-sided inequalities */
  255.78 +      for (row = npp->r_head; row != NULL; row = next_row)
  255.79 +      {  next_row = row->next;
  255.80 +         if (row->lb != -DBL_MAX && row->ub != +DBL_MAX &&
  255.81 +             row->lb < row->ub)
  255.82 +         {  ret = npp_make_equality(npp, row);
  255.83 +            if (ret == 0)
  255.84 +               ;
  255.85 +            else if (ret == 1)
  255.86 +            {  /* row was replaced by equality constraint */
  255.87 +#ifdef GLP_DEBUG
  255.88 +               xprintf("2");
  255.89 +#endif
  255.90 +            }
  255.91 +            else
  255.92 +               xassert(ret != ret);
  255.93 +         }
  255.94 +      }
  255.95 +      /* process columns which are originally fixed */
  255.96 +      for (col = npp->c_head; col != NULL; col = next_col)
  255.97 +      {  next_col = col->next;
  255.98 +         if (col->lb == col->ub)
  255.99 +         {  /* process fixed column */
 255.100 +#ifdef GLP_DEBUG
 255.101 +            xprintf("3");
 255.102 +#endif
 255.103 +            npp_fixed_col(npp, col);
 255.104 +            /* column was deleted */
 255.105 +         }
 255.106 +      }
 255.107 +      /* process columns which are originally double-bounded */
 255.108 +      for (col = npp->c_head; col != NULL; col = next_col)
 255.109 +      {  next_col = col->next;
 255.110 +         if (col->lb != -DBL_MAX && col->ub != +DBL_MAX &&
 255.111 +             col->lb < col->ub)
 255.112 +         {  ret = npp_make_fixed(npp, col);
 255.113 +            if (ret == 0)
 255.114 +               ;
 255.115 +            else if (ret == 1)
 255.116 +            {  /* column was replaced by fixed column; process it */
 255.117 +#ifdef GLP_DEBUG
 255.118 +               xprintf("4");
 255.119 +#endif
 255.120 +               npp_fixed_col(npp, col);
 255.121 +               /* column was deleted */
 255.122 +            }
 255.123 +         }
 255.124 +      }
 255.125 +      return;
 255.126 +}
 255.127 +
 255.128 +/***********************************************************************
 255.129 +*  NAME
 255.130 +*
 255.131 +*  npp_process_row - perform basic row processing
 255.132 +*
 255.133 +*  SYNOPSIS
 255.134 +*
 255.135 +*  #include "glpnpp.h"
 255.136 +*  int npp_process_row(NPP *npp, NPPROW *row, int hard);
 255.137 +*
 255.138 +*  DESCRIPTION
 255.139 +*
 255.140 +*  The routine npp_process_row performs basic row processing that
 255.141 +*  currently includes:
 255.142 +*
 255.143 +*  1) removing empty row;
 255.144 +*
 255.145 +*  2) removing equality constraint row singleton and corresponding
 255.146 +*     column;
 255.147 +*
 255.148 +*  3) removing inequality constraint row singleton and corresponding
 255.149 +*     column if it was fixed;
 255.150 +*
 255.151 +*  4) performing general row analysis;
 255.152 +*
 255.153 +*  5) removing redundant row bounds;
 255.154 +*
 255.155 +*  6) removing forcing row and corresponding columns;
 255.156 +*
 255.157 +*  7) removing row which becomes free due to redundant bounds;
 255.158 +*
 255.159 +*  8) computing implied bounds for all columns in the row and using
 255.160 +*     them to strengthen current column bounds (MIP only, optional,
 255.161 +*     performed if the flag hard is on).
 255.162 +*
 255.163 +*  Additionally the routine may activate affected rows and/or columns
 255.164 +*  for further processing.
 255.165 +*
 255.166 +*  RETURNS
 255.167 +*
 255.168 +*  0           success;
 255.169 +*
 255.170 +*  GLP_ENOPFS  primal/integer infeasibility detected;
 255.171 +*
 255.172 +*  GLP_ENODFS  dual infeasibility detected. */
 255.173 +
 255.174 +int npp_process_row(NPP *npp, NPPROW *row, int hard)
 255.175 +{     /* perform basic row processing */
 255.176 +      NPPCOL *col;
 255.177 +      NPPAIJ *aij, *next_aij, *aaa;
 255.178 +      int ret;
 255.179 +      /* row must not be free */
 255.180 +      xassert(!(row->lb == -DBL_MAX && row->ub == +DBL_MAX));
 255.181 +      /* start processing row */
 255.182 +      if (row->ptr == NULL)
 255.183 +      {  /* empty row */
 255.184 +         ret = npp_empty_row(npp, row);
 255.185 +         if (ret == 0)
 255.186 +         {  /* row was deleted */
 255.187 +#ifdef GLP_DEBUG
 255.188 +            xprintf("A");
 255.189 +#endif
 255.190 +            return 0;
 255.191 +         }
 255.192 +         else if (ret == 1)
 255.193 +         {  /* primal infeasibility */
 255.194 +            return GLP_ENOPFS;
 255.195 +         }
 255.196 +         else
 255.197 +            xassert(ret != ret);
 255.198 +      }
 255.199 +      if (row->ptr->r_next == NULL)
 255.200 +      {  /* row singleton */
 255.201 +         col = row->ptr->col;
 255.202 +         if (row->lb == row->ub)
 255.203 +         {  /* equality constraint */
 255.204 +            ret = npp_eq_singlet(npp, row);
 255.205 +            if (ret == 0)
 255.206 +            {  /* column was fixed, row was deleted */
 255.207 +#ifdef GLP_DEBUG
 255.208 +               xprintf("B");
 255.209 +#endif
 255.210 +               /* activate rows affected by column */
 255.211 +               for (aij = col->ptr; aij != NULL; aij = aij->c_next)
 255.212 +                  npp_activate_row(npp, aij->row);
 255.213 +               /* process fixed column */
 255.214 +               npp_fixed_col(npp, col);
 255.215 +               /* column was deleted */
 255.216 +               return 0;
 255.217 +            }
 255.218 +            else if (ret == 1 || ret == 2)
 255.219 +            {  /* primal/integer infeasibility */
 255.220 +               return GLP_ENOPFS;
 255.221 +            }
 255.222 +            else
 255.223 +               xassert(ret != ret);
 255.224 +         }
 255.225 +         else
 255.226 +         {  /* inequality constraint */
 255.227 +            ret = npp_ineq_singlet(npp, row);
 255.228 +            if (0 <= ret && ret <= 3)
 255.229 +            {  /* row was deleted */
 255.230 +#ifdef GLP_DEBUG
 255.231 +               xprintf("C");
 255.232 +#endif
 255.233 +               /* activate column, since its length was changed due to
 255.234 +                  row deletion */
 255.235 +               npp_activate_col(npp, col);
 255.236 +               if (ret >= 2)
 255.237 +               {  /* column bounds changed significantly or column was
 255.238 +                     fixed */
 255.239 +                  /* activate rows affected by column */
 255.240 +                  for (aij = col->ptr; aij != NULL; aij = aij->c_next)
 255.241 +                     npp_activate_row(npp, aij->row);
 255.242 +               }
 255.243 +               if (ret == 3)
 255.244 +               {  /* column was fixed; process it */
 255.245 +#ifdef GLP_DEBUG
 255.246 +                  xprintf("D");
 255.247 +#endif
 255.248 +                  npp_fixed_col(npp, col);
 255.249 +                  /* column was deleted */
 255.250 +               }
 255.251 +               return 0;
 255.252 +            }
 255.253 +            else if (ret == 4)
 255.254 +            {  /* primal infeasibility */
 255.255 +               return GLP_ENOPFS;
 255.256 +            }
 255.257 +            else
 255.258 +               xassert(ret != ret);
 255.259 +         }
 255.260 +      }
 255.261 +#if 0
 255.262 +      /* sometimes this causes too large round-off errors; probably
 255.263 +         pivot coefficient should be chosen more carefully */
 255.264 +      if (row->ptr->r_next->r_next == NULL)
 255.265 +      {  /* row doubleton */
 255.266 +         if (row->lb == row->ub)
 255.267 +         {  /* equality constraint */
 255.268 +            if (!(row->ptr->col->is_int ||
 255.269 +                  row->ptr->r_next->col->is_int))
 255.270 +            {  /* both columns are continuous */
 255.271 +               NPPCOL *q;
 255.272 +               q = npp_eq_doublet(npp, row);
 255.273 +               if (q != NULL)
 255.274 +               {  /* column q was eliminated */
 255.275 +#ifdef GLP_DEBUG
 255.276 +                  xprintf("E");
 255.277 +#endif
 255.278 +                  /* now column q is singleton of type "implied slack
 255.279 +                     variable"; we process it here to make sure that on
 255.280 +                     recovering basic solution the row is always active
 255.281 +                     equality constraint (as required by the routine
 255.282 +                     rcv_eq_doublet) */
 255.283 +                  xassert(npp_process_col(npp, q) == 0);
 255.284 +                  /* column q was deleted; note that row p also may be
 255.285 +                     deleted */
 255.286 +                  return 0;
 255.287 +               }
 255.288 +            }
 255.289 +         }
 255.290 +      }
 255.291 +#endif
 255.292 +      /* general row analysis */
 255.293 +      ret = npp_analyze_row(npp, row);
 255.294 +      xassert(0x00 <= ret && ret <= 0xFF);
 255.295 +      if (ret == 0x33)
 255.296 +      {  /* row bounds are inconsistent with column bounds */
 255.297 +         return GLP_ENOPFS;
 255.298 +      }
 255.299 +      if ((ret & 0x0F) == 0x00)
 255.300 +      {  /* row lower bound does not exist or redundant */
 255.301 +         if (row->lb != -DBL_MAX)
 255.302 +         {  /* remove redundant row lower bound */
 255.303 +#ifdef GLP_DEBUG
 255.304 +            xprintf("F");
 255.305 +#endif
 255.306 +            npp_inactive_bound(npp, row, 0);
 255.307 +         }
 255.308 +      }
 255.309 +      else if ((ret & 0x0F) == 0x01)
 255.310 +      {  /* row lower bound can be active */
 255.311 +         /* see below */
 255.312 +      }
 255.313 +      else if ((ret & 0x0F) == 0x02)
 255.314 +      {  /* row lower bound is a forcing bound */
 255.315 +#ifdef GLP_DEBUG
 255.316 +         xprintf("G");
 255.317 +#endif
 255.318 +         /* process forcing row */
 255.319 +         if (npp_forcing_row(npp, row, 0) == 0)
 255.320 +fixup:   {  /* columns were fixed, row was made free */
 255.321 +            for (aij = row->ptr; aij != NULL; aij = next_aij)
 255.322 +            {  /* process column fixed by forcing row */
 255.323 +#ifdef GLP_DEBUG
 255.324 +               xprintf("H");
 255.325 +#endif
 255.326 +               col = aij->col;
 255.327 +               next_aij = aij->r_next;
 255.328 +               /* activate rows affected by column */
 255.329 +               for (aaa = col->ptr; aaa != NULL; aaa = aaa->c_next)
 255.330 +                  npp_activate_row(npp, aaa->row);
 255.331 +               /* process fixed column */
 255.332 +               npp_fixed_col(npp, col);
 255.333 +               /* column was deleted */
 255.334 +            }
 255.335 +            /* process free row (which now is empty due to deletion of
 255.336 +               all its columns) */
 255.337 +            npp_free_row(npp, row);
 255.338 +            /* row was deleted */
 255.339 +            return 0;
 255.340 +         }
 255.341 +      }
 255.342 +      else
 255.343 +         xassert(ret != ret);
 255.344 +      if ((ret & 0xF0) == 0x00)
 255.345 +      {  /* row upper bound does not exist or redundant */
 255.346 +         if (row->ub != +DBL_MAX)
 255.347 +         {  /* remove redundant row upper bound */
 255.348 +#ifdef GLP_DEBUG
 255.349 +            xprintf("I");
 255.350 +#endif
 255.351 +            npp_inactive_bound(npp, row, 1);
 255.352 +         }
 255.353 +      }
 255.354 +      else if ((ret & 0xF0) == 0x10)
 255.355 +      {  /* row upper bound can be active */
 255.356 +         /* see below */
 255.357 +      }
 255.358 +      else if ((ret & 0xF0) == 0x20)
 255.359 +      {  /* row upper bound is a forcing bound */
 255.360 +#ifdef GLP_DEBUG
 255.361 +         xprintf("J");
 255.362 +#endif
 255.363 +         /* process forcing row */
 255.364 +         if (npp_forcing_row(npp, row, 1) == 0) goto fixup;
 255.365 +      }
 255.366 +      else
 255.367 +         xassert(ret != ret);
 255.368 +      if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
 255.369 +      {  /* row became free due to redundant bounds removal */
 255.370 +#ifdef GLP_DEBUG
 255.371 +         xprintf("K");
 255.372 +#endif
 255.373 +         /* activate its columns, since their length will change due
 255.374 +            to row deletion */
 255.375 +         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
 255.376 +            npp_activate_col(npp, aij->col);
 255.377 +         /* process free row */
 255.378 +         npp_free_row(npp, row);
 255.379 +         /* row was deleted */
 255.380 +         return 0;
 255.381 +      }
 255.382 +#if 1 /* 23/XII-2009 */
 255.383 +      /* row lower and/or upper bounds can be active */
 255.384 +      if (npp->sol == GLP_MIP && hard)
 255.385 +      {  /* improve current column bounds (optional) */
 255.386 +         if (npp_improve_bounds(npp, row, 1) < 0)
 255.387 +            return GLP_ENOPFS;
 255.388 +      }
 255.389 +#endif
 255.390 +      return 0;
 255.391 +}
 255.392 +
 255.393 +/***********************************************************************
 255.394 +*  NAME
 255.395 +*
 255.396 +*  npp_improve_bounds - improve current column bounds
 255.397 +*
 255.398 +*  SYNOPSIS
 255.399 +*
 255.400 +*  #include "glpnpp.h"
 255.401 +*  int npp_improve_bounds(NPP *npp, NPPROW *row, int flag);
 255.402 +*
 255.403 +*  DESCRIPTION
 255.404 +*
 255.405 +*  The routine npp_improve_bounds analyzes specified row (inequality
 255.406 +*  or equality constraint) to determine implied column bounds and then
 255.407 +*  uses these bounds to improve (strengthen) current column bounds.
 255.408 +*
 255.409 +*  If the flag is on and current column bounds changed significantly
 255.410 +*  or the column was fixed, the routine activate rows affected by the
 255.411 +*  column for further processing. (This feature is intended to be used
 255.412 +*  in the main loop of the routine npp_process_row.)
 255.413 +*
 255.414 +*  NOTE: This operation can be used for MIP problem only.
 255.415 +*
 255.416 +*  RETURNS
 255.417 +*
 255.418 +*  The routine npp_improve_bounds returns the number of significantly
 255.419 +*  changed bounds plus the number of column having been fixed due to
 255.420 +*  bound improvements. However, if the routine detects primal/integer
 255.421 +*  infeasibility, it returns a negative value. */
 255.422 +
 255.423 +int npp_improve_bounds(NPP *npp, NPPROW *row, int flag)
 255.424 +{     /* improve current column bounds */
 255.425 +      NPPCOL *col;
 255.426 +      NPPAIJ *aij, *next_aij, *aaa;
 255.427 +      int kase, ret, count = 0;
 255.428 +      double lb, ub;
 255.429 +      xassert(npp->sol == GLP_MIP);
 255.430 +      /* row must not be free */
 255.431 +      xassert(!(row->lb == -DBL_MAX && row->ub == +DBL_MAX));
 255.432 +      /* determine implied column bounds */
 255.433 +      npp_implied_bounds(npp, row);
 255.434 +      /* and use these bounds to strengthen current column bounds */
 255.435 +      for (aij = row->ptr; aij != NULL; aij = next_aij)
 255.436 +      {  col = aij->col;
 255.437 +         next_aij = aij->r_next;
 255.438 +         for (kase = 0; kase <= 1; kase++)
 255.439 +         {  /* save current column bounds */
 255.440 +            lb = col->lb, ub = col->ub;
 255.441 +            if (kase == 0)
 255.442 +            {  /* process implied column lower bound */
 255.443 +               if (col->ll.ll == -DBL_MAX) continue;
 255.444 +               ret = npp_implied_lower(npp, col, col->ll.ll);
 255.445 +            }
 255.446 +            else
 255.447 +            {  /* process implied column upper bound */
 255.448 +               if (col->uu.uu == +DBL_MAX) continue;
 255.449 +               ret = npp_implied_upper(npp, col, col->uu.uu);
 255.450 +            }
 255.451 +            if (ret == 0 || ret == 1)
 255.452 +            {  /* current column bounds did not change or changed, but
 255.453 +                  not significantly; restore current column bounds */
 255.454 +               col->lb = lb, col->ub = ub;
 255.455 +            }
 255.456 +            else if (ret == 2 || ret == 3)
 255.457 +            {  /* current column bounds changed significantly or column
 255.458 +                  was fixed */
 255.459 +#ifdef GLP_DEBUG
 255.460 +               xprintf("L");
 255.461 +#endif
 255.462 +               count++;
 255.463 +               /* activate other rows affected by column, if required */
 255.464 +               if (flag)
 255.465 +               {  for (aaa = col->ptr; aaa != NULL; aaa = aaa->c_next)
 255.466 +                  {  if (aaa->row != row)
 255.467 +                        npp_activate_row(npp, aaa->row);
 255.468 +                  }
 255.469 +               }
 255.470 +               if (ret == 3)
 255.471 +               {  /* process fixed column */
 255.472 +#ifdef GLP_DEBUG
 255.473 +                  xprintf("M");
 255.474 +#endif
 255.475 +                  npp_fixed_col(npp, col);
 255.476 +                  /* column was deleted */
 255.477 +                  break; /* for kase */
 255.478 +               }
 255.479 +            }
 255.480 +            else if (ret == 4)
 255.481 +            {  /* primal/integer infeasibility */
 255.482 +               return -1;
 255.483 +            }
 255.484 +            else
 255.485 +               xassert(ret != ret);
 255.486 +         }
 255.487 +      }
 255.488 +      return count;
 255.489 +}
 255.490 +
 255.491 +/***********************************************************************
 255.492 +*  NAME
 255.493 +*
 255.494 +*  npp_process_col - perform basic column processing
 255.495 +*
 255.496 +*  SYNOPSIS
 255.497 +*
 255.498 +*  #include "glpnpp.h"
 255.499 +*  int npp_process_col(NPP *npp, NPPCOL *col);
 255.500 +*
 255.501 +*  DESCRIPTION
 255.502 +*
 255.503 +*  The routine npp_process_col performs basic column processing that
 255.504 +*  currently includes:
 255.505 +*
 255.506 +*  1) fixing and removing empty column;
 255.507 +*
 255.508 +*  2) removing column singleton, which is implied slack variable, and
 255.509 +*     corresponding row if it becomes free;
 255.510 +*
 255.511 +*  3) removing bounds of column, which is implied free variable, and
 255.512 +*     replacing corresponding row by equality constraint.
 255.513 +*
 255.514 +*  Additionally the routine may activate affected rows and/or columns
 255.515 +*  for further processing.
 255.516 +*
 255.517 +*  RETURNS
 255.518 +*
 255.519 +*  0           success;
 255.520 +*
 255.521 +*  GLP_ENOPFS  primal/integer infeasibility detected;
 255.522 +*
 255.523 +*  GLP_ENODFS  dual infeasibility detected. */
 255.524 +
 255.525 +int npp_process_col(NPP *npp, NPPCOL *col)
 255.526 +{     /* perform basic column processing */
 255.527 +      NPPROW *row;
 255.528 +      NPPAIJ *aij;
 255.529 +      int ret;
 255.530 +      /* column must not be fixed */
 255.531 +      xassert(col->lb < col->ub);
 255.532 +      /* start processing column */
 255.533 +      if (col->ptr == NULL)
 255.534 +      {  /* empty column */
 255.535 +         ret = npp_empty_col(npp, col);
 255.536 +         if (ret == 0)
 255.537 +         {  /* column was fixed and deleted */
 255.538 +#ifdef GLP_DEBUG
 255.539 +            xprintf("N");
 255.540 +#endif
 255.541 +            return 0;
 255.542 +         }
 255.543 +         else if (ret == 1)
 255.544 +         {  /* dual infeasibility */
 255.545 +            return GLP_ENODFS;
 255.546 +         }
 255.547 +         else
 255.548 +            xassert(ret != ret);
 255.549 +      }
 255.550 +      if (col->ptr->c_next == NULL)
 255.551 +      {  /* column singleton */
 255.552 +         row = col->ptr->row;
 255.553 +         if (row->lb == row->ub)
 255.554 +         {  /* equality constraint */
 255.555 +            if (!col->is_int)
 255.556 +slack:      {  /* implied slack variable */
 255.557 +#ifdef GLP_DEBUG
 255.558 +               xprintf("O");
 255.559 +#endif
 255.560 +               npp_implied_slack(npp, col);
 255.561 +               /* column was deleted */
 255.562 +               if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
 255.563 +               {  /* row became free due to implied slack variable */
 255.564 +#ifdef GLP_DEBUG
 255.565 +                  xprintf("P");
 255.566 +#endif
 255.567 +                  /* activate columns affected by row */
 255.568 +                  for (aij = row->ptr; aij != NULL; aij = aij->r_next)
 255.569 +                     npp_activate_col(npp, aij->col);
 255.570 +                  /* process free row */
 255.571 +                  npp_free_row(npp, row);
 255.572 +                  /* row was deleted */
 255.573 +               }
 255.574 +               else
 255.575 +               {  /* row became inequality constraint; activate it
 255.576 +                     since its length changed due to column deletion */
 255.577 +                  npp_activate_row(npp, row);
 255.578 +               }
 255.579 +               return 0;
 255.580 +            }
 255.581 +         }
 255.582 +         else
 255.583 +         {  /* inequality constraint */
 255.584 +            if (!col->is_int)
 255.585 +            {  ret = npp_implied_free(npp, col);
 255.586 +               if (ret == 0)
 255.587 +               {  /* implied free variable */
 255.588 +#ifdef GLP_DEBUG
 255.589 +                  xprintf("Q");
 255.590 +#endif
 255.591 +                  /* column bounds were removed, row was replaced by
 255.592 +                     equality constraint */
 255.593 +                  goto slack;
 255.594 +               }
 255.595 +               else if (ret == 1)
 255.596 +               {  /* column is not implied free variable, because its
 255.597 +                     lower and/or upper bounds can be active */
 255.598 +               }
 255.599 +               else if (ret == 2)
 255.600 +               {  /* dual infeasibility */
 255.601 +                  return GLP_ENODFS;
 255.602 +               }
 255.603 +            }
 255.604 +         }
 255.605 +      }
 255.606 +      /* column still exists */
 255.607 +      return 0;
 255.608 +}
 255.609 +
 255.610 +/***********************************************************************
 255.611 +*  NAME
 255.612 +*
 255.613 +*  npp_process_prob - perform basic LP/MIP processing
 255.614 +*
 255.615 +*  SYNOPSIS
 255.616 +*
 255.617 +*  #include "glpnpp.h"
 255.618 +*  int npp_process_prob(NPP *npp, int hard);
 255.619 +*
 255.620 +*  DESCRIPTION
 255.621 +*
 255.622 +*  The routine npp_process_prob performs basic LP/MIP processing that
 255.623 +*  currently includes:
 255.624 +*
 255.625 +*  1) initial LP/MIP processing (see the routine npp_clean_prob),
 255.626 +*
 255.627 +*  2) basic row processing (see the routine npp_process_row), and
 255.628 +*
 255.629 +*  3) basic column processing (see the routine npp_process_col).
 255.630 +*
 255.631 +*  If the flag hard is on, the routine attempts to improve current
 255.632 +*  column bounds multiple times within the main processing loop, in
 255.633 +*  which case this feature may take a time. Otherwise, if the flag hard
 255.634 +*  is off, improving column bounds is performed only once at the end of
 255.635 +*  the main loop. (Note that this feature is used for MIP only.)
 255.636 +*
 255.637 +*  The routine uses two sets: the set of active rows and the set of
 255.638 +*  active columns. Rows/columns are marked by a flag (the field temp in
 255.639 +*  NPPROW/NPPCOL). If the flag is non-zero, the row/column is active,
 255.640 +*  in which case it is placed in the beginning of the row/column list;
 255.641 +*  otherwise, if the flag is zero, the row/column is inactive, in which
 255.642 +*  case it is placed in the end of the row/column list. If a row/column
 255.643 +*  being currently processed may affect other rows/columns, the latters
 255.644 +*  are activated for further processing.
 255.645 +*
 255.646 +*  RETURNS
 255.647 +*
 255.648 +*  0           success;
 255.649 +*
 255.650 +*  GLP_ENOPFS  primal/integer infeasibility detected;
 255.651 +*
 255.652 +*  GLP_ENODFS  dual infeasibility detected. */
 255.653 +
 255.654 +int npp_process_prob(NPP *npp, int hard)
 255.655 +{     /* perform basic LP/MIP processing */
 255.656 +      NPPROW *row;
 255.657 +      NPPCOL *col;
 255.658 +      int processing, ret;
 255.659 +      /* perform initial LP/MIP processing */
 255.660 +      npp_clean_prob(npp);
 255.661 +      /* activate all remaining rows and columns */
 255.662 +      for (row = npp->r_head; row != NULL; row = row->next)
 255.663 +         row->temp = 1;
 255.664 +      for (col = npp->c_head; col != NULL; col = col->next)
 255.665 +         col->temp = 1;
 255.666 +      /* main processing loop */
 255.667 +      processing = 1;
 255.668 +      while (processing)
 255.669 +      {  processing = 0;
 255.670 +         /* process all active rows */
 255.671 +         for (;;)
 255.672 +         {  row = npp->r_head;
 255.673 +            if (row == NULL || !row->temp) break;
 255.674 +            npp_deactivate_row(npp, row);
 255.675 +            ret = npp_process_row(npp, row, hard);
 255.676 +            if (ret != 0) goto done;
 255.677 +            processing = 1;
 255.678 +         }
 255.679 +         /* process all active columns */
 255.680 +         for (;;)
 255.681 +         {  col = npp->c_head;
 255.682 +            if (col == NULL || !col->temp) break;
 255.683 +            npp_deactivate_col(npp, col);
 255.684 +            ret = npp_process_col(npp, col);
 255.685 +            if (ret != 0) goto done;
 255.686 +            processing = 1;
 255.687 +         }
 255.688 +      }
 255.689 +#if 1 /* 23/XII-2009 */
 255.690 +      if (npp->sol == GLP_MIP && !hard)
 255.691 +      {  /* improve current column bounds (optional) */
 255.692 +         for (row = npp->r_head; row != NULL; row = row->next)
 255.693 +         {  if (npp_improve_bounds(npp, row, 0) < 0)
 255.694 +            {  ret = GLP_ENOPFS;
 255.695 +               goto done;
 255.696 +            }
 255.697 +         }
 255.698 +      }
 255.699 +#endif
 255.700 +      /* all seems ok */
 255.701 +      ret = 0;
 255.702 +done: xassert(ret == 0 || ret == GLP_ENOPFS || ret == GLP_ENODFS);
 255.703 +#ifdef GLP_DEBUG
 255.704 +      xprintf("\n");
 255.705 +#endif
 255.706 +      return ret;
 255.707 +}
 255.708 +
 255.709 +/**********************************************************************/
 255.710 +
 255.711 +int npp_simplex(NPP *npp, const glp_smcp *parm)
 255.712 +{     /* process LP prior to applying primal/dual simplex method */
 255.713 +      int ret;
 255.714 +      xassert(npp->sol == GLP_SOL);
 255.715 +      xassert(parm == parm);
 255.716 +      ret = npp_process_prob(npp, 0);
 255.717 +      return ret;
 255.718 +}
 255.719 +
 255.720 +/**********************************************************************/
 255.721 +
 255.722 +int npp_integer(NPP *npp, const glp_iocp *parm)
 255.723 +{     /* process MIP prior to applying branch-and-bound method */
 255.724 +      NPPROW *row, *prev_row;
 255.725 +      NPPCOL *col;
 255.726 +      NPPAIJ *aij;
 255.727 +      int count, ret;
 255.728 +      xassert(npp->sol == GLP_MIP);
 255.729 +      xassert(parm == parm);
 255.730 +      /*==============================================================*/
 255.731 +      /* perform basic MIP processing */
 255.732 +      ret = npp_process_prob(npp, 1);
 255.733 +      if (ret != 0) goto done;
 255.734 +      /*==============================================================*/
 255.735 +      /* binarize problem, if required */
 255.736 +      if (parm->binarize)
 255.737 +         npp_binarize_prob(npp);
 255.738 +      /*==============================================================*/
 255.739 +      /* identify hidden packing inequalities */
 255.740 +      count = 0;
 255.741 +      /* new rows will be added to the end of the row list, so we go
 255.742 +         from the end to beginning of the row list */
 255.743 +      for (row = npp->r_tail; row != NULL; row = prev_row)
 255.744 +      {  prev_row = row->prev;
 255.745 +         /* skip free row */
 255.746 +         if (row->lb == -DBL_MAX && row->ub == +DBL_MAX) continue;
 255.747 +         /* skip equality constraint */
 255.748 +         if (row->lb == row->ub) continue;
 255.749 +         /* skip row having less than two variables */
 255.750 +         if (row->ptr == NULL || row->ptr->r_next == NULL) continue;
 255.751 +         /* skip row having non-binary variables */
 255.752 +         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
 255.753 +         {  col = aij->col;
 255.754 +            if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
 255.755 +               break;
 255.756 +         }
 255.757 +         if (aij != NULL) continue;
 255.758 +         count += npp_hidden_packing(npp, row);
 255.759 +      }
 255.760 +      if (count > 0)
 255.761 +         xprintf("%d hidden packing inequaliti(es) were detected\n",
 255.762 +            count);
 255.763 +      /*==============================================================*/
 255.764 +      /* identify hidden covering inequalities */
 255.765 +      count = 0;
 255.766 +      /* new rows will be added to the end of the row list, so we go
 255.767 +         from the end to beginning of the row list */
 255.768 +      for (row = npp->r_tail; row != NULL; row = prev_row)
 255.769 +      {  prev_row = row->prev;
 255.770 +         /* skip free row */
 255.771 +         if (row->lb == -DBL_MAX && row->ub == +DBL_MAX) continue;
 255.772 +         /* skip equality constraint */
 255.773 +         if (row->lb == row->ub) continue;
 255.774 +         /* skip row having less than three variables */
 255.775 +         if (row->ptr == NULL || row->ptr->r_next == NULL ||
 255.776 +             row->ptr->r_next->r_next == NULL) continue;
 255.777 +         /* skip row having non-binary variables */
 255.778 +         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
 255.779 +         {  col = aij->col;
 255.780 +            if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
 255.781 +               break;
 255.782 +         }
 255.783 +         if (aij != NULL) continue;
 255.784 +         count += npp_hidden_covering(npp, row);
 255.785 +      }
 255.786 +      if (count > 0)
 255.787 +         xprintf("%d hidden covering inequaliti(es) were detected\n",
 255.788 +            count);
 255.789 +      /*==============================================================*/
 255.790 +      /* reduce inequality constraint coefficients */
 255.791 +      count = 0;
 255.792 +      /* new rows will be added to the end of the row list, so we go
 255.793 +         from the end to beginning of the row list */
 255.794 +      for (row = npp->r_tail; row != NULL; row = prev_row)
 255.795 +      {  prev_row = row->prev;
 255.796 +         /* skip equality constraint */
 255.797 +         if (row->lb == row->ub) continue;
 255.798 +         count += npp_reduce_ineq_coef(npp, row);
 255.799 +      }
 255.800 +      if (count > 0)
 255.801 +         xprintf("%d constraint coefficient(s) were reduced\n", count);
 255.802 +      /*==============================================================*/
 255.803 +#ifdef GLP_DEBUG
 255.804 +      routine(npp);
 255.805 +#endif
 255.806 +      /*==============================================================*/
 255.807 +      /* all seems ok */
 255.808 +      ret = 0;
 255.809 +done: return ret;
 255.810 +}
 255.811 +
 255.812 +/* eof */
   256.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   256.2 +++ b/src/glpqmd.c	Mon Dec 06 13:09:21 2010 +0100
   256.3 @@ -0,0 +1,584 @@
   256.4 +/* glpqmd.c (quotient minimum degree algorithm) */
   256.5 +
   256.6 +/***********************************************************************
   256.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   256.8 +*
   256.9 +*  THIS CODE IS THE RESULT OF TRANSLATION OF THE FORTRAN SUBROUTINES
  256.10 +*  GENQMD, QMDRCH, QMDQT, QMDUPD, AND QMDMRG FROM THE BOOK:
  256.11 +*
  256.12 +*  ALAN GEORGE, JOSEPH W-H LIU. COMPUTER SOLUTION OF LARGE SPARSE
  256.13 +*  POSITIVE DEFINITE SYSTEMS. PRENTICE-HALL, 1981.
  256.14 +*
  256.15 +*  THE TRANSLATION HAS BEEN DONE WITH THE PERMISSION OF THE AUTHORS
  256.16 +*  OF THE ORIGINAL FORTRAN SUBROUTINES: ALAN GEORGE AND JOSEPH LIU,
  256.17 +*  UNIVERSITY OF WATERLOO, WATERLOO, ONTARIO, CANADA.
  256.18 +*
  256.19 +*  The translation was made by Andrew Makhorin <mao@gnu.org>.
  256.20 +*
  256.21 +*  GLPK is free software: you can redistribute it and/or modify it
  256.22 +*  under the terms of the GNU General Public License as published by
  256.23 +*  the Free Software Foundation, either version 3 of the License, or
  256.24 +*  (at your option) any later version.
  256.25 +*
  256.26 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  256.27 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  256.28 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  256.29 +*  License for more details.
  256.30 +*
  256.31 +*  You should have received a copy of the GNU General Public License
  256.32 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  256.33 +***********************************************************************/
  256.34 +
  256.35 +#include "glpqmd.h"
  256.36 +
  256.37 +/***********************************************************************
  256.38 +*  NAME
  256.39 +*
  256.40 +*  genqmd - GENeral Quotient Minimum Degree algorithm
  256.41 +*
  256.42 +*  SYNOPSIS
  256.43 +*
  256.44 +*  #include "glpqmd.h"
  256.45 +*  void genqmd(int *neqns, int xadj[], int adjncy[], int perm[],
  256.46 +*     int invp[], int deg[], int marker[], int rchset[], int nbrhd[],
  256.47 +*     int qsize[], int qlink[], int *nofsub);
  256.48 +*
  256.49 +*  PURPOSE
  256.50 +*
  256.51 +*  This routine implements the minimum degree algorithm. It makes use
  256.52 +*  of the implicit representation of the elimination graph by quotient
  256.53 +*  graphs, and the notion of indistinguishable nodes.
  256.54 +*
  256.55 +*  CAUTION
  256.56 +*
  256.57 +*  The adjancy vector adjncy will be destroyed.
  256.58 +*
  256.59 +*  INPUT PARAMETERS
  256.60 +*
  256.61 +*  neqns  - number of equations;
  256.62 +*  (xadj, adjncy) -
  256.63 +*           the adjancy structure.
  256.64 +*
  256.65 +*  OUTPUT PARAMETERS
  256.66 +*
  256.67 +*  perm   - the minimum degree ordering;
  256.68 +*  invp   - the inverse of perm.
  256.69 +*
  256.70 +*  WORKING PARAMETERS
  256.71 +*
  256.72 +*  deg    - the degree vector. deg[i] is negative means node i has been
  256.73 +*           numbered;
  256.74 +*  marker - a marker vector, where marker[i] is negative means node i
  256.75 +*           has been merged with another nodeand thus can be ignored;
  256.76 +*  rchset - vector used for the reachable set;
  256.77 +*  nbrhd  - vector used for neighborhood set;
  256.78 +*  qsize  - vector used to store the size of indistinguishable
  256.79 +*           supernodes;
  256.80 +*  qlink  - vector used to store indistinguishable nodes, i, qlink[i],
  256.81 +*           qlink[qlink[i]], ... are the members of the supernode
  256.82 +*           represented by i.
  256.83 +*
  256.84 +*  PROGRAM SUBROUTINES
  256.85 +*
  256.86 +*  qmdrch, qmdqt, qmdupd.
  256.87 +***********************************************************************/
  256.88 +
  256.89 +void genqmd(int *_neqns, int xadj[], int adjncy[], int perm[],
  256.90 +      int invp[], int deg[], int marker[], int rchset[], int nbrhd[],
  256.91 +      int qsize[], int qlink[], int *_nofsub)
  256.92 +{     int inode, ip, irch, j, mindeg, ndeg, nhdsze, node, np, num,
  256.93 +         nump1, nxnode, rchsze, search, thresh;
  256.94 +#     define neqns  (*_neqns)
  256.95 +#     define nofsub (*_nofsub)
  256.96 +      /* Initialize degree vector and other working variables. */
  256.97 +      mindeg = neqns;
  256.98 +      nofsub = 0;
  256.99 +      for (node = 1; node <= neqns; node++)
 256.100 +      {  perm[node] = node;
 256.101 +         invp[node] = node;
 256.102 +         marker[node] = 0;
 256.103 +         qsize[node] = 1;
 256.104 +         qlink[node] = 0;
 256.105 +         ndeg = xadj[node+1] - xadj[node];
 256.106 +         deg[node] = ndeg;
 256.107 +         if (ndeg < mindeg) mindeg = ndeg;
 256.108 +      }
 256.109 +      num = 0;
 256.110 +      /* Perform threshold search to get a node of min degree.
 256.111 +         Variable search point to where search should start. */
 256.112 +s200: search = 1;
 256.113 +      thresh = mindeg;
 256.114 +      mindeg = neqns;
 256.115 +s300: nump1 = num + 1;
 256.116 +      if (nump1 > search) search = nump1;
 256.117 +      for (j = search; j <= neqns; j++)
 256.118 +      {  node = perm[j];
 256.119 +         if (marker[node] >= 0)
 256.120 +         {  ndeg = deg[node];
 256.121 +            if (ndeg <= thresh) goto s500;
 256.122 +            if (ndeg < mindeg) mindeg = ndeg;
 256.123 +         }
 256.124 +      }
 256.125 +      goto s200;
 256.126 +      /* Node has minimum degree. Find its reachable sets by calling
 256.127 +         qmdrch. */
 256.128 +s500: search = j;
 256.129 +      nofsub += deg[node];
 256.130 +      marker[node] = 1;
 256.131 +      qmdrch(&node, xadj, adjncy, deg, marker, &rchsze, rchset, &nhdsze,
 256.132 +         nbrhd);
 256.133 +      /* Eliminate all nodes indistinguishable from node. They are given
 256.134 +         by node, qlink[node], ... . */
 256.135 +      nxnode = node;
 256.136 +s600: num++;
 256.137 +      np = invp[nxnode];
 256.138 +      ip = perm[num];
 256.139 +      perm[np] = ip;
 256.140 +      invp[ip] = np;
 256.141 +      perm[num] = nxnode;
 256.142 +      invp[nxnode] = num;
 256.143 +      deg[nxnode] = -1;
 256.144 +      nxnode = qlink[nxnode];
 256.145 +      if (nxnode > 0) goto s600;
 256.146 +      if (rchsze > 0)
 256.147 +      {  /* Update the degrees of the nodes in the reachable set and
 256.148 +            identify indistinguishable nodes. */
 256.149 +         qmdupd(xadj, adjncy, &rchsze, rchset, deg, qsize, qlink,
 256.150 +            marker, &rchset[rchsze+1], &nbrhd[nhdsze+1]);
 256.151 +         /* Reset marker value of nodes in reach set. Update threshold
 256.152 +            value for cyclic search. Also call qmdqt to form new
 256.153 +            quotient graph. */
 256.154 +         marker[node] = 0;
 256.155 +         for (irch = 1; irch <= rchsze; irch++)
 256.156 +         {  inode = rchset[irch];
 256.157 +            if (marker[inode] >= 0)
 256.158 +            {  marker[inode] = 0;
 256.159 +               ndeg = deg[inode];
 256.160 +               if (ndeg < mindeg) mindeg = ndeg;
 256.161 +               if (ndeg <= thresh)
 256.162 +               {  mindeg = thresh;
 256.163 +                  thresh = ndeg;
 256.164 +                  search = invp[inode];
 256.165 +               }
 256.166 +            }
 256.167 +         }
 256.168 +         if (nhdsze > 0)
 256.169 +            qmdqt(&node, xadj, adjncy, marker, &rchsze, rchset, nbrhd);
 256.170 +      }
 256.171 +      if (num < neqns) goto s300;
 256.172 +      return;
 256.173 +#     undef neqns
 256.174 +#     undef nofsub
 256.175 +}
 256.176 +
 256.177 +/***********************************************************************
 256.178 +*  NAME
 256.179 +*
 256.180 +*  qmdrch - Quotient MD ReaCHable set
 256.181 +*
 256.182 +*  SYNOPSIS
 256.183 +*
 256.184 +*  #include "glpqmd.h"
 256.185 +*  void qmdrch(int *root, int xadj[], int adjncy[], int deg[],
 256.186 +*     int marker[], int *rchsze, int rchset[], int *nhdsze,
 256.187 +*     int nbrhd[]);
 256.188 +*
 256.189 +*  PURPOSE
 256.190 +*
 256.191 +*  This subroutine determines the reachable set of a node through a
 256.192 +*  given subset. The adjancy structure is assumed to be stored in a
 256.193 +*  quotient graph format.
 256.194 +* 
 256.195 +*  INPUT PARAMETERS
 256.196 +*
 256.197 +*  root   - the given node not in the subset;
 256.198 +*  (xadj, adjncy) -
 256.199 +*           the adjancy structure pair;
 256.200 +*  deg    - the degree vector. deg[i] < 0 means the node belongs to the
 256.201 +*           given subset.
 256.202 +*
 256.203 +*  OUTPUT PARAMETERS
 256.204 +*
 256.205 +*  (rchsze, rchset) -
 256.206 +*           the reachable set;
 256.207 +*  (nhdsze, nbrhd) -
 256.208 +*           the neighborhood set.
 256.209 +*
 256.210 +*  UPDATED PARAMETERS
 256.211 +*
 256.212 +*  marker - the marker vector for reach and nbrhd sets. > 0 means the
 256.213 +*           node is in reach set. < 0 means the node has been merged
 256.214 +*           with others in the quotient or it is in nbrhd set.
 256.215 +***********************************************************************/
 256.216 +
 256.217 +void qmdrch(int *_root, int xadj[], int adjncy[], int deg[],
 256.218 +      int marker[], int *_rchsze, int rchset[], int *_nhdsze,
 256.219 +      int nbrhd[])
 256.220 +{     int i, istop, istrt, j, jstop, jstrt, nabor, node;
 256.221 +#     define root   (*_root)
 256.222 +#     define rchsze (*_rchsze)
 256.223 +#     define nhdsze (*_nhdsze)
 256.224 +      /* Loop through the neighbors of root in the quotient graph. */
 256.225 +      nhdsze = 0;
 256.226 +      rchsze = 0;
 256.227 +      istrt = xadj[root];
 256.228 +      istop = xadj[root+1] - 1;
 256.229 +      if (istop < istrt) return;
 256.230 +      for (i = istrt; i <= istop; i++)
 256.231 +      {  nabor = adjncy[i];
 256.232 +         if (nabor == 0) return;
 256.233 +         if (marker[nabor] == 0)
 256.234 +         {  if (deg[nabor] >= 0)
 256.235 +            {  /* Include nabor into the reachable set. */
 256.236 +               rchsze++;
 256.237 +               rchset[rchsze] = nabor;
 256.238 +               marker[nabor] = 1;
 256.239 +               goto s600;
 256.240 +            }
 256.241 +            /* nabor has been eliminated. Find nodes reachable from
 256.242 +               it. */
 256.243 +            marker[nabor] = -1;
 256.244 +            nhdsze++;
 256.245 +            nbrhd[nhdsze] = nabor;
 256.246 +s300:       jstrt = xadj[nabor];
 256.247 +            jstop = xadj[nabor+1] - 1;
 256.248 +            for (j = jstrt; j <= jstop; j++)
 256.249 +            {  node = adjncy[j];
 256.250 +               nabor = - node;
 256.251 +               if (node < 0) goto s300;
 256.252 +               if (node == 0) goto s600;
 256.253 +               if (marker[node] == 0)
 256.254 +               {  rchsze++;
 256.255 +                  rchset[rchsze] = node;
 256.256 +                  marker[node] = 1;
 256.257 +               }
 256.258 +            }
 256.259 +         }
 256.260 +s600:    ;
 256.261 +      }
 256.262 +      return;
 256.263 +#     undef root
 256.264 +#     undef rchsze
 256.265 +#     undef nhdsze
 256.266 +}
 256.267 +
 256.268 +/***********************************************************************
 256.269 +*  NAME
 256.270 +*
 256.271 +*  qmdqt - Quotient MD Quotient graph Transformation
 256.272 +*
 256.273 +*  SYNOPSIS
 256.274 +*
 256.275 +*  #include "glpqmd.h"
 256.276 +*  void qmdqt(int *root, int xadj[], int adjncy[], int marker[],
 256.277 +*     int *rchsze, int rchset[], int nbrhd[]);
 256.278 +*
 256.279 +*  PURPOSE
 256.280 +*
 256.281 +*  This subroutine performs the quotient graph transformation after a
 256.282 +*  node has been eliminated.
 256.283 +*
 256.284 +*  INPUT PARAMETERS
 256.285 +*
 256.286 +*  root   - the node just eliminated. It becomes the representative of
 256.287 +*           the new supernode;
 256.288 +*  (xadj, adjncy) -
 256.289 +*           the adjancy structure;
 256.290 +*  (rchsze, rchset) -
 256.291 +*           the reachable set of root in the old quotient graph;
 256.292 +*  nbrhd  - the neighborhood set which will be merged with root to form
 256.293 +*           the new supernode;
 256.294 +*  marker - the marker vector.
 256.295 +*
 256.296 +*  UPDATED PARAMETERS
 256.297 +*
 256.298 +*  adjncy - becomes the adjncy of the quotient graph.
 256.299 +***********************************************************************/
 256.300 +
 256.301 +void qmdqt(int *_root, int xadj[], int adjncy[], int marker[],
 256.302 +      int *_rchsze, int rchset[], int nbrhd[])
 256.303 +{     int inhd, irch, j, jstop, jstrt, link, nabor, node;
 256.304 +#     define root   (*_root)
 256.305 +#     define rchsze (*_rchsze)
 256.306 +      irch = 0;
 256.307 +      inhd = 0;
 256.308 +      node = root;
 256.309 +s100: jstrt = xadj[node];
 256.310 +      jstop = xadj[node+1] - 2;
 256.311 +      if (jstop >= jstrt)
 256.312 +      {  /* Place reach nodes into the adjacent list of node. */
 256.313 +         for (j = jstrt; j <= jstop; j++)
 256.314 +         {  irch++;
 256.315 +            adjncy[j] = rchset[irch];
 256.316 +            if (irch >= rchsze) goto s400;
 256.317 +         }
 256.318 +      }
 256.319 +      /* Link to other space provided by the nbrhd set. */
 256.320 +      link = adjncy[jstop+1];
 256.321 +      node = - link;
 256.322 +      if (link >= 0)
 256.323 +      {  inhd++;
 256.324 +         node = nbrhd[inhd];
 256.325 +         adjncy[jstop+1] = - node;
 256.326 +      }
 256.327 +      goto s100;
 256.328 +      /* All reachable nodes have been saved. End the adjacent list.
 256.329 +         Add root to the neighborhood list of each node in the reach
 256.330 +         set. */
 256.331 +s400: adjncy[j+1] = 0;
 256.332 +      for (irch = 1; irch <= rchsze; irch++)
 256.333 +      {  node = rchset[irch];
 256.334 +         if (marker[node] >= 0)
 256.335 +         {  jstrt = xadj[node];
 256.336 +            jstop = xadj[node+1] - 1;
 256.337 +            for (j = jstrt; j <= jstop; j++)
 256.338 +            {  nabor = adjncy[j];
 256.339 +               if (marker[nabor] < 0)
 256.340 +               {  adjncy[j] = root;
 256.341 +                  goto s600;
 256.342 +               }
 256.343 +            }
 256.344 +         }
 256.345 +s600:    ;
 256.346 +      }
 256.347 +      return;
 256.348 +#     undef root
 256.349 +#     undef rchsze
 256.350 +}
 256.351 +
 256.352 +/***********************************************************************
 256.353 +*  NAME
 256.354 +*
 256.355 +*  qmdupd - Quotient MD UPDate
 256.356 +*
 256.357 +*  SYNOPSIS
 256.358 +*
 256.359 +*  #include "glpqmd.h"
 256.360 +*  void qmdupd(int xadj[], int adjncy[], int *nlist, int list[],
 256.361 +*     int deg[], int qsize[], int qlink[], int marker[], int rchset[],
 256.362 +*     int nbrhd[]);
 256.363 +*
 256.364 +*  PURPOSE
 256.365 +*
 256.366 +*  This routine performs degree update for a set of nodes in the minimum
 256.367 +*  degree algorithm.
 256.368 +*
 256.369 +*  INPUT PARAMETERS
 256.370 +*
 256.371 +*  (xadj, adjncy) -
 256.372 +*           the adjancy structure;
 256.373 +*  (nlist, list) -
 256.374 +*           the list of nodes whose degree has to be updated.
 256.375 +*
 256.376 +*  UPDATED PARAMETERS
 256.377 +*
 256.378 +*  deg    - the degree vector;
 256.379 +*  qsize  - size of indistinguishable supernodes;
 256.380 +*  qlink  - linked list for indistinguishable nodes;
 256.381 +*  marker - used to mark those nodes in reach/nbrhd sets.
 256.382 +*
 256.383 +*  WORKING PARAMETERS
 256.384 +*
 256.385 +*  rchset - the reachable set;
 256.386 +*  nbrhd  - the neighborhood set.
 256.387 +*
 256.388 +*  PROGRAM SUBROUTINES
 256.389 +*
 256.390 +*  qmdmrg.
 256.391 +***********************************************************************/
 256.392 +
 256.393 +void qmdupd(int xadj[], int adjncy[], int *_nlist, int list[],
 256.394 +      int deg[], int qsize[], int qlink[], int marker[], int rchset[],
 256.395 +      int nbrhd[])
 256.396 +{     int deg0, deg1, il, inhd, inode, irch, j, jstop, jstrt, mark,
 256.397 +         nabor, nhdsze, node, rchsze;
 256.398 +#     define nlist  (*_nlist)
 256.399 +      /* Find all eliminated supernodes that are adjacent to some nodes
 256.400 +         in the given list. Put them into (nhdsze, nbrhd). deg0 contains
 256.401 +         the number of nodes in the list. */
 256.402 +      if (nlist <= 0) return;
 256.403 +      deg0 = 0;
 256.404 +      nhdsze = 0;
 256.405 +      for (il = 1; il <= nlist; il++)
 256.406 +      {  node = list[il];
 256.407 +         deg0 += qsize[node];
 256.408 +         jstrt = xadj[node];
 256.409 +         jstop = xadj[node+1] - 1;
 256.410 +         for (j = jstrt; j <= jstop; j++)
 256.411 +         {  nabor = adjncy[j];
 256.412 +            if (marker[nabor] == 0 && deg[nabor] < 0)
 256.413 +            {  marker[nabor] = -1;
 256.414 +               nhdsze++;
 256.415 +               nbrhd[nhdsze] = nabor;
 256.416 +            }
 256.417 +         }
 256.418 +      }
 256.419 +      /* Merge indistinguishable nodes in the list by calling the
 256.420 +         subroutine qmdmrg. */
 256.421 +      if (nhdsze > 0)
 256.422 +         qmdmrg(xadj, adjncy, deg, qsize, qlink, marker, &deg0, &nhdsze,
 256.423 +            nbrhd, rchset, &nbrhd[nhdsze+1]);
 256.424 +      /* Find the new degrees of the nodes that have not been merged. */
 256.425 +      for (il = 1; il <= nlist; il++)
 256.426 +      {  node = list[il];
 256.427 +         mark = marker[node];
 256.428 +         if (mark == 0 || mark == 1)
 256.429 +         {  marker[node] = 2;
 256.430 +            qmdrch(&node, xadj, adjncy, deg, marker, &rchsze, rchset,
 256.431 +               &nhdsze, nbrhd);
 256.432 +            deg1 = deg0;
 256.433 +            if (rchsze > 0)
 256.434 +            {  for (irch = 1; irch <= rchsze; irch++)
 256.435 +               {  inode = rchset[irch];
 256.436 +                  deg1 += qsize[inode];
 256.437 +                  marker[inode] = 0;
 256.438 +               }
 256.439 +            }
 256.440 +            deg[node] = deg1 - 1;
 256.441 +            if (nhdsze > 0)
 256.442 +            {  for (inhd = 1; inhd <= nhdsze; inhd++)
 256.443 +               {  inode = nbrhd[inhd];
 256.444 +                  marker[inode] = 0;
 256.445 +               }
 256.446 +            }
 256.447 +         }
 256.448 +      }
 256.449 +      return;
 256.450 +#     undef nlist
 256.451 +}
 256.452 +
 256.453 +/***********************************************************************
 256.454 +*  NAME
 256.455 +*
 256.456 +*  qmdmrg - Quotient MD MeRGe
 256.457 +*
 256.458 +*  SYNOPSIS
 256.459 +*
 256.460 +*  #include "qmdmrg.h"
 256.461 +*  void qmdmrg(int xadj[], int adjncy[], int deg[], int qsize[],
 256.462 +*     int qlink[], int marker[], int *deg0, int *nhdsze, int nbrhd[],
 256.463 +*     int rchset[], int ovrlp[]);
 256.464 +*
 256.465 +*  PURPOSE
 256.466 +*
 256.467 +*  This routine merges indistinguishable nodes in the minimum degree
 256.468 +*  ordering algorithm. It also computes the new degrees of these new
 256.469 +*  supernodes.
 256.470 +*
 256.471 +*  INPUT PARAMETERS
 256.472 +*
 256.473 +*  (xadj, adjncy) -
 256.474 +*           the adjancy structure;
 256.475 +*  deg0   - the number of nodes in the given set;
 256.476 +*  (nhdsze, nbrhd) -
 256.477 +*           the set of eliminated supernodes adjacent to some nodes in
 256.478 +*           the set.
 256.479 +*
 256.480 +*  UPDATED PARAMETERS
 256.481 +*
 256.482 +*  deg    - the degree vector;
 256.483 +*  qsize  - size of indistinguishable nodes;
 256.484 +*  qlink  - linked list for indistinguishable nodes;
 256.485 +*  marker - the given set is given by those nodes with marker value set
 256.486 +*           to 1. Those nodes with degree updated will have marker value
 256.487 +*           set to 2.
 256.488 +*
 256.489 +*  WORKING PARAMETERS
 256.490 +*
 256.491 +*  rchset - the reachable set;
 256.492 +*  ovrlp  - temp vector to store the intersection of two reachable sets.
 256.493 +***********************************************************************/
 256.494 +
 256.495 +void qmdmrg(int xadj[], int adjncy[], int deg[], int qsize[],
 256.496 +      int qlink[], int marker[], int *_deg0, int *_nhdsze, int nbrhd[],
 256.497 +      int rchset[], int ovrlp[])
 256.498 +{     int deg1, head, inhd, iov, irch, j, jstop, jstrt, link, lnode,
 256.499 +         mark, mrgsze, nabor, node, novrlp, rchsze, root;
 256.500 +#     define deg0   (*_deg0)
 256.501 +#     define nhdsze (*_nhdsze)
 256.502 +      /* Initialization. */
 256.503 +      if (nhdsze <= 0) return;
 256.504 +      for (inhd = 1; inhd <= nhdsze; inhd++)
 256.505 +      {  root = nbrhd[inhd];
 256.506 +         marker[root] = 0;
 256.507 +      }
 256.508 +      /* Loop through each eliminated supernode in the set
 256.509 +         (nhdsze, nbrhd). */
 256.510 +      for (inhd = 1; inhd <= nhdsze; inhd++)
 256.511 +      {  root = nbrhd[inhd];
 256.512 +         marker[root] = -1;
 256.513 +         rchsze = 0;
 256.514 +         novrlp = 0;
 256.515 +         deg1 = 0;
 256.516 +s200:    jstrt = xadj[root];
 256.517 +         jstop = xadj[root+1] - 1;
 256.518 +         /* Determine the reachable set and its intersection with the
 256.519 +            input reachable set. */
 256.520 +         for (j = jstrt; j <= jstop; j++)
 256.521 +         {  nabor = adjncy[j];
 256.522 +            root = - nabor;
 256.523 +            if (nabor < 0) goto s200;
 256.524 +            if (nabor == 0) break;
 256.525 +            mark = marker[nabor];
 256.526 +            if (mark == 0)
 256.527 +            {  rchsze++;
 256.528 +               rchset[rchsze] = nabor;
 256.529 +               deg1 += qsize[nabor];
 256.530 +               marker[nabor] = 1;
 256.531 +            }
 256.532 +            else if (mark == 1)
 256.533 +            {  novrlp++;
 256.534 +               ovrlp[novrlp] = nabor;
 256.535 +               marker[nabor] = 2;
 256.536 +            }
 256.537 +         }
 256.538 +         /* From the overlapped set, determine the nodes that can be
 256.539 +            merged together. */
 256.540 +         head = 0;
 256.541 +         mrgsze = 0;
 256.542 +         for (iov = 1; iov <= novrlp; iov++)
 256.543 +         {  node = ovrlp[iov];
 256.544 +            jstrt = xadj[node];
 256.545 +            jstop = xadj[node+1] - 1;
 256.546 +            for (j = jstrt; j <= jstop; j++)
 256.547 +            {  nabor = adjncy[j];
 256.548 +               if (marker[nabor] == 0)
 256.549 +               {  marker[node] = 1;
 256.550 +                  goto s1100;
 256.551 +               }
 256.552 +            }
 256.553 +            /* Node belongs to the new merged supernode. Update the
 256.554 +               vectors qlink and qsize. */
 256.555 +            mrgsze += qsize[node];
 256.556 +            marker[node] = -1;
 256.557 +            lnode = node;
 256.558 +s900:       link = qlink[lnode];
 256.559 +            if (link > 0)
 256.560 +            {  lnode = link;
 256.561 +               goto s900;
 256.562 +            }
 256.563 +            qlink[lnode] = head;
 256.564 +            head = node;
 256.565 +s1100:      ;
 256.566 +         }
 256.567 +         if (head > 0)
 256.568 +         {  qsize[head] = mrgsze;
 256.569 +            deg[head] = deg0 + deg1 - 1;
 256.570 +            marker[head] = 2;
 256.571 +         }
 256.572 +         /* Reset marker values. */
 256.573 +         root = nbrhd[inhd];
 256.574 +         marker[root] = 0;
 256.575 +         if (rchsze > 0)
 256.576 +         {  for (irch = 1; irch <= rchsze; irch++)
 256.577 +            {  node = rchset[irch];
 256.578 +               marker[node] = 0;
 256.579 +            }
 256.580 +         }
 256.581 +      }
 256.582 +      return;
 256.583 +#     undef deg0
 256.584 +#     undef nhdsze
 256.585 +}
 256.586 +
 256.587 +/* eof */
   257.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   257.2 +++ b/src/glpqmd.h	Mon Dec 06 13:09:21 2010 +0100
   257.3 @@ -0,0 +1,59 @@
   257.4 +/* glpqmd.h (quotient minimum degree algorithm) */
   257.5 +
   257.6 +/***********************************************************************
   257.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   257.8 +*
   257.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  257.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  257.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  257.12 +*  E-mail: <mao@gnu.org>.
  257.13 +*
  257.14 +*  GLPK is free software: you can redistribute it and/or modify it
  257.15 +*  under the terms of the GNU General Public License as published by
  257.16 +*  the Free Software Foundation, either version 3 of the License, or
  257.17 +*  (at your option) any later version.
  257.18 +*
  257.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  257.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  257.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  257.22 +*  License for more details.
  257.23 +*
  257.24 +*  You should have received a copy of the GNU General Public License
  257.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  257.26 +***********************************************************************/
  257.27 +
  257.28 +#ifndef GLPQMD_H
  257.29 +#define GLPQMD_H
  257.30 +
  257.31 +#define genqmd _glp_qmd_genqmd
  257.32 +void genqmd(int *neqns, int xadj[], int adjncy[], int perm[],
  257.33 +      int invp[], int deg[], int marker[], int rchset[], int nbrhd[],
  257.34 +      int qsize[], int qlink[], int *nofsub);
  257.35 +/* GENeral Quotient Minimum Degree algorithm */
  257.36 +
  257.37 +#define qmdrch _glp_qmd_qmdrch
  257.38 +void qmdrch(int *root, int xadj[], int adjncy[], int deg[],
  257.39 +      int marker[], int *rchsze, int rchset[], int *nhdsze,
  257.40 +      int nbrhd[]);
  257.41 +/* Quotient MD ReaCHable set */
  257.42 +
  257.43 +#define qmdqt _glp_qmd_qmdqt
  257.44 +void qmdqt(int *root, int xadj[], int adjncy[], int marker[],
  257.45 +      int *rchsze, int rchset[], int nbrhd[]);
  257.46 +/* Quotient MD Quotient graph Transformation */
  257.47 +
  257.48 +#define qmdupd _glp_qmd_qmdupd
  257.49 +void qmdupd(int xadj[], int adjncy[], int *nlist, int list[],
  257.50 +      int deg[], int qsize[], int qlink[], int marker[], int rchset[],
  257.51 +      int nbrhd[]);
  257.52 +/* Quotient MD UPDate */
  257.53 +
  257.54 +#define qmdmrg _glp_qmd_qmdmrg
  257.55 +void qmdmrg(int xadj[], int adjncy[], int deg[], int qsize[],
  257.56 +      int qlink[], int marker[], int *deg0, int *nhdsze, int nbrhd[],
  257.57 +      int rchset[], int ovrlp[]);
  257.58 +/* Quotient MD MeRGe */
  257.59 +
  257.60 +#endif
  257.61 +
  257.62 +/* eof */
   258.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   258.2 +++ b/src/glprgr.c	Mon Dec 06 13:09:21 2010 +0100
   258.3 @@ -0,0 +1,165 @@
   258.4 +/* glprgr.c */
   258.5 +
   258.6 +/***********************************************************************
   258.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   258.8 +*
   258.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  258.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  258.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  258.12 +*  E-mail: <mao@gnu.org>.
  258.13 +*
  258.14 +*  GLPK is free software: you can redistribute it and/or modify it
  258.15 +*  under the terms of the GNU General Public License as published by
  258.16 +*  the Free Software Foundation, either version 3 of the License, or
  258.17 +*  (at your option) any later version.
  258.18 +*
  258.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  258.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  258.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  258.22 +*  License for more details.
  258.23 +*
  258.24 +*  You should have received a copy of the GNU General Public License
  258.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  258.26 +***********************************************************************/
  258.27 +
  258.28 +#define _GLPSTD_ERRNO
  258.29 +#define _GLPSTD_STDIO
  258.30 +#include "glpenv.h"
  258.31 +#include "glprgr.h"
  258.32 +#define xfault xerror
  258.33 +
  258.34 +/***********************************************************************
  258.35 +*  NAME
  258.36 +*
  258.37 +*  rgr_write_bmp16 - write 16-color raster image in BMP file format
  258.38 +*
  258.39 +*  SYNOPSIS
  258.40 +*
  258.41 +*  #include "glprgr.h"
  258.42 +*  int rgr_write_bmp16(const char *fname, int m, int n, const char
  258.43 +*     map[]);
  258.44 +*
  258.45 +*  DESCRIPTION
  258.46 +*
  258.47 +*  The routine rgr_write_bmp16 writes 16-color raster image in
  258.48 +*  uncompressed BMP file format (Windows bitmap) to a binary file whose
  258.49 +*  name is specified by the character string fname.
  258.50 +*
  258.51 +*  The parameters m and n specify, respectively, the number of rows and
  258.52 +*  the numbers of columns (i.e. height and width) of the raster image.
  258.53 +*
  258.54 +*  The character array map has m*n elements. Elements map[0, ..., n-1]
  258.55 +*  correspond to the first (top) scanline, elements map[n, ..., 2*n-1]
  258.56 +*  correspond to the second scanline, etc.
  258.57 +*
  258.58 +*  Each element of the array map specifies a color of the corresponding
  258.59 +*  pixel as 8-bit binary number XXXXIRGB, where four high-order bits (X)
  258.60 +*  are ignored, I is high intensity bit, R is red color bit, G is green
  258.61 +*  color bit, and B is blue color bit. Thus, all 16 possible colors are
  258.62 +*  coded as following hexadecimal numbers:
  258.63 +*
  258.64 +*     0x00 = black         0x08 = dark gray
  258.65 +*     0x01 = blue          0x09 = bright blue
  258.66 +*     0x02 = green         0x0A = bright green
  258.67 +*     0x03 = cyan          0x0B = bright cyan
  258.68 +*     0x04 = red           0x0C = bright red
  258.69 +*     0x05 = magenta       0x0D = bright magenta
  258.70 +*     0x06 = brown         0x0E = yellow
  258.71 +*     0x07 = light gray    0x0F = white
  258.72 +*
  258.73 +*  RETURNS
  258.74 +*
  258.75 +*  If no error occured, the routine returns zero; otherwise, it prints
  258.76 +*  an appropriate error message and returns non-zero. */
  258.77 +
  258.78 +static void put_byte(FILE *fp, int c)
  258.79 +{     fputc(c, fp);
  258.80 +      return;
  258.81 +}
  258.82 +
  258.83 +static void put_word(FILE *fp, int w)
  258.84 +{     /* big endian */
  258.85 +      put_byte(fp, w);
  258.86 +      put_byte(fp, w >> 8);
  258.87 +      return;
  258.88 +}
  258.89 +
  258.90 +static void put_dword(FILE *fp, int d)
  258.91 +{     /* big endian */
  258.92 +      put_word(fp, d);
  258.93 +      put_word(fp, d >> 16);
  258.94 +      return;
  258.95 +}
  258.96 +
  258.97 +int rgr_write_bmp16(const char *fname, int m, int n, const char map[])
  258.98 +{     FILE *fp;
  258.99 +      int offset, bmsize, i, j, b, ret = 0;
 258.100 +      if (!(1 <= m && m <= 32767))
 258.101 +         xfault("rgr_write_bmp16: m = %d; invalid height\n", m);
 258.102 +      if (!(1 <= n && n <= 32767))
 258.103 +         xfault("rgr_write_bmp16: n = %d; invalid width\n", n);
 258.104 +      fp = fopen(fname, "wb");
 258.105 +      if (fp == NULL)
 258.106 +      {  xprintf("rgr_write_bmp16: unable to create `%s' - %s\n",
 258.107 +            fname, strerror(errno));
 258.108 +         ret = 1;
 258.109 +         goto fini;
 258.110 +      }
 258.111 +      offset = 14 + 40 + 16 * 4;
 258.112 +      bmsize = (4 * n + 31) / 32;
 258.113 +      /* struct BMPFILEHEADER (14 bytes) */
 258.114 +      /* UINT bfType */          put_byte(fp, 'B'), put_byte(fp, 'M');
 258.115 +      /* DWORD bfSize */         put_dword(fp, offset + bmsize * 4);
 258.116 +      /* UINT bfReserved1 */     put_word(fp, 0);
 258.117 +      /* UNIT bfReserved2 */     put_word(fp, 0);
 258.118 +      /* DWORD bfOffBits */      put_dword(fp, offset);
 258.119 +      /* struct BMPINFOHEADER (40 bytes) */
 258.120 +      /* DWORD biSize */         put_dword(fp, 40);
 258.121 +      /* LONG biWidth */         put_dword(fp, n);
 258.122 +      /* LONG biHeight */        put_dword(fp, m);
 258.123 +      /* WORD biPlanes */        put_word(fp, 1);
 258.124 +      /* WORD biBitCount */      put_word(fp, 4);
 258.125 +      /* DWORD biCompression */  put_dword(fp, 0 /* BI_RGB */);
 258.126 +      /* DWORD biSizeImage */    put_dword(fp, 0);
 258.127 +      /* LONG biXPelsPerMeter */ put_dword(fp, 2953 /* 75 dpi */);
 258.128 +      /* LONG biYPelsPerMeter */ put_dword(fp, 2953 /* 75 dpi */);
 258.129 +      /* DWORD biClrUsed */      put_dword(fp, 0);
 258.130 +      /* DWORD biClrImportant */ put_dword(fp, 0);
 258.131 +      /* struct RGBQUAD (16 * 4 = 64 bytes) */
 258.132 +      /* CGA-compatible colors: */
 258.133 +      /* 0x00 = black */         put_dword(fp, 0x000000);
 258.134 +      /* 0x01 = blue */          put_dword(fp, 0x000080);
 258.135 +      /* 0x02 = green */         put_dword(fp, 0x008000);
 258.136 +      /* 0x03 = cyan */          put_dword(fp, 0x008080);
 258.137 +      /* 0x04 = red */           put_dword(fp, 0x800000);
 258.138 +      /* 0x05 = magenta */       put_dword(fp, 0x800080);
 258.139 +      /* 0x06 = brown */         put_dword(fp, 0x808000);
 258.140 +      /* 0x07 = light gray */    put_dword(fp, 0xC0C0C0);
 258.141 +      /* 0x08 = dark gray */     put_dword(fp, 0x808080);
 258.142 +      /* 0x09 = bright blue */   put_dword(fp, 0x0000FF);
 258.143 +      /* 0x0A = bright green */  put_dword(fp, 0x00FF00);
 258.144 +      /* 0x0B = bright cyan */   put_dword(fp, 0x00FFFF);
 258.145 +      /* 0x0C = bright red */    put_dword(fp, 0xFF0000);
 258.146 +      /* 0x0D = bright magenta */ put_dword(fp, 0xFF00FF);
 258.147 +      /* 0x0E = yellow */        put_dword(fp, 0xFFFF00);
 258.148 +      /* 0x0F = white */         put_dword(fp, 0xFFFFFF);
 258.149 +      /* pixel data bits */
 258.150 +      b = 0;
 258.151 +      for (i = m - 1; i >= 0; i--)
 258.152 +      {  for (j = 0; j < ((n + 7) / 8) * 8; j++)
 258.153 +         {  b <<= 4;
 258.154 +            b |= (j < n ? map[i * n + j] & 15 : 0);
 258.155 +            if (j & 1) put_byte(fp, b);
 258.156 +         }
 258.157 +      }
 258.158 +      fflush(fp);
 258.159 +      if (ferror(fp))
 258.160 +      {  xprintf("rgr_write_bmp16: write error on `%s' - %s\n",
 258.161 +            fname, strerror(errno));
 258.162 +         ret = 1;
 258.163 +      }
 258.164 +fini: if (fp != NULL) fclose(fp);
 258.165 +      return ret;
 258.166 +}
 258.167 +
 258.168 +/* eof */
   259.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   259.2 +++ b/src/glprgr.h	Mon Dec 06 13:09:21 2010 +0100
   259.3 @@ -0,0 +1,34 @@
   259.4 +/* glprgr.h (raster graphics) */
   259.5 +
   259.6 +/***********************************************************************
   259.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   259.8 +*
   259.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  259.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  259.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  259.12 +*  E-mail: <mao@gnu.org>.
  259.13 +*
  259.14 +*  GLPK is free software: you can redistribute it and/or modify it
  259.15 +*  under the terms of the GNU General Public License as published by
  259.16 +*  the Free Software Foundation, either version 3 of the License, or
  259.17 +*  (at your option) any later version.
  259.18 +*
  259.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  259.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  259.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  259.22 +*  License for more details.
  259.23 +*
  259.24 +*  You should have received a copy of the GNU General Public License
  259.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  259.26 +***********************************************************************/
  259.27 +
  259.28 +#ifndef GLPRGR_H
  259.29 +#define GLPRGR_H
  259.30 +
  259.31 +#define rgr_write_bmp16 _glp_rgr_write_bmp16
  259.32 +int rgr_write_bmp16(const char *fname, int m, int n, const char map[]);
  259.33 +/* write 16-color raster image in BMP file format */
  259.34 +
  259.35 +#endif
  259.36 +
  259.37 +/* eof */
   260.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   260.2 +++ b/src/glprng.h	Mon Dec 06 13:09:21 2010 +0100
   260.3 @@ -0,0 +1,68 @@
   260.4 +/* glprng.h (pseudo-random number generator) */
   260.5 +
   260.6 +/***********************************************************************
   260.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   260.8 +*
   260.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  260.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  260.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  260.12 +*  E-mail: <mao@gnu.org>.
  260.13 +*
  260.14 +*  GLPK is free software: you can redistribute it and/or modify it
  260.15 +*  under the terms of the GNU General Public License as published by
  260.16 +*  the Free Software Foundation, either version 3 of the License, or
  260.17 +*  (at your option) any later version.
  260.18 +*
  260.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  260.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  260.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  260.22 +*  License for more details.
  260.23 +*
  260.24 +*  You should have received a copy of the GNU General Public License
  260.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  260.26 +***********************************************************************/
  260.27 +
  260.28 +#ifndef GLPRNG_H
  260.29 +#define GLPRNG_H
  260.30 +
  260.31 +typedef struct RNG RNG;
  260.32 +
  260.33 +struct RNG
  260.34 +{     /* Knuth's portable pseudo-random number generator */
  260.35 +      int A[56];
  260.36 +      /* pseudo-random values */
  260.37 +      int *fptr;
  260.38 +      /* the next A value to be exported */
  260.39 +};
  260.40 +
  260.41 +#define rng_create_rand _glp_rng_create_rand
  260.42 +RNG *rng_create_rand(void);
  260.43 +/* create pseudo-random number generator */
  260.44 +
  260.45 +#define rng_init_rand _glp_rng_init_rand
  260.46 +void rng_init_rand(RNG *rand, int seed);
  260.47 +/* initialize pseudo-random number generator */
  260.48 +
  260.49 +#define rng_next_rand _glp_rng_next_rand
  260.50 +int rng_next_rand(RNG *rand);
  260.51 +/* obtain pseudo-random integer in the range [0, 2^31-1] */
  260.52 +
  260.53 +#define rng_unif_rand _glp_rng_unif_rand
  260.54 +int rng_unif_rand(RNG *rand, int m);
  260.55 +/* obtain pseudo-random integer in the range [0, m-1] */
  260.56 +
  260.57 +#define rng_delete_rand _glp_rng_delete_rand
  260.58 +void rng_delete_rand(RNG *rand);
  260.59 +/* delete pseudo-random number generator */
  260.60 +
  260.61 +#define rng_unif_01 _glp_rng_unif_01
  260.62 +double rng_unif_01(RNG *rand);
  260.63 +/* obtain pseudo-random number in the range [0, 1] */
  260.64 +
  260.65 +#define rng_uniform _glp_rng_uniform
  260.66 +double rng_uniform(RNG *rand, double a, double b);
  260.67 +/* obtain pseudo-random number in the range [a, b] */
  260.68 +
  260.69 +#endif
  260.70 +
  260.71 +/* eof */
   261.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   261.2 +++ b/src/glprng01.c	Mon Dec 06 13:09:21 2010 +0100
   261.3 @@ -0,0 +1,227 @@
   261.4 +/* glprng01.c */
   261.5 +
   261.6 +/***********************************************************************
   261.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   261.8 +*
   261.9 +*  This code is a modified version of the module GB_FLIP, a portable
  261.10 +*  pseudo-random number generator. The original version of GB_FLIP is
  261.11 +*  a part of The Stanford GraphBase developed by Donald E. Knuth (see
  261.12 +*  http://www-cs-staff.stanford.edu/~knuth/sgb.html).
  261.13 +*
  261.14 +*  Note that all changes concern only external names, so this modified
  261.15 +*  version produces exactly the same results as the original version.
  261.16 +*
  261.17 +*  Changes were made by Andrew Makhorin <mao@gnu.org>.
  261.18 +*
  261.19 +*  GLPK is free software: you can redistribute it and/or modify it
  261.20 +*  under the terms of the GNU General Public License as published by
  261.21 +*  the Free Software Foundation, either version 3 of the License, or
  261.22 +*  (at your option) any later version.
  261.23 +*
  261.24 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  261.25 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  261.26 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  261.27 +*  License for more details.
  261.28 +*
  261.29 +*  You should have received a copy of the GNU General Public License
  261.30 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  261.31 +***********************************************************************/
  261.32 +
  261.33 +#include "glpenv.h"
  261.34 +#include "glprng.h"
  261.35 +
  261.36 +#if 0
  261.37 +int A[56] = { -1 };
  261.38 +#else
  261.39 +#define A (rand->A)
  261.40 +#endif
  261.41 +/* pseudo-random values */
  261.42 +
  261.43 +#if 0
  261.44 +int *fptr = A;
  261.45 +#else
  261.46 +#define fptr (rand->fptr)
  261.47 +#endif
  261.48 +/* the next A value to be exported */
  261.49 +
  261.50 +#define mod_diff(x, y) (((x) - (y)) & 0x7FFFFFFF)
  261.51 +/* difference modulo 2^31 */
  261.52 +
  261.53 +static int flip_cycle(RNG *rand)
  261.54 +{     /* this is an auxiliary routine to do 55 more steps of the basic
  261.55 +         recurrence, at high speed, and to reset fptr */
  261.56 +      int *ii, *jj;
  261.57 +      for (ii = &A[1], jj = &A[32]; jj <= &A[55]; ii++, jj++)
  261.58 +         *ii = mod_diff(*ii, *jj);
  261.59 +      for (jj = &A[1]; ii <= &A[55]; ii++, jj++)
  261.60 +         *ii = mod_diff(*ii, *jj);
  261.61 +      fptr = &A[54];
  261.62 +      return A[55];
  261.63 +}
  261.64 +
  261.65 +/***********************************************************************
  261.66 +*  NAME
  261.67 +*
  261.68 +*  rng_create_rand - create pseudo-random number generator
  261.69 +*
  261.70 +*  SYNOPSIS
  261.71 +*
  261.72 +*  #include "glprng.h"
  261.73 +*  RNG *rng_create_rand(void);
  261.74 +*
  261.75 +*  DESCRIPTION
  261.76 +*
  261.77 +*  The routine rng_create_rand creates and initializes a pseudo-random
  261.78 +*  number generator.
  261.79 +*
  261.80 +*  RETURNS
  261.81 +*
  261.82 +*  The routine returns a pointer to the generator created. */
  261.83 +
  261.84 +RNG *rng_create_rand(void)
  261.85 +{     RNG *rand;
  261.86 +      int i;
  261.87 +      rand = xmalloc(sizeof(RNG));
  261.88 +      A[0] = -1;
  261.89 +      for (i = 1; i <= 55; i++) A[i] = 0;
  261.90 +      fptr = A;
  261.91 +      rng_init_rand(rand, 1);
  261.92 +      return rand;
  261.93 +}
  261.94 +
  261.95 +/***********************************************************************
  261.96 +*  NAME
  261.97 +*
  261.98 +*  rng_init_rand - initialize pseudo-random number generator
  261.99 +*
 261.100 +*  SYNOPSIS
 261.101 +*
 261.102 +*  #include "glprng.h"
 261.103 +*  void rng_init_rand(RNG *rand, int seed);
 261.104 +*
 261.105 +*  DESCRIPTION
 261.106 +*
 261.107 +*  The routine rng_init_rand initializes the pseudo-random number
 261.108 +*  generator. The parameter seed may be any integer number. Note that
 261.109 +*  on creating the generator this routine is called with the parameter
 261.110 +*  seed equal to 1. */
 261.111 +
 261.112 +void rng_init_rand(RNG *rand, int seed)
 261.113 +{     int i;
 261.114 +      int prev = seed, next = 1;
 261.115 +      seed = prev = mod_diff(prev, 0);
 261.116 +      A[55] = prev;
 261.117 +      for (i = 21; i; i = (i + 21) % 55)
 261.118 +      {  A[i] = next;
 261.119 +         next = mod_diff(prev, next);
 261.120 +         if (seed & 1)
 261.121 +            seed = 0x40000000 + (seed >> 1);
 261.122 +         else
 261.123 +            seed >>= 1;
 261.124 +         next = mod_diff(next, seed);
 261.125 +         prev = A[i];
 261.126 +      }
 261.127 +      flip_cycle(rand);
 261.128 +      flip_cycle(rand);
 261.129 +      flip_cycle(rand);
 261.130 +      flip_cycle(rand);
 261.131 +      flip_cycle(rand);
 261.132 +      return;
 261.133 +}
 261.134 +
 261.135 +/***********************************************************************
 261.136 +*  NAME
 261.137 +*
 261.138 +*  rng_next_rand - obtain pseudo-random integer in the range [0, 2^31-1]
 261.139 +*
 261.140 +*  SYNOPSIS
 261.141 +*
 261.142 +*  #include "glprng.h"
 261.143 +*  int rng_next_rand(RNG *rand);
 261.144 +*
 261.145 +*  RETURNS
 261.146 +*
 261.147 +*  The routine rng_next_rand returns a next pseudo-random integer which
 261.148 +*  is uniformly distributed between 0 and 2^31-1, inclusive. The period
 261.149 +*  length of the generated numbers is 2^85 - 2^30. The low order bits of
 261.150 +*  the generated numbers are just as random as the high-order bits. */
 261.151 +
 261.152 +int rng_next_rand(RNG *rand)
 261.153 +{     return
 261.154 +         *fptr >= 0 ? *fptr-- : flip_cycle(rand);
 261.155 +}
 261.156 +
 261.157 +/***********************************************************************
 261.158 +*  NAME
 261.159 +*
 261.160 +*  rng_unif_rand - obtain pseudo-random integer in the range [0, m-1]
 261.161 +*
 261.162 +*  SYNOPSIS
 261.163 +*
 261.164 +*  #include "glprng.h"
 261.165 +*  int rng_unif_rand(RNG *rand, int m);
 261.166 +*
 261.167 +*  RETURNS
 261.168 +*
 261.169 +*  The routine rng_unif_rand returns a next pseudo-random integer which
 261.170 +*  is uniformly distributed between 0 and m-1, inclusive, where m is any
 261.171 +*  positive integer less than 2^31. */
 261.172 +
 261.173 +#define two_to_the_31 ((unsigned int)0x80000000)
 261.174 +
 261.175 +int rng_unif_rand(RNG *rand, int m)
 261.176 +{     unsigned int t = two_to_the_31 - (two_to_the_31 % m);
 261.177 +      int r;
 261.178 +      xassert(m > 0);
 261.179 +      do { r = rng_next_rand(rand); } while (t <= (unsigned int)r);
 261.180 +      return r % m;
 261.181 +}
 261.182 +
 261.183 +/***********************************************************************
 261.184 +*  NAME
 261.185 +*
 261.186 +*  rng_delete_rand - delete pseudo-random number generator
 261.187 +*
 261.188 +*  SYNOPSIS
 261.189 +*
 261.190 +*  #include "glprng.h"
 261.191 +*  void rng_delete_rand(RNG *rand);
 261.192 +*
 261.193 +*  DESCRIPTION
 261.194 +*
 261.195 +*  The routine rng_delete_rand frees all the memory allocated to the
 261.196 +*  specified pseudo-random number generator. */
 261.197 +
 261.198 +void rng_delete_rand(RNG *rand)
 261.199 +{     xfree(rand);
 261.200 +      return;
 261.201 +}
 261.202 +
 261.203 +/**********************************************************************/
 261.204 +
 261.205 +#if 0
 261.206 +/* To be sure that this modified version produces the same results as
 261.207 +   the original version, run this validation program. */
 261.208 +
 261.209 +int main(void)
 261.210 +{     RNG *rand;
 261.211 +      int j;
 261.212 +      rand = rng_create_rand();
 261.213 +      rng_init_rand(rand, -314159);
 261.214 +      if (rng_next_rand(rand) != 119318998)
 261.215 +      {  fprintf(stderr, "Failure on the first try!\n");
 261.216 +         return -1;
 261.217 +      }
 261.218 +      for (j = 1; j <= 133; j++) rng_next_rand(rand);
 261.219 +      if (rng_unif_rand(rand, 0x55555555) != 748103812)
 261.220 +      {  fprintf(stderr, "Failure on the second try!\n");
 261.221 +         return -2;
 261.222 +      }
 261.223 +      fprintf(stderr, "OK, the random-number generator routines seem to"
 261.224 +         " work!\n");
 261.225 +      rng_delete_rand(rand);
 261.226 +      return 0;
 261.227 +}
 261.228 +#endif
 261.229 +
 261.230 +/* eof */
   262.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   262.2 +++ b/src/glprng02.c	Mon Dec 06 13:09:21 2010 +0100
   262.3 @@ -0,0 +1,76 @@
   262.4 +/* glprng02.c */
   262.5 +
   262.6 +/***********************************************************************
   262.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   262.8 +*
   262.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  262.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  262.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  262.12 +*  E-mail: <mao@gnu.org>.
  262.13 +*
  262.14 +*  GLPK is free software: you can redistribute it and/or modify it
  262.15 +*  under the terms of the GNU General Public License as published by
  262.16 +*  the Free Software Foundation, either version 3 of the License, or
  262.17 +*  (at your option) any later version.
  262.18 +*
  262.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  262.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  262.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  262.22 +*  License for more details.
  262.23 +*
  262.24 +*  You should have received a copy of the GNU General Public License
  262.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  262.26 +***********************************************************************/
  262.27 +
  262.28 +#include "glpenv.h"
  262.29 +#include "glprng.h"
  262.30 +#define xfault xerror
  262.31 +
  262.32 +/***********************************************************************
  262.33 +*  NAME
  262.34 +*
  262.35 +*  rng_unif_01 - obtain pseudo-random number in the range [0, 1]
  262.36 +*
  262.37 +*  SYNOPSIS
  262.38 +*
  262.39 +*  #include "glprng.h"
  262.40 +*  double rng_unif_01(RNG *rand);
  262.41 +*
  262.42 +*  RETURNS
  262.43 +*
  262.44 +*  The routine rng_unif_01 returns a next pseudo-random number which is
  262.45 +*  uniformly distributed in the range [0, 1]. */
  262.46 +
  262.47 +double rng_unif_01(RNG *rand)
  262.48 +{     double x;
  262.49 +      x = (double)rng_next_rand(rand) / 2147483647.0;
  262.50 +      xassert(0.0 <= x && x <= 1.0);
  262.51 +      return x;
  262.52 +}
  262.53 +
  262.54 +/***********************************************************************
  262.55 +*  NAME
  262.56 +*
  262.57 +*  rng_uniform - obtain pseudo-random number in the range [a, b]
  262.58 +*
  262.59 +*  SYNOPSIS
  262.60 +*
  262.61 +*  #include "glprng.h"
  262.62 +*  double rng_uniform(RNG *rand, double a, double b);
  262.63 +*
  262.64 +*  RETURNS
  262.65 +*
  262.66 +*  The routine rng_uniform returns a next pseudo-random number which is
  262.67 +*  uniformly distributed in the range [a, b]. */
  262.68 +
  262.69 +double rng_uniform(RNG *rand, double a, double b)
  262.70 +{     double x;
  262.71 +      if (a >= b)
  262.72 +         xfault("rng_uniform: a = %g, b = %g; invalid range\n", a, b);
  262.73 +      x = rng_unif_01(rand);
  262.74 +      x = a * (1.0 - x) + b * x;
  262.75 +      xassert(a <= x && x <= b);
  262.76 +      return x;
  262.77 +}
  262.78 +
  262.79 +/* eof */
   263.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   263.2 +++ b/src/glpscf.c	Mon Dec 06 13:09:21 2010 +0100
   263.3 @@ -0,0 +1,634 @@
   263.4 +/* glpscf.c (Schur complement factorization) */
   263.5 +
   263.6 +/***********************************************************************
   263.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   263.8 +*
   263.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  263.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  263.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  263.12 +*  E-mail: <mao@gnu.org>.
  263.13 +*
  263.14 +*  GLPK is free software: you can redistribute it and/or modify it
  263.15 +*  under the terms of the GNU General Public License as published by
  263.16 +*  the Free Software Foundation, either version 3 of the License, or
  263.17 +*  (at your option) any later version.
  263.18 +*
  263.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  263.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  263.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  263.22 +*  License for more details.
  263.23 +*
  263.24 +*  You should have received a copy of the GNU General Public License
  263.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  263.26 +***********************************************************************/
  263.27 +
  263.28 +#include "glpenv.h"
  263.29 +#include "glpscf.h"
  263.30 +#define xfault xerror
  263.31 +
  263.32 +#define _GLPSCF_DEBUG 0
  263.33 +
  263.34 +#define eps 1e-10
  263.35 +
  263.36 +/***********************************************************************
  263.37 +*  NAME
  263.38 +*
  263.39 +*  scf_create_it - create Schur complement factorization
  263.40 +*
  263.41 +*  SYNOPSIS
  263.42 +*
  263.43 +*  #include "glpscf.h"
  263.44 +*  SCF *scf_create_it(int n_max);
  263.45 +*
  263.46 +*  DESCRIPTION
  263.47 +*
  263.48 +*  The routine scf_create_it creates the factorization of matrix C,
  263.49 +*  which initially has no rows and columns.
  263.50 +*
  263.51 +*  The parameter n_max specifies the maximal order of matrix C to be
  263.52 +*  factorized, 1 <= n_max <= 32767.
  263.53 +*
  263.54 +*  RETURNS
  263.55 +*
  263.56 +*  The routine scf_create_it returns a pointer to the structure SCF,
  263.57 +*  which defines the factorization. */
  263.58 +
  263.59 +SCF *scf_create_it(int n_max)
  263.60 +{     SCF *scf;
  263.61 +#if _GLPSCF_DEBUG
  263.62 +      xprintf("scf_create_it: warning: debug mode enabled\n");
  263.63 +#endif
  263.64 +      if (!(1 <= n_max && n_max <= 32767))
  263.65 +         xfault("scf_create_it: n_max = %d; invalid parameter\n",
  263.66 +            n_max);
  263.67 +      scf = xmalloc(sizeof(SCF));
  263.68 +      scf->n_max = n_max;
  263.69 +      scf->n = 0;
  263.70 +      scf->f = xcalloc(1 + n_max * n_max, sizeof(double));
  263.71 +      scf->u = xcalloc(1 + n_max * (n_max + 1) / 2, sizeof(double));
  263.72 +      scf->p = xcalloc(1 + n_max, sizeof(int));
  263.73 +      scf->t_opt = SCF_TBG;
  263.74 +      scf->rank = 0;
  263.75 +#if _GLPSCF_DEBUG
  263.76 +      scf->c = xcalloc(1 + n_max * n_max, sizeof(double));
  263.77 +#else
  263.78 +      scf->c = NULL;
  263.79 +#endif
  263.80 +      scf->w = xcalloc(1 + n_max, sizeof(double));
  263.81 +      return scf;
  263.82 +}
  263.83 +
  263.84 +/***********************************************************************
  263.85 +*  The routine f_loc determines location of matrix element F[i,j] in
  263.86 +*  the one-dimensional array f. */
  263.87 +
  263.88 +static int f_loc(SCF *scf, int i, int j)
  263.89 +{     int n_max = scf->n_max;
  263.90 +      int n = scf->n;
  263.91 +      xassert(1 <= i && i <= n);
  263.92 +      xassert(1 <= j && j <= n);
  263.93 +      return (i - 1) * n_max + j;
  263.94 +}
  263.95 +
  263.96 +/***********************************************************************
  263.97 +*  The routine u_loc determines location of matrix element U[i,j] in
  263.98 +*  the one-dimensional array u. */
  263.99 +
 263.100 +static int u_loc(SCF *scf, int i, int j)
 263.101 +{     int n_max = scf->n_max;
 263.102 +      int n = scf->n;
 263.103 +      xassert(1 <= i && i <= n);
 263.104 +      xassert(i <= j && j <= n);
 263.105 +      return (i - 1) * n_max + j - i * (i - 1) / 2;
 263.106 +}
 263.107 +
 263.108 +/***********************************************************************
 263.109 +*  The routine bg_transform applies Bartels-Golub version of gaussian
 263.110 +*  elimination to restore triangular structure of matrix U.
 263.111 +*
 263.112 +*  On entry matrix U has the following structure:
 263.113 +*
 263.114 +*        1       k         n
 263.115 +*     1  * * * * * * * * * *
 263.116 +*        . * * * * * * * * *
 263.117 +*        . . * * * * * * * *
 263.118 +*        . . . * * * * * * *
 263.119 +*     k  . . . . * * * * * *
 263.120 +*        . . . . . * * * * *
 263.121 +*        . . . . . . * * * *
 263.122 +*        . . . . . . . * * *
 263.123 +*        . . . . . . . . * *
 263.124 +*     n  . . . . # # # # # #
 263.125 +*
 263.126 +*  where '#' is a row spike to be eliminated.
 263.127 +*
 263.128 +*  Elements of n-th row are passed separately in locations un[k], ...,
 263.129 +*  un[n]. On exit the content of the array un is destroyed.
 263.130 +*
 263.131 +*  REFERENCES
 263.132 +*
 263.133 +*  R.H.Bartels, G.H.Golub, "The Simplex Method of Linear Programming
 263.134 +*  Using LU-decomposition", Comm. ACM, 12, pp. 266-68, 1969. */
 263.135 +
 263.136 +static void bg_transform(SCF *scf, int k, double un[])
 263.137 +{     int n = scf->n;
 263.138 +      double *f = scf->f;
 263.139 +      double *u = scf->u;
 263.140 +      int j, k1, kj, kk, n1, nj;
 263.141 +      double t;
 263.142 +      xassert(1 <= k && k <= n);
 263.143 +      /* main elimination loop */
 263.144 +      for (k = k; k < n; k++)
 263.145 +      {  /* determine location of U[k,k] */
 263.146 +         kk = u_loc(scf, k, k);
 263.147 +         /* determine location of F[k,1] */
 263.148 +         k1 = f_loc(scf, k, 1);
 263.149 +         /* determine location of F[n,1] */
 263.150 +         n1 = f_loc(scf, n, 1);
 263.151 +         /* if |U[k,k]| < |U[n,k]|, interchange k-th and n-th rows to
 263.152 +            provide |U[k,k]| >= |U[n,k]| */
 263.153 +         if (fabs(u[kk]) < fabs(un[k]))
 263.154 +         {  /* interchange k-th and n-th rows of matrix U */
 263.155 +            for (j = k, kj = kk; j <= n; j++, kj++)
 263.156 +               t = u[kj], u[kj] = un[j], un[j] = t;
 263.157 +            /* interchange k-th and n-th rows of matrix F to keep the
 263.158 +               main equality F * C = U * P */
 263.159 +            for (j = 1, kj = k1, nj = n1; j <= n; j++, kj++, nj++)
 263.160 +               t = f[kj], f[kj] = f[nj], f[nj] = t;
 263.161 +         }
 263.162 +         /* now |U[k,k]| >= |U[n,k]| */
 263.163 +         /* if U[k,k] is too small in the magnitude, replace U[k,k] and
 263.164 +            U[n,k] by exact zero */
 263.165 +         if (fabs(u[kk]) < eps) u[kk] = un[k] = 0.0;
 263.166 +         /* if U[n,k] is already zero, elimination is not needed */
 263.167 +         if (un[k] == 0.0) continue;
 263.168 +         /* compute gaussian multiplier t = U[n,k] / U[k,k] */
 263.169 +         t = un[k] / u[kk];
 263.170 +         /* apply gaussian elimination to nullify U[n,k] */
 263.171 +         /* (n-th row of U) := (n-th row of U) - t * (k-th row of U) */
 263.172 +         for (j = k+1, kj = kk+1; j <= n; j++, kj++)
 263.173 +            un[j] -= t * u[kj];
 263.174 +         /* (n-th row of F) := (n-th row of F) - t * (k-th row of F)
 263.175 +            to keep the main equality F * C = U * P */
 263.176 +         for (j = 1, kj = k1, nj = n1; j <= n; j++, kj++, nj++)
 263.177 +            f[nj] -= t * f[kj];
 263.178 +      }
 263.179 +      /* if U[n,n] is too small in the magnitude, replace it by exact
 263.180 +         zero */
 263.181 +      if (fabs(un[n]) < eps) un[n] = 0.0;
 263.182 +      /* store U[n,n] in a proper location */
 263.183 +      u[u_loc(scf, n, n)] = un[n];
 263.184 +      return;
 263.185 +}
 263.186 +
 263.187 +/***********************************************************************
 263.188 +*  The routine givens computes the parameters of Givens plane rotation
 263.189 +*  c = cos(teta) and s = sin(teta) such that:
 263.190 +*
 263.191 +*     ( c -s ) ( a )   ( r )
 263.192 +*     (      ) (   ) = (   ) ,
 263.193 +*     ( s  c ) ( b )   ( 0 )
 263.194 +*
 263.195 +*  where a and b are given scalars.
 263.196 +*
 263.197 +*  REFERENCES
 263.198 +*
 263.199 +*  G.H.Golub, C.F.Van Loan, "Matrix Computations", 2nd ed. */
 263.200 +
 263.201 +static void givens(double a, double b, double *c, double *s)
 263.202 +{     double t;
 263.203 +      if (b == 0.0)
 263.204 +         (*c) = 1.0, (*s) = 0.0;
 263.205 +      else if (fabs(a) <= fabs(b))
 263.206 +         t = - a / b, (*s) = 1.0 / sqrt(1.0 + t * t), (*c) = (*s) * t;
 263.207 +      else
 263.208 +         t = - b / a, (*c) = 1.0 / sqrt(1.0 + t * t), (*s) = (*c) * t;
 263.209 +      return;
 263.210 +}
 263.211 +
 263.212 +/*----------------------------------------------------------------------
 263.213 +*  The routine gr_transform applies Givens plane rotations to restore
 263.214 +*  triangular structure of matrix U.
 263.215 +*
 263.216 +*  On entry matrix U has the following structure:
 263.217 +*
 263.218 +*        1       k         n
 263.219 +*     1  * * * * * * * * * *
 263.220 +*        . * * * * * * * * *
 263.221 +*        . . * * * * * * * *
 263.222 +*        . . . * * * * * * *
 263.223 +*     k  . . . . * * * * * *
 263.224 +*        . . . . . * * * * *
 263.225 +*        . . . . . . * * * *
 263.226 +*        . . . . . . . * * *
 263.227 +*        . . . . . . . . * *
 263.228 +*     n  . . . . # # # # # #
 263.229 +*
 263.230 +*  where '#' is a row spike to be eliminated.
 263.231 +*
 263.232 +*  Elements of n-th row are passed separately in locations un[k], ...,
 263.233 +*  un[n]. On exit the content of the array un is destroyed.
 263.234 +*
 263.235 +*  REFERENCES
 263.236 +*
 263.237 +*  R.H.Bartels, G.H.Golub, "The Simplex Method of Linear Programming
 263.238 +*  Using LU-decomposition", Comm. ACM, 12, pp. 266-68, 1969. */
 263.239 +
 263.240 +static void gr_transform(SCF *scf, int k, double un[])
 263.241 +{     int n = scf->n;
 263.242 +      double *f = scf->f;
 263.243 +      double *u = scf->u;
 263.244 +      int j, k1, kj, kk, n1, nj;
 263.245 +      double c, s;
 263.246 +      xassert(1 <= k && k <= n);
 263.247 +      /* main elimination loop */
 263.248 +      for (k = k; k < n; k++)
 263.249 +      {  /* determine location of U[k,k] */
 263.250 +         kk = u_loc(scf, k, k);
 263.251 +         /* determine location of F[k,1] */
 263.252 +         k1 = f_loc(scf, k, 1);
 263.253 +         /* determine location of F[n,1] */
 263.254 +         n1 = f_loc(scf, n, 1);
 263.255 +         /* if both U[k,k] and U[n,k] are too small in the magnitude,
 263.256 +            replace them by exact zero */
 263.257 +         if (fabs(u[kk]) < eps && fabs(un[k]) < eps)
 263.258 +            u[kk] = un[k] = 0.0;
 263.259 +         /* if U[n,k] is already zero, elimination is not needed */
 263.260 +         if (un[k] == 0.0) continue;
 263.261 +         /* compute the parameters of Givens plane rotation */
 263.262 +         givens(u[kk], un[k], &c, &s);
 263.263 +         /* apply Givens rotation to k-th and n-th rows of matrix U */
 263.264 +         for (j = k, kj = kk; j <= n; j++, kj++)
 263.265 +         {  double ukj = u[kj], unj = un[j];
 263.266 +            u[kj] = c * ukj - s * unj;
 263.267 +            un[j] = s * ukj + c * unj;
 263.268 +         }
 263.269 +         /* apply Givens rotation to k-th and n-th rows of matrix F
 263.270 +            to keep the main equality F * C = U * P */
 263.271 +         for (j = 1, kj = k1, nj = n1; j <= n; j++, kj++, nj++)
 263.272 +         {  double fkj = f[kj], fnj = f[nj];
 263.273 +            f[kj] = c * fkj - s * fnj;
 263.274 +            f[nj] = s * fkj + c * fnj;
 263.275 +         }
 263.276 +      }
 263.277 +      /* if U[n,n] is too small in the magnitude, replace it by exact
 263.278 +         zero */
 263.279 +      if (fabs(un[n]) < eps) un[n] = 0.0;
 263.280 +      /* store U[n,n] in a proper location */
 263.281 +      u[u_loc(scf, n, n)] = un[n];
 263.282 +      return;
 263.283 +}
 263.284 +
 263.285 +/***********************************************************************
 263.286 +*  The routine transform restores triangular structure of matrix U.
 263.287 +*  It is a driver to the routines bg_transform and gr_transform (see
 263.288 +*  comments to these routines above). */
 263.289 +
 263.290 +static void transform(SCF *scf, int k, double un[])
 263.291 +{     switch (scf->t_opt)
 263.292 +      {  case SCF_TBG:
 263.293 +            bg_transform(scf, k, un);
 263.294 +            break;
 263.295 +         case SCF_TGR:
 263.296 +            gr_transform(scf, k, un);
 263.297 +            break;
 263.298 +         default:
 263.299 +            xassert(scf != scf);
 263.300 +      }
 263.301 +      return;
 263.302 +}
 263.303 +
 263.304 +/***********************************************************************
 263.305 +*  The routine estimate_rank estimates the rank of matrix C.
 263.306 +*
 263.307 +*  Since all transformations applied to matrix F are non-singular,
 263.308 +*  and F is assumed to be well conditioned, from the main equaility
 263.309 +*  F * C = U * P it follows that rank(C) = rank(U), where rank(U) is
 263.310 +*  estimated as the number of non-zero diagonal elements of U. */
 263.311 +
 263.312 +static int estimate_rank(SCF *scf)
 263.313 +{     int n_max = scf->n_max;
 263.314 +      int n = scf->n;
 263.315 +      double *u = scf->u;
 263.316 +      int i, ii, inc, rank = 0;
 263.317 +      for (i = 1, ii = u_loc(scf, i, i), inc = n_max; i <= n;
 263.318 +         i++, ii += inc, inc--)
 263.319 +         if (u[ii] != 0.0) rank++;
 263.320 +      return rank;
 263.321 +}
 263.322 +
 263.323 +#if _GLPSCF_DEBUG
 263.324 +/***********************************************************************
 263.325 +*  The routine check_error computes the maximal relative error between
 263.326 +*  left- and right-hand sides of the main equality F * C = U * P. (This
 263.327 +*  routine is intended only for debugging.) */
 263.328 +
 263.329 +static void check_error(SCF *scf, const char *func)
 263.330 +{     int n = scf->n;
 263.331 +      double *f = scf->f;
 263.332 +      double *u = scf->u;
 263.333 +      int *p = scf->p;
 263.334 +      double *c = scf->c;
 263.335 +      int i, j, k;
 263.336 +      double d, dmax = 0.0, s, t;
 263.337 +      xassert(c != NULL);
 263.338 +      for (i = 1; i <= n; i++)
 263.339 +      {  for (j = 1; j <= n; j++)
 263.340 +         {  /* compute element (i,j) of product F * C */
 263.341 +            s = 0.0;
 263.342 +            for (k = 1; k <= n; k++)
 263.343 +               s += f[f_loc(scf, i, k)] * c[f_loc(scf, k, j)];
 263.344 +            /* compute element (i,j) of product U * P */
 263.345 +            k = p[j];
 263.346 +            t = (i <= k ? u[u_loc(scf, i, k)] : 0.0);
 263.347 +            /* compute the maximal relative error */
 263.348 +            d = fabs(s - t) / (1.0 + fabs(t));
 263.349 +            if (dmax < d) dmax = d;
 263.350 +         }
 263.351 +      }
 263.352 +      if (dmax > 1e-8)
 263.353 +         xprintf("%s: dmax = %g; relative error too large\n", func,
 263.354 +            dmax);
 263.355 +      return;
 263.356 +}
 263.357 +#endif
 263.358 +
 263.359 +/***********************************************************************
 263.360 +*  NAME
 263.361 +*
 263.362 +*  scf_update_exp - update factorization on expanding C
 263.363 +*
 263.364 +*  SYNOPSIS
 263.365 +*
 263.366 +*  #include "glpscf.h"
 263.367 +*  int scf_update_exp(SCF *scf, const double x[], const double y[],
 263.368 +*     double z);
 263.369 +*
 263.370 +*  DESCRIPTION
 263.371 +*
 263.372 +*  The routine scf_update_exp updates the factorization of matrix C on
 263.373 +*  expanding it by adding a new row and column as follows:
 263.374 +*
 263.375 +*             ( C  x )
 263.376 +*     new C = (      )
 263.377 +*             ( y' z )
 263.378 +*
 263.379 +*  where x[1,...,n] is a new column, y[1,...,n] is a new row, and z is
 263.380 +*  a new diagonal element.
 263.381 +*
 263.382 +*  If on entry the factorization is empty, the parameters x and y can
 263.383 +*  be specified as NULL.
 263.384 +*
 263.385 +*  RETURNS
 263.386 +*
 263.387 +*  0  The factorization has been successfully updated.
 263.388 +*
 263.389 +*  SCF_ESING
 263.390 +*     The factorization has been successfully updated, however, new
 263.391 +*     matrix C is singular within working precision. Note that the new
 263.392 +*     factorization remains valid.
 263.393 +*
 263.394 +*  SCF_ELIMIT
 263.395 +*     There is not enough room to expand the factorization, because
 263.396 +*     n = n_max. The factorization remains unchanged.
 263.397 +*
 263.398 +*  ALGORITHM
 263.399 +*
 263.400 +*  We can see that:
 263.401 +*
 263.402 +*     ( F  0 ) ( C  x )   ( FC  Fx )   ( UP  Fx )
 263.403 +*     (      ) (      ) = (        ) = (        ) =
 263.404 +*     ( 0  1 ) ( y' z )   ( y'   z )   ( y'   z )
 263.405 +*
 263.406 +*        ( U   Fx ) ( P  0 )
 263.407 +*     =  (        ) (      ),
 263.408 +*        ( y'P' z ) ( 0  1 )
 263.409 +*
 263.410 +*  therefore to keep the main equality F * C = U * P we can take:
 263.411 +*
 263.412 +*             ( F  0 )           ( U   Fx )           ( P  0 )
 263.413 +*     new F = (      ),  new U = (        ),  new P = (      ),
 263.414 +*             ( 0  1 )           ( y'P' z )           ( 0  1 )
 263.415 +*
 263.416 +*  and eliminate the row spike y'P' in the last row of new U to restore
 263.417 +*  its upper triangular structure. */
 263.418 +
 263.419 +int scf_update_exp(SCF *scf, const double x[], const double y[],
 263.420 +      double z)
 263.421 +{     int n_max = scf->n_max;
 263.422 +      int n = scf->n;
 263.423 +      double *f = scf->f;
 263.424 +      double *u = scf->u;
 263.425 +      int *p = scf->p;
 263.426 +#if _GLPSCF_DEBUG
 263.427 +      double *c = scf->c;
 263.428 +#endif
 263.429 +      double *un = scf->w;
 263.430 +      int i, ij, in, j, k, nj, ret = 0;
 263.431 +      double t;
 263.432 +      /* check if the factorization can be expanded */
 263.433 +      if (n == n_max)
 263.434 +      {  /* there is not enough room */
 263.435 +         ret = SCF_ELIMIT;
 263.436 +         goto done;
 263.437 +      }
 263.438 +      /* increase the order of the factorization */
 263.439 +      scf->n = ++n;
 263.440 +      /* fill new zero column of matrix F */
 263.441 +      for (i = 1, in = f_loc(scf, i, n); i < n; i++, in += n_max)
 263.442 +         f[in] = 0.0;
 263.443 +      /* fill new zero row of matrix F */
 263.444 +      for (j = 1, nj = f_loc(scf, n, j); j < n; j++, nj++)
 263.445 +         f[nj] = 0.0;
 263.446 +      /* fill new unity diagonal element of matrix F */
 263.447 +      f[f_loc(scf, n, n)] = 1.0;
 263.448 +      /* compute new column of matrix U, which is (old F) * x */
 263.449 +      for (i = 1; i < n; i++)
 263.450 +      {  /* u[i,n] := (i-th row of old F) * x */
 263.451 +         t = 0.0;
 263.452 +         for (j = 1, ij = f_loc(scf, i, 1); j < n; j++, ij++)
 263.453 +            t += f[ij] * x[j];
 263.454 +         u[u_loc(scf, i, n)] = t;
 263.455 +      }
 263.456 +      /* compute new (spiked) row of matrix U, which is (old P) * y */
 263.457 +      for (j = 1; j < n; j++) un[j] = y[p[j]];
 263.458 +      /* store new diagonal element of matrix U, which is z */
 263.459 +      un[n] = z;
 263.460 +      /* expand matrix P */
 263.461 +      p[n] = n;
 263.462 +#if _GLPSCF_DEBUG
 263.463 +      /* expand matrix C */
 263.464 +      /* fill its new column, which is x */
 263.465 +      for (i = 1, in = f_loc(scf, i, n); i < n; i++, in += n_max)
 263.466 +         c[in] = x[i];
 263.467 +      /* fill its new row, which is y */
 263.468 +      for (j = 1, nj = f_loc(scf, n, j); j < n; j++, nj++)
 263.469 +         c[nj] = y[j];
 263.470 +      /* fill its new diagonal element, which is z */
 263.471 +      c[f_loc(scf, n, n)] = z;
 263.472 +#endif
 263.473 +      /* restore upper triangular structure of matrix U */
 263.474 +      for (k = 1; k < n; k++)
 263.475 +         if (un[k] != 0.0) break;
 263.476 +      transform(scf, k, un);
 263.477 +      /* estimate the rank of matrices C and U */
 263.478 +      scf->rank = estimate_rank(scf);
 263.479 +      if (scf->rank != n) ret = SCF_ESING;
 263.480 +#if _GLPSCF_DEBUG
 263.481 +      /* check that the factorization is accurate enough */
 263.482 +      check_error(scf, "scf_update_exp");
 263.483 +#endif
 263.484 +done: return ret;
 263.485 +}
 263.486 +
 263.487 +/***********************************************************************
 263.488 +*  The routine solve solves the system C * x = b.
 263.489 +*
 263.490 +*  From the main equation F * C = U * P it follows that:
 263.491 +*
 263.492 +*     C * x = b  =>  F * C * x = F * b  =>  U * P * x = F * b  =>
 263.493 +*
 263.494 +*     P * x = inv(U) * F * b  =>  x = P' * inv(U) * F * b.
 263.495 +*
 263.496 +*  On entry the array x contains right-hand side vector b. On exit this
 263.497 +*  array contains solution vector x. */
 263.498 +
 263.499 +static void solve(SCF *scf, double x[])
 263.500 +{     int n = scf->n;
 263.501 +      double *f = scf->f;
 263.502 +      double *u = scf->u;
 263.503 +      int *p = scf->p;
 263.504 +      double *y = scf->w;
 263.505 +      int i, j, ij;
 263.506 +      double t;
 263.507 +      /* y := F * b */
 263.508 +      for (i = 1; i <= n; i++)
 263.509 +      {  /* y[i] = (i-th row of F) * b */
 263.510 +         t = 0.0;
 263.511 +         for (j = 1, ij = f_loc(scf, i, 1); j <= n; j++, ij++)
 263.512 +            t += f[ij] * x[j];
 263.513 +         y[i] = t;
 263.514 +      }
 263.515 +      /* y := inv(U) * y */
 263.516 +      for (i = n; i >= 1; i--)
 263.517 +      {  t = y[i];
 263.518 +         for (j = n, ij = u_loc(scf, i, n); j > i; j--, ij--)
 263.519 +            t -= u[ij] * y[j];
 263.520 +         y[i] = t / u[ij];
 263.521 +      }
 263.522 +      /* x := P' * y */
 263.523 +      for (i = 1; i <= n; i++) x[p[i]] = y[i];
 263.524 +      return;
 263.525 +}
 263.526 +
 263.527 +/***********************************************************************
 263.528 +*  The routine tsolve solves the transposed system C' * x = b.
 263.529 +*
 263.530 +*  From the main equation F * C = U * P it follows that:
 263.531 +*
 263.532 +*     C' * F' = P' * U',
 263.533 +*
 263.534 +*  therefore:
 263.535 +*
 263.536 +*     C' * x = b  =>  C' * F' * inv(F') * x = b  =>
 263.537 +*
 263.538 +*     P' * U' * inv(F') * x = b  =>  U' * inv(F') * x = P * b  =>
 263.539 +*
 263.540 +*     inv(F') * x = inv(U') * P * b  =>  x = F' * inv(U') * P * b.
 263.541 +*
 263.542 +*  On entry the array x contains right-hand side vector b. On exit this
 263.543 +*  array contains solution vector x. */
 263.544 +
 263.545 +static void tsolve(SCF *scf, double x[])
 263.546 +{     int n = scf->n;
 263.547 +      double *f = scf->f;
 263.548 +      double *u = scf->u;
 263.549 +      int *p = scf->p;
 263.550 +      double *y = scf->w;
 263.551 +      int i, j, ij;
 263.552 +      double t;
 263.553 +      /* y := P * b */
 263.554 +      for (i = 1; i <= n; i++) y[i] = x[p[i]];
 263.555 +      /* y := inv(U') * y */
 263.556 +      for (i = 1; i <= n; i++)
 263.557 +      {  /* compute y[i] */
 263.558 +         ij = u_loc(scf, i, i);
 263.559 +         t = (y[i] /= u[ij]);
 263.560 +         /* substitute y[i] in other equations */
 263.561 +         for (j = i+1, ij++; j <= n; j++, ij++)
 263.562 +            y[j] -= u[ij] * t;
 263.563 +      }
 263.564 +      /* x := F' * y (computed as linear combination of rows of F) */
 263.565 +      for (j = 1; j <= n; j++) x[j] = 0.0;
 263.566 +      for (i = 1; i <= n; i++)
 263.567 +      {  t = y[i]; /* coefficient of linear combination */
 263.568 +         for (j = 1, ij = f_loc(scf, i, 1); j <= n; j++, ij++)
 263.569 +            x[j] += f[ij] * t;
 263.570 +      }
 263.571 +      return;
 263.572 +}
 263.573 +
 263.574 +/***********************************************************************
 263.575 +*  NAME
 263.576 +*
 263.577 +*  scf_solve_it - solve either system C * x = b or C' * x = b
 263.578 +*
 263.579 +*  SYNOPSIS
 263.580 +*
 263.581 +*  #include "glpscf.h"
 263.582 +*  void scf_solve_it(SCF *scf, int tr, double x[]);
 263.583 +*
 263.584 +*  DESCRIPTION
 263.585 +*
 263.586 +*  The routine scf_solve_it solves either the system C * x = b (if tr
 263.587 +*  is zero) or the system C' * x = b, where C' is a matrix transposed
 263.588 +*  to C (if tr is non-zero). C is assumed to be non-singular.
 263.589 +*
 263.590 +*  On entry the array x should contain the right-hand side vector b in
 263.591 +*  locations x[1], ..., x[n], where n is the order of matrix C. On exit
 263.592 +*  the array x contains the solution vector x in the same locations. */
 263.593 +
 263.594 +void scf_solve_it(SCF *scf, int tr, double x[])
 263.595 +{     if (scf->rank < scf->n)
 263.596 +         xfault("scf_solve_it: singular matrix\n");
 263.597 +      if (!tr)
 263.598 +         solve(scf, x);
 263.599 +      else
 263.600 +         tsolve(scf, x);
 263.601 +      return;
 263.602 +}
 263.603 +
 263.604 +void scf_reset_it(SCF *scf)
 263.605 +{     /* reset factorization for empty matrix C */
 263.606 +      scf->n = scf->rank = 0;
 263.607 +      return;
 263.608 +}
 263.609 +
 263.610 +/***********************************************************************
 263.611 +*  NAME
 263.612 +*
 263.613 +*  scf_delete_it - delete Schur complement factorization
 263.614 +*
 263.615 +*  SYNOPSIS
 263.616 +*
 263.617 +*  #include "glpscf.h"
 263.618 +*  void scf_delete_it(SCF *scf);
 263.619 +*
 263.620 +*  DESCRIPTION
 263.621 +*
 263.622 +*  The routine scf_delete_it deletes the specified factorization and
 263.623 +*  frees all the memory allocated to this object. */
 263.624 +
 263.625 +void scf_delete_it(SCF *scf)
 263.626 +{     xfree(scf->f);
 263.627 +      xfree(scf->u);
 263.628 +      xfree(scf->p);
 263.629 +#if _GLPSCF_DEBUG
 263.630 +      xfree(scf->c);
 263.631 +#endif
 263.632 +      xfree(scf->w);
 263.633 +      xfree(scf);
 263.634 +      return;
 263.635 +}
 263.636 +
 263.637 +/* eof */
   264.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   264.2 +++ b/src/glpscf.h	Mon Dec 06 13:09:21 2010 +0100
   264.3 @@ -0,0 +1,126 @@
   264.4 +/* glpscf.h (Schur complement factorization) */
   264.5 +
   264.6 +/***********************************************************************
   264.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   264.8 +*
   264.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  264.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  264.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  264.12 +*  E-mail: <mao@gnu.org>.
  264.13 +*
  264.14 +*  GLPK is free software: you can redistribute it and/or modify it
  264.15 +*  under the terms of the GNU General Public License as published by
  264.16 +*  the Free Software Foundation, either version 3 of the License, or
  264.17 +*  (at your option) any later version.
  264.18 +*
  264.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  264.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  264.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  264.22 +*  License for more details.
  264.23 +*
  264.24 +*  You should have received a copy of the GNU General Public License
  264.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  264.26 +***********************************************************************/
  264.27 +
  264.28 +#ifndef GLPSCF_H
  264.29 +#define GLPSCF_H
  264.30 +
  264.31 +/***********************************************************************
  264.32 +*  The structure SCF defines the following factorization of a square
  264.33 +*  nxn matrix C (which is the Schur complement):
  264.34 +*
  264.35 +*     F * C = U * P,
  264.36 +*
  264.37 +*  where F is a square transforming matrix, U is an upper triangular
  264.38 +*  matrix, P is a permutation matrix.
  264.39 +*
  264.40 +*  It is assumed that matrix C is small and dense, so matrices F and U
  264.41 +*  are stored in the dense format by rows as follows:
  264.42 +*
  264.43 +*        1         n       n_max    1         n       n_max
  264.44 +*      1 * * * * * * x x x x      1 * * * * * * x x x x
  264.45 +*        * * * * * * x x x x        . * * * * * x x x x
  264.46 +*        * * * * * * x x x x        . . * * * * x x x x
  264.47 +*        * * * * * * x x x x        . . . * * * x x x x
  264.48 +*        * * * * * * x x x x        . . . . * * x x x x
  264.49 +*      n * * * * * * x x x x      n . . . . . * x x x x
  264.50 +*        x x x x x x x x x x        . . . . . . x x x x
  264.51 +*        x x x x x x x x x x        . . . . . . . x x x
  264.52 +*        x x x x x x x x x x        . . . . . . . . x x
  264.53 +*  n_max x x x x x x x x x x  n_max . . . . . . . . . x
  264.54 +*
  264.55 +*             matrix F                   matrix U
  264.56 +*
  264.57 +*  where '*' are matrix elements, 'x' are reserved locations.
  264.58 +*
  264.59 +*  Permutation matrix P is stored in row-like format.
  264.60 +*
  264.61 +*  Matrix C normally is not stored.
  264.62 +*
  264.63 +*  REFERENCES
  264.64 +*
  264.65 +*  1. M.A.Saunders, "LUSOL: A basis package for constrained optimiza-
  264.66 +*     tion," SCCM, Stanford University, 2006.
  264.67 +*
  264.68 +*  2. M.A.Saunders, "Notes 5: Basis Updates," CME 318, Stanford Univer-
  264.69 +*     sity, Spring 2006.
  264.70 +*
  264.71 +*  3. M.A.Saunders, "Notes 6: LUSOL---a Basis Factorization Package,"
  264.72 +*     ibid. */
  264.73 +
  264.74 +typedef struct SCF SCF;
  264.75 +
  264.76 +struct SCF
  264.77 +{     /* Schur complement factorization */
  264.78 +      int n_max;
  264.79 +      /* maximal order of matrices C, F, U, P; n_max >= 1 */
  264.80 +      int n;
  264.81 +      /* current order of matrices C, F, U, P; n >= 0 */
  264.82 +      double *f; /* double f[1+n_max*n_max]; */
  264.83 +      /* matrix F stored by rows */
  264.84 +      double *u; /* double u[1+n_max*(n_max+1)/2]; */
  264.85 +      /* upper triangle of matrix U stored by rows */
  264.86 +      int *p; /* int p[1+n_max]; */
  264.87 +      /* matrix P; p[i] = j means that P[i,j] = 1 */
  264.88 +      int t_opt;
  264.89 +      /* type of transformation used to restore triangular structure of
  264.90 +         matrix U: */
  264.91 +#define SCF_TBG      1  /* Bartels-Golub elimination */
  264.92 +#define SCF_TGR      2  /* Givens plane rotation */
  264.93 +      int rank;
  264.94 +      /* estimated rank of matrices C and U */
  264.95 +      double *c; /* double c[1+n_max*n_max]; */
  264.96 +      /* matrix C stored in the same format as matrix F and used only
  264.97 +         for debugging; normally this array is not allocated */
  264.98 +      double *w; /* double w[1+n_max]; */
  264.99 +      /* working array */
 264.100 +};
 264.101 +
 264.102 +/* return codes: */
 264.103 +#define SCF_ESING    1  /* singular matrix */
 264.104 +#define SCF_ELIMIT   2  /* update limit reached */
 264.105 +
 264.106 +#define scf_create_it _glp_scf_create_it
 264.107 +SCF *scf_create_it(int n_max);
 264.108 +/* create Schur complement factorization */
 264.109 +
 264.110 +#define scf_update_exp _glp_scf_update_exp
 264.111 +int scf_update_exp(SCF *scf, const double x[], const double y[],
 264.112 +      double z);
 264.113 +/* update factorization on expanding C */
 264.114 +
 264.115 +#define scf_solve_it _glp_scf_solve_it
 264.116 +void scf_solve_it(SCF *scf, int tr, double x[]);
 264.117 +/* solve either system C * x = b or C' * x = b */
 264.118 +
 264.119 +#define scf_reset_it _glp_scf_reset_it
 264.120 +void scf_reset_it(SCF *scf);
 264.121 +/* reset factorization for empty matrix C */
 264.122 +
 264.123 +#define scf_delete_it _glp_scf_delete_it
 264.124 +void scf_delete_it(SCF *scf);
 264.125 +/* delete Schur complement factorization */
 264.126 +
 264.127 +#endif
 264.128 +
 264.129 +/* eof */
   265.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   265.2 +++ b/src/glpscl.c	Mon Dec 06 13:09:21 2010 +0100
   265.3 @@ -0,0 +1,476 @@
   265.4 +/* glpscl.c */
   265.5 +
   265.6 +/***********************************************************************
   265.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   265.8 +*
   265.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  265.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  265.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  265.12 +*  E-mail: <mao@gnu.org>.
  265.13 +*
  265.14 +*  GLPK is free software: you can redistribute it and/or modify it
  265.15 +*  under the terms of the GNU General Public License as published by
  265.16 +*  the Free Software Foundation, either version 3 of the License, or
  265.17 +*  (at your option) any later version.
  265.18 +*
  265.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  265.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  265.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  265.22 +*  License for more details.
  265.23 +*
  265.24 +*  You should have received a copy of the GNU General Public License
  265.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  265.26 +***********************************************************************/
  265.27 +
  265.28 +#include "glpapi.h"
  265.29 +
  265.30 +/***********************************************************************
  265.31 +*  min_row_aij - determine minimal |a[i,j]| in i-th row
  265.32 +*
  265.33 +*  This routine returns minimal magnitude of (non-zero) constraint
  265.34 +*  coefficients in i-th row of the constraint matrix.
  265.35 +*
  265.36 +*  If the parameter scaled is zero, the original constraint matrix A is
  265.37 +*  assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
  265.38 +*
  265.39 +*  If i-th row of the matrix is empty, the routine returns 1. */
  265.40 +
  265.41 +static double min_row_aij(glp_prob *lp, int i, int scaled)
  265.42 +{     GLPAIJ *aij;
  265.43 +      double min_aij, temp;
  265.44 +      xassert(1 <= i && i <= lp->m);
  265.45 +      min_aij = 1.0;
  265.46 +      for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
  265.47 +      {  temp = fabs(aij->val);
  265.48 +         if (scaled) temp *= (aij->row->rii * aij->col->sjj);
  265.49 +         if (aij->r_prev == NULL || min_aij > temp)
  265.50 +            min_aij = temp;
  265.51 +      }
  265.52 +      return min_aij;
  265.53 +}
  265.54 +
  265.55 +/***********************************************************************
  265.56 +*  max_row_aij - determine maximal |a[i,j]| in i-th row
  265.57 +*
  265.58 +*  This routine returns maximal magnitude of (non-zero) constraint
  265.59 +*  coefficients in i-th row of the constraint matrix.
  265.60 +*
  265.61 +*  If the parameter scaled is zero, the original constraint matrix A is
  265.62 +*  assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
  265.63 +*
  265.64 +*  If i-th row of the matrix is empty, the routine returns 1. */
  265.65 +
  265.66 +static double max_row_aij(glp_prob *lp, int i, int scaled)
  265.67 +{     GLPAIJ *aij;
  265.68 +      double max_aij, temp;
  265.69 +      xassert(1 <= i && i <= lp->m);
  265.70 +      max_aij = 1.0;
  265.71 +      for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
  265.72 +      {  temp = fabs(aij->val);
  265.73 +         if (scaled) temp *= (aij->row->rii * aij->col->sjj);
  265.74 +         if (aij->r_prev == NULL || max_aij < temp)
  265.75 +            max_aij = temp;
  265.76 +      }
  265.77 +      return max_aij;
  265.78 +}
  265.79 +
  265.80 +/***********************************************************************
  265.81 +*  min_col_aij - determine minimal |a[i,j]| in j-th column
  265.82 +*
  265.83 +*  This routine returns minimal magnitude of (non-zero) constraint
  265.84 +*  coefficients in j-th column of the constraint matrix.
  265.85 +*
  265.86 +*  If the parameter scaled is zero, the original constraint matrix A is
  265.87 +*  assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
  265.88 +*
  265.89 +*  If j-th column of the matrix is empty, the routine returns 1. */
  265.90 +
  265.91 +static double min_col_aij(glp_prob *lp, int j, int scaled)
  265.92 +{     GLPAIJ *aij;
  265.93 +      double min_aij, temp;
  265.94 +      xassert(1 <= j && j <= lp->n);
  265.95 +      min_aij = 1.0;
  265.96 +      for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next)
  265.97 +      {  temp = fabs(aij->val);
  265.98 +         if (scaled) temp *= (aij->row->rii * aij->col->sjj);
  265.99 +         if (aij->c_prev == NULL || min_aij > temp)
 265.100 +            min_aij = temp;
 265.101 +      }
 265.102 +      return min_aij;
 265.103 +}
 265.104 +
 265.105 +/***********************************************************************
 265.106 +*  max_col_aij - determine maximal |a[i,j]| in j-th column
 265.107 +*
 265.108 +*  This routine returns maximal magnitude of (non-zero) constraint
 265.109 +*  coefficients in j-th column of the constraint matrix.
 265.110 +*
 265.111 +*  If the parameter scaled is zero, the original constraint matrix A is
 265.112 +*  assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
 265.113 +*
 265.114 +*  If j-th column of the matrix is empty, the routine returns 1. */
 265.115 +
 265.116 +static double max_col_aij(glp_prob *lp, int j, int scaled)
 265.117 +{     GLPAIJ *aij;
 265.118 +      double max_aij, temp;
 265.119 +      xassert(1 <= j && j <= lp->n);
 265.120 +      max_aij = 1.0;
 265.121 +      for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next)
 265.122 +      {  temp = fabs(aij->val);
 265.123 +         if (scaled) temp *= (aij->row->rii * aij->col->sjj);
 265.124 +         if (aij->c_prev == NULL || max_aij < temp)
 265.125 +            max_aij = temp;
 265.126 +      }
 265.127 +      return max_aij;
 265.128 +}
 265.129 +
 265.130 +/***********************************************************************
 265.131 +*  min_mat_aij - determine minimal |a[i,j]| in constraint matrix
 265.132 +*
 265.133 +*  This routine returns minimal magnitude of (non-zero) constraint
 265.134 +*  coefficients in the constraint matrix.
 265.135 +*
 265.136 +*  If the parameter scaled is zero, the original constraint matrix A is
 265.137 +*  assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
 265.138 +*
 265.139 +*  If the matrix is empty, the routine returns 1. */
 265.140 +
 265.141 +static double min_mat_aij(glp_prob *lp, int scaled)
 265.142 +{     int i;
 265.143 +      double min_aij, temp;
 265.144 +      min_aij = 1.0;
 265.145 +      for (i = 1; i <= lp->m; i++)
 265.146 +      {  temp = min_row_aij(lp, i, scaled);
 265.147 +         if (i == 1 || min_aij > temp)
 265.148 +            min_aij = temp;
 265.149 +      }
 265.150 +      return min_aij;
 265.151 +}
 265.152 +
 265.153 +/***********************************************************************
 265.154 +*  max_mat_aij - determine maximal |a[i,j]| in constraint matrix
 265.155 +*
 265.156 +*  This routine returns maximal magnitude of (non-zero) constraint
 265.157 +*  coefficients in the constraint matrix.
 265.158 +*
 265.159 +*  If the parameter scaled is zero, the original constraint matrix A is
 265.160 +*  assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
 265.161 +*
 265.162 +*  If the matrix is empty, the routine returns 1. */
 265.163 +
 265.164 +static double max_mat_aij(glp_prob *lp, int scaled)
 265.165 +{     int i;
 265.166 +      double max_aij, temp;
 265.167 +      max_aij = 1.0;
 265.168 +      for (i = 1; i <= lp->m; i++)
 265.169 +      {  temp = max_row_aij(lp, i, scaled);
 265.170 +         if (i == 1 || max_aij < temp)
 265.171 +            max_aij = temp;
 265.172 +      }
 265.173 +      return max_aij;
 265.174 +}
 265.175 +
 265.176 +/***********************************************************************
 265.177 +*  eq_scaling - perform equilibration scaling
 265.178 +*
 265.179 +*  This routine performs equilibration scaling of rows and columns of
 265.180 +*  the constraint matrix.
 265.181 +*
 265.182 +*  If the parameter flag is zero, the routine scales rows at first and
 265.183 +*  then columns. Otherwise, the routine scales columns and then rows.
 265.184 +*
 265.185 +*  Rows are scaled as follows:
 265.186 +*
 265.187 +*                         n
 265.188 +*     a'[i,j] = a[i,j] / max |a[i,j]|,  i = 1,...,m.
 265.189 +*                        j=1
 265.190 +*
 265.191 +*  This makes the infinity (maximum) norm of each row of the matrix
 265.192 +*  equal to 1.
 265.193 +*
 265.194 +*  Columns are scaled as follows:
 265.195 +*
 265.196 +*                         n
 265.197 +*     a'[i,j] = a[i,j] / max |a[i,j]|,  j = 1,...,n.
 265.198 +*                        i=1
 265.199 +*
 265.200 +*  This makes the infinity (maximum) norm of each column of the matrix
 265.201 +*  equal to 1. */
 265.202 +
 265.203 +static void eq_scaling(glp_prob *lp, int flag)
 265.204 +{     int i, j, pass;
 265.205 +      double temp;
 265.206 +      xassert(flag == 0 || flag == 1);
 265.207 +      for (pass = 0; pass <= 1; pass++)
 265.208 +      {  if (pass == flag)
 265.209 +         {  /* scale rows */
 265.210 +            for (i = 1; i <= lp->m; i++)
 265.211 +            {  temp = max_row_aij(lp, i, 1);
 265.212 +               glp_set_rii(lp, i, glp_get_rii(lp, i) / temp);
 265.213 +            }
 265.214 +         }
 265.215 +         else
 265.216 +         {  /* scale columns */
 265.217 +            for (j = 1; j <= lp->n; j++)
 265.218 +            {  temp = max_col_aij(lp, j, 1);
 265.219 +               glp_set_sjj(lp, j, glp_get_sjj(lp, j) / temp);
 265.220 +            }
 265.221 +         }
 265.222 +      }
 265.223 +      return;
 265.224 +}
 265.225 +
 265.226 +/***********************************************************************
 265.227 +*  gm_scaling - perform geometric mean scaling
 265.228 +*
 265.229 +*  This routine performs geometric mean scaling of rows and columns of
 265.230 +*  the constraint matrix.
 265.231 +*
 265.232 +*  If the parameter flag is zero, the routine scales rows at first and
 265.233 +*  then columns. Otherwise, the routine scales columns and then rows.
 265.234 +*
 265.235 +*  Rows are scaled as follows:
 265.236 +*
 265.237 +*     a'[i,j] = a[i,j] / sqrt(alfa[i] * beta[i]),  i = 1,...,m,
 265.238 +*
 265.239 +*  where:
 265.240 +*                n                        n
 265.241 +*     alfa[i] = min |a[i,j]|,  beta[i] = max |a[i,j]|.
 265.242 +*               j=1                      j=1
 265.243 +*
 265.244 +*  This allows decreasing the ratio beta[i] / alfa[i] for each row of
 265.245 +*  the matrix.
 265.246 +*
 265.247 +*  Columns are scaled as follows:
 265.248 +*
 265.249 +*     a'[i,j] = a[i,j] / sqrt(alfa[j] * beta[j]),  j = 1,...,n,
 265.250 +*
 265.251 +*  where:
 265.252 +*                m                        m
 265.253 +*     alfa[j] = min |a[i,j]|,  beta[j] = max |a[i,j]|.
 265.254 +*               i=1                      i=1
 265.255 +*
 265.256 +*  This allows decreasing the ratio beta[j] / alfa[j] for each column
 265.257 +*  of the matrix. */
 265.258 +
 265.259 +static void gm_scaling(glp_prob *lp, int flag)
 265.260 +{     int i, j, pass;
 265.261 +      double temp;
 265.262 +      xassert(flag == 0 || flag == 1);
 265.263 +      for (pass = 0; pass <= 1; pass++)
 265.264 +      {  if (pass == flag)
 265.265 +         {  /* scale rows */
 265.266 +            for (i = 1; i <= lp->m; i++)
 265.267 +            {  temp = min_row_aij(lp, i, 1) * max_row_aij(lp, i, 1);
 265.268 +               glp_set_rii(lp, i, glp_get_rii(lp, i) / sqrt(temp));
 265.269 +            }
 265.270 +         }
 265.271 +         else
 265.272 +         {  /* scale columns */
 265.273 +            for (j = 1; j <= lp->n; j++)
 265.274 +            {  temp = min_col_aij(lp, j, 1) * max_col_aij(lp, j, 1);
 265.275 +               glp_set_sjj(lp, j, glp_get_sjj(lp, j) / sqrt(temp));
 265.276 +            }
 265.277 +         }
 265.278 +      }
 265.279 +      return;
 265.280 +}
 265.281 +
 265.282 +/***********************************************************************
 265.283 +*  max_row_ratio - determine worst scaling "quality" for rows
 265.284 +*
 265.285 +*  This routine returns the worst scaling "quality" for rows of the
 265.286 +*  currently scaled constraint matrix:
 265.287 +*
 265.288 +*              m
 265.289 +*     ratio = max ratio[i],
 265.290 +*             i=1
 265.291 +*  where:
 265.292 +*                 n              n
 265.293 +*     ratio[i] = max |a[i,j]| / min |a[i,j]|,  1 <= i <= m,
 265.294 +*                j=1            j=1
 265.295 +*
 265.296 +*  is the scaling "quality" of i-th row. */
 265.297 +
 265.298 +static double max_row_ratio(glp_prob *lp)
 265.299 +{     int i;
 265.300 +      double ratio, temp;
 265.301 +      ratio = 1.0;
 265.302 +      for (i = 1; i <= lp->m; i++)
 265.303 +      {  temp = max_row_aij(lp, i, 1) / min_row_aij(lp, i, 1);
 265.304 +         if (i == 1 || ratio < temp) ratio = temp;
 265.305 +      }
 265.306 +      return ratio;
 265.307 +}
 265.308 +
 265.309 +/***********************************************************************
 265.310 +*  max_col_ratio - determine worst scaling "quality" for columns
 265.311 +*
 265.312 +*  This routine returns the worst scaling "quality" for columns of the
 265.313 +*  currently scaled constraint matrix:
 265.314 +*
 265.315 +*              n
 265.316 +*     ratio = max ratio[j],
 265.317 +*             j=1
 265.318 +*  where:
 265.319 +*                 m              m
 265.320 +*     ratio[j] = max |a[i,j]| / min |a[i,j]|,  1 <= j <= n,
 265.321 +*                i=1            i=1
 265.322 +*
 265.323 +*  is the scaling "quality" of j-th column. */
 265.324 +
 265.325 +static double max_col_ratio(glp_prob *lp)
 265.326 +{     int j;
 265.327 +      double ratio, temp;
 265.328 +      ratio = 1.0;
 265.329 +      for (j = 1; j <= lp->n; j++)
 265.330 +      {  temp = max_col_aij(lp, j, 1) / min_col_aij(lp, j, 1);
 265.331 +         if (j == 1 || ratio < temp) ratio = temp;
 265.332 +      }
 265.333 +      return ratio;
 265.334 +}
 265.335 +
 265.336 +/***********************************************************************
 265.337 +*  gm_iterate - perform iterative geometric mean scaling
 265.338 +*
 265.339 +*  This routine performs iterative geometric mean scaling of rows and
 265.340 +*  columns of the constraint matrix.
 265.341 +*
 265.342 +*  The parameter it_max specifies the maximal number of iterations.
 265.343 +*  Recommended value of it_max is 15.
 265.344 +*
 265.345 +*  The parameter tau specifies a minimal improvement of the scaling
 265.346 +*  "quality" on each iteration, 0 < tau < 1. It means than the scaling
 265.347 +*  process continues while the following condition is satisfied:
 265.348 +*
 265.349 +*     ratio[k] <= tau * ratio[k-1],
 265.350 +*
 265.351 +*  where ratio = max |a[i,j]| / min |a[i,j]| is the scaling "quality"
 265.352 +*  to be minimized, k is the iteration number. Recommended value of tau
 265.353 +*  is 0.90. */
 265.354 +
 265.355 +static void gm_iterate(glp_prob *lp, int it_max, double tau)
 265.356 +{     int k, flag;
 265.357 +      double ratio = 0.0, r_old;
 265.358 +      /* if the scaling "quality" for rows is better than for columns,
 265.359 +         the rows are scaled first; otherwise, the columns are scaled
 265.360 +         first */
 265.361 +      flag = (max_row_ratio(lp) > max_col_ratio(lp));
 265.362 +      for (k = 1; k <= it_max; k++)
 265.363 +      {  /* save the scaling "quality" from previous iteration */
 265.364 +         r_old = ratio;
 265.365 +         /* determine the current scaling "quality" */
 265.366 +         ratio = max_mat_aij(lp, 1) / min_mat_aij(lp, 1);
 265.367 +#if 0
 265.368 +         xprintf("k = %d; ratio = %g\n", k, ratio);
 265.369 +#endif
 265.370 +         /* if improvement is not enough, terminate scaling */
 265.371 +         if (k > 1 && ratio > tau * r_old) break;
 265.372 +         /* otherwise, perform another iteration */
 265.373 +         gm_scaling(lp, flag);
 265.374 +      }
 265.375 +      return;
 265.376 +}
 265.377 +
 265.378 +/***********************************************************************
 265.379 +*  NAME
 265.380 +*
 265.381 +*  scale_prob - scale problem data
 265.382 +*
 265.383 +*  SYNOPSIS
 265.384 +*
 265.385 +*  #include "glpscl.h"
 265.386 +*  void scale_prob(glp_prob *lp, int flags);
 265.387 +*
 265.388 +*  DESCRIPTION
 265.389 +*
 265.390 +*  The routine scale_prob performs automatic scaling of problem data
 265.391 +*  for the specified problem object. */
 265.392 +
 265.393 +static void scale_prob(glp_prob *lp, int flags)
 265.394 +{     static const char *fmt =
 265.395 +         "%s: min|aij| = %10.3e  max|aij| = %10.3e  ratio = %10.3e\n";
 265.396 +      double min_aij, max_aij, ratio;
 265.397 +      xprintf("Scaling...\n");
 265.398 +      /* cancel the current scaling effect */
 265.399 +      glp_unscale_prob(lp);
 265.400 +      /* report original scaling "quality" */
 265.401 +      min_aij = min_mat_aij(lp, 1);
 265.402 +      max_aij = max_mat_aij(lp, 1);
 265.403 +      ratio = max_aij / min_aij;
 265.404 +      xprintf(fmt, " A", min_aij, max_aij, ratio);
 265.405 +      /* check if the problem is well scaled */
 265.406 +      if (min_aij >= 0.10 && max_aij <= 10.0)
 265.407 +      {  xprintf("Problem data seem to be well scaled\n");
 265.408 +         /* skip scaling, if required */
 265.409 +         if (flags & GLP_SF_SKIP) goto done;
 265.410 +      }
 265.411 +      /* perform iterative geometric mean scaling, if required */
 265.412 +      if (flags & GLP_SF_GM)
 265.413 +      {  gm_iterate(lp, 15, 0.90);
 265.414 +         min_aij = min_mat_aij(lp, 1);
 265.415 +         max_aij = max_mat_aij(lp, 1);
 265.416 +         ratio = max_aij / min_aij;
 265.417 +         xprintf(fmt, "GM", min_aij, max_aij, ratio);
 265.418 +      }
 265.419 +      /* perform equilibration scaling, if required */
 265.420 +      if (flags & GLP_SF_EQ)
 265.421 +      {  eq_scaling(lp, max_row_ratio(lp) > max_col_ratio(lp));
 265.422 +         min_aij = min_mat_aij(lp, 1);
 265.423 +         max_aij = max_mat_aij(lp, 1);
 265.424 +         ratio = max_aij / min_aij;
 265.425 +         xprintf(fmt, "EQ", min_aij, max_aij, ratio);
 265.426 +      }
 265.427 +      /* round scale factors to nearest power of two, if required */
 265.428 +      if (flags & GLP_SF_2N)
 265.429 +      {  int i, j;
 265.430 +         for (i = 1; i <= lp->m; i++)
 265.431 +            glp_set_rii(lp, i, round2n(glp_get_rii(lp, i)));
 265.432 +         for (j = 1; j <= lp->n; j++)
 265.433 +            glp_set_sjj(lp, j, round2n(glp_get_sjj(lp, j)));
 265.434 +         min_aij = min_mat_aij(lp, 1);
 265.435 +         max_aij = max_mat_aij(lp, 1);
 265.436 +         ratio = max_aij / min_aij;
 265.437 +         xprintf(fmt, "2N", min_aij, max_aij, ratio);
 265.438 +      }
 265.439 +done: return;
 265.440 +}
 265.441 +
 265.442 +/***********************************************************************
 265.443 +*  NAME
 265.444 +*
 265.445 +*  glp_scale_prob - scale problem data
 265.446 +*
 265.447 +*  SYNOPSIS
 265.448 +*
 265.449 +*  void glp_scale_prob(glp_prob *lp, int flags);
 265.450 +*
 265.451 +*  DESCRIPTION
 265.452 +*
 265.453 +*  The routine glp_scale_prob performs automatic scaling of problem
 265.454 +*  data for the specified problem object.
 265.455 +*
 265.456 +*  The parameter flags specifies scaling options used by the routine.
 265.457 +*  Options can be combined with the bitwise OR operator and may be the
 265.458 +*  following:
 265.459 +*
 265.460 +*  GLP_SF_GM      perform geometric mean scaling;
 265.461 +*  GLP_SF_EQ      perform equilibration scaling;
 265.462 +*  GLP_SF_2N      round scale factors to nearest power of two;
 265.463 +*  GLP_SF_SKIP    skip scaling, if the problem is well scaled.
 265.464 +*
 265.465 +*  The parameter flags may be specified as GLP_SF_AUTO, in which case
 265.466 +*  the routine chooses scaling options automatically. */
 265.467 +
 265.468 +void glp_scale_prob(glp_prob *lp, int flags)
 265.469 +{     if (flags & ~(GLP_SF_GM | GLP_SF_EQ | GLP_SF_2N | GLP_SF_SKIP |
 265.470 +                    GLP_SF_AUTO))
 265.471 +         xerror("glp_scale_prob: flags = 0x%02X; invalid scaling option"
 265.472 +            "s\n", flags);
 265.473 +      if (flags & GLP_SF_AUTO)
 265.474 +         flags = (GLP_SF_GM | GLP_SF_EQ | GLP_SF_SKIP);
 265.475 +      scale_prob(lp, flags);
 265.476 +      return;
 265.477 +}
 265.478 +
 265.479 +/* eof */
   266.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   266.2 +++ b/src/glpsdf.c	Mon Dec 06 13:09:21 2010 +0100
   266.3 @@ -0,0 +1,262 @@
   266.4 +/* glpsdf.c (plain data file reading routines) */
   266.5 +
   266.6 +/***********************************************************************
   266.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   266.8 +*
   266.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  266.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  266.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  266.12 +*  E-mail: <mao@gnu.org>.
  266.13 +*
  266.14 +*  GLPK is free software: you can redistribute it and/or modify it
  266.15 +*  under the terms of the GNU General Public License as published by
  266.16 +*  the Free Software Foundation, either version 3 of the License, or
  266.17 +*  (at your option) any later version.
  266.18 +*
  266.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  266.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  266.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  266.22 +*  License for more details.
  266.23 +*
  266.24 +*  You should have received a copy of the GNU General Public License
  266.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  266.26 +***********************************************************************/
  266.27 +
  266.28 +#define GLPSDF_H
  266.29 +
  266.30 +#define GLP_DATA_DEFINED
  266.31 +typedef struct glp_data glp_data;
  266.32 +
  266.33 +#include "glpapi.h"
  266.34 +
  266.35 +struct glp_data
  266.36 +{     /* plain data file */
  266.37 +      char *fname;
  266.38 +      /* name of data file */
  266.39 +      XFILE *fp;
  266.40 +      /* stream assigned to data file */
  266.41 +      void *jump; /* jmp_buf jump; */
  266.42 +      /* label for go to in case of error */
  266.43 +      int count;
  266.44 +      /* line count */
  266.45 +      int c;
  266.46 +      /* current character of XEOF */
  266.47 +      char item[255+1];
  266.48 +      /* current data item */
  266.49 +};
  266.50 +
  266.51 +static void next_char(glp_data *data);
  266.52 +
  266.53 +glp_data *glp_sdf_open_file(const char *fname)
  266.54 +{     /* open plain data file */
  266.55 +      glp_data *data = NULL;
  266.56 +      XFILE *fp;
  266.57 +      jmp_buf jump;
  266.58 +      fp = xfopen(fname, "r");
  266.59 +      if (fp == NULL)
  266.60 +      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
  266.61 +         goto done;
  266.62 +      }
  266.63 +      data = xmalloc(sizeof(glp_data));
  266.64 +      data->fname = xmalloc(strlen(fname)+1);
  266.65 +      strcpy(data->fname, fname);
  266.66 +      data->fp = fp;
  266.67 +      data->jump = NULL;
  266.68 +      data->count = 0;
  266.69 +      data->c = '\n';
  266.70 +      data->item[0] = '\0';
  266.71 +      /* read the very first character */
  266.72 +      if (setjmp(jump))
  266.73 +      {  glp_sdf_close_file(data);
  266.74 +         data = NULL;
  266.75 +         goto done;
  266.76 +      }
  266.77 +      data->jump = jump;
  266.78 +      next_char(data);
  266.79 +      data->jump = NULL;
  266.80 +done: return data;
  266.81 +}
  266.82 +
  266.83 +void glp_sdf_set_jump(glp_data *data, void *jump)
  266.84 +{     /* set up error handling */
  266.85 +      data->jump = jump;
  266.86 +      return;
  266.87 +}
  266.88 +
  266.89 +void glp_sdf_error(glp_data *data, const char *fmt, ...)
  266.90 +{     /* print error message */
  266.91 +      va_list arg;
  266.92 +      xprintf("%s:%d: ", data->fname, data->count);
  266.93 +      va_start(arg, fmt);
  266.94 +      xvprintf(fmt, arg);
  266.95 +      va_end(arg);
  266.96 +      if (data->jump == NULL)
  266.97 +         xerror("");
  266.98 +      else
  266.99 +         longjmp(data->jump, 1);
 266.100 +      /* no return */
 266.101 +}
 266.102 +
 266.103 +void glp_sdf_warning(glp_data *data, const char *fmt, ...)
 266.104 +{     /* print warning message */
 266.105 +      va_list arg;
 266.106 +      xprintf("%s:%d: warning: ", data->fname, data->count);
 266.107 +      va_start(arg, fmt);
 266.108 +      xvprintf(fmt, arg);
 266.109 +      va_end(arg);
 266.110 +      return;
 266.111 +}
 266.112 +
 266.113 +static void next_char(glp_data *data)
 266.114 +{     /* read next character */
 266.115 +      int c;
 266.116 +      if (data->c == XEOF)
 266.117 +         glp_sdf_error(data, "unexpected end of file\n");
 266.118 +      else if (data->c == '\n')
 266.119 +         data->count++;
 266.120 +      c = xfgetc(data->fp);
 266.121 +      if (c < 0)
 266.122 +      {  if (xferror(data->fp))
 266.123 +            glp_sdf_error(data, "read error - %s\n", xerrmsg());
 266.124 +         else if (data->c == '\n')
 266.125 +            c = XEOF;
 266.126 +         else
 266.127 +         {  glp_sdf_warning(data, "missing final end of line\n");
 266.128 +            c = '\n';
 266.129 +         }
 266.130 +      }
 266.131 +      else if (c == '\n')
 266.132 +         ;
 266.133 +      else if (isspace(c))
 266.134 +         c = ' ';
 266.135 +      else if (iscntrl(c))
 266.136 +         glp_sdf_error(data, "invalid control character 0x%02X\n", c);
 266.137 +      data->c = c;
 266.138 +      return;
 266.139 +}
 266.140 +
 266.141 +static void skip_pad(glp_data *data)
 266.142 +{     /* skip uninteresting characters and comments */
 266.143 +loop: while (data->c == ' ' || data->c == '\n')
 266.144 +         next_char(data);
 266.145 +      if (data->c == '/')
 266.146 +      {  next_char(data);
 266.147 +         if (data->c != '*')
 266.148 +            glp_sdf_error(data, "invalid use of slash\n");
 266.149 +         next_char(data);
 266.150 +         for (;;)
 266.151 +         {  if (data->c == '*')
 266.152 +            {  next_char(data);
 266.153 +               if (data->c == '/')
 266.154 +               {  next_char(data);
 266.155 +                  break;
 266.156 +               }
 266.157 +            }
 266.158 +            next_char(data);
 266.159 +         }
 266.160 +         goto loop;
 266.161 +      }
 266.162 +      return;
 266.163 +}
 266.164 +
 266.165 +static void next_item(glp_data *data)
 266.166 +{     /* read next item */
 266.167 +      int len;
 266.168 +      skip_pad(data);
 266.169 +      len = 0;
 266.170 +      while (!(data->c == ' ' || data->c == '\n'))
 266.171 +      {  data->item[len++] = (char)data->c;
 266.172 +         if (len == sizeof(data->item))
 266.173 +            glp_sdf_error(data, "data item `%.31s...' too long\n",
 266.174 +               data->item);
 266.175 +         next_char(data);
 266.176 +      }
 266.177 +      data->item[len] = '\0';
 266.178 +      return;
 266.179 +}
 266.180 +
 266.181 +int glp_sdf_read_int(glp_data *data)
 266.182 +{     /* read integer number */
 266.183 +      int x;
 266.184 +      next_item(data);
 266.185 +      switch (str2int(data->item, &x))
 266.186 +      {  case 0:
 266.187 +            break;
 266.188 +         case 1:
 266.189 +            glp_sdf_error(data, "integer `%s' out of range\n",
 266.190 +               data->item);
 266.191 +         case 2:
 266.192 +            glp_sdf_error(data, "cannot convert `%s' to integer\n",
 266.193 +               data->item);
 266.194 +         default:
 266.195 +            xassert(data != data);
 266.196 +      }
 266.197 +      return x;
 266.198 +}
 266.199 +
 266.200 +double glp_sdf_read_num(glp_data *data)
 266.201 +{     /* read floating-point number */
 266.202 +      double x;
 266.203 +      next_item(data);
 266.204 +      switch (str2num(data->item, &x))
 266.205 +      {  case 0:
 266.206 +            break;
 266.207 +         case 1:
 266.208 +            glp_sdf_error(data, "number `%s' out of range\n",
 266.209 +               data->item);
 266.210 +         case 2:
 266.211 +            glp_sdf_error(data, "cannot convert `%s' to number\n",
 266.212 +               data->item);
 266.213 +         default:
 266.214 +            xassert(data != data);
 266.215 +      }
 266.216 +      return x;
 266.217 +}
 266.218 +
 266.219 +const char *glp_sdf_read_item(glp_data *data)
 266.220 +{     /* read data item */
 266.221 +      next_item(data);
 266.222 +      return data->item;
 266.223 +}
 266.224 +
 266.225 +const char *glp_sdf_read_text(glp_data *data)
 266.226 +{     /* read text until end of line */
 266.227 +      int c, len = 0;
 266.228 +      for (;;)
 266.229 +      {  c = data->c;
 266.230 +         next_char(data);
 266.231 +         if (c == ' ')
 266.232 +         {  /* ignore initial spaces */
 266.233 +            if (len == 0) continue;
 266.234 +            /* and multiple ones */
 266.235 +            if (data->item[len-1] == ' ') continue;
 266.236 +         }
 266.237 +         else if (c == '\n')
 266.238 +         {  /* remove trailing space */
 266.239 +            if (len > 0 && data->item[len-1] == ' ') len--;
 266.240 +            /* and stop reading */
 266.241 +            break;
 266.242 +         }
 266.243 +         /* add current character to the buffer */
 266.244 +         data->item[len++] = (char)c;
 266.245 +         if (len == sizeof(data->item))
 266.246 +            glp_sdf_error(data, "line too long\n", data->item);
 266.247 +      }
 266.248 +      data->item[len] = '\0';
 266.249 +      return data->item;
 266.250 +}
 266.251 +
 266.252 +int glp_sdf_line(glp_data *data)
 266.253 +{     /* determine current line number */
 266.254 +      return data->count;
 266.255 +}
 266.256 +
 266.257 +void glp_sdf_close_file(glp_data *data)
 266.258 +{     /* close plain data file */
 266.259 +      xfclose(data->fp);
 266.260 +      xfree(data->fname);
 266.261 +      xfree(data);
 266.262 +      return;
 266.263 +}
 266.264 +
 266.265 +/* eof */
   267.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   267.2 +++ b/src/glpspm.c	Mon Dec 06 13:09:21 2010 +0100
   267.3 @@ -0,0 +1,846 @@
   267.4 +/* glpspm.c */
   267.5 +
   267.6 +/***********************************************************************
   267.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   267.8 +*
   267.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  267.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  267.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  267.12 +*  E-mail: <mao@gnu.org>.
  267.13 +*
  267.14 +*  GLPK is free software: you can redistribute it and/or modify it
  267.15 +*  under the terms of the GNU General Public License as published by
  267.16 +*  the Free Software Foundation, either version 3 of the License, or
  267.17 +*  (at your option) any later version.
  267.18 +*
  267.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  267.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  267.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  267.22 +*  License for more details.
  267.23 +*
  267.24 +*  You should have received a copy of the GNU General Public License
  267.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  267.26 +***********************************************************************/
  267.27 +
  267.28 +#include "glphbm.h"
  267.29 +#include "glprgr.h"
  267.30 +#include "glpspm.h"
  267.31 +
  267.32 +/***********************************************************************
  267.33 +*  NAME
  267.34 +*
  267.35 +*  spm_create_mat - create general sparse matrix
  267.36 +*
  267.37 +*  SYNOPSIS
  267.38 +*
  267.39 +*  #include "glpspm.h"
  267.40 +*  SPM *spm_create_mat(int m, int n);
  267.41 +*
  267.42 +*  DESCRIPTION
  267.43 +*
  267.44 +*  The routine spm_create_mat creates a general sparse matrix having
  267.45 +*  m rows and n columns. Being created the matrix is zero (empty), i.e.
  267.46 +*  has no elements.
  267.47 +*
  267.48 +*  RETURNS
  267.49 +*
  267.50 +*  The routine returns a pointer to the matrix created. */
  267.51 +
  267.52 +SPM *spm_create_mat(int m, int n)
  267.53 +{     SPM *A;
  267.54 +      xassert(0 <= m && m < INT_MAX);
  267.55 +      xassert(0 <= n && n < INT_MAX);
  267.56 +      A = xmalloc(sizeof(SPM));
  267.57 +      A->m = m;
  267.58 +      A->n = n;
  267.59 +      if (m == 0 || n == 0)
  267.60 +      {  A->pool = NULL;
  267.61 +         A->row = NULL;
  267.62 +         A->col = NULL;
  267.63 +      }
  267.64 +      else
  267.65 +      {  int i, j;
  267.66 +         A->pool = dmp_create_pool();
  267.67 +         A->row = xcalloc(1+m, sizeof(SPME *));
  267.68 +         for (i = 1; i <= m; i++) A->row[i] = NULL;
  267.69 +         A->col = xcalloc(1+n, sizeof(SPME *));
  267.70 +         for (j = 1; j <= n; j++) A->col[j] = NULL;
  267.71 +      }
  267.72 +      return A;
  267.73 +}
  267.74 +
  267.75 +/***********************************************************************
  267.76 +*  NAME
  267.77 +*
  267.78 +*  spm_new_elem - add new element to sparse matrix
  267.79 +*
  267.80 +*  SYNOPSIS
  267.81 +*
  267.82 +*  #include "glpspm.h"
  267.83 +*  SPME *spm_new_elem(SPM *A, int i, int j, double val);
  267.84 +*
  267.85 +*  DESCRIPTION
  267.86 +*
  267.87 +*  The routine spm_new_elem adds a new element to the specified sparse
  267.88 +*  matrix. Parameters i, j, and val specify the row number, the column
  267.89 +*  number, and a numerical value of the element, respectively.
  267.90 +*
  267.91 +*  RETURNS
  267.92 +*
  267.93 +*  The routine returns a pointer to the new element added. */
  267.94 +
  267.95 +SPME *spm_new_elem(SPM *A, int i, int j, double val)
  267.96 +{     SPME *e;
  267.97 +      xassert(1 <= i && i <= A->m);
  267.98 +      xassert(1 <= j && j <= A->n);
  267.99 +      e = dmp_get_atom(A->pool, sizeof(SPME));
 267.100 +      e->i = i;
 267.101 +      e->j = j;
 267.102 +      e->val = val;
 267.103 +      e->r_prev = NULL;
 267.104 +      e->r_next = A->row[i];
 267.105 +      if (e->r_next != NULL) e->r_next->r_prev = e;
 267.106 +      e->c_prev = NULL;
 267.107 +      e->c_next = A->col[j];
 267.108 +      if (e->c_next != NULL) e->c_next->c_prev = e;
 267.109 +      A->row[i] = A->col[j] = e;
 267.110 +      return e;
 267.111 +}
 267.112 +
 267.113 +/***********************************************************************
 267.114 +*  NAME
 267.115 +*
 267.116 +*  spm_delete_mat - delete general sparse matrix
 267.117 +*
 267.118 +*  SYNOPSIS
 267.119 +*
 267.120 +*  #include "glpspm.h"
 267.121 +*  void spm_delete_mat(SPM *A);
 267.122 +*
 267.123 +*  DESCRIPTION
 267.124 +*
 267.125 +*  The routine deletes the specified general sparse matrix freeing all
 267.126 +*  the memory allocated to this object. */
 267.127 +
 267.128 +void spm_delete_mat(SPM *A)
 267.129 +{     /* delete sparse matrix */
 267.130 +      if (A->pool != NULL) dmp_delete_pool(A->pool);
 267.131 +      if (A->row != NULL) xfree(A->row);
 267.132 +      if (A->col != NULL) xfree(A->col);
 267.133 +      xfree(A);
 267.134 +      return;
 267.135 +}
 267.136 +
 267.137 +/***********************************************************************
 267.138 +*  NAME
 267.139 +*
 267.140 +*  spm_test_mat_e - create test sparse matrix of E(n,c) class
 267.141 +*
 267.142 +*  SYNOPSIS
 267.143 +*
 267.144 +*  #include "glpspm.h"
 267.145 +*  SPM *spm_test_mat_e(int n, int c);
 267.146 +*
 267.147 +*  DESCRIPTION
 267.148 +*
 267.149 +*  The routine spm_test_mat_e creates a test sparse matrix of E(n,c)
 267.150 +*  class as described in the book: Ole 0sterby, Zahari Zlatev. Direct
 267.151 +*  Methods for Sparse Matrices. Springer-Verlag, 1983.
 267.152 +*
 267.153 +*  Matrix of E(n,c) class is a symmetric positive definite matrix of
 267.154 +*  the order n. It has the number 4 on its main diagonal and the number
 267.155 +*  -1 on its four co-diagonals, two of which are neighbour to the main
 267.156 +*  diagonal and two others are shifted from the main diagonal on the
 267.157 +*  distance c.
 267.158 +*
 267.159 +*  It is necessary that n >= 3 and 2 <= c <= n-1.
 267.160 +*
 267.161 +*  RETURNS
 267.162 +*
 267.163 +*  The routine returns a pointer to the matrix created. */
 267.164 +
 267.165 +SPM *spm_test_mat_e(int n, int c)
 267.166 +{     SPM *A;
 267.167 +      int i;
 267.168 +      xassert(n >= 3 && 2 <= c && c <= n-1);
 267.169 +      A = spm_create_mat(n, n);
 267.170 +      for (i = 1; i <= n; i++)
 267.171 +         spm_new_elem(A, i, i, 4.0);
 267.172 +      for (i = 1; i <= n-1; i++)
 267.173 +      {  spm_new_elem(A, i, i+1, -1.0);
 267.174 +         spm_new_elem(A, i+1, i, -1.0);
 267.175 +      }
 267.176 +      for (i = 1; i <= n-c; i++)
 267.177 +      {  spm_new_elem(A, i, i+c, -1.0);
 267.178 +         spm_new_elem(A, i+c, i, -1.0);
 267.179 +      }
 267.180 +      return A;
 267.181 +}
 267.182 +
 267.183 +/***********************************************************************
 267.184 +*  NAME
 267.185 +*
 267.186 +*  spm_test_mat_d - create test sparse matrix of D(n,c) class
 267.187 +*
 267.188 +*  SYNOPSIS
 267.189 +*
 267.190 +*  #include "glpspm.h"
 267.191 +*  SPM *spm_test_mat_d(int n, int c);
 267.192 +*
 267.193 +*  DESCRIPTION
 267.194 +*
 267.195 +*  The routine spm_test_mat_d creates a test sparse matrix of D(n,c)
 267.196 +*  class as described in the book: Ole 0sterby, Zahari Zlatev. Direct
 267.197 +*  Methods for Sparse Matrices. Springer-Verlag, 1983.
 267.198 +*
 267.199 +*  Matrix of D(n,c) class is a non-singular matrix of the order n. It
 267.200 +*  has unity main diagonal, three co-diagonals above the main diagonal
 267.201 +*  on the distance c, which are cyclically continued below the main
 267.202 +*  diagonal, and a triangle block of the size 10x10 in the upper right
 267.203 +*  corner.
 267.204 +*
 267.205 +*  It is necessary that n >= 14 and 1 <= c <= n-13.
 267.206 +*
 267.207 +*  RETURNS
 267.208 +*
 267.209 +*  The routine returns a pointer to the matrix created. */
 267.210 +
 267.211 +SPM *spm_test_mat_d(int n, int c)
 267.212 +{     SPM *A;
 267.213 +      int i, j;
 267.214 +      xassert(n >= 14 && 1 <= c && c <= n-13);
 267.215 +      A = spm_create_mat(n, n);
 267.216 +      for (i = 1; i <= n; i++)
 267.217 +         spm_new_elem(A, i, i, 1.0);
 267.218 +      for (i = 1; i <= n-c; i++)
 267.219 +         spm_new_elem(A, i, i+c, (double)(i+1));
 267.220 +      for (i = n-c+1; i <= n; i++)
 267.221 +         spm_new_elem(A, i, i-n+c, (double)(i+1));
 267.222 +      for (i = 1; i <= n-c-1; i++)
 267.223 +         spm_new_elem(A, i, i+c+1, (double)(-i));
 267.224 +      for (i = n-c; i <= n; i++)
 267.225 +         spm_new_elem(A, i, i-n+c+1, (double)(-i));
 267.226 +      for (i = 1; i <= n-c-2; i++)
 267.227 +         spm_new_elem(A, i, i+c+2, 16.0);
 267.228 +      for (i = n-c-1; i <= n; i++)
 267.229 +         spm_new_elem(A, i, i-n+c+2, 16.0);
 267.230 +      for (j = 1; j <= 10; j++)
 267.231 +         for (i = 1; i <= 11-j; i++)
 267.232 +            spm_new_elem(A, i, n-11+i+j, 100.0 * (double)j);
 267.233 +      return A;
 267.234 +}
 267.235 +
 267.236 +/***********************************************************************
 267.237 +*  NAME
 267.238 +*
 267.239 +*  spm_show_mat - write sparse matrix pattern in BMP file format
 267.240 +*
 267.241 +*  SYNOPSIS
 267.242 +*
 267.243 +*  #include "glpspm.h"
 267.244 +*  int spm_show_mat(const SPM *A, const char *fname);
 267.245 +*
 267.246 +*  DESCRIPTION
 267.247 +*
 267.248 +*  The routine spm_show_mat writes pattern of the specified sparse
 267.249 +*  matrix in uncompressed BMP file format (Windows bitmap) to a binary
 267.250 +*  file whose name is specified by the character string fname.
 267.251 +*
 267.252 +*  Each pixel corresponds to one matrix element. The pixel colors have
 267.253 +*  the following meaning:
 267.254 +*
 267.255 +*  Black    structurally zero element
 267.256 +*  White    positive element
 267.257 +*  Cyan     negative element
 267.258 +*  Green    zero element
 267.259 +*  Red      duplicate element
 267.260 +*
 267.261 +*  RETURNS
 267.262 +*
 267.263 +*  If no error occured, the routine returns zero. Otherwise, it prints
 267.264 +*  an appropriate error message and returns non-zero. */
 267.265 +
 267.266 +int spm_show_mat(const SPM *A, const char *fname)
 267.267 +{     int m = A->m;
 267.268 +      int n = A->n;
 267.269 +      int i, j, k, ret;
 267.270 +      char *map;
 267.271 +      xprintf("spm_show_mat: writing matrix pattern to `%s'...\n",
 267.272 +         fname);
 267.273 +      xassert(1 <= m && m <= 32767);
 267.274 +      xassert(1 <= n && n <= 32767);
 267.275 +      map = xmalloc(m * n);
 267.276 +      memset(map, 0x08, m * n);
 267.277 +      for (i = 1; i <= m; i++)
 267.278 +      {  SPME *e;
 267.279 +         for (e = A->row[i]; e != NULL; e = e->r_next)
 267.280 +         {  j = e->j;
 267.281 +            xassert(1 <= j && j <= n);
 267.282 +            k = n * (i - 1) + (j - 1);
 267.283 +            if (map[k] != 0x08)
 267.284 +               map[k] = 0x0C;
 267.285 +            else if (e->val > 0.0)
 267.286 +               map[k] = 0x0F;
 267.287 +            else if (e->val < 0.0)
 267.288 +               map[k] = 0x0B;
 267.289 +            else
 267.290 +               map[k] = 0x0A;
 267.291 +         }
 267.292 +      }
 267.293 +      ret = rgr_write_bmp16(fname, m, n, map);
 267.294 +      xfree(map);
 267.295 +      return ret;
 267.296 +}
 267.297 +
 267.298 +/***********************************************************************
 267.299 +*  NAME
 267.300 +*
 267.301 +*  spm_read_hbm - read sparse matrix in Harwell-Boeing format
 267.302 +*
 267.303 +*  SYNOPSIS
 267.304 +*
 267.305 +*  #include "glpspm.h"
 267.306 +*  SPM *spm_read_hbm(const char *fname);
 267.307 +*
 267.308 +*  DESCRIPTION
 267.309 +*
 267.310 +*  The routine spm_read_hbm reads a sparse matrix in the Harwell-Boeing
 267.311 +*  format from a text file whose name is the character string fname.
 267.312 +*
 267.313 +*  Detailed description of the Harwell-Boeing format recognised by this
 267.314 +*  routine can be found in the following report:
 267.315 +*
 267.316 +*  I.S.Duff, R.G.Grimes, J.G.Lewis. User's Guide for the Harwell-Boeing
 267.317 +*  Sparse Matrix Collection (Release I), TR/PA/92/86, October 1992.
 267.318 +*
 267.319 +*  NOTE
 267.320 +*
 267.321 +*  The routine spm_read_hbm reads the matrix "as is", due to which zero
 267.322 +*  and/or duplicate elements can appear in the matrix.
 267.323 +*
 267.324 +*  RETURNS
 267.325 +*
 267.326 +*  If no error occured, the routine returns a pointer to the matrix
 267.327 +*  created. Otherwise, the routine prints an appropriate error message
 267.328 +*  and returns NULL. */
 267.329 +
 267.330 +SPM *spm_read_hbm(const char *fname)
 267.331 +{     SPM *A = NULL;
 267.332 +      HBM *hbm;
 267.333 +      int nrow, ncol, nnzero, i, j, beg, end, ptr, *colptr, *rowind;
 267.334 +      double val, *values;
 267.335 +      char *mxtype;
 267.336 +      hbm = hbm_read_mat(fname);
 267.337 +      if (hbm == NULL)
 267.338 +      {  xprintf("spm_read_hbm: unable to read matrix\n");
 267.339 +         goto fini;
 267.340 +      }
 267.341 +      mxtype = hbm->mxtype;
 267.342 +      nrow = hbm->nrow;
 267.343 +      ncol = hbm->ncol;
 267.344 +      nnzero = hbm->nnzero;
 267.345 +      colptr = hbm->colptr;
 267.346 +      rowind = hbm->rowind;
 267.347 +      values = hbm->values;
 267.348 +      if (!(strcmp(mxtype, "RSA") == 0 || strcmp(mxtype, "PSA") == 0 ||
 267.349 +            strcmp(mxtype, "RUA") == 0 || strcmp(mxtype, "PUA") == 0 ||
 267.350 +            strcmp(mxtype, "RRA") == 0 || strcmp(mxtype, "PRA") == 0))
 267.351 +      {  xprintf("spm_read_hbm: matrix type `%s' not supported\n",
 267.352 +            mxtype);
 267.353 +         goto fini;
 267.354 +      }
 267.355 +      A = spm_create_mat(nrow, ncol);
 267.356 +      if (mxtype[1] == 'S' || mxtype[1] == 'U')
 267.357 +         xassert(nrow == ncol);
 267.358 +      for (j = 1; j <= ncol; j++)
 267.359 +      {  beg = colptr[j];
 267.360 +         end = colptr[j+1];
 267.361 +         xassert(1 <= beg && beg <= end && end <= nnzero + 1);
 267.362 +         for (ptr = beg; ptr < end; ptr++)
 267.363 +         {  i = rowind[ptr];
 267.364 +            xassert(1 <= i && i <= nrow);
 267.365 +            if (mxtype[0] == 'R')
 267.366 +               val = values[ptr];
 267.367 +            else
 267.368 +               val = 1.0;
 267.369 +            spm_new_elem(A, i, j, val);
 267.370 +            if (mxtype[1] == 'S' && i != j)
 267.371 +               spm_new_elem(A, j, i, val);
 267.372 +         }
 267.373 +      }
 267.374 +fini: if (hbm != NULL) hbm_free_mat(hbm);
 267.375 +      return A;
 267.376 +}
 267.377 +
 267.378 +/***********************************************************************
 267.379 +*  NAME
 267.380 +*
 267.381 +*  spm_count_nnz - determine number of non-zeros in sparse matrix
 267.382 +*
 267.383 +*  SYNOPSIS
 267.384 +*
 267.385 +*  #include "glpspm.h"
 267.386 +*  int spm_count_nnz(const SPM *A);
 267.387 +*
 267.388 +*  RETURNS
 267.389 +*
 267.390 +*  The routine spm_count_nnz returns the number of structural non-zero
 267.391 +*  elements in the specified sparse matrix. */
 267.392 +
 267.393 +int spm_count_nnz(const SPM *A)
 267.394 +{     SPME *e;
 267.395 +      int i, nnz = 0;
 267.396 +      for (i = 1; i <= A->m; i++)
 267.397 +         for (e = A->row[i]; e != NULL; e = e->r_next) nnz++;
 267.398 +      return nnz;
 267.399 +}
 267.400 +
 267.401 +/***********************************************************************
 267.402 +*  NAME
 267.403 +*
 267.404 +*  spm_drop_zeros - remove zero elements from sparse matrix
 267.405 +*
 267.406 +*  SYNOPSIS
 267.407 +*
 267.408 +*  #include "glpspm.h"
 267.409 +*  int spm_drop_zeros(SPM *A, double eps);
 267.410 +*
 267.411 +*  DESCRIPTION
 267.412 +*
 267.413 +*  The routine spm_drop_zeros removes all elements from the specified
 267.414 +*  sparse matrix, whose absolute value is less than eps.
 267.415 +*
 267.416 +*  If the parameter eps is 0, only zero elements are removed from the
 267.417 +*  matrix.
 267.418 +*
 267.419 +*  RETURNS
 267.420 +*
 267.421 +*  The routine returns the number of elements removed. */
 267.422 +
 267.423 +int spm_drop_zeros(SPM *A, double eps)
 267.424 +{     SPME *e, *next;
 267.425 +      int i, count = 0;
 267.426 +      for (i = 1; i <= A->m; i++)
 267.427 +      {  for (e = A->row[i]; e != NULL; e = next)
 267.428 +         {  next = e->r_next;
 267.429 +            if (e->val == 0.0 || fabs(e->val) < eps)
 267.430 +            {  /* remove element from the row list */
 267.431 +               if (e->r_prev == NULL)
 267.432 +                  A->row[e->i] = e->r_next;
 267.433 +               else
 267.434 +                  e->r_prev->r_next = e->r_next;
 267.435 +               if (e->r_next == NULL)
 267.436 +                  ;
 267.437 +               else
 267.438 +                  e->r_next->r_prev = e->r_prev;
 267.439 +               /* remove element from the column list */
 267.440 +               if (e->c_prev == NULL)
 267.441 +                  A->col[e->j] = e->c_next;
 267.442 +               else
 267.443 +                  e->c_prev->c_next = e->c_next;
 267.444 +               if (e->c_next == NULL)
 267.445 +                  ;
 267.446 +               else
 267.447 +                  e->c_next->c_prev = e->c_prev;
 267.448 +               /* return element to the memory pool */
 267.449 +               dmp_free_atom(A->pool, e, sizeof(SPME));
 267.450 +               count++;
 267.451 +            }
 267.452 +         }
 267.453 +      }
 267.454 +      return count;
 267.455 +}
 267.456 +
 267.457 +/***********************************************************************
 267.458 +*  NAME
 267.459 +*
 267.460 +*  spm_read_mat - read sparse matrix from text file
 267.461 +*
 267.462 +*  SYNOPSIS
 267.463 +*
 267.464 +*  #include "glpspm.h"
 267.465 +*  SPM *spm_read_mat(const char *fname);
 267.466 +*
 267.467 +*  DESCRIPTION
 267.468 +*
 267.469 +*  The routine reads a sparse matrix from a text file whose name is
 267.470 +*  specified by the parameter fname.
 267.471 +*
 267.472 +*  For the file format see description of the routine spm_write_mat.
 267.473 +*
 267.474 +*  RETURNS
 267.475 +*
 267.476 +*  On success the routine returns a pointer to the matrix created,
 267.477 +*  otherwise NULL. */
 267.478 +
 267.479 +#if 1
 267.480 +SPM *spm_read_mat(const char *fname)
 267.481 +{     xassert(fname != fname);
 267.482 +      return NULL;
 267.483 +}
 267.484 +#else
 267.485 +SPM *spm_read_mat(const char *fname)
 267.486 +{     SPM *A = NULL;
 267.487 +      PDS *pds;
 267.488 +      jmp_buf jump;
 267.489 +      int i, j, k, m, n, nnz, fail = 0;
 267.490 +      double val;
 267.491 +      xprintf("spm_read_mat: reading matrix from `%s'...\n", fname);
 267.492 +      pds = pds_open_file(fname);
 267.493 +      if (pds == NULL)
 267.494 +      {  xprintf("spm_read_mat: unable to open `%s' - %s\n", fname,
 267.495 +            strerror(errno));
 267.496 +         fail = 1;
 267.497 +         goto done;
 267.498 +      }
 267.499 +      if (setjmp(jump))
 267.500 +      {  fail = 1;
 267.501 +         goto done;
 267.502 +      }
 267.503 +      pds_set_jump(pds, jump);
 267.504 +      /* number of rows, number of columns, number of non-zeros */
 267.505 +      m = pds_scan_int(pds);
 267.506 +      if (m < 0)
 267.507 +         pds_error(pds, "invalid number of rows\n");
 267.508 +      n = pds_scan_int(pds);
 267.509 +      if (n < 0)
 267.510 +         pds_error(pds, "invalid number of columns\n");
 267.511 +      nnz = pds_scan_int(pds);
 267.512 +      if (nnz < 0)
 267.513 +         pds_error(pds, "invalid number of non-zeros\n");
 267.514 +      /* create matrix */
 267.515 +      xprintf("spm_read_mat: %d rows, %d columns, %d non-zeros\n",
 267.516 +         m, n, nnz);
 267.517 +      A = spm_create_mat(m, n);
 267.518 +      /* read matrix elements */
 267.519 +      for (k = 1; k <= nnz; k++)
 267.520 +      {  /* row index, column index, element value */
 267.521 +         i = pds_scan_int(pds);
 267.522 +         if (!(1 <= i && i <= m))
 267.523 +            pds_error(pds, "row index out of range\n");
 267.524 +         j = pds_scan_int(pds);
 267.525 +         if (!(1 <= j && j <= n))
 267.526 +            pds_error(pds, "column index out of range\n");
 267.527 +         val = pds_scan_num(pds);
 267.528 +         /* add new element to the matrix */
 267.529 +         spm_new_elem(A, i, j, val);
 267.530 +      }
 267.531 +      xprintf("spm_read_mat: %d lines were read\n", pds->count);
 267.532 +done: if (pds != NULL) pds_close_file(pds);
 267.533 +      if (fail && A != NULL) spm_delete_mat(A), A = NULL;
 267.534 +      return A;
 267.535 +}
 267.536 +#endif
 267.537 +
 267.538 +/***********************************************************************
 267.539 +*  NAME
 267.540 +*
 267.541 +*  spm_write_mat - write sparse matrix to text file
 267.542 +*
 267.543 +*  SYNOPSIS
 267.544 +*
 267.545 +*  #include "glpspm.h"
 267.546 +*  int spm_write_mat(const SPM *A, const char *fname);
 267.547 +*
 267.548 +*  DESCRIPTION
 267.549 +*
 267.550 +*  The routine spm_write_mat writes the specified sparse matrix to a
 267.551 +*  text file whose name is specified by the parameter fname. This file
 267.552 +*  can be read back with the routine spm_read_mat.
 267.553 +*
 267.554 +*  RETURNS
 267.555 +*
 267.556 +*  On success the routine returns zero, otherwise non-zero.
 267.557 +*
 267.558 +*  FILE FORMAT
 267.559 +*
 267.560 +*  The file created by the routine spm_write_mat is a plain text file,
 267.561 +*  which contains the following information:
 267.562 +*
 267.563 +*     m n nnz
 267.564 +*     row[1] col[1] val[1]
 267.565 +*     row[2] col[2] val[2]
 267.566 +*     . . .
 267.567 +*     row[nnz] col[nnz] val[nnz]
 267.568 +*
 267.569 +*  where:
 267.570 +*  m is the number of rows;
 267.571 +*  n is the number of columns;
 267.572 +*  nnz is the number of non-zeros;
 267.573 +*  row[k], k = 1,...,nnz, are row indices;
 267.574 +*  col[k], k = 1,...,nnz, are column indices;
 267.575 +*  val[k], k = 1,...,nnz, are element values. */
 267.576 +
 267.577 +#if 1
 267.578 +int spm_write_mat(const SPM *A, const char *fname)
 267.579 +{     xassert(A != A);
 267.580 +      xassert(fname != fname);
 267.581 +      return 0;
 267.582 +}
 267.583 +#else
 267.584 +int spm_write_mat(const SPM *A, const char *fname)
 267.585 +{     FILE *fp;
 267.586 +      int i, nnz, ret = 0;
 267.587 +      xprintf("spm_write_mat: writing matrix to `%s'...\n", fname);
 267.588 +      fp = fopen(fname, "w");
 267.589 +      if (fp == NULL)
 267.590 +      {  xprintf("spm_write_mat: unable to create `%s' - %s\n", fname,
 267.591 +            strerror(errno));
 267.592 +         ret = 1;
 267.593 +         goto done;
 267.594 +      }
 267.595 +      /* number of rows, number of columns, number of non-zeros */
 267.596 +      nnz = spm_count_nnz(A);
 267.597 +      fprintf(fp, "%d %d %d\n", A->m, A->n, nnz);
 267.598 +      /* walk through rows of the matrix */
 267.599 +      for (i = 1; i <= A->m; i++)
 267.600 +      {  SPME *e;
 267.601 +         /* walk through elements of i-th row */
 267.602 +         for (e = A->row[i]; e != NULL; e = e->r_next)
 267.603 +         {  /* row index, column index, element value */
 267.604 +            fprintf(fp, "%d %d %.*g\n", e->i, e->j, DBL_DIG, e->val);
 267.605 +         }
 267.606 +      }
 267.607 +      fflush(fp);
 267.608 +      if (ferror(fp))
 267.609 +      {  xprintf("spm_write_mat: writing error on `%s' - %s\n", fname,
 267.610 +            strerror(errno));
 267.611 +         ret = 1;
 267.612 +         goto done;
 267.613 +      }
 267.614 +      xprintf("spm_write_mat: %d lines were written\n", 1 + nnz);
 267.615 +done: if (fp != NULL) fclose(fp);
 267.616 +      return ret;
 267.617 +}
 267.618 +#endif
 267.619 +
 267.620 +/***********************************************************************
 267.621 +*  NAME
 267.622 +*
 267.623 +*  spm_transpose - transpose sparse matrix
 267.624 +*
 267.625 +*  SYNOPSIS
 267.626 +*
 267.627 +*  #include "glpspm.h"
 267.628 +*  SPM *spm_transpose(const SPM *A);
 267.629 +*
 267.630 +*  RETURNS
 267.631 +*
 267.632 +*  The routine computes and returns sparse matrix B, which is a matrix
 267.633 +*  transposed to sparse matrix A. */
 267.634 +
 267.635 +SPM *spm_transpose(const SPM *A)
 267.636 +{     SPM *B;
 267.637 +      int i;
 267.638 +      B = spm_create_mat(A->n, A->m);
 267.639 +      for (i = 1; i <= A->m; i++)
 267.640 +      {  SPME *e;
 267.641 +         for (e = A->row[i]; e != NULL; e = e->r_next)
 267.642 +            spm_new_elem(B, e->j, i, e->val);
 267.643 +      }
 267.644 +      return B;
 267.645 +}
 267.646 +
 267.647 +SPM *spm_add_sym(const SPM *A, const SPM *B)
 267.648 +{     /* add two sparse matrices (symbolic phase) */
 267.649 +      SPM *C;
 267.650 +      int i, j, *flag;
 267.651 +      xassert(A->m == B->m);
 267.652 +      xassert(A->n == B->n);
 267.653 +      /* create resultant matrix */
 267.654 +      C = spm_create_mat(A->m, A->n);
 267.655 +      /* allocate and clear the flag array */
 267.656 +      flag = xcalloc(1+C->n, sizeof(int));
 267.657 +      for (j = 1; j <= C->n; j++)
 267.658 +         flag[j] = 0;
 267.659 +      /* compute pattern of C = A + B */
 267.660 +      for (i = 1; i <= C->m; i++)
 267.661 +      {  SPME *e;
 267.662 +         /* at the beginning i-th row of C is empty */
 267.663 +         /* (i-th row of C) := (i-th row of C) union (i-th row of A) */
 267.664 +         for (e = A->row[i]; e != NULL; e = e->r_next)
 267.665 +         {  /* (note that i-th row of A may have duplicate elements) */
 267.666 +            j = e->j;
 267.667 +            if (!flag[j])
 267.668 +            {  spm_new_elem(C, i, j, 0.0);
 267.669 +               flag[j] = 1;
 267.670 +            }
 267.671 +         }
 267.672 +         /* (i-th row of C) := (i-th row of C) union (i-th row of B) */
 267.673 +         for (e = B->row[i]; e != NULL; e = e->r_next)
 267.674 +         {  /* (note that i-th row of B may have duplicate elements) */
 267.675 +            j = e->j;
 267.676 +            if (!flag[j])
 267.677 +            {  spm_new_elem(C, i, j, 0.0);
 267.678 +               flag[j] = 1;
 267.679 +            }
 267.680 +         }
 267.681 +         /* reset the flag array */
 267.682 +         for (e = C->row[i]; e != NULL; e = e->r_next)
 267.683 +            flag[e->j] = 0;
 267.684 +      }
 267.685 +      /* check and deallocate the flag array */
 267.686 +      for (j = 1; j <= C->n; j++)
 267.687 +         xassert(!flag[j]);
 267.688 +      xfree(flag);
 267.689 +      return C;
 267.690 +}
 267.691 +
 267.692 +void spm_add_num(SPM *C, double alfa, const SPM *A, double beta,
 267.693 +      const SPM *B)
 267.694 +{     /* add two sparse matrices (numeric phase) */
 267.695 +      int i, j;
 267.696 +      double *work;
 267.697 +      /* allocate and clear the working array */
 267.698 +      work = xcalloc(1+C->n, sizeof(double));
 267.699 +      for (j = 1; j <= C->n; j++)
 267.700 +         work[j] = 0.0;
 267.701 +      /* compute matrix C = alfa * A + beta * B */
 267.702 +      for (i = 1; i <= C->n; i++)
 267.703 +      {  SPME *e;
 267.704 +         /* work := alfa * (i-th row of A) + beta * (i-th row of B) */
 267.705 +         /* (note that A and/or B may have duplicate elements) */
 267.706 +         for (e = A->row[i]; e != NULL; e = e->r_next)
 267.707 +            work[e->j] += alfa * e->val;
 267.708 +         for (e = B->row[i]; e != NULL; e = e->r_next)
 267.709 +            work[e->j] += beta * e->val;
 267.710 +         /* (i-th row of C) := work, work := 0 */
 267.711 +         for (e = C->row[i]; e != NULL; e = e->r_next)
 267.712 +         {  j = e->j;
 267.713 +            e->val = work[j];
 267.714 +            work[j] = 0.0;
 267.715 +         }
 267.716 +      }
 267.717 +      /* check and deallocate the working array */
 267.718 +      for (j = 1; j <= C->n; j++)
 267.719 +         xassert(work[j] == 0.0);
 267.720 +      xfree(work);
 267.721 +      return;
 267.722 +}
 267.723 +
 267.724 +SPM *spm_add_mat(double alfa, const SPM *A, double beta, const SPM *B)
 267.725 +{     /* add two sparse matrices (driver routine) */
 267.726 +      SPM *C;
 267.727 +      C = spm_add_sym(A, B);
 267.728 +      spm_add_num(C, alfa, A, beta, B);
 267.729 +      return C;
 267.730 +}
 267.731 +
 267.732 +SPM *spm_mul_sym(const SPM *A, const SPM *B)
 267.733 +{     /* multiply two sparse matrices (symbolic phase) */
 267.734 +      int i, j, k, *flag;
 267.735 +      SPM *C;
 267.736 +      xassert(A->n == B->m);
 267.737 +      /* create resultant matrix */
 267.738 +      C = spm_create_mat(A->m, B->n);
 267.739 +      /* allocate and clear the flag array */
 267.740 +      flag = xcalloc(1+C->n, sizeof(int));
 267.741 +      for (j = 1; j <= C->n; j++)
 267.742 +         flag[j] = 0;
 267.743 +      /* compute pattern of C = A * B */
 267.744 +      for (i = 1; i <= C->m; i++)
 267.745 +      {  SPME *e, *ee;
 267.746 +         /* compute pattern of i-th row of C */
 267.747 +         for (e = A->row[i]; e != NULL; e = e->r_next)
 267.748 +         {  k = e->j;
 267.749 +            for (ee = B->row[k]; ee != NULL; ee = ee->r_next)
 267.750 +            {  j = ee->j;
 267.751 +               /* if a[i,k] != 0 and b[k,j] != 0 then c[i,j] != 0 */
 267.752 +               if (!flag[j])
 267.753 +               {  /* c[i,j] does not exist, so create it */
 267.754 +                  spm_new_elem(C, i, j, 0.0);
 267.755 +                  flag[j] = 1;
 267.756 +               }
 267.757 +            }
 267.758 +         }
 267.759 +         /* reset the flag array */
 267.760 +         for (e = C->row[i]; e != NULL; e = e->r_next)
 267.761 +            flag[e->j] = 0;
 267.762 +      }
 267.763 +      /* check and deallocate the flag array */
 267.764 +      for (j = 1; j <= C->n; j++)
 267.765 +         xassert(!flag[j]);
 267.766 +      xfree(flag);
 267.767 +      return C;
 267.768 +}
 267.769 +
 267.770 +void spm_mul_num(SPM *C, const SPM *A, const SPM *B)
 267.771 +{     /* multiply two sparse matrices (numeric phase) */
 267.772 +      int i, j;
 267.773 +      double *work;
 267.774 +      /* allocate and clear the working array */
 267.775 +      work = xcalloc(1+A->n, sizeof(double));
 267.776 +      for (j = 1; j <= A->n; j++)
 267.777 +         work[j] = 0.0;
 267.778 +      /* compute matrix C = A * B */
 267.779 +      for (i = 1; i <= C->m; i++)
 267.780 +      {  SPME *e, *ee;
 267.781 +         double temp;
 267.782 +         /* work := (i-th row of A) */
 267.783 +         /* (note that A may have duplicate elements) */
 267.784 +         for (e = A->row[i]; e != NULL; e = e->r_next)
 267.785 +            work[e->j] += e->val;
 267.786 +         /* compute i-th row of C */
 267.787 +         for (e = C->row[i]; e != NULL; e = e->r_next)
 267.788 +         {  j = e->j;
 267.789 +            /* c[i,j] := work * (j-th column of B) */
 267.790 +            temp = 0.0;
 267.791 +            for (ee = B->col[j]; ee != NULL; ee = ee->c_next)
 267.792 +               temp += work[ee->i] * ee->val;
 267.793 +            e->val = temp;
 267.794 +         }
 267.795 +         /* reset the working array */
 267.796 +         for (e = A->row[i]; e != NULL; e = e->r_next)
 267.797 +            work[e->j] = 0.0;
 267.798 +      }
 267.799 +      /* check and deallocate the working array */
 267.800 +      for (j = 1; j <= A->n; j++)
 267.801 +         xassert(work[j] == 0.0);
 267.802 +      xfree(work);
 267.803 +      return;
 267.804 +}
 267.805 +
 267.806 +SPM *spm_mul_mat(const SPM *A, const SPM *B)
 267.807 +{     /* multiply two sparse matrices (driver routine) */
 267.808 +      SPM *C;
 267.809 +      C = spm_mul_sym(A, B);
 267.810 +      spm_mul_num(C, A, B);
 267.811 +      return C;
 267.812 +}
 267.813 +
 267.814 +PER *spm_create_per(int n)
 267.815 +{     /* create permutation matrix */
 267.816 +      PER *P;
 267.817 +      int k;
 267.818 +      xassert(n >= 0);
 267.819 +      P = xmalloc(sizeof(PER));
 267.820 +      P->n = n;
 267.821 +      P->row = xcalloc(1+n, sizeof(int));
 267.822 +      P->col = xcalloc(1+n, sizeof(int));
 267.823 +      /* initially it is identity matrix */
 267.824 +      for (k = 1; k <= n; k++)
 267.825 +         P->row[k] = P->col[k] = k;
 267.826 +      return P;
 267.827 +}
 267.828 +
 267.829 +void spm_check_per(PER *P)
 267.830 +{     /* check permutation matrix for correctness */
 267.831 +      int i, j;
 267.832 +      xassert(P->n >= 0);
 267.833 +      for (i = 1; i <= P->n; i++)
 267.834 +      {  j = P->row[i];
 267.835 +         xassert(1 <= j && j <= P->n);
 267.836 +         xassert(P->col[j] == i);
 267.837 +      }
 267.838 +      return;
 267.839 +}
 267.840 +
 267.841 +void spm_delete_per(PER *P)
 267.842 +{     /* delete permutation matrix */
 267.843 +      xfree(P->row);
 267.844 +      xfree(P->col);
 267.845 +      xfree(P);
 267.846 +      return;
 267.847 +}
 267.848 +
 267.849 +/* eof */
   268.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   268.2 +++ b/src/glpspm.h	Mon Dec 06 13:09:21 2010 +0100
   268.3 @@ -0,0 +1,165 @@
   268.4 +/* glpspm.h (general sparse matrix) */
   268.5 +
   268.6 +/***********************************************************************
   268.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   268.8 +*
   268.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  268.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  268.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  268.12 +*  E-mail: <mao@gnu.org>.
  268.13 +*
  268.14 +*  GLPK is free software: you can redistribute it and/or modify it
  268.15 +*  under the terms of the GNU General Public License as published by
  268.16 +*  the Free Software Foundation, either version 3 of the License, or
  268.17 +*  (at your option) any later version.
  268.18 +*
  268.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  268.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  268.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  268.22 +*  License for more details.
  268.23 +*
  268.24 +*  You should have received a copy of the GNU General Public License
  268.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  268.26 +***********************************************************************/
  268.27 +
  268.28 +#ifndef GLPSPM_H
  268.29 +#define GLPSPM_H
  268.30 +
  268.31 +#include "glpdmp.h"
  268.32 +
  268.33 +typedef struct SPM SPM;
  268.34 +typedef struct SPME SPME;
  268.35 +
  268.36 +struct SPM
  268.37 +{     /* general sparse matrix */
  268.38 +      int m;
  268.39 +      /* number of rows, m >= 0 */
  268.40 +      int n;
  268.41 +      /* number of columns, n >= 0 */
  268.42 +      DMP *pool;
  268.43 +      /* memory pool to store matrix elements */
  268.44 +      SPME **row; /* SPME *row[1+m]; */
  268.45 +      /* row[i], 1 <= i <= m, is a pointer to i-th row list */
  268.46 +      SPME **col; /* SPME *col[1+n]; */
  268.47 +      /* col[j], 1 <= j <= n, is a pointer to j-th column list */
  268.48 +};
  268.49 +
  268.50 +struct SPME
  268.51 +{     /* sparse matrix element */
  268.52 +      int i;
  268.53 +      /* row number */
  268.54 +      int j;
  268.55 +      /* column number */
  268.56 +      double val;
  268.57 +      /* element value */
  268.58 +      SPME *r_prev;
  268.59 +      /* pointer to previous element in the same row */
  268.60 +      SPME *r_next;
  268.61 +      /* pointer to next element in the same row */
  268.62 +      SPME *c_prev;
  268.63 +      /* pointer to previous element in the same column */
  268.64 +      SPME *c_next;
  268.65 +      /* pointer to next element in the same column */
  268.66 +};
  268.67 +
  268.68 +typedef struct PER PER;
  268.69 +
  268.70 +struct PER
  268.71 +{     /* permutation matrix */
  268.72 +      int n;
  268.73 +      /* matrix order, n >= 0 */
  268.74 +      int *row; /* int row[1+n]; */
  268.75 +      /* row[i] = j means p[i,j] = 1 */
  268.76 +      int *col; /* int col[1+n]; */
  268.77 +      /* col[j] = i means p[i,j] = 1 */
  268.78 +};
  268.79 +
  268.80 +#define spm_create_mat _glp_spm_create_mat
  268.81 +SPM *spm_create_mat(int m, int n);
  268.82 +/* create general sparse matrix */
  268.83 +
  268.84 +#define spm_new_elem _glp_spm_new_elem
  268.85 +SPME *spm_new_elem(SPM *A, int i, int j, double val);
  268.86 +/* add new element to sparse matrix */
  268.87 +
  268.88 +#define spm_delete_mat _glp_spm_delete_mat
  268.89 +void spm_delete_mat(SPM *A);
  268.90 +/* delete general sparse matrix */
  268.91 +
  268.92 +#define spm_test_mat_e _glp_spm_test_mat_e
  268.93 +SPM *spm_test_mat_e(int n, int c);
  268.94 +/* create test sparse matrix of E(n,c) class */
  268.95 +
  268.96 +#define spm_test_mat_d _glp_spm_test_mat_d
  268.97 +SPM *spm_test_mat_d(int n, int c);
  268.98 +/* create test sparse matrix of D(n,c) class */
  268.99 +
 268.100 +#define spm_show_mat _glp_spm_show_mat
 268.101 +int spm_show_mat(const SPM *A, const char *fname);
 268.102 +/* write sparse matrix pattern in BMP file format */
 268.103 +
 268.104 +#define spm_read_hbm _glp_spm_read_hbm
 268.105 +SPM *spm_read_hbm(const char *fname);
 268.106 +/* read sparse matrix in Harwell-Boeing format */
 268.107 +
 268.108 +#define spm_count_nnz _glp_spm_count_nnz
 268.109 +int spm_count_nnz(const SPM *A);
 268.110 +/* determine number of non-zeros in sparse matrix */
 268.111 +
 268.112 +#define spm_drop_zeros _glp_spm_drop_zeros
 268.113 +int spm_drop_zeros(SPM *A, double eps);
 268.114 +/* remove zero elements from sparse matrix */
 268.115 +
 268.116 +#define spm_read_mat _glp_spm_read_mat
 268.117 +SPM *spm_read_mat(const char *fname);
 268.118 +/* read sparse matrix from text file */
 268.119 +
 268.120 +#define spm_write_mat _glp_spm_write_mat
 268.121 +int spm_write_mat(const SPM *A, const char *fname);
 268.122 +/* write sparse matrix to text file */
 268.123 +
 268.124 +#define spm_transpose _glp_spm_transpose
 268.125 +SPM *spm_transpose(const SPM *A);
 268.126 +/* transpose sparse matrix */
 268.127 +
 268.128 +#define spm_add_sym _glp_spm_add_sym
 268.129 +SPM *spm_add_sym(const SPM *A, const SPM *B);
 268.130 +/* add two sparse matrices (symbolic phase) */
 268.131 +
 268.132 +#define spm_add_num _glp_spm_add_num
 268.133 +void spm_add_num(SPM *C, double alfa, const SPM *A, double beta,
 268.134 +      const SPM *B);
 268.135 +/* add two sparse matrices (numeric phase) */
 268.136 +
 268.137 +#define spm_add_mat _glp_spm_add_mat
 268.138 +SPM *spm_add_mat(double alfa, const SPM *A, double beta,
 268.139 +      const SPM *B);
 268.140 +/* add two sparse matrices (driver routine) */
 268.141 +
 268.142 +#define spm_mul_sym _glp_spm_mul_sym
 268.143 +SPM *spm_mul_sym(const SPM *A, const SPM *B);
 268.144 +/* multiply two sparse matrices (symbolic phase) */
 268.145 +
 268.146 +#define spm_mul_num _glp_spm_mul_num
 268.147 +void spm_mul_num(SPM *C, const SPM *A, const SPM *B);
 268.148 +/* multiply two sparse matrices (numeric phase) */
 268.149 +
 268.150 +#define spm_mul_mat _glp_spm_mul_mat
 268.151 +SPM *spm_mul_mat(const SPM *A, const SPM *B);
 268.152 +/* multiply two sparse matrices (driver routine) */
 268.153 +
 268.154 +#define spm_create_per _glp_spm_create_per
 268.155 +PER *spm_create_per(int n);
 268.156 +/* create permutation matrix */
 268.157 +
 268.158 +#define spm_check_per _glp_spm_check_per
 268.159 +void spm_check_per(PER *P);
 268.160 +/* check permutation matrix for correctness */
 268.161 +
 268.162 +#define spm_delete_per _glp_spm_delete_per
 268.163 +void spm_delete_per(PER *P);
 268.164 +/* delete permutation matrix */
 268.165 +
 268.166 +#endif
 268.167 +
 268.168 +/* eof */
   269.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   269.2 +++ b/src/glpspx.h	Mon Dec 06 13:09:21 2010 +0100
   269.3 @@ -0,0 +1,40 @@
   269.4 +/* glpspx.h (core simplex solvers) */
   269.5 +
   269.6 +/***********************************************************************
   269.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   269.8 +*
   269.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  269.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  269.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  269.12 +*  E-mail: <mao@gnu.org>.
  269.13 +*
  269.14 +*  GLPK is free software: you can redistribute it and/or modify it
  269.15 +*  under the terms of the GNU General Public License as published by
  269.16 +*  the Free Software Foundation, either version 3 of the License, or
  269.17 +*  (at your option) any later version.
  269.18 +*
  269.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  269.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  269.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  269.22 +*  License for more details.
  269.23 +*
  269.24 +*  You should have received a copy of the GNU General Public License
  269.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  269.26 +***********************************************************************/
  269.27 +
  269.28 +#ifndef GLPSPX_H
  269.29 +#define GLPSPX_H
  269.30 +
  269.31 +#include "glpapi.h"
  269.32 +
  269.33 +#define spx_primal _glp_spx_primal
  269.34 +int spx_primal(glp_prob *lp, const glp_smcp *parm);
  269.35 +/* core LP solver based on the primal simplex method */
  269.36 +
  269.37 +#define spx_dual _glp_spx_dual
  269.38 +int spx_dual(glp_prob *lp, const glp_smcp *parm);
  269.39 +/* core LP solver based on the dual simplex method */
  269.40 +
  269.41 +#endif
  269.42 +
  269.43 +/* eof */
   270.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   270.2 +++ b/src/glpspx01.c	Mon Dec 06 13:09:21 2010 +0100
   270.3 @@ -0,0 +1,2954 @@
   270.4 +/* glpspx01.c (primal simplex method) */
   270.5 +
   270.6 +/***********************************************************************
   270.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   270.8 +*
   270.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  270.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  270.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  270.12 +*  E-mail: <mao@gnu.org>.
  270.13 +*
  270.14 +*  GLPK is free software: you can redistribute it and/or modify it
  270.15 +*  under the terms of the GNU General Public License as published by
  270.16 +*  the Free Software Foundation, either version 3 of the License, or
  270.17 +*  (at your option) any later version.
  270.18 +*
  270.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  270.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  270.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  270.22 +*  License for more details.
  270.23 +*
  270.24 +*  You should have received a copy of the GNU General Public License
  270.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  270.26 +***********************************************************************/
  270.27 +
  270.28 +#include "glpspx.h"
  270.29 +
  270.30 +struct csa
  270.31 +{     /* common storage area */
  270.32 +      /*--------------------------------------------------------------*/
  270.33 +      /* LP data */
  270.34 +      int m;
  270.35 +      /* number of rows (auxiliary variables), m > 0 */
  270.36 +      int n;
  270.37 +      /* number of columns (structural variables), n > 0 */
  270.38 +      char *type; /* char type[1+m+n]; */
  270.39 +      /* type[0] is not used;
  270.40 +         type[k], 1 <= k <= m+n, is the type of variable x[k]:
  270.41 +         GLP_FR - free variable
  270.42 +         GLP_LO - variable with lower bound
  270.43 +         GLP_UP - variable with upper bound
  270.44 +         GLP_DB - double-bounded variable
  270.45 +         GLP_FX - fixed variable */
  270.46 +      double *lb; /* double lb[1+m+n]; */
  270.47 +      /* lb[0] is not used;
  270.48 +         lb[k], 1 <= k <= m+n, is an lower bound of variable x[k];
  270.49 +         if x[k] has no lower bound, lb[k] is zero */
  270.50 +      double *ub; /* double ub[1+m+n]; */
  270.51 +      /* ub[0] is not used;
  270.52 +         ub[k], 1 <= k <= m+n, is an upper bound of variable x[k];
  270.53 +         if x[k] has no upper bound, ub[k] is zero;
  270.54 +         if x[k] is of fixed type, ub[k] is the same as lb[k] */
  270.55 +      double *coef; /* double coef[1+m+n]; */
  270.56 +      /* coef[0] is not used;
  270.57 +         coef[k], 1 <= k <= m+n, is an objective coefficient at
  270.58 +         variable x[k] (note that on phase I auxiliary variables also
  270.59 +         may have non-zero objective coefficients) */
  270.60 +      /*--------------------------------------------------------------*/
  270.61 +      /* original objective function */
  270.62 +      double *obj; /* double obj[1+n]; */
  270.63 +      /* obj[0] is a constant term of the original objective function;
  270.64 +         obj[j], 1 <= j <= n, is an original objective coefficient at
  270.65 +         structural variable x[m+j] */
  270.66 +      double zeta;
  270.67 +      /* factor used to scale original objective coefficients; its
  270.68 +         sign defines original optimization direction: zeta > 0 means
  270.69 +         minimization, zeta < 0 means maximization */
  270.70 +      /*--------------------------------------------------------------*/
  270.71 +      /* constraint matrix A; it has m rows and n columns and is stored
  270.72 +         by columns */
  270.73 +      int *A_ptr; /* int A_ptr[1+n+1]; */
  270.74 +      /* A_ptr[0] is not used;
  270.75 +         A_ptr[j], 1 <= j <= n, is starting position of j-th column in
  270.76 +         arrays A_ind and A_val; note that A_ptr[1] is always 1;
  270.77 +         A_ptr[n+1] indicates the position after the last element in
  270.78 +         arrays A_ind and A_val */
  270.79 +      int *A_ind; /* int A_ind[A_ptr[n+1]]; */
  270.80 +      /* row indices */
  270.81 +      double *A_val; /* double A_val[A_ptr[n+1]]; */
  270.82 +      /* non-zero element values */
  270.83 +      /*--------------------------------------------------------------*/
  270.84 +      /* basis header */
  270.85 +      int *head; /* int head[1+m+n]; */
  270.86 +      /* head[0] is not used;
  270.87 +         head[i], 1 <= i <= m, is the ordinal number of basic variable
  270.88 +         xB[i]; head[i] = k means that xB[i] = x[k] and i-th column of
  270.89 +         matrix B is k-th column of matrix (I|-A);
  270.90 +         head[m+j], 1 <= j <= n, is the ordinal number of non-basic
  270.91 +         variable xN[j]; head[m+j] = k means that xN[j] = x[k] and j-th
  270.92 +         column of matrix N is k-th column of matrix (I|-A) */
  270.93 +      char *stat; /* char stat[1+n]; */
  270.94 +      /* stat[0] is not used;
  270.95 +         stat[j], 1 <= j <= n, is the status of non-basic variable
  270.96 +         xN[j], which defines its active bound:
  270.97 +         GLP_NL - lower bound is active
  270.98 +         GLP_NU - upper bound is active
  270.99 +         GLP_NF - free variable
 270.100 +         GLP_NS - fixed variable */
 270.101 +      /*--------------------------------------------------------------*/
 270.102 +      /* matrix B is the basis matrix; it is composed from columns of
 270.103 +         the augmented constraint matrix (I|-A) corresponding to basic
 270.104 +         variables and stored in a factorized (invertable) form */
 270.105 +      int valid;
 270.106 +      /* factorization is valid only if this flag is set */
 270.107 +      BFD *bfd; /* BFD bfd[1:m,1:m]; */
 270.108 +      /* factorized (invertable) form of the basis matrix */
 270.109 +      /*--------------------------------------------------------------*/
 270.110 +      /* matrix N is a matrix composed from columns of the augmented
 270.111 +         constraint matrix (I|-A) corresponding to non-basic variables
 270.112 +         except fixed ones; it is stored by rows and changes every time
 270.113 +         the basis changes */
 270.114 +      int *N_ptr; /* int N_ptr[1+m+1]; */
 270.115 +      /* N_ptr[0] is not used;
 270.116 +         N_ptr[i], 1 <= i <= m, is starting position of i-th row in
 270.117 +         arrays N_ind and N_val; note that N_ptr[1] is always 1;
 270.118 +         N_ptr[m+1] indicates the position after the last element in
 270.119 +         arrays N_ind and N_val */
 270.120 +      int *N_len; /* int N_len[1+m]; */
 270.121 +      /* N_len[0] is not used;
 270.122 +         N_len[i], 1 <= i <= m, is length of i-th row (0 to n) */
 270.123 +      int *N_ind; /* int N_ind[N_ptr[m+1]]; */
 270.124 +      /* column indices */
 270.125 +      double *N_val; /* double N_val[N_ptr[m+1]]; */
 270.126 +      /* non-zero element values */
 270.127 +      /*--------------------------------------------------------------*/
 270.128 +      /* working parameters */
 270.129 +      int phase;
 270.130 +      /* search phase:
 270.131 +         0 - not determined yet
 270.132 +         1 - search for primal feasible solution
 270.133 +         2 - search for optimal solution */
 270.134 +      glp_long tm_beg;
 270.135 +      /* time value at the beginning of the search */
 270.136 +      int it_beg;
 270.137 +      /* simplex iteration count at the beginning of the search */
 270.138 +      int it_cnt;
 270.139 +      /* simplex iteration count; it increases by one every time the
 270.140 +         basis changes (including the case when a non-basic variable
 270.141 +         jumps to its opposite bound) */
 270.142 +      int it_dpy;
 270.143 +      /* simplex iteration count at the most recent display output */
 270.144 +      /*--------------------------------------------------------------*/
 270.145 +      /* basic solution components */
 270.146 +      double *bbar; /* double bbar[1+m]; */
 270.147 +      /* bbar[0] is not used;
 270.148 +         bbar[i], 1 <= i <= m, is primal value of basic variable xB[i]
 270.149 +         (if xB[i] is free, its primal value is not updated) */
 270.150 +      double *cbar; /* double cbar[1+n]; */
 270.151 +      /* cbar[0] is not used;
 270.152 +         cbar[j], 1 <= j <= n, is reduced cost of non-basic variable
 270.153 +         xN[j] (if xN[j] is fixed, its reduced cost is not updated) */
 270.154 +      /*--------------------------------------------------------------*/
 270.155 +      /* the following pricing technique options may be used:
 270.156 +         GLP_PT_STD - standard ("textbook") pricing;
 270.157 +         GLP_PT_PSE - projected steepest edge;
 270.158 +         GLP_PT_DVX - Devex pricing (not implemented yet);
 270.159 +         in case of GLP_PT_STD the reference space is not used, and all
 270.160 +         steepest edge coefficients are set to 1 */
 270.161 +      int refct;
 270.162 +      /* this count is set to an initial value when the reference space
 270.163 +         is defined and decreases by one every time the basis changes;
 270.164 +         once this count reaches zero, the reference space is redefined
 270.165 +         again */
 270.166 +      char *refsp; /* char refsp[1+m+n]; */
 270.167 +      /* refsp[0] is not used;
 270.168 +         refsp[k], 1 <= k <= m+n, is the flag which means that variable
 270.169 +         x[k] belongs to the current reference space */
 270.170 +      double *gamma; /* double gamma[1+n]; */
 270.171 +      /* gamma[0] is not used;
 270.172 +         gamma[j], 1 <= j <= n, is the steepest edge coefficient for
 270.173 +         non-basic variable xN[j]; if xN[j] is fixed, gamma[j] is not
 270.174 +         used and just set to 1 */
 270.175 +      /*--------------------------------------------------------------*/
 270.176 +      /* non-basic variable xN[q] chosen to enter the basis */
 270.177 +      int q;
 270.178 +      /* index of the non-basic variable xN[q] chosen, 1 <= q <= n;
 270.179 +         if the set of eligible non-basic variables is empty and thus
 270.180 +         no variable has been chosen, q is set to 0 */
 270.181 +      /*--------------------------------------------------------------*/
 270.182 +      /* pivot column of the simplex table corresponding to non-basic
 270.183 +         variable xN[q] chosen is the following vector:
 270.184 +            T * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q],
 270.185 +         where B is the current basis matrix, N[q] is a column of the
 270.186 +         matrix (I|-A) corresponding to xN[q] */
 270.187 +      int tcol_nnz;
 270.188 +      /* number of non-zero components, 0 <= nnz <= m */
 270.189 +      int *tcol_ind; /* int tcol_ind[1+m]; */
 270.190 +      /* tcol_ind[0] is not used;
 270.191 +         tcol_ind[t], 1 <= t <= nnz, is an index of non-zero component,
 270.192 +         i.e. tcol_ind[t] = i means that tcol_vec[i] != 0 */
 270.193 +      double *tcol_vec; /* double tcol_vec[1+m]; */
 270.194 +      /* tcol_vec[0] is not used;
 270.195 +         tcol_vec[i], 1 <= i <= m, is a numeric value of i-th component
 270.196 +         of the column */
 270.197 +      double tcol_max;
 270.198 +      /* infinity (maximum) norm of the column (max |tcol_vec[i]|) */
 270.199 +      int tcol_num;
 270.200 +      /* number of significant non-zero components, which means that:
 270.201 +         |tcol_vec[i]| >= eps for i in tcol_ind[1,...,num],
 270.202 +         |tcol_vec[i]| <  eps for i in tcol_ind[num+1,...,nnz],
 270.203 +         where eps is a pivot tolerance */
 270.204 +      /*--------------------------------------------------------------*/
 270.205 +      /* basic variable xB[p] chosen to leave the basis */
 270.206 +      int p;
 270.207 +      /* index of the basic variable xB[p] chosen, 1 <= p <= m;
 270.208 +         p = 0 means that no basic variable reaches its bound;
 270.209 +         p < 0 means that non-basic variable xN[q] reaches its opposite
 270.210 +         bound before any basic variable */
 270.211 +      int p_stat;
 270.212 +      /* new status (GLP_NL, GLP_NU, or GLP_NS) to be assigned to xB[p]
 270.213 +         once it has left the basis */
 270.214 +      double teta;
 270.215 +      /* change of non-basic variable xN[q] (see above), on which xB[p]
 270.216 +         (or, if p < 0, xN[q] itself) reaches its bound */
 270.217 +      /*--------------------------------------------------------------*/
 270.218 +      /* pivot row of the simplex table corresponding to basic variable
 270.219 +         xB[p] chosen is the following vector:
 270.220 +            T' * e[p] = - N' * inv(B') * e[p] = - N' * rho,
 270.221 +         where B' is a matrix transposed to the current basis matrix,
 270.222 +         N' is a matrix, whose rows are columns of the matrix (I|-A)
 270.223 +         corresponding to non-basic non-fixed variables */
 270.224 +      int trow_nnz;
 270.225 +      /* number of non-zero components, 0 <= nnz <= n */
 270.226 +      int *trow_ind; /* int trow_ind[1+n]; */
 270.227 +      /* trow_ind[0] is not used;
 270.228 +         trow_ind[t], 1 <= t <= nnz, is an index of non-zero component,
 270.229 +         i.e. trow_ind[t] = j means that trow_vec[j] != 0 */
 270.230 +      double *trow_vec; /* int trow_vec[1+n]; */
 270.231 +      /* trow_vec[0] is not used;
 270.232 +         trow_vec[j], 1 <= j <= n, is a numeric value of j-th component
 270.233 +         of the row */
 270.234 +      /*--------------------------------------------------------------*/
 270.235 +      /* working arrays */
 270.236 +      double *work1; /* double work1[1+m]; */
 270.237 +      double *work2; /* double work2[1+m]; */
 270.238 +      double *work3; /* double work3[1+m]; */
 270.239 +      double *work4; /* double work4[1+m]; */
 270.240 +};
 270.241 +
 270.242 +static const double kappa = 0.10;
 270.243 +
 270.244 +/***********************************************************************
 270.245 +*  alloc_csa - allocate common storage area
 270.246 +*
 270.247 +*  This routine allocates all arrays in the common storage area (CSA)
 270.248 +*  and returns a pointer to the CSA. */
 270.249 +
 270.250 +static struct csa *alloc_csa(glp_prob *lp)
 270.251 +{     struct csa *csa;
 270.252 +      int m = lp->m;
 270.253 +      int n = lp->n;
 270.254 +      int nnz = lp->nnz;
 270.255 +      csa = xmalloc(sizeof(struct csa));
 270.256 +      xassert(m > 0 && n > 0);
 270.257 +      csa->m = m;
 270.258 +      csa->n = n;
 270.259 +      csa->type = xcalloc(1+m+n, sizeof(char));
 270.260 +      csa->lb = xcalloc(1+m+n, sizeof(double));
 270.261 +      csa->ub = xcalloc(1+m+n, sizeof(double));
 270.262 +      csa->coef = xcalloc(1+m+n, sizeof(double));
 270.263 +      csa->obj = xcalloc(1+n, sizeof(double));
 270.264 +      csa->A_ptr = xcalloc(1+n+1, sizeof(int));
 270.265 +      csa->A_ind = xcalloc(1+nnz, sizeof(int));
 270.266 +      csa->A_val = xcalloc(1+nnz, sizeof(double));
 270.267 +      csa->head = xcalloc(1+m+n, sizeof(int));
 270.268 +      csa->stat = xcalloc(1+n, sizeof(char));
 270.269 +      csa->N_ptr = xcalloc(1+m+1, sizeof(int));
 270.270 +      csa->N_len = xcalloc(1+m, sizeof(int));
 270.271 +      csa->N_ind = NULL; /* will be allocated later */
 270.272 +      csa->N_val = NULL; /* will be allocated later */
 270.273 +      csa->bbar = xcalloc(1+m, sizeof(double));
 270.274 +      csa->cbar = xcalloc(1+n, sizeof(double));
 270.275 +      csa->refsp = xcalloc(1+m+n, sizeof(char));
 270.276 +      csa->gamma = xcalloc(1+n, sizeof(double));
 270.277 +      csa->tcol_ind = xcalloc(1+m, sizeof(int));
 270.278 +      csa->tcol_vec = xcalloc(1+m, sizeof(double));
 270.279 +      csa->trow_ind = xcalloc(1+n, sizeof(int));
 270.280 +      csa->trow_vec = xcalloc(1+n, sizeof(double));
 270.281 +      csa->work1 = xcalloc(1+m, sizeof(double));
 270.282 +      csa->work2 = xcalloc(1+m, sizeof(double));
 270.283 +      csa->work3 = xcalloc(1+m, sizeof(double));
 270.284 +      csa->work4 = xcalloc(1+m, sizeof(double));
 270.285 +      return csa;
 270.286 +}
 270.287 +
 270.288 +/***********************************************************************
 270.289 +*  init_csa - initialize common storage area
 270.290 +*
 270.291 +*  This routine initializes all data structures in the common storage
 270.292 +*  area (CSA). */
 270.293 +
 270.294 +static void alloc_N(struct csa *csa);
 270.295 +static void build_N(struct csa *csa);
 270.296 +
 270.297 +static void init_csa(struct csa *csa, glp_prob *lp)
 270.298 +{     int m = csa->m;
 270.299 +      int n = csa->n;
 270.300 +      char *type = csa->type;
 270.301 +      double *lb = csa->lb;
 270.302 +      double *ub = csa->ub;
 270.303 +      double *coef = csa->coef;
 270.304 +      double *obj = csa->obj;
 270.305 +      int *A_ptr = csa->A_ptr;
 270.306 +      int *A_ind = csa->A_ind;
 270.307 +      double *A_val = csa->A_val;
 270.308 +      int *head = csa->head;
 270.309 +      char *stat = csa->stat;
 270.310 +      char *refsp = csa->refsp;
 270.311 +      double *gamma = csa->gamma;
 270.312 +      int i, j, k, loc;
 270.313 +      double cmax;
 270.314 +      /* auxiliary variables */
 270.315 +      for (i = 1; i <= m; i++)
 270.316 +      {  GLPROW *row = lp->row[i];
 270.317 +         type[i] = (char)row->type;
 270.318 +         lb[i] = row->lb * row->rii;
 270.319 +         ub[i] = row->ub * row->rii;
 270.320 +         coef[i] = 0.0;
 270.321 +      }
 270.322 +      /* structural variables */
 270.323 +      for (j = 1; j <= n; j++)
 270.324 +      {  GLPCOL *col = lp->col[j];
 270.325 +         type[m+j] = (char)col->type;
 270.326 +         lb[m+j] = col->lb / col->sjj;
 270.327 +         ub[m+j] = col->ub / col->sjj;
 270.328 +         coef[m+j] = col->coef * col->sjj;
 270.329 +      }
 270.330 +      /* original objective function */
 270.331 +      obj[0] = lp->c0;
 270.332 +      memcpy(&obj[1], &coef[m+1], n * sizeof(double));
 270.333 +      /* factor used to scale original objective coefficients */
 270.334 +      cmax = 0.0;
 270.335 +      for (j = 1; j <= n; j++)
 270.336 +         if (cmax < fabs(obj[j])) cmax = fabs(obj[j]);
 270.337 +      if (cmax == 0.0) cmax = 1.0;
 270.338 +      switch (lp->dir)
 270.339 +      {  case GLP_MIN:
 270.340 +            csa->zeta = + 1.0 / cmax;
 270.341 +            break;
 270.342 +         case GLP_MAX:
 270.343 +            csa->zeta = - 1.0 / cmax;
 270.344 +            break;
 270.345 +         default:
 270.346 +            xassert(lp != lp);
 270.347 +      }
 270.348 +#if 1
 270.349 +      if (fabs(csa->zeta) < 1.0) csa->zeta *= 1000.0;
 270.350 +#endif
 270.351 +      /* matrix A (by columns) */
 270.352 +      loc = 1;
 270.353 +      for (j = 1; j <= n; j++)
 270.354 +      {  GLPAIJ *aij;
 270.355 +         A_ptr[j] = loc;
 270.356 +         for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next)
 270.357 +         {  A_ind[loc] = aij->row->i;
 270.358 +            A_val[loc] = aij->row->rii * aij->val * aij->col->sjj;
 270.359 +            loc++;
 270.360 +         }
 270.361 +      }
 270.362 +      A_ptr[n+1] = loc;
 270.363 +      xassert(loc == lp->nnz+1);
 270.364 +      /* basis header */
 270.365 +      xassert(lp->valid);
 270.366 +      memcpy(&head[1], &lp->head[1], m * sizeof(int));
 270.367 +      k = 0;
 270.368 +      for (i = 1; i <= m; i++)
 270.369 +      {  GLPROW *row = lp->row[i];
 270.370 +         if (row->stat != GLP_BS)
 270.371 +         {  k++;
 270.372 +            xassert(k <= n);
 270.373 +            head[m+k] = i;
 270.374 +            stat[k] = (char)row->stat;
 270.375 +         }
 270.376 +      }
 270.377 +      for (j = 1; j <= n; j++)
 270.378 +      {  GLPCOL *col = lp->col[j];
 270.379 +         if (col->stat != GLP_BS)
 270.380 +         {  k++;
 270.381 +            xassert(k <= n);
 270.382 +            head[m+k] = m + j;
 270.383 +            stat[k] = (char)col->stat;
 270.384 +         }
 270.385 +      }
 270.386 +      xassert(k == n);
 270.387 +      /* factorization of matrix B */
 270.388 +      csa->valid = 1, lp->valid = 0;
 270.389 +      csa->bfd = lp->bfd, lp->bfd = NULL;
 270.390 +      /* matrix N (by rows) */
 270.391 +      alloc_N(csa);
 270.392 +      build_N(csa);
 270.393 +      /* working parameters */
 270.394 +      csa->phase = 0;
 270.395 +      csa->tm_beg = xtime();
 270.396 +      csa->it_beg = csa->it_cnt = lp->it_cnt;
 270.397 +      csa->it_dpy = -1;
 270.398 +      /* reference space and steepest edge coefficients */
 270.399 +      csa->refct = 0;
 270.400 +      memset(&refsp[1], 0, (m+n) * sizeof(char));
 270.401 +      for (j = 1; j <= n; j++) gamma[j] = 1.0;
 270.402 +      return;
 270.403 +}
 270.404 +
 270.405 +/***********************************************************************
 270.406 +*  invert_B - compute factorization of the basis matrix
 270.407 +*
 270.408 +*  This routine computes factorization of the current basis matrix B.
 270.409 +*
 270.410 +*  If the operation is successful, the routine returns zero, otherwise
 270.411 +*  non-zero. */
 270.412 +
 270.413 +static int inv_col(void *info, int i, int ind[], double val[])
 270.414 +{     /* this auxiliary routine returns row indices and numeric values
 270.415 +         of non-zero elements of i-th column of the basis matrix */
 270.416 +      struct csa *csa = info;
 270.417 +      int m = csa->m;
 270.418 +#ifdef GLP_DEBUG
 270.419 +      int n = csa->n;
 270.420 +#endif
 270.421 +      int *A_ptr = csa->A_ptr;
 270.422 +      int *A_ind = csa->A_ind;
 270.423 +      double *A_val = csa->A_val;
 270.424 +      int *head = csa->head;
 270.425 +      int k, len, ptr, t;
 270.426 +#ifdef GLP_DEBUG
 270.427 +      xassert(1 <= i && i <= m);
 270.428 +#endif
 270.429 +      k = head[i]; /* B[i] is k-th column of (I|-A) */
 270.430 +#ifdef GLP_DEBUG
 270.431 +      xassert(1 <= k && k <= m+n);
 270.432 +#endif
 270.433 +      if (k <= m)
 270.434 +      {  /* B[i] is k-th column of submatrix I */
 270.435 +         len = 1;
 270.436 +         ind[1] = k;
 270.437 +         val[1] = 1.0;
 270.438 +      }
 270.439 +      else
 270.440 +      {  /* B[i] is (k-m)-th column of submatrix (-A) */
 270.441 +         ptr = A_ptr[k-m];
 270.442 +         len = A_ptr[k-m+1] - ptr;
 270.443 +         memcpy(&ind[1], &A_ind[ptr], len * sizeof(int));
 270.444 +         memcpy(&val[1], &A_val[ptr], len * sizeof(double));
 270.445 +         for (t = 1; t <= len; t++) val[t] = - val[t];
 270.446 +      }
 270.447 +      return len;
 270.448 +}
 270.449 +
 270.450 +static int invert_B(struct csa *csa)
 270.451 +{     int ret;
 270.452 +      ret = bfd_factorize(csa->bfd, csa->m, NULL, inv_col, csa);
 270.453 +      csa->valid = (ret == 0);
 270.454 +      return ret;
 270.455 +}
 270.456 +
 270.457 +/***********************************************************************
 270.458 +*  update_B - update factorization of the basis matrix
 270.459 +*
 270.460 +*  This routine replaces i-th column of the basis matrix B by k-th
 270.461 +*  column of the augmented constraint matrix (I|-A) and then updates
 270.462 +*  the factorization of B.
 270.463 +*
 270.464 +*  If the factorization has been successfully updated, the routine
 270.465 +*  returns zero, otherwise non-zero. */
 270.466 +
 270.467 +static int update_B(struct csa *csa, int i, int k)
 270.468 +{     int m = csa->m;
 270.469 +#ifdef GLP_DEBUG
 270.470 +      int n = csa->n;
 270.471 +#endif
 270.472 +      int ret;
 270.473 +#ifdef GLP_DEBUG
 270.474 +      xassert(1 <= i && i <= m);
 270.475 +      xassert(1 <= k && k <= m+n);
 270.476 +#endif
 270.477 +      if (k <= m)
 270.478 +      {  /* new i-th column of B is k-th column of I */
 270.479 +         int ind[1+1];
 270.480 +         double val[1+1];
 270.481 +         ind[1] = k;
 270.482 +         val[1] = 1.0;
 270.483 +         xassert(csa->valid);
 270.484 +         ret = bfd_update_it(csa->bfd, i, 0, 1, ind, val);
 270.485 +      }
 270.486 +      else
 270.487 +      {  /* new i-th column of B is (k-m)-th column of (-A) */
 270.488 +         int *A_ptr = csa->A_ptr;
 270.489 +         int *A_ind = csa->A_ind;
 270.490 +         double *A_val = csa->A_val;
 270.491 +         double *val = csa->work1;
 270.492 +         int beg, end, ptr, len;
 270.493 +         beg = A_ptr[k-m];
 270.494 +         end = A_ptr[k-m+1];
 270.495 +         len = 0;
 270.496 +         for (ptr = beg; ptr < end; ptr++)
 270.497 +            val[++len] = - A_val[ptr];
 270.498 +         xassert(csa->valid);
 270.499 +         ret = bfd_update_it(csa->bfd, i, 0, len, &A_ind[beg-1], val);
 270.500 +      }
 270.501 +      csa->valid = (ret == 0);
 270.502 +      return ret;
 270.503 +}
 270.504 +
 270.505 +/***********************************************************************
 270.506 +*  error_ftran - compute residual vector r = h - B * x
 270.507 +*
 270.508 +*  This routine computes the residual vector r = h - B * x, where B is
 270.509 +*  the current basis matrix, h is the vector of right-hand sides, x is
 270.510 +*  the solution vector. */
 270.511 +
 270.512 +static void error_ftran(struct csa *csa, double h[], double x[],
 270.513 +      double r[])
 270.514 +{     int m = csa->m;
 270.515 +#ifdef GLP_DEBUG
 270.516 +      int n = csa->n;
 270.517 +#endif
 270.518 +      int *A_ptr = csa->A_ptr;
 270.519 +      int *A_ind = csa->A_ind;
 270.520 +      double *A_val = csa->A_val;
 270.521 +      int *head = csa->head;
 270.522 +      int i, k, beg, end, ptr;
 270.523 +      double temp;
 270.524 +      /* compute the residual vector:
 270.525 +         r = h - B * x = h - B[1] * x[1] - ... - B[m] * x[m],
 270.526 +         where B[1], ..., B[m] are columns of matrix B */
 270.527 +      memcpy(&r[1], &h[1], m * sizeof(double));
 270.528 +      for (i = 1; i <= m; i++)
 270.529 +      {  temp = x[i];
 270.530 +         if (temp == 0.0) continue;
 270.531 +         k = head[i]; /* B[i] is k-th column of (I|-A) */
 270.532 +#ifdef GLP_DEBUG
 270.533 +         xassert(1 <= k && k <= m+n);
 270.534 +#endif
 270.535 +         if (k <= m)
 270.536 +         {  /* B[i] is k-th column of submatrix I */
 270.537 +            r[k] -= temp;
 270.538 +         }
 270.539 +         else
 270.540 +         {  /* B[i] is (k-m)-th column of submatrix (-A) */
 270.541 +            beg = A_ptr[k-m];
 270.542 +            end = A_ptr[k-m+1];
 270.543 +            for (ptr = beg; ptr < end; ptr++)
 270.544 +               r[A_ind[ptr]] += A_val[ptr] * temp;
 270.545 +         }
 270.546 +      }
 270.547 +      return;
 270.548 +}
 270.549 +
 270.550 +/***********************************************************************
 270.551 +*  refine_ftran - refine solution of B * x = h
 270.552 +*
 270.553 +*  This routine performs one iteration to refine the solution of
 270.554 +*  the system B * x = h, where B is the current basis matrix, h is the
 270.555 +*  vector of right-hand sides, x is the solution vector. */
 270.556 +
 270.557 +static void refine_ftran(struct csa *csa, double h[], double x[])
 270.558 +{     int m = csa->m;
 270.559 +      double *r = csa->work1;
 270.560 +      double *d = csa->work1;
 270.561 +      int i;
 270.562 +      /* compute the residual vector r = h - B * x */
 270.563 +      error_ftran(csa, h, x, r);
 270.564 +      /* compute the correction vector d = inv(B) * r */
 270.565 +      xassert(csa->valid);
 270.566 +      bfd_ftran(csa->bfd, d);
 270.567 +      /* refine the solution vector (new x) = (old x) + d */
 270.568 +      for (i = 1; i <= m; i++) x[i] += d[i];
 270.569 +      return;
 270.570 +}
 270.571 +
 270.572 +/***********************************************************************
 270.573 +*  error_btran - compute residual vector r = h - B'* x
 270.574 +*
 270.575 +*  This routine computes the residual vector r = h - B'* x, where B'
 270.576 +*  is a matrix transposed to the current basis matrix, h is the vector
 270.577 +*  of right-hand sides, x is the solution vector. */
 270.578 +
 270.579 +static void error_btran(struct csa *csa, double h[], double x[],
 270.580 +      double r[])
 270.581 +{     int m = csa->m;
 270.582 +#ifdef GLP_DEBUG
 270.583 +      int n = csa->n;
 270.584 +#endif
 270.585 +      int *A_ptr = csa->A_ptr;
 270.586 +      int *A_ind = csa->A_ind;
 270.587 +      double *A_val = csa->A_val;
 270.588 +      int *head = csa->head;
 270.589 +      int i, k, beg, end, ptr;
 270.590 +      double temp;
 270.591 +      /* compute the residual vector r = b - B'* x */
 270.592 +      for (i = 1; i <= m; i++)
 270.593 +      {  /* r[i] := b[i] - (i-th column of B)'* x */
 270.594 +         k = head[i]; /* B[i] is k-th column of (I|-A) */
 270.595 +#ifdef GLP_DEBUG
 270.596 +         xassert(1 <= k && k <= m+n);
 270.597 +#endif
 270.598 +         temp = h[i];
 270.599 +         if (k <= m)
 270.600 +         {  /* B[i] is k-th column of submatrix I */
 270.601 +            temp -= x[k];
 270.602 +         }
 270.603 +         else
 270.604 +         {  /* B[i] is (k-m)-th column of submatrix (-A) */
 270.605 +            beg = A_ptr[k-m];
 270.606 +            end = A_ptr[k-m+1];
 270.607 +            for (ptr = beg; ptr < end; ptr++)
 270.608 +               temp += A_val[ptr] * x[A_ind[ptr]];
 270.609 +         }
 270.610 +         r[i] = temp;
 270.611 +      }
 270.612 +      return;
 270.613 +}
 270.614 +
 270.615 +/***********************************************************************
 270.616 +*  refine_btran - refine solution of B'* x = h
 270.617 +*
 270.618 +*  This routine performs one iteration to refine the solution of the
 270.619 +*  system B'* x = h, where B' is a matrix transposed to the current
 270.620 +*  basis matrix, h is the vector of right-hand sides, x is the solution
 270.621 +*  vector. */
 270.622 +
 270.623 +static void refine_btran(struct csa *csa, double h[], double x[])
 270.624 +{     int m = csa->m;
 270.625 +      double *r = csa->work1;
 270.626 +      double *d = csa->work1;
 270.627 +      int i;
 270.628 +      /* compute the residual vector r = h - B'* x */
 270.629 +      error_btran(csa, h, x, r);
 270.630 +      /* compute the correction vector d = inv(B') * r */
 270.631 +      xassert(csa->valid);
 270.632 +      bfd_btran(csa->bfd, d);
 270.633 +      /* refine the solution vector (new x) = (old x) + d */
 270.634 +      for (i = 1; i <= m; i++) x[i] += d[i];
 270.635 +      return;
 270.636 +}
 270.637 +
 270.638 +/***********************************************************************
 270.639 +*  alloc_N - allocate matrix N
 270.640 +*
 270.641 +*  This routine determines maximal row lengths of matrix N, sets its
 270.642 +*  row pointers, and then allocates arrays N_ind and N_val.
 270.643 +*
 270.644 +*  Note that some fixed structural variables may temporarily become
 270.645 +*  double-bounded, so corresponding columns of matrix A should not be
 270.646 +*  ignored on calculating maximal row lengths of matrix N. */
 270.647 +
 270.648 +static void alloc_N(struct csa *csa)
 270.649 +{     int m = csa->m;
 270.650 +      int n = csa->n;
 270.651 +      int *A_ptr = csa->A_ptr;
 270.652 +      int *A_ind = csa->A_ind;
 270.653 +      int *N_ptr = csa->N_ptr;
 270.654 +      int *N_len = csa->N_len;
 270.655 +      int i, j, beg, end, ptr;
 270.656 +      /* determine number of non-zeros in each row of the augmented
 270.657 +         constraint matrix (I|-A) */
 270.658 +      for (i = 1; i <= m; i++)
 270.659 +         N_len[i] = 1;
 270.660 +      for (j = 1; j <= n; j++)
 270.661 +      {  beg = A_ptr[j];
 270.662 +         end = A_ptr[j+1];
 270.663 +         for (ptr = beg; ptr < end; ptr++)
 270.664 +            N_len[A_ind[ptr]]++;
 270.665 +      }
 270.666 +      /* determine maximal row lengths of matrix N and set its row
 270.667 +         pointers */
 270.668 +      N_ptr[1] = 1;
 270.669 +      for (i = 1; i <= m; i++)
 270.670 +      {  /* row of matrix N cannot have more than n non-zeros */
 270.671 +         if (N_len[i] > n) N_len[i] = n;
 270.672 +         N_ptr[i+1] = N_ptr[i] + N_len[i];
 270.673 +      }
 270.674 +      /* now maximal number of non-zeros in matrix N is known */
 270.675 +      csa->N_ind = xcalloc(N_ptr[m+1], sizeof(int));
 270.676 +      csa->N_val = xcalloc(N_ptr[m+1], sizeof(double));
 270.677 +      return;
 270.678 +}
 270.679 +
 270.680 +/***********************************************************************
 270.681 +*  add_N_col - add column of matrix (I|-A) to matrix N
 270.682 +*
 270.683 +*  This routine adds j-th column to matrix N which is k-th column of
 270.684 +*  the augmented constraint matrix (I|-A). (It is assumed that old j-th
 270.685 +*  column was previously removed from matrix N.) */
 270.686 +
 270.687 +static void add_N_col(struct csa *csa, int j, int k)
 270.688 +{     int m = csa->m;
 270.689 +#ifdef GLP_DEBUG
 270.690 +      int n = csa->n;
 270.691 +#endif
 270.692 +      int *N_ptr = csa->N_ptr;
 270.693 +      int *N_len = csa->N_len;
 270.694 +      int *N_ind = csa->N_ind;
 270.695 +      double *N_val = csa->N_val;
 270.696 +      int pos;
 270.697 +#ifdef GLP_DEBUG
 270.698 +      xassert(1 <= j && j <= n);
 270.699 +      xassert(1 <= k && k <= m+n);
 270.700 +#endif
 270.701 +      if (k <= m)
 270.702 +      {  /* N[j] is k-th column of submatrix I */
 270.703 +         pos = N_ptr[k] + (N_len[k]++);
 270.704 +#ifdef GLP_DEBUG
 270.705 +         xassert(pos < N_ptr[k+1]);
 270.706 +#endif
 270.707 +         N_ind[pos] = j;
 270.708 +         N_val[pos] = 1.0;
 270.709 +      }
 270.710 +      else
 270.711 +      {  /* N[j] is (k-m)-th column of submatrix (-A) */
 270.712 +         int *A_ptr = csa->A_ptr;
 270.713 +         int *A_ind = csa->A_ind;
 270.714 +         double *A_val = csa->A_val;
 270.715 +         int i, beg, end, ptr;
 270.716 +         beg = A_ptr[k-m];
 270.717 +         end = A_ptr[k-m+1];
 270.718 +         for (ptr = beg; ptr < end; ptr++)
 270.719 +         {  i = A_ind[ptr]; /* row number */
 270.720 +            pos = N_ptr[i] + (N_len[i]++);
 270.721 +#ifdef GLP_DEBUG
 270.722 +            xassert(pos < N_ptr[i+1]);
 270.723 +#endif
 270.724 +            N_ind[pos] = j;
 270.725 +            N_val[pos] = - A_val[ptr];
 270.726 +         }
 270.727 +      }
 270.728 +      return;
 270.729 +}
 270.730 +
 270.731 +/***********************************************************************
 270.732 +*  del_N_col - remove column of matrix (I|-A) from matrix N
 270.733 +*
 270.734 +*  This routine removes j-th column from matrix N which is k-th column
 270.735 +*  of the augmented constraint matrix (I|-A). */
 270.736 +
 270.737 +static void del_N_col(struct csa *csa, int j, int k)
 270.738 +{     int m = csa->m;
 270.739 +#ifdef GLP_DEBUG
 270.740 +      int n = csa->n;
 270.741 +#endif
 270.742 +      int *N_ptr = csa->N_ptr;
 270.743 +      int *N_len = csa->N_len;
 270.744 +      int *N_ind = csa->N_ind;
 270.745 +      double *N_val = csa->N_val;
 270.746 +      int pos, head, tail;
 270.747 +#ifdef GLP_DEBUG
 270.748 +      xassert(1 <= j && j <= n);
 270.749 +      xassert(1 <= k && k <= m+n);
 270.750 +#endif
 270.751 +      if (k <= m)
 270.752 +      {  /* N[j] is k-th column of submatrix I */
 270.753 +         /* find element in k-th row of N */
 270.754 +         head = N_ptr[k];
 270.755 +         for (pos = head; N_ind[pos] != j; pos++) /* nop */;
 270.756 +         /* and remove it from the row list */
 270.757 +         tail = head + (--N_len[k]);
 270.758 +#ifdef GLP_DEBUG
 270.759 +         xassert(pos <= tail);
 270.760 +#endif
 270.761 +         N_ind[pos] = N_ind[tail];
 270.762 +         N_val[pos] = N_val[tail];
 270.763 +      }
 270.764 +      else
 270.765 +      {  /* N[j] is (k-m)-th column of submatrix (-A) */
 270.766 +         int *A_ptr = csa->A_ptr;
 270.767 +         int *A_ind = csa->A_ind;
 270.768 +         int i, beg, end, ptr;
 270.769 +         beg = A_ptr[k-m];
 270.770 +         end = A_ptr[k-m+1];
 270.771 +         for (ptr = beg; ptr < end; ptr++)
 270.772 +         {  i = A_ind[ptr]; /* row number */
 270.773 +            /* find element in i-th row of N */
 270.774 +            head = N_ptr[i];
 270.775 +            for (pos = head; N_ind[pos] != j; pos++) /* nop */;
 270.776 +            /* and remove it from the row list */
 270.777 +            tail = head + (--N_len[i]);
 270.778 +#ifdef GLP_DEBUG
 270.779 +            xassert(pos <= tail);
 270.780 +#endif
 270.781 +            N_ind[pos] = N_ind[tail];
 270.782 +            N_val[pos] = N_val[tail];
 270.783 +         }
 270.784 +      }
 270.785 +      return;
 270.786 +}
 270.787 +
 270.788 +/***********************************************************************
 270.789 +*  build_N - build matrix N for current basis
 270.790 +*
 270.791 +*  This routine builds matrix N for the current basis from columns
 270.792 +*  of the augmented constraint matrix (I|-A) corresponding to non-basic
 270.793 +*  non-fixed variables. */
 270.794 +
 270.795 +static void build_N(struct csa *csa)
 270.796 +{     int m = csa->m;
 270.797 +      int n = csa->n;
 270.798 +      int *head = csa->head;
 270.799 +      char *stat = csa->stat;
 270.800 +      int *N_len = csa->N_len;
 270.801 +      int j, k;
 270.802 +      /* N := empty matrix */
 270.803 +      memset(&N_len[1], 0, m * sizeof(int));
 270.804 +      /* go through non-basic columns of matrix (I|-A) */
 270.805 +      for (j = 1; j <= n; j++)
 270.806 +      {  if (stat[j] != GLP_NS)
 270.807 +         {  /* xN[j] is non-fixed; add j-th column to matrix N which is
 270.808 +               k-th column of matrix (I|-A) */
 270.809 +            k = head[m+j]; /* x[k] = xN[j] */
 270.810 +#ifdef GLP_DEBUG
 270.811 +            xassert(1 <= k && k <= m+n);
 270.812 +#endif
 270.813 +            add_N_col(csa, j, k);
 270.814 +         }
 270.815 +      }
 270.816 +      return;
 270.817 +}
 270.818 +
 270.819 +/***********************************************************************
 270.820 +*  get_xN - determine current value of non-basic variable xN[j]
 270.821 +*
 270.822 +*  This routine returns the current value of non-basic variable xN[j],
 270.823 +*  which is a value of its active bound. */
 270.824 +
 270.825 +static double get_xN(struct csa *csa, int j)
 270.826 +{     int m = csa->m;
 270.827 +#ifdef GLP_DEBUG
 270.828 +      int n = csa->n;
 270.829 +#endif
 270.830 +      double *lb = csa->lb;
 270.831 +      double *ub = csa->ub;
 270.832 +      int *head = csa->head;
 270.833 +      char *stat = csa->stat;
 270.834 +      int k;
 270.835 +      double xN;
 270.836 +#ifdef GLP_DEBUG
 270.837 +      xassert(1 <= j && j <= n);
 270.838 +#endif
 270.839 +      k = head[m+j]; /* x[k] = xN[j] */
 270.840 +#ifdef GLP_DEBUG
 270.841 +      xassert(1 <= k && k <= m+n);
 270.842 +#endif
 270.843 +      switch (stat[j])
 270.844 +      {  case GLP_NL:
 270.845 +            /* x[k] is on its lower bound */
 270.846 +            xN = lb[k]; break;
 270.847 +         case GLP_NU:
 270.848 +            /* x[k] is on its upper bound */
 270.849 +            xN = ub[k]; break;
 270.850 +         case GLP_NF:
 270.851 +            /* x[k] is free non-basic variable */
 270.852 +            xN = 0.0; break;
 270.853 +         case GLP_NS:
 270.854 +            /* x[k] is fixed non-basic variable */
 270.855 +            xN = lb[k]; break;
 270.856 +         default:
 270.857 +            xassert(stat != stat);
 270.858 +      }
 270.859 +      return xN;
 270.860 +}
 270.861 +
 270.862 +/***********************************************************************
 270.863 +*  eval_beta - compute primal values of basic variables
 270.864 +*
 270.865 +*  This routine computes current primal values of all basic variables:
 270.866 +*
 270.867 +*     beta = - inv(B) * N * xN,
 270.868 +*
 270.869 +*  where B is the current basis matrix, N is a matrix built of columns
 270.870 +*  of matrix (I|-A) corresponding to non-basic variables, and xN is the
 270.871 +*  vector of current values of non-basic variables. */
 270.872 +
 270.873 +static void eval_beta(struct csa *csa, double beta[])
 270.874 +{     int m = csa->m;
 270.875 +      int n = csa->n;
 270.876 +      int *A_ptr = csa->A_ptr;
 270.877 +      int *A_ind = csa->A_ind;
 270.878 +      double *A_val = csa->A_val;
 270.879 +      int *head = csa->head;
 270.880 +      double *h = csa->work2;
 270.881 +      int i, j, k, beg, end, ptr;
 270.882 +      double xN;
 270.883 +      /* compute the right-hand side vector:
 270.884 +         h := - N * xN = - N[1] * xN[1] - ... - N[n] * xN[n],
 270.885 +         where N[1], ..., N[n] are columns of matrix N */
 270.886 +      for (i = 1; i <= m; i++)
 270.887 +         h[i] = 0.0;
 270.888 +      for (j = 1; j <= n; j++)
 270.889 +      {  k = head[m+j]; /* x[k] = xN[j] */
 270.890 +#ifdef GLP_DEBUG
 270.891 +         xassert(1 <= k && k <= m+n);
 270.892 +#endif
 270.893 +         /* determine current value of xN[j] */
 270.894 +         xN = get_xN(csa, j);
 270.895 +         if (xN == 0.0) continue;
 270.896 +         if (k <= m)
 270.897 +         {  /* N[j] is k-th column of submatrix I */
 270.898 +            h[k] -= xN;
 270.899 +         }
 270.900 +         else
 270.901 +         {  /* N[j] is (k-m)-th column of submatrix (-A) */
 270.902 +            beg = A_ptr[k-m];
 270.903 +            end = A_ptr[k-m+1];
 270.904 +            for (ptr = beg; ptr < end; ptr++)
 270.905 +               h[A_ind[ptr]] += xN * A_val[ptr];
 270.906 +         }
 270.907 +      }
 270.908 +      /* solve system B * beta = h */
 270.909 +      memcpy(&beta[1], &h[1], m * sizeof(double));
 270.910 +      xassert(csa->valid);
 270.911 +      bfd_ftran(csa->bfd, beta);
 270.912 +      /* and refine the solution */
 270.913 +      refine_ftran(csa, h, beta);
 270.914 +      return;
 270.915 +}
 270.916 +
 270.917 +/***********************************************************************
 270.918 +*  eval_pi - compute vector of simplex multipliers
 270.919 +*
 270.920 +*  This routine computes the vector of current simplex multipliers:
 270.921 +*
 270.922 +*     pi = inv(B') * cB,
 270.923 +*
 270.924 +*  where B' is a matrix transposed to the current basis matrix, cB is
 270.925 +*  a subvector of objective coefficients at basic variables. */
 270.926 +
 270.927 +static void eval_pi(struct csa *csa, double pi[])
 270.928 +{     int m = csa->m;
 270.929 +      double *c = csa->coef;
 270.930 +      int *head = csa->head;
 270.931 +      double *cB = csa->work2;
 270.932 +      int i;
 270.933 +      /* construct the right-hand side vector cB */
 270.934 +      for (i = 1; i <= m; i++)
 270.935 +         cB[i] = c[head[i]];
 270.936 +      /* solve system B'* pi = cB */
 270.937 +      memcpy(&pi[1], &cB[1], m * sizeof(double));
 270.938 +      xassert(csa->valid);
 270.939 +      bfd_btran(csa->bfd, pi);
 270.940 +      /* and refine the solution */
 270.941 +      refine_btran(csa, cB, pi);
 270.942 +      return;
 270.943 +}
 270.944 +
 270.945 +/***********************************************************************
 270.946 +*  eval_cost - compute reduced cost of non-basic variable xN[j]
 270.947 +*
 270.948 +*  This routine computes the current reduced cost of non-basic variable
 270.949 +*  xN[j]:
 270.950 +*
 270.951 +*     d[j] = cN[j] - N'[j] * pi,
 270.952 +*
 270.953 +*  where cN[j] is the objective coefficient at variable xN[j], N[j] is
 270.954 +*  a column of the augmented constraint matrix (I|-A) corresponding to
 270.955 +*  xN[j], pi is the vector of simplex multipliers. */
 270.956 +
 270.957 +static double eval_cost(struct csa *csa, double pi[], int j)
 270.958 +{     int m = csa->m;
 270.959 +#ifdef GLP_DEBUG
 270.960 +      int n = csa->n;
 270.961 +#endif
 270.962 +      double *coef = csa->coef;
 270.963 +      int *head = csa->head;
 270.964 +      int k;
 270.965 +      double dj;
 270.966 +#ifdef GLP_DEBUG
 270.967 +      xassert(1 <= j && j <= n);
 270.968 +#endif
 270.969 +      k = head[m+j]; /* x[k] = xN[j] */
 270.970 +#ifdef GLP_DEBUG
 270.971 +      xassert(1 <= k && k <= m+n);
 270.972 +#endif
 270.973 +      dj = coef[k];
 270.974 +      if (k <= m)
 270.975 +      {  /* N[j] is k-th column of submatrix I */
 270.976 +         dj -= pi[k];
 270.977 +      }
 270.978 +      else
 270.979 +      {  /* N[j] is (k-m)-th column of submatrix (-A) */
 270.980 +         int *A_ptr = csa->A_ptr;
 270.981 +         int *A_ind = csa->A_ind;
 270.982 +         double *A_val = csa->A_val;
 270.983 +         int beg, end, ptr;
 270.984 +         beg = A_ptr[k-m];
 270.985 +         end = A_ptr[k-m+1];
 270.986 +         for (ptr = beg; ptr < end; ptr++)
 270.987 +            dj += A_val[ptr] * pi[A_ind[ptr]];
 270.988 +      }
 270.989 +      return dj;
 270.990 +}
 270.991 +
 270.992 +/***********************************************************************
 270.993 +*  eval_bbar - compute and store primal values of basic variables
 270.994 +*
 270.995 +*  This routine computes primal values of all basic variables and then
 270.996 +*  stores them in the solution array. */
 270.997 +
 270.998 +static void eval_bbar(struct csa *csa)
 270.999 +{     eval_beta(csa, csa->bbar);
270.1000 +      return;
270.1001 +}
270.1002 +
270.1003 +/***********************************************************************
270.1004 +*  eval_cbar - compute and store reduced costs of non-basic variables
270.1005 +*
270.1006 +*  This routine computes reduced costs of all non-basic variables and
270.1007 +*  then stores them in the solution array. */
270.1008 +
270.1009 +static void eval_cbar(struct csa *csa)
270.1010 +{
270.1011 +#ifdef GLP_DEBUG
270.1012 +      int m = csa->m;
270.1013 +#endif
270.1014 +      int n = csa->n;
270.1015 +#ifdef GLP_DEBUG
270.1016 +      int *head = csa->head;
270.1017 +#endif
270.1018 +      double *cbar = csa->cbar;
270.1019 +      double *pi = csa->work3;
270.1020 +      int j;
270.1021 +#ifdef GLP_DEBUG
270.1022 +      int k;
270.1023 +#endif
270.1024 +      /* compute simplex multipliers */
270.1025 +      eval_pi(csa, pi);
270.1026 +      /* compute and store reduced costs */
270.1027 +      for (j = 1; j <= n; j++)
270.1028 +      {
270.1029 +#ifdef GLP_DEBUG
270.1030 +         k = head[m+j]; /* x[k] = xN[j] */
270.1031 +         xassert(1 <= k && k <= m+n);
270.1032 +#endif
270.1033 +         cbar[j] = eval_cost(csa, pi, j);
270.1034 +      }
270.1035 +      return;
270.1036 +}
270.1037 +
270.1038 +/***********************************************************************
270.1039 +*  reset_refsp - reset the reference space
270.1040 +*
270.1041 +*  This routine resets (redefines) the reference space used in the
270.1042 +*  projected steepest edge pricing algorithm. */
270.1043 +
270.1044 +static void reset_refsp(struct csa *csa)
270.1045 +{     int m = csa->m;
270.1046 +      int n = csa->n;
270.1047 +      int *head = csa->head;
270.1048 +      char *refsp = csa->refsp;
270.1049 +      double *gamma = csa->gamma;
270.1050 +      int j, k;
270.1051 +      xassert(csa->refct == 0);
270.1052 +      csa->refct = 1000;
270.1053 +      memset(&refsp[1], 0, (m+n) * sizeof(char));
270.1054 +      for (j = 1; j <= n; j++)
270.1055 +      {  k = head[m+j]; /* x[k] = xN[j] */
270.1056 +         refsp[k] = 1;
270.1057 +         gamma[j] = 1.0;
270.1058 +      }
270.1059 +      return;
270.1060 +}
270.1061 +
270.1062 +/***********************************************************************
270.1063 +*  eval_gamma - compute steepest edge coefficient
270.1064 +*
270.1065 +*  This routine computes the steepest edge coefficient for non-basic
270.1066 +*  variable xN[j] using its direct definition:
270.1067 +*
270.1068 +*     gamma[j] = delta[j] +  sum   alfa[i,j]^2,
270.1069 +*                           i in R
270.1070 +*
270.1071 +*  where delta[j] = 1, if xN[j] is in the current reference space,
270.1072 +*  and 0 otherwise; R is a set of basic variables xB[i], which are in
270.1073 +*  the current reference space; alfa[i,j] are elements of the current
270.1074 +*  simplex table.
270.1075 +*
270.1076 +*  NOTE: The routine is intended only for debugginig purposes. */
270.1077 +
270.1078 +static double eval_gamma(struct csa *csa, int j)
270.1079 +{     int m = csa->m;
270.1080 +#ifdef GLP_DEBUG
270.1081 +      int n = csa->n;
270.1082 +#endif
270.1083 +      int *head = csa->head;
270.1084 +      char *refsp = csa->refsp;
270.1085 +      double *alfa = csa->work3;
270.1086 +      double *h = csa->work3;
270.1087 +      int i, k;
270.1088 +      double gamma;
270.1089 +#ifdef GLP_DEBUG
270.1090 +      xassert(1 <= j && j <= n);
270.1091 +#endif
270.1092 +      k = head[m+j]; /* x[k] = xN[j] */
270.1093 +#ifdef GLP_DEBUG
270.1094 +      xassert(1 <= k && k <= m+n);
270.1095 +#endif
270.1096 +      /* construct the right-hand side vector h = - N[j] */
270.1097 +      for (i = 1; i <= m; i++)
270.1098 +         h[i] = 0.0;
270.1099 +      if (k <= m)
270.1100 +      {  /* N[j] is k-th column of submatrix I */
270.1101 +         h[k] = -1.0;
270.1102 +      }
270.1103 +      else
270.1104 +      {  /* N[j] is (k-m)-th column of submatrix (-A) */
270.1105 +         int *A_ptr = csa->A_ptr;
270.1106 +         int *A_ind = csa->A_ind;
270.1107 +         double *A_val = csa->A_val;
270.1108 +         int beg, end, ptr;
270.1109 +         beg = A_ptr[k-m];
270.1110 +         end = A_ptr[k-m+1];
270.1111 +         for (ptr = beg; ptr < end; ptr++)
270.1112 +            h[A_ind[ptr]] = A_val[ptr];
270.1113 +      }
270.1114 +      /* solve system B * alfa = h */
270.1115 +      xassert(csa->valid);
270.1116 +      bfd_ftran(csa->bfd, alfa);
270.1117 +      /* compute gamma */
270.1118 +      gamma = (refsp[k] ? 1.0 : 0.0);
270.1119 +      for (i = 1; i <= m; i++)
270.1120 +      {  k = head[i];
270.1121 +#ifdef GLP_DEBUG
270.1122 +         xassert(1 <= k && k <= m+n);
270.1123 +#endif
270.1124 +         if (refsp[k]) gamma += alfa[i] * alfa[i];
270.1125 +      }
270.1126 +      return gamma;
270.1127 +}
270.1128 +
270.1129 +/***********************************************************************
270.1130 +*  chuzc - choose non-basic variable (column of the simplex table)
270.1131 +*
270.1132 +*  This routine chooses non-basic variable xN[q], which has largest
270.1133 +*  weighted reduced cost:
270.1134 +*
270.1135 +*     |d[q]| / sqrt(gamma[q]) = max  |d[j]| / sqrt(gamma[j]),
270.1136 +*                              j in J
270.1137 +*
270.1138 +*  where J is a subset of eligible non-basic variables xN[j], d[j] is
270.1139 +*  reduced cost of xN[j], gamma[j] is the steepest edge coefficient.
270.1140 +*
270.1141 +*  The working objective function is always minimized, so the sign of
270.1142 +*  d[q] determines direction, in which xN[q] has to change:
270.1143 +*
270.1144 +*     if d[q] < 0, xN[q] has to increase;
270.1145 +*
270.1146 +*     if d[q] > 0, xN[q] has to decrease.
270.1147 +*
270.1148 +*  If |d[j]| <= tol_dj, where tol_dj is a specified tolerance, xN[j]
270.1149 +*  is not included in J and therefore ignored. (It is assumed that the
270.1150 +*  working objective row is appropriately scaled, i.e. max|c[k]| = 1.)
270.1151 +*
270.1152 +*  If J is empty and no variable has been chosen, q is set to 0. */
270.1153 +
270.1154 +static void chuzc(struct csa *csa, double tol_dj)
270.1155 +{     int n = csa->n;
270.1156 +      char *stat = csa->stat;
270.1157 +      double *cbar = csa->cbar;
270.1158 +      double *gamma = csa->gamma;
270.1159 +      int j, q;
270.1160 +      double dj, best, temp;
270.1161 +      /* nothing is chosen so far */
270.1162 +      q = 0, best = 0.0;
270.1163 +      /* look through the list of non-basic variables */
270.1164 +      for (j = 1; j <= n; j++)
270.1165 +      {  dj = cbar[j];
270.1166 +         switch (stat[j])
270.1167 +         {  case GLP_NL:
270.1168 +               /* xN[j] can increase */
270.1169 +               if (dj >= - tol_dj) continue;
270.1170 +               break;
270.1171 +            case GLP_NU:
270.1172 +               /* xN[j] can decrease */
270.1173 +               if (dj <= + tol_dj) continue;
270.1174 +               break;
270.1175 +            case GLP_NF:
270.1176 +               /* xN[j] can change in any direction */
270.1177 +               if (- tol_dj <= dj && dj <= + tol_dj) continue;
270.1178 +               break;
270.1179 +            case GLP_NS:
270.1180 +               /* xN[j] cannot change at all */
270.1181 +               continue;
270.1182 +            default:
270.1183 +               xassert(stat != stat);
270.1184 +         }
270.1185 +         /* xN[j] is eligible non-basic variable; choose one which has
270.1186 +            largest weighted reduced cost */
270.1187 +#ifdef GLP_DEBUG
270.1188 +         xassert(gamma[j] > 0.0);
270.1189 +#endif
270.1190 +         temp = (dj * dj) / gamma[j];
270.1191 +         if (best < temp)
270.1192 +            q = j, best = temp;
270.1193 +      }
270.1194 +      /* store the index of non-basic variable xN[q] chosen */
270.1195 +      csa->q = q;
270.1196 +      return;
270.1197 +}
270.1198 +
270.1199 +/***********************************************************************
270.1200 +*  eval_tcol - compute pivot column of the simplex table
270.1201 +*
270.1202 +*  This routine computes the pivot column of the simplex table, which
270.1203 +*  corresponds to non-basic variable xN[q] chosen.
270.1204 +*
270.1205 +*  The pivot column is the following vector:
270.1206 +*
270.1207 +*     tcol = T * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q],
270.1208 +*
270.1209 +*  where B is the current basis matrix, N[q] is a column of the matrix
270.1210 +*  (I|-A) corresponding to variable xN[q]. */
270.1211 +
270.1212 +static void eval_tcol(struct csa *csa)
270.1213 +{     int m = csa->m;
270.1214 +#ifdef GLP_DEBUG
270.1215 +      int n = csa->n;
270.1216 +#endif
270.1217 +      int *head = csa->head;
270.1218 +      int q = csa->q;
270.1219 +      int *tcol_ind = csa->tcol_ind;
270.1220 +      double *tcol_vec = csa->tcol_vec;
270.1221 +      double *h = csa->tcol_vec;
270.1222 +      int i, k, nnz;
270.1223 +#ifdef GLP_DEBUG
270.1224 +      xassert(1 <= q && q <= n);
270.1225 +#endif
270.1226 +      k = head[m+q]; /* x[k] = xN[q] */
270.1227 +#ifdef GLP_DEBUG
270.1228 +      xassert(1 <= k && k <= m+n);
270.1229 +#endif
270.1230 +      /* construct the right-hand side vector h = - N[q] */
270.1231 +      for (i = 1; i <= m; i++)
270.1232 +         h[i] = 0.0;
270.1233 +      if (k <= m)
270.1234 +      {  /* N[q] is k-th column of submatrix I */
270.1235 +         h[k] = -1.0;
270.1236 +      }
270.1237 +      else
270.1238 +      {  /* N[q] is (k-m)-th column of submatrix (-A) */
270.1239 +         int *A_ptr = csa->A_ptr;
270.1240 +         int *A_ind = csa->A_ind;
270.1241 +         double *A_val = csa->A_val;
270.1242 +         int beg, end, ptr;
270.1243 +         beg = A_ptr[k-m];
270.1244 +         end = A_ptr[k-m+1];
270.1245 +         for (ptr = beg; ptr < end; ptr++)
270.1246 +            h[A_ind[ptr]] = A_val[ptr];
270.1247 +      }
270.1248 +      /* solve system B * tcol = h */
270.1249 +      xassert(csa->valid);
270.1250 +      bfd_ftran(csa->bfd, tcol_vec);
270.1251 +      /* construct sparse pattern of the pivot column */
270.1252 +      nnz = 0;
270.1253 +      for (i = 1; i <= m; i++)
270.1254 +      {  if (tcol_vec[i] != 0.0)
270.1255 +            tcol_ind[++nnz] = i;
270.1256 +      }
270.1257 +      csa->tcol_nnz = nnz;
270.1258 +      return;
270.1259 +}
270.1260 +
270.1261 +/***********************************************************************
270.1262 +*  refine_tcol - refine pivot column of the simplex table
270.1263 +*
270.1264 +*  This routine refines the pivot column of the simplex table assuming
270.1265 +*  that it was previously computed by the routine eval_tcol. */
270.1266 +
270.1267 +static void refine_tcol(struct csa *csa)
270.1268 +{     int m = csa->m;
270.1269 +#ifdef GLP_DEBUG
270.1270 +      int n = csa->n;
270.1271 +#endif
270.1272 +      int *head = csa->head;
270.1273 +      int q = csa->q;
270.1274 +      int *tcol_ind = csa->tcol_ind;
270.1275 +      double *tcol_vec = csa->tcol_vec;
270.1276 +      double *h = csa->work3;
270.1277 +      int i, k, nnz;
270.1278 +#ifdef GLP_DEBUG
270.1279 +      xassert(1 <= q && q <= n);
270.1280 +#endif
270.1281 +      k = head[m+q]; /* x[k] = xN[q] */
270.1282 +#ifdef GLP_DEBUG
270.1283 +      xassert(1 <= k && k <= m+n);
270.1284 +#endif
270.1285 +      /* construct the right-hand side vector h = - N[q] */
270.1286 +      for (i = 1; i <= m; i++)
270.1287 +         h[i] = 0.0;
270.1288 +      if (k <= m)
270.1289 +      {  /* N[q] is k-th column of submatrix I */
270.1290 +         h[k] = -1.0;
270.1291 +      }
270.1292 +      else
270.1293 +      {  /* N[q] is (k-m)-th column of submatrix (-A) */
270.1294 +         int *A_ptr = csa->A_ptr;
270.1295 +         int *A_ind = csa->A_ind;
270.1296 +         double *A_val = csa->A_val;
270.1297 +         int beg, end, ptr;
270.1298 +         beg = A_ptr[k-m];
270.1299 +         end = A_ptr[k-m+1];
270.1300 +         for (ptr = beg; ptr < end; ptr++)
270.1301 +            h[A_ind[ptr]] = A_val[ptr];
270.1302 +      }
270.1303 +      /* refine solution of B * tcol = h */
270.1304 +      refine_ftran(csa, h, tcol_vec);
270.1305 +      /* construct sparse pattern of the pivot column */
270.1306 +      nnz = 0;
270.1307 +      for (i = 1; i <= m; i++)
270.1308 +      {  if (tcol_vec[i] != 0.0)
270.1309 +            tcol_ind[++nnz] = i;
270.1310 +      }
270.1311 +      csa->tcol_nnz = nnz;
270.1312 +      return;
270.1313 +}
270.1314 +
270.1315 +/***********************************************************************
270.1316 +*  sort_tcol - sort pivot column of the simplex table
270.1317 +*
270.1318 +*  This routine reorders the list of non-zero elements of the pivot
270.1319 +*  column to put significant elements, whose magnitude is not less than
270.1320 +*  a specified tolerance, in front of the list, and stores the number
270.1321 +*  of significant elements in tcol_num. */
270.1322 +
270.1323 +static void sort_tcol(struct csa *csa, double tol_piv)
270.1324 +{
270.1325 +#ifdef GLP_DEBUG
270.1326 +      int m = csa->m;
270.1327 +#endif
270.1328 +      int nnz = csa->tcol_nnz;
270.1329 +      int *tcol_ind = csa->tcol_ind;
270.1330 +      double *tcol_vec = csa->tcol_vec;
270.1331 +      int i, num, pos;
270.1332 +      double big, eps, temp;
270.1333 +      /* compute infinity (maximum) norm of the column */
270.1334 +      big = 0.0;
270.1335 +      for (pos = 1; pos <= nnz; pos++)
270.1336 +      {
270.1337 +#ifdef GLP_DEBUG
270.1338 +         i = tcol_ind[pos];
270.1339 +         xassert(1 <= i && i <= m);
270.1340 +#endif
270.1341 +         temp = fabs(tcol_vec[tcol_ind[pos]]);
270.1342 +         if (big < temp) big = temp;
270.1343 +      }
270.1344 +      csa->tcol_max = big;
270.1345 +      /* determine absolute pivot tolerance */
270.1346 +      eps = tol_piv * (1.0 + 0.01 * big);
270.1347 +      /* move significant column components to front of the list */
270.1348 +      for (num = 0; num < nnz; )
270.1349 +      {  i = tcol_ind[nnz];
270.1350 +         if (fabs(tcol_vec[i]) < eps)
270.1351 +            nnz--;
270.1352 +         else
270.1353 +         {  num++;
270.1354 +            tcol_ind[nnz] = tcol_ind[num];
270.1355 +            tcol_ind[num] = i;
270.1356 +         }
270.1357 +      }
270.1358 +      csa->tcol_num = num;
270.1359 +      return;
270.1360 +}
270.1361 +
270.1362 +/***********************************************************************
270.1363 +*  chuzr - choose basic variable (row of the simplex table)
270.1364 +*
270.1365 +*  This routine chooses basic variable xB[p], which reaches its bound
270.1366 +*  first on changing non-basic variable xN[q] in valid direction.
270.1367 +*
270.1368 +*  The parameter rtol is a relative tolerance used to relax bounds of
270.1369 +*  basic variables. If rtol = 0, the routine implements the standard
270.1370 +*  ratio test. Otherwise, if rtol > 0, the routine implements Harris'
270.1371 +*  two-pass ratio test. In the latter case rtol should be about three
270.1372 +*  times less than a tolerance used to check primal feasibility. */
270.1373 +
270.1374 +static void chuzr(struct csa *csa, double rtol)
270.1375 +{     int m = csa->m;
270.1376 +#ifdef GLP_DEBUG
270.1377 +      int n = csa->n;
270.1378 +#endif
270.1379 +      char *type = csa->type;
270.1380 +      double *lb = csa->lb;
270.1381 +      double *ub = csa->ub;
270.1382 +      double *coef = csa->coef;
270.1383 +      int *head = csa->head;
270.1384 +      int phase = csa->phase;
270.1385 +      double *bbar = csa->bbar;
270.1386 +      double *cbar = csa->cbar;
270.1387 +      int q = csa->q;
270.1388 +      int *tcol_ind = csa->tcol_ind;
270.1389 +      double *tcol_vec = csa->tcol_vec;
270.1390 +      int tcol_num = csa->tcol_num;
270.1391 +      int i, i_stat, k, p, p_stat, pos;
270.1392 +      double alfa, big, delta, s, t, teta, tmax;
270.1393 +#ifdef GLP_DEBUG
270.1394 +      xassert(1 <= q && q <= n);
270.1395 +#endif
270.1396 +      /* s := - sign(d[q]), where d[q] is reduced cost of xN[q] */
270.1397 +#ifdef GLP_DEBUG
270.1398 +      xassert(cbar[q] != 0.0);
270.1399 +#endif
270.1400 +      s = (cbar[q] > 0.0 ? -1.0 : +1.0);
270.1401 +      /*** FIRST PASS ***/
270.1402 +      k = head[m+q]; /* x[k] = xN[q] */
270.1403 +#ifdef GLP_DEBUG
270.1404 +      xassert(1 <= k && k <= m+n);
270.1405 +#endif
270.1406 +      if (type[k] == GLP_DB)
270.1407 +      {  /* xN[q] has both lower and upper bounds */
270.1408 +         p = -1, p_stat = 0, teta = ub[k] - lb[k], big = 1.0;
270.1409 +      }
270.1410 +      else
270.1411 +      {  /* xN[q] has no opposite bound */
270.1412 +         p = 0, p_stat = 0, teta = DBL_MAX, big = 0.0;
270.1413 +      }
270.1414 +      /* walk through significant elements of the pivot column */
270.1415 +      for (pos = 1; pos <= tcol_num; pos++)
270.1416 +      {  i = tcol_ind[pos];
270.1417 +#ifdef GLP_DEBUG
270.1418 +         xassert(1 <= i && i <= m);
270.1419 +#endif
270.1420 +         k = head[i]; /* x[k] = xB[i] */
270.1421 +#ifdef GLP_DEBUG
270.1422 +         xassert(1 <= k && k <= m+n);
270.1423 +#endif
270.1424 +         alfa = s * tcol_vec[i];
270.1425 +#ifdef GLP_DEBUG
270.1426 +         xassert(alfa != 0.0);
270.1427 +#endif
270.1428 +         /* xB[i] = ... + alfa * xN[q] + ..., and due to s we need to
270.1429 +            consider the only case when xN[q] is increasing */
270.1430 +         if (alfa > 0.0)
270.1431 +         {  /* xB[i] is increasing */
270.1432 +            if (phase == 1 && coef[k] < 0.0)
270.1433 +            {  /* xB[i] violates its lower bound, which plays the role
270.1434 +                  of an upper bound on phase I */
270.1435 +               delta = rtol * (1.0 + kappa * fabs(lb[k]));
270.1436 +               t = ((lb[k] + delta) - bbar[i]) / alfa;
270.1437 +               i_stat = GLP_NL;
270.1438 +            }
270.1439 +            else if (phase == 1 && coef[k] > 0.0)
270.1440 +            {  /* xB[i] violates its upper bound, which plays the role
270.1441 +                  of an lower bound on phase I */
270.1442 +               continue;
270.1443 +            }
270.1444 +            else if (type[k] == GLP_UP || type[k] == GLP_DB ||
270.1445 +                     type[k] == GLP_FX)
270.1446 +            {  /* xB[i] is within its bounds and has an upper bound */
270.1447 +               delta = rtol * (1.0 + kappa * fabs(ub[k]));
270.1448 +               t = ((ub[k] + delta) - bbar[i]) / alfa;
270.1449 +               i_stat = GLP_NU;
270.1450 +            }
270.1451 +            else
270.1452 +            {  /* xB[i] is within its bounds and has no upper bound */
270.1453 +               continue;
270.1454 +            }
270.1455 +         }
270.1456 +         else
270.1457 +         {  /* xB[i] is decreasing */
270.1458 +            if (phase == 1 && coef[k] > 0.0)
270.1459 +            {  /* xB[i] violates its upper bound, which plays the role
270.1460 +                  of an lower bound on phase I */
270.1461 +               delta = rtol * (1.0 + kappa * fabs(ub[k]));
270.1462 +               t = ((ub[k] - delta) - bbar[i]) / alfa;
270.1463 +               i_stat = GLP_NU;
270.1464 +            }
270.1465 +            else if (phase == 1 && coef[k] < 0.0)
270.1466 +            {  /* xB[i] violates its lower bound, which plays the role
270.1467 +                  of an upper bound on phase I */
270.1468 +               continue;
270.1469 +            }
270.1470 +            else if (type[k] == GLP_LO || type[k] == GLP_DB ||
270.1471 +                     type[k] == GLP_FX)
270.1472 +            {  /* xB[i] is within its bounds and has an lower bound */
270.1473 +               delta = rtol * (1.0 + kappa * fabs(lb[k]));
270.1474 +               t = ((lb[k] - delta) - bbar[i]) / alfa;
270.1475 +               i_stat = GLP_NL;
270.1476 +            }
270.1477 +            else
270.1478 +            {  /* xB[i] is within its bounds and has no lower bound */
270.1479 +               continue;
270.1480 +            }
270.1481 +         }
270.1482 +         /* t is a change of xN[q], on which xB[i] reaches its bound
270.1483 +            (possibly relaxed); since the basic solution is assumed to
270.1484 +            be primal feasible (or pseudo feasible on phase I), t has
270.1485 +            to be non-negative by definition; however, it may happen
270.1486 +            that xB[i] slightly (i.e. within a tolerance) violates its
270.1487 +            bound, that leads to negative t; in the latter case, if
270.1488 +            xB[i] is chosen, negative t means that xN[q] changes in
270.1489 +            wrong direction; if pivot alfa[i,q] is close to zero, even
270.1490 +            small bound violation of xB[i] may lead to a large change
270.1491 +            of xN[q] in wrong direction; let, for example, xB[i] >= 0
270.1492 +            and in the current basis its value be -5e-9; let also xN[q]
270.1493 +            be on its zero bound and should increase; from the ratio
270.1494 +            test rule it follows that the pivot alfa[i,q] < 0; however,
270.1495 +            if alfa[i,q] is, say, -1e-9, the change of xN[q] in wrong
270.1496 +            direction is 5e-9 / (-1e-9) = -5, and using it for updating
270.1497 +            values of other basic variables will give absolutely wrong
270.1498 +            results; therefore, if t is negative, we should replace it
270.1499 +            by exact zero assuming that xB[i] is exactly on its bound,
270.1500 +            and the violation appears due to round-off errors */
270.1501 +         if (t < 0.0) t = 0.0;
270.1502 +         /* apply minimal ratio test */
270.1503 +         if (teta > t || teta == t && big < fabs(alfa))
270.1504 +            p = i, p_stat = i_stat, teta = t, big = fabs(alfa);
270.1505 +      }
270.1506 +      /* the second pass is skipped in the following cases: */
270.1507 +      /* if the standard ratio test is used */
270.1508 +      if (rtol == 0.0) goto done;
270.1509 +      /* if xN[q] reaches its opposite bound or if no basic variable
270.1510 +         has been chosen on the first pass */
270.1511 +      if (p <= 0) goto done;
270.1512 +      /* if xB[p] is a blocking variable, i.e. if it prevents xN[q]
270.1513 +         from any change */
270.1514 +      if (teta == 0.0) goto done;
270.1515 +      /*** SECOND PASS ***/
270.1516 +      /* here tmax is a maximal change of xN[q], on which the solution
270.1517 +         remains primal feasible (or pseudo feasible on phase I) within
270.1518 +         a tolerance */
270.1519 +#if 0
270.1520 +      tmax = (1.0 + 10.0 * DBL_EPSILON) * teta;
270.1521 +#else
270.1522 +      tmax = teta;
270.1523 +#endif
270.1524 +      /* nothing is chosen so far */
270.1525 +      p = 0, p_stat = 0, teta = DBL_MAX, big = 0.0;
270.1526 +      /* walk through significant elements of the pivot column */
270.1527 +      for (pos = 1; pos <= tcol_num; pos++)
270.1528 +      {  i = tcol_ind[pos];
270.1529 +#ifdef GLP_DEBUG
270.1530 +         xassert(1 <= i && i <= m);
270.1531 +#endif
270.1532 +         k = head[i]; /* x[k] = xB[i] */
270.1533 +#ifdef GLP_DEBUG
270.1534 +         xassert(1 <= k && k <= m+n);
270.1535 +#endif
270.1536 +         alfa = s * tcol_vec[i];
270.1537 +#ifdef GLP_DEBUG
270.1538 +         xassert(alfa != 0.0);
270.1539 +#endif
270.1540 +         /* xB[i] = ... + alfa * xN[q] + ..., and due to s we need to
270.1541 +            consider the only case when xN[q] is increasing */
270.1542 +         if (alfa > 0.0)
270.1543 +         {  /* xB[i] is increasing */
270.1544 +            if (phase == 1 && coef[k] < 0.0)
270.1545 +            {  /* xB[i] violates its lower bound, which plays the role
270.1546 +                  of an upper bound on phase I */
270.1547 +               t = (lb[k] - bbar[i]) / alfa;
270.1548 +               i_stat = GLP_NL;
270.1549 +            }
270.1550 +            else if (phase == 1 && coef[k] > 0.0)
270.1551 +            {  /* xB[i] violates its upper bound, which plays the role
270.1552 +                  of an lower bound on phase I */
270.1553 +               continue;
270.1554 +            }
270.1555 +            else if (type[k] == GLP_UP || type[k] == GLP_DB ||
270.1556 +                     type[k] == GLP_FX)
270.1557 +            {  /* xB[i] is within its bounds and has an upper bound */
270.1558 +               t = (ub[k] - bbar[i]) / alfa;
270.1559 +               i_stat = GLP_NU;
270.1560 +            }
270.1561 +            else
270.1562 +            {  /* xB[i] is within its bounds and has no upper bound */
270.1563 +               continue;
270.1564 +            }
270.1565 +         }
270.1566 +         else
270.1567 +         {  /* xB[i] is decreasing */
270.1568 +            if (phase == 1 && coef[k] > 0.0)
270.1569 +            {  /* xB[i] violates its upper bound, which plays the role
270.1570 +                  of an lower bound on phase I */
270.1571 +               t = (ub[k] - bbar[i]) / alfa;
270.1572 +               i_stat = GLP_NU;
270.1573 +            }
270.1574 +            else if (phase == 1 && coef[k] < 0.0)
270.1575 +            {  /* xB[i] violates its lower bound, which plays the role
270.1576 +                  of an upper bound on phase I */
270.1577 +               continue;
270.1578 +            }
270.1579 +            else if (type[k] == GLP_LO || type[k] == GLP_DB ||
270.1580 +                     type[k] == GLP_FX)
270.1581 +            {  /* xB[i] is within its bounds and has an lower bound */
270.1582 +               t = (lb[k] - bbar[i]) / alfa;
270.1583 +               i_stat = GLP_NL;
270.1584 +            }
270.1585 +            else
270.1586 +            {  /* xB[i] is within its bounds and has no lower bound */
270.1587 +               continue;
270.1588 +            }
270.1589 +         }
270.1590 +         /* (see comments for the first pass) */
270.1591 +         if (t < 0.0) t = 0.0;
270.1592 +         /* t is a change of xN[q], on which xB[i] reaches its bound;
270.1593 +            if t <= tmax, all basic variables can violate their bounds
270.1594 +            only within relaxation tolerance delta; we can use this
270.1595 +            freedom and choose basic variable having largest influence
270.1596 +            coefficient to avoid possible numeric instability */
270.1597 +         if (t <= tmax && big < fabs(alfa))
270.1598 +            p = i, p_stat = i_stat, teta = t, big = fabs(alfa);
270.1599 +      }
270.1600 +      /* something must be chosen on the second pass */
270.1601 +      xassert(p != 0);
270.1602 +done: /* store the index and status of basic variable xB[p] chosen */
270.1603 +      csa->p = p;
270.1604 +      if (p > 0 && type[head[p]] == GLP_FX)
270.1605 +         csa->p_stat = GLP_NS;
270.1606 +      else
270.1607 +         csa->p_stat = p_stat;
270.1608 +      /* store corresponding change of non-basic variable xN[q] */
270.1609 +#ifdef GLP_DEBUG
270.1610 +      xassert(teta >= 0.0);
270.1611 +#endif
270.1612 +      csa->teta = s * teta;
270.1613 +      return;
270.1614 +}
270.1615 +
270.1616 +/***********************************************************************
270.1617 +*  eval_rho - compute pivot row of the inverse
270.1618 +*
270.1619 +*  This routine computes the pivot (p-th) row of the inverse inv(B),
270.1620 +*  which corresponds to basic variable xB[p] chosen:
270.1621 +*
270.1622 +*     rho = inv(B') * e[p],
270.1623 +*
270.1624 +*  where B' is a matrix transposed to the current basis matrix, e[p]
270.1625 +*  is unity vector. */
270.1626 +
270.1627 +static void eval_rho(struct csa *csa, double rho[])
270.1628 +{     int m = csa->m;
270.1629 +      int p = csa->p;
270.1630 +      double *e = rho;
270.1631 +      int i;
270.1632 +#ifdef GLP_DEBUG
270.1633 +      xassert(1 <= p && p <= m);
270.1634 +#endif
270.1635 +      /* construct the right-hand side vector e[p] */
270.1636 +      for (i = 1; i <= m; i++)
270.1637 +         e[i] = 0.0;
270.1638 +      e[p] = 1.0;
270.1639 +      /* solve system B'* rho = e[p] */
270.1640 +      xassert(csa->valid);
270.1641 +      bfd_btran(csa->bfd, rho);
270.1642 +      return;
270.1643 +}
270.1644 +
270.1645 +/***********************************************************************
270.1646 +*  refine_rho - refine pivot row of the inverse
270.1647 +*
270.1648 +*  This routine refines the pivot row of the inverse inv(B) assuming
270.1649 +*  that it was previously computed by the routine eval_rho. */
270.1650 +
270.1651 +static void refine_rho(struct csa *csa, double rho[])
270.1652 +{     int m = csa->m;
270.1653 +      int p = csa->p;
270.1654 +      double *e = csa->work3;
270.1655 +      int i;
270.1656 +#ifdef GLP_DEBUG
270.1657 +      xassert(1 <= p && p <= m);
270.1658 +#endif
270.1659 +      /* construct the right-hand side vector e[p] */
270.1660 +      for (i = 1; i <= m; i++)
270.1661 +         e[i] = 0.0;
270.1662 +      e[p] = 1.0;
270.1663 +      /* refine solution of B'* rho = e[p] */
270.1664 +      refine_btran(csa, e, rho);
270.1665 +      return;
270.1666 +}
270.1667 +
270.1668 +/***********************************************************************
270.1669 +*  eval_trow - compute pivot row of the simplex table
270.1670 +*
270.1671 +*  This routine computes the pivot row of the simplex table, which
270.1672 +*  corresponds to basic variable xB[p] chosen.
270.1673 +*
270.1674 +*  The pivot row is the following vector:
270.1675 +*
270.1676 +*     trow = T'* e[p] = - N'* inv(B') * e[p] = - N' * rho,
270.1677 +*
270.1678 +*  where rho is the pivot row of the inverse inv(B) previously computed
270.1679 +*  by the routine eval_rho.
270.1680 +*
270.1681 +*  Note that elements of the pivot row corresponding to fixed non-basic
270.1682 +*  variables are not computed. */
270.1683 +
270.1684 +static void eval_trow(struct csa *csa, double rho[])
270.1685 +{     int m = csa->m;
270.1686 +      int n = csa->n;
270.1687 +#ifdef GLP_DEBUG
270.1688 +      char *stat = csa->stat;
270.1689 +#endif
270.1690 +      int *N_ptr = csa->N_ptr;
270.1691 +      int *N_len = csa->N_len;
270.1692 +      int *N_ind = csa->N_ind;
270.1693 +      double *N_val = csa->N_val;
270.1694 +      int *trow_ind = csa->trow_ind;
270.1695 +      double *trow_vec = csa->trow_vec;
270.1696 +      int i, j, beg, end, ptr, nnz;
270.1697 +      double temp;
270.1698 +      /* clear the pivot row */
270.1699 +      for (j = 1; j <= n; j++)
270.1700 +         trow_vec[j] = 0.0;
270.1701 +      /* compute the pivot row as a linear combination of rows of the
270.1702 +         matrix N: trow = - rho[1] * N'[1] - ... - rho[m] * N'[m] */
270.1703 +      for (i = 1; i <= m; i++)
270.1704 +      {  temp = rho[i];
270.1705 +         if (temp == 0.0) continue;
270.1706 +         /* trow := trow - rho[i] * N'[i] */
270.1707 +         beg = N_ptr[i];
270.1708 +         end = beg + N_len[i];
270.1709 +         for (ptr = beg; ptr < end; ptr++)
270.1710 +         {
270.1711 +#ifdef GLP_DEBUG
270.1712 +            j = N_ind[ptr];
270.1713 +            xassert(1 <= j && j <= n);
270.1714 +            xassert(stat[j] != GLP_NS);
270.1715 +#endif
270.1716 +            trow_vec[N_ind[ptr]] -= temp * N_val[ptr];
270.1717 +         }
270.1718 +      }
270.1719 +      /* construct sparse pattern of the pivot row */
270.1720 +      nnz = 0;
270.1721 +      for (j = 1; j <= n; j++)
270.1722 +      {  if (trow_vec[j] != 0.0)
270.1723 +            trow_ind[++nnz] = j;
270.1724 +      }
270.1725 +      csa->trow_nnz = nnz;
270.1726 +      return;
270.1727 +}
270.1728 +
270.1729 +/***********************************************************************
270.1730 +*  update_bbar - update values of basic variables
270.1731 +*
270.1732 +*  This routine updates values of all basic variables for the adjacent
270.1733 +*  basis. */
270.1734 +
270.1735 +static void update_bbar(struct csa *csa)
270.1736 +{
270.1737 +#ifdef GLP_DEBUG
270.1738 +      int m = csa->m;
270.1739 +      int n = csa->n;
270.1740 +#endif
270.1741 +      double *bbar = csa->bbar;
270.1742 +      int q = csa->q;
270.1743 +      int tcol_nnz = csa->tcol_nnz;
270.1744 +      int *tcol_ind = csa->tcol_ind;
270.1745 +      double *tcol_vec = csa->tcol_vec;
270.1746 +      int p = csa->p;
270.1747 +      double teta = csa->teta;
270.1748 +      int i, pos;
270.1749 +#ifdef GLP_DEBUG
270.1750 +      xassert(1 <= q && q <= n);
270.1751 +      xassert(p < 0 || 1 <= p && p <= m);
270.1752 +#endif
270.1753 +      /* if xN[q] leaves the basis, compute its value in the adjacent
270.1754 +         basis, where it will replace xB[p] */
270.1755 +      if (p > 0)
270.1756 +         bbar[p] = get_xN(csa, q) + teta;
270.1757 +      /* update values of other basic variables (except xB[p], because
270.1758 +         it will be replaced by xN[q]) */
270.1759 +      if (teta == 0.0) goto done;
270.1760 +      for (pos = 1; pos <= tcol_nnz; pos++)
270.1761 +      {  i = tcol_ind[pos];
270.1762 +         /* skip xB[p] */
270.1763 +         if (i == p) continue;
270.1764 +         /* (change of xB[i]) = alfa[i,q] * (change of xN[q]) */
270.1765 +         bbar[i] += tcol_vec[i] * teta;
270.1766 +      }
270.1767 +done: return;
270.1768 +}
270.1769 +
270.1770 +/***********************************************************************
270.1771 +*  reeval_cost - recompute reduced cost of non-basic variable xN[q]
270.1772 +*
270.1773 +*  This routine recomputes reduced cost of non-basic variable xN[q] for
270.1774 +*  the current basis more accurately using its direct definition:
270.1775 +*
270.1776 +*     d[q] = cN[q] - N'[q] * pi =
270.1777 +*
270.1778 +*          = cN[q] - N'[q] * (inv(B') * cB) =
270.1779 +*
270.1780 +*          = cN[q] - (cB' * inv(B) * N[q]) =
270.1781 +*
270.1782 +*          = cN[q] + cB' * (pivot column).
270.1783 +*
270.1784 +*  It is assumed that the pivot column of the simplex table is already
270.1785 +*  computed. */
270.1786 +
270.1787 +static double reeval_cost(struct csa *csa)
270.1788 +{     int m = csa->m;
270.1789 +#ifdef GLP_DEBUG
270.1790 +      int n = csa->n;
270.1791 +#endif
270.1792 +      double *coef = csa->coef;
270.1793 +      int *head = csa->head;
270.1794 +      int q = csa->q;
270.1795 +      int tcol_nnz = csa->tcol_nnz;
270.1796 +      int *tcol_ind = csa->tcol_ind;
270.1797 +      double *tcol_vec = csa->tcol_vec;
270.1798 +      int i, pos;
270.1799 +      double dq;
270.1800 +#ifdef GLP_DEBUG
270.1801 +      xassert(1 <= q && q <= n);
270.1802 +#endif
270.1803 +      dq = coef[head[m+q]];
270.1804 +      for (pos = 1; pos <= tcol_nnz; pos++)
270.1805 +      {  i = tcol_ind[pos];
270.1806 +#ifdef GLP_DEBUG
270.1807 +         xassert(1 <= i && i <= m);
270.1808 +#endif
270.1809 +         dq += coef[head[i]] * tcol_vec[i];
270.1810 +      }
270.1811 +      return dq;
270.1812 +}
270.1813 +
270.1814 +/***********************************************************************
270.1815 +*  update_cbar - update reduced costs of non-basic variables
270.1816 +*
270.1817 +*  This routine updates reduced costs of all (except fixed) non-basic
270.1818 +*  variables for the adjacent basis. */
270.1819 +
270.1820 +static void update_cbar(struct csa *csa)
270.1821 +{
270.1822 +#ifdef GLP_DEBUG
270.1823 +      int n = csa->n;
270.1824 +#endif
270.1825 +      double *cbar = csa->cbar;
270.1826 +      int q = csa->q;
270.1827 +      int trow_nnz = csa->trow_nnz;
270.1828 +      int *trow_ind = csa->trow_ind;
270.1829 +      double *trow_vec = csa->trow_vec;
270.1830 +      int j, pos;
270.1831 +      double new_dq;
270.1832 +#ifdef GLP_DEBUG
270.1833 +      xassert(1 <= q && q <= n);
270.1834 +#endif
270.1835 +      /* compute reduced cost of xB[p] in the adjacent basis, where it
270.1836 +         will replace xN[q] */
270.1837 +#ifdef GLP_DEBUG
270.1838 +      xassert(trow_vec[q] != 0.0);
270.1839 +#endif
270.1840 +      new_dq = (cbar[q] /= trow_vec[q]);
270.1841 +      /* update reduced costs of other non-basic variables (except
270.1842 +         xN[q], because it will be replaced by xB[p]) */
270.1843 +      for (pos = 1; pos <= trow_nnz; pos++)
270.1844 +      {  j = trow_ind[pos];
270.1845 +         /* skip xN[q] */
270.1846 +         if (j == q) continue;
270.1847 +         cbar[j] -= trow_vec[j] * new_dq;
270.1848 +      }
270.1849 +      return;
270.1850 +}
270.1851 +
270.1852 +/***********************************************************************
270.1853 +*  update_gamma - update steepest edge coefficients
270.1854 +*
270.1855 +*  This routine updates steepest-edge coefficients for the adjacent
270.1856 +*  basis. */
270.1857 +
270.1858 +static void update_gamma(struct csa *csa)
270.1859 +{     int m = csa->m;
270.1860 +#ifdef GLP_DEBUG
270.1861 +      int n = csa->n;
270.1862 +#endif
270.1863 +      char *type = csa->type;
270.1864 +      int *A_ptr = csa->A_ptr;
270.1865 +      int *A_ind = csa->A_ind;
270.1866 +      double *A_val = csa->A_val;
270.1867 +      int *head = csa->head;
270.1868 +      char *refsp = csa->refsp;
270.1869 +      double *gamma = csa->gamma;
270.1870 +      int q = csa->q;
270.1871 +      int tcol_nnz = csa->tcol_nnz;
270.1872 +      int *tcol_ind = csa->tcol_ind;
270.1873 +      double *tcol_vec = csa->tcol_vec;
270.1874 +      int p = csa->p;
270.1875 +      int trow_nnz = csa->trow_nnz;
270.1876 +      int *trow_ind = csa->trow_ind;
270.1877 +      double *trow_vec = csa->trow_vec;
270.1878 +      double *u = csa->work3;
270.1879 +      int i, j, k, pos, beg, end, ptr;
270.1880 +      double gamma_q, delta_q, pivot, s, t, t1, t2;
270.1881 +#ifdef GLP_DEBUG
270.1882 +      xassert(1 <= p && p <= m);
270.1883 +      xassert(1 <= q && q <= n);
270.1884 +#endif
270.1885 +      /* the basis changes, so decrease the count */
270.1886 +      xassert(csa->refct > 0);
270.1887 +      csa->refct--;
270.1888 +      /* recompute gamma[q] for the current basis more accurately and
270.1889 +         compute auxiliary vector u */
270.1890 +      gamma_q = delta_q = (refsp[head[m+q]] ? 1.0 : 0.0);
270.1891 +      for (i = 1; i <= m; i++) u[i] = 0.0;
270.1892 +      for (pos = 1; pos <= tcol_nnz; pos++)
270.1893 +      {  i = tcol_ind[pos];
270.1894 +         if (refsp[head[i]])
270.1895 +         {  u[i] = t = tcol_vec[i];
270.1896 +            gamma_q += t * t;
270.1897 +         }
270.1898 +         else
270.1899 +            u[i] = 0.0;
270.1900 +      }
270.1901 +      xassert(csa->valid);
270.1902 +      bfd_btran(csa->bfd, u);
270.1903 +      /* update gamma[k] for other non-basic variables (except fixed
270.1904 +         variables and xN[q], because it will be replaced by xB[p]) */
270.1905 +      pivot = trow_vec[q];
270.1906 +#ifdef GLP_DEBUG
270.1907 +      xassert(pivot != 0.0);
270.1908 +#endif
270.1909 +      for (pos = 1; pos <= trow_nnz; pos++)
270.1910 +      {  j = trow_ind[pos];
270.1911 +         /* skip xN[q] */
270.1912 +         if (j == q) continue;
270.1913 +         /* compute t */
270.1914 +         t = trow_vec[j] / pivot;
270.1915 +         /* compute inner product s = N'[j] * u */
270.1916 +         k = head[m+j]; /* x[k] = xN[j] */
270.1917 +         if (k <= m)
270.1918 +            s = u[k];
270.1919 +         else
270.1920 +         {  s = 0.0;
270.1921 +            beg = A_ptr[k-m];
270.1922 +            end = A_ptr[k-m+1];
270.1923 +            for (ptr = beg; ptr < end; ptr++)
270.1924 +               s -= A_val[ptr] * u[A_ind[ptr]];
270.1925 +         }
270.1926 +         /* compute gamma[k] for the adjacent basis */
270.1927 +         t1 = gamma[j] + t * t * gamma_q + 2.0 * t * s;
270.1928 +         t2 = (refsp[k] ? 1.0 : 0.0) + delta_q * t * t;
270.1929 +         gamma[j] = (t1 >= t2 ? t1 : t2);
270.1930 +         if (gamma[j] < DBL_EPSILON) gamma[j] = DBL_EPSILON;
270.1931 +      }
270.1932 +      /* compute gamma[q] for the adjacent basis */
270.1933 +      if (type[head[p]] == GLP_FX)
270.1934 +         gamma[q] = 1.0;
270.1935 +      else
270.1936 +      {  gamma[q] = gamma_q / (pivot * pivot);
270.1937 +         if (gamma[q] < DBL_EPSILON) gamma[q] = DBL_EPSILON;
270.1938 +      }
270.1939 +      return;
270.1940 +}
270.1941 +
270.1942 +/***********************************************************************
270.1943 +*  err_in_bbar - compute maximal relative error in primal solution
270.1944 +*
270.1945 +*  This routine returns maximal relative error:
270.1946 +*
270.1947 +*     max |beta[i] - bbar[i]| / (1 + |beta[i]|),
270.1948 +*
270.1949 +*  where beta and bbar are, respectively, directly computed and the
270.1950 +*  current (updated) values of basic variables.
270.1951 +*
270.1952 +*  NOTE: The routine is intended only for debugginig purposes. */
270.1953 +
270.1954 +static double err_in_bbar(struct csa *csa)
270.1955 +{     int m = csa->m;
270.1956 +      double *bbar = csa->bbar;
270.1957 +      int i;
270.1958 +      double e, emax, *beta;
270.1959 +      beta = xcalloc(1+m, sizeof(double));
270.1960 +      eval_beta(csa, beta);
270.1961 +      emax = 0.0;
270.1962 +      for (i = 1; i <= m; i++)
270.1963 +      {  e = fabs(beta[i] - bbar[i]) / (1.0 + fabs(beta[i]));
270.1964 +         if (emax < e) emax = e;
270.1965 +      }
270.1966 +      xfree(beta);
270.1967 +      return emax;
270.1968 +}
270.1969 +
270.1970 +/***********************************************************************
270.1971 +*  err_in_cbar - compute maximal relative error in dual solution
270.1972 +*
270.1973 +*  This routine returns maximal relative error:
270.1974 +*
270.1975 +*     max |cost[j] - cbar[j]| / (1 + |cost[j]|),
270.1976 +*
270.1977 +*  where cost and cbar are, respectively, directly computed and the
270.1978 +*  current (updated) reduced costs of non-basic non-fixed variables.
270.1979 +*
270.1980 +*  NOTE: The routine is intended only for debugginig purposes. */
270.1981 +
270.1982 +static double err_in_cbar(struct csa *csa)
270.1983 +{     int m = csa->m;
270.1984 +      int n = csa->n;
270.1985 +      char *stat = csa->stat;
270.1986 +      double *cbar = csa->cbar;
270.1987 +      int j;
270.1988 +      double e, emax, cost, *pi;
270.1989 +      pi = xcalloc(1+m, sizeof(double));
270.1990 +      eval_pi(csa, pi);
270.1991 +      emax = 0.0;
270.1992 +      for (j = 1; j <= n; j++)
270.1993 +      {  if (stat[j] == GLP_NS) continue;
270.1994 +         cost = eval_cost(csa, pi, j);
270.1995 +         e = fabs(cost - cbar[j]) / (1.0 + fabs(cost));
270.1996 +         if (emax < e) emax = e;
270.1997 +      }
270.1998 +      xfree(pi);
270.1999 +      return emax;
270.2000 +}
270.2001 +
270.2002 +/***********************************************************************
270.2003 +*  err_in_gamma - compute maximal relative error in steepest edge cff.
270.2004 +*
270.2005 +*  This routine returns maximal relative error:
270.2006 +*
270.2007 +*     max |gamma'[j] - gamma[j]| / (1 + |gamma'[j]),
270.2008 +*
270.2009 +*  where gamma'[j] and gamma[j] are, respectively, directly computed
270.2010 +*  and the current (updated) steepest edge coefficients for non-basic
270.2011 +*  non-fixed variable x[j].
270.2012 +*
270.2013 +*  NOTE: The routine is intended only for debugginig purposes. */
270.2014 +
270.2015 +static double err_in_gamma(struct csa *csa)
270.2016 +{     int n = csa->n;
270.2017 +      char *stat = csa->stat;
270.2018 +      double *gamma = csa->gamma;
270.2019 +      int j;
270.2020 +      double e, emax, temp;
270.2021 +      emax = 0.0;
270.2022 +      for (j = 1; j <= n; j++)
270.2023 +      {  if (stat[j] == GLP_NS)
270.2024 +         {  xassert(gamma[j] == 1.0);
270.2025 +            continue;
270.2026 +         }
270.2027 +         temp = eval_gamma(csa, j);
270.2028 +         e = fabs(temp - gamma[j]) / (1.0 + fabs(temp));
270.2029 +         if (emax < e) emax = e;
270.2030 +      }
270.2031 +      return emax;
270.2032 +}
270.2033 +
270.2034 +/***********************************************************************
270.2035 +*  change_basis - change basis header
270.2036 +*
270.2037 +*  This routine changes the basis header to make it corresponding to
270.2038 +*  the adjacent basis. */
270.2039 +
270.2040 +static void change_basis(struct csa *csa)
270.2041 +{     int m = csa->m;
270.2042 +#ifdef GLP_DEBUG
270.2043 +      int n = csa->n;
270.2044 +      char *type = csa->type;
270.2045 +#endif
270.2046 +      int *head = csa->head;
270.2047 +      char *stat = csa->stat;
270.2048 +      int q = csa->q;
270.2049 +      int p = csa->p;
270.2050 +      int p_stat = csa->p_stat;
270.2051 +      int k;
270.2052 +#ifdef GLP_DEBUG
270.2053 +      xassert(1 <= q && q <= n);
270.2054 +#endif
270.2055 +      if (p < 0)
270.2056 +      {  /* xN[q] goes to its opposite bound */
270.2057 +#ifdef GLP_DEBUG
270.2058 +         k = head[m+q]; /* x[k] = xN[q] */
270.2059 +         xassert(1 <= k && k <= m+n);
270.2060 +         xassert(type[k] == GLP_DB);
270.2061 +#endif
270.2062 +         switch (stat[q])
270.2063 +         {  case GLP_NL:
270.2064 +               /* xN[q] increases */
270.2065 +               stat[q] = GLP_NU;
270.2066 +               break;
270.2067 +            case GLP_NU:
270.2068 +               /* xN[q] decreases */
270.2069 +               stat[q] = GLP_NL;
270.2070 +               break;
270.2071 +            default:
270.2072 +               xassert(stat != stat);
270.2073 +         }
270.2074 +      }
270.2075 +      else
270.2076 +      {  /* xB[p] leaves the basis, xN[q] enters the basis */
270.2077 +#ifdef GLP_DEBUG
270.2078 +         xassert(1 <= p && p <= m);
270.2079 +         k = head[p]; /* x[k] = xB[p] */
270.2080 +         switch (p_stat)
270.2081 +         {  case GLP_NL:
270.2082 +               /* xB[p] goes to its lower bound */
270.2083 +               xassert(type[k] == GLP_LO || type[k] == GLP_DB);
270.2084 +               break;
270.2085 +            case GLP_NU:
270.2086 +               /* xB[p] goes to its upper bound */
270.2087 +               xassert(type[k] == GLP_UP || type[k] == GLP_DB);
270.2088 +               break;
270.2089 +            case GLP_NS:
270.2090 +               /* xB[p] goes to its fixed value */
270.2091 +               xassert(type[k] == GLP_NS);
270.2092 +               break;
270.2093 +            default:
270.2094 +               xassert(p_stat != p_stat);
270.2095 +         }
270.2096 +#endif
270.2097 +         /* xB[p] <-> xN[q] */
270.2098 +         k = head[p], head[p] = head[m+q], head[m+q] = k;
270.2099 +         stat[q] = (char)p_stat;
270.2100 +      }
270.2101 +      return;
270.2102 +}
270.2103 +
270.2104 +/***********************************************************************
270.2105 +*  set_aux_obj - construct auxiliary objective function
270.2106 +*
270.2107 +*  The auxiliary objective function is a separable piecewise linear
270.2108 +*  convex function, which is the sum of primal infeasibilities:
270.2109 +*
270.2110 +*     z = t[1] + ... + t[m+n] -> minimize,
270.2111 +*
270.2112 +*  where:
270.2113 +*
270.2114 +*            / lb[k] - x[k], if x[k] < lb[k]
270.2115 +*            |
270.2116 +*     t[k] = <  0, if lb[k] <= x[k] <= ub[k]
270.2117 +*            |
270.2118 +*            \ x[k] - ub[k], if x[k] > ub[k]
270.2119 +*
270.2120 +*  This routine computes objective coefficients for the current basis
270.2121 +*  and returns the number of non-zero terms t[k]. */
270.2122 +
270.2123 +static int set_aux_obj(struct csa *csa, double tol_bnd)
270.2124 +{     int m = csa->m;
270.2125 +      int n = csa->n;
270.2126 +      char *type = csa->type;
270.2127 +      double *lb = csa->lb;
270.2128 +      double *ub = csa->ub;
270.2129 +      double *coef = csa->coef;
270.2130 +      int *head = csa->head;
270.2131 +      double *bbar = csa->bbar;
270.2132 +      int i, k, cnt = 0;
270.2133 +      double eps;
270.2134 +      /* use a bit more restrictive tolerance */
270.2135 +      tol_bnd *= 0.90;
270.2136 +      /* clear all objective coefficients */
270.2137 +      for (k = 1; k <= m+n; k++)
270.2138 +         coef[k] = 0.0;
270.2139 +      /* walk through the list of basic variables */
270.2140 +      for (i = 1; i <= m; i++)
270.2141 +      {  k = head[i]; /* x[k] = xB[i] */
270.2142 +         if (type[k] == GLP_LO || type[k] == GLP_DB ||
270.2143 +             type[k] == GLP_FX)
270.2144 +         {  /* x[k] has lower bound */
270.2145 +            eps = tol_bnd * (1.0 + kappa * fabs(lb[k]));
270.2146 +            if (bbar[i] < lb[k] - eps)
270.2147 +            {  /* and violates it */
270.2148 +               coef[k] = -1.0;
270.2149 +               cnt++;
270.2150 +            }
270.2151 +         }
270.2152 +         if (type[k] == GLP_UP || type[k] == GLP_DB ||
270.2153 +             type[k] == GLP_FX)
270.2154 +         {  /* x[k] has upper bound */
270.2155 +            eps = tol_bnd * (1.0 + kappa * fabs(ub[k]));
270.2156 +            if (bbar[i] > ub[k] + eps)
270.2157 +            {  /* and violates it */
270.2158 +               coef[k] = +1.0;
270.2159 +               cnt++;
270.2160 +            }
270.2161 +         }
270.2162 +      }
270.2163 +      return cnt;
270.2164 +}
270.2165 +
270.2166 +/***********************************************************************
270.2167 +*  set_orig_obj - restore original objective function
270.2168 +*
270.2169 +*  This routine assigns scaled original objective coefficients to the
270.2170 +*  working objective function. */
270.2171 +
270.2172 +static void set_orig_obj(struct csa *csa)
270.2173 +{     int m = csa->m;
270.2174 +      int n = csa->n;
270.2175 +      double *coef = csa->coef;
270.2176 +      double *obj = csa->obj;
270.2177 +      double zeta = csa->zeta;
270.2178 +      int i, j;
270.2179 +      for (i = 1; i <= m; i++)
270.2180 +         coef[i] = 0.0;
270.2181 +      for (j = 1; j <= n; j++)
270.2182 +         coef[m+j] = zeta * obj[j];
270.2183 +      return;
270.2184 +}
270.2185 +
270.2186 +/***********************************************************************
270.2187 +*  check_stab - check numerical stability of basic solution
270.2188 +*
270.2189 +*  If the current basic solution is primal feasible (or pseudo feasible
270.2190 +*  on phase I) within a tolerance, this routine returns zero, otherwise
270.2191 +*  it returns non-zero. */
270.2192 +
270.2193 +static int check_stab(struct csa *csa, double tol_bnd)
270.2194 +{     int m = csa->m;
270.2195 +#ifdef GLP_DEBUG
270.2196 +      int n = csa->n;
270.2197 +#endif
270.2198 +      char *type = csa->type;
270.2199 +      double *lb = csa->lb;
270.2200 +      double *ub = csa->ub;
270.2201 +      double *coef = csa->coef;
270.2202 +      int *head = csa->head;
270.2203 +      int phase = csa->phase;
270.2204 +      double *bbar = csa->bbar;
270.2205 +      int i, k;
270.2206 +      double eps;
270.2207 +      /* walk through the list of basic variables */
270.2208 +      for (i = 1; i <= m; i++)
270.2209 +      {  k = head[i]; /* x[k] = xB[i] */
270.2210 +#ifdef GLP_DEBUG
270.2211 +         xassert(1 <= k && k <= m+n);
270.2212 +#endif
270.2213 +         if (phase == 1 && coef[k] < 0.0)
270.2214 +         {  /* x[k] must not be greater than its lower bound */
270.2215 +#ifdef GLP_DEBUG
270.2216 +            xassert(type[k] == GLP_LO || type[k] == GLP_DB ||
270.2217 +                    type[k] == GLP_FX);
270.2218 +#endif
270.2219 +            eps = tol_bnd * (1.0 + kappa * fabs(lb[k]));
270.2220 +            if (bbar[i] > lb[k] + eps) return 1;
270.2221 +         }
270.2222 +         else if (phase == 1 && coef[k] > 0.0)
270.2223 +         {  /* x[k] must not be less than its upper bound */
270.2224 +#ifdef GLP_DEBUG
270.2225 +            xassert(type[k] == GLP_UP || type[k] == GLP_DB ||
270.2226 +                    type[k] == GLP_FX);
270.2227 +#endif
270.2228 +            eps = tol_bnd * (1.0 + kappa * fabs(ub[k]));
270.2229 +            if (bbar[i] < ub[k] - eps) return 1;
270.2230 +         }
270.2231 +         else
270.2232 +         {  /* either phase = 1 and coef[k] = 0, or phase = 2 */
270.2233 +            if (type[k] == GLP_LO || type[k] == GLP_DB ||
270.2234 +                type[k] == GLP_FX)
270.2235 +            {  /* x[k] must not be less than its lower bound */
270.2236 +               eps = tol_bnd * (1.0 + kappa * fabs(lb[k]));
270.2237 +               if (bbar[i] < lb[k] - eps) return 1;
270.2238 +            }
270.2239 +            if (type[k] == GLP_UP || type[k] == GLP_DB ||
270.2240 +                type[k] == GLP_FX)
270.2241 +            {  /* x[k] must not be greater then its upper bound */
270.2242 +               eps = tol_bnd * (1.0 + kappa * fabs(ub[k]));
270.2243 +               if (bbar[i] > ub[k] + eps) return 1;
270.2244 +            }
270.2245 +         }
270.2246 +      }
270.2247 +      /* basic solution is primal feasible within a tolerance */
270.2248 +      return 0;
270.2249 +}
270.2250 +
270.2251 +/***********************************************************************
270.2252 +*  check_feas - check primal feasibility of basic solution
270.2253 +*
270.2254 +*  If the current basic solution is primal feasible within a tolerance,
270.2255 +*  this routine returns zero, otherwise it returns non-zero. */
270.2256 +
270.2257 +static int check_feas(struct csa *csa, double tol_bnd)
270.2258 +{     int m = csa->m;
270.2259 +#ifdef GLP_DEBUG
270.2260 +      int n = csa->n;
270.2261 +      char *type = csa->type;
270.2262 +#endif
270.2263 +      double *lb = csa->lb;
270.2264 +      double *ub = csa->ub;
270.2265 +      double *coef = csa->coef;
270.2266 +      int *head = csa->head;
270.2267 +      double *bbar = csa->bbar;
270.2268 +      int i, k;
270.2269 +      double eps;
270.2270 +      xassert(csa->phase == 1);
270.2271 +      /* walk through the list of basic variables */
270.2272 +      for (i = 1; i <= m; i++)
270.2273 +      {  k = head[i]; /* x[k] = xB[i] */
270.2274 +#ifdef GLP_DEBUG
270.2275 +         xassert(1 <= k && k <= m+n);
270.2276 +#endif
270.2277 +         if (coef[k] < 0.0)
270.2278 +         {  /* check if x[k] still violates its lower bound */
270.2279 +#ifdef GLP_DEBUG
270.2280 +            xassert(type[k] == GLP_LO || type[k] == GLP_DB ||
270.2281 +                    type[k] == GLP_FX);
270.2282 +#endif
270.2283 +            eps = tol_bnd * (1.0 + kappa * fabs(lb[k]));
270.2284 +            if (bbar[i] < lb[k] - eps) return 1;
270.2285 +         }
270.2286 +         else if (coef[k] > 0.0)
270.2287 +         {  /* check if x[k] still violates its upper bound */
270.2288 +#ifdef GLP_DEBUG
270.2289 +            xassert(type[k] == GLP_UP || type[k] == GLP_DB ||
270.2290 +                    type[k] == GLP_FX);
270.2291 +#endif
270.2292 +            eps = tol_bnd * (1.0 + kappa * fabs(ub[k]));
270.2293 +            if (bbar[i] > ub[k] + eps) return 1;
270.2294 +         }
270.2295 +      }
270.2296 +      /* basic solution is primal feasible within a tolerance */
270.2297 +      return 0;
270.2298 +}
270.2299 +
270.2300 +/***********************************************************************
270.2301 +*  eval_obj - compute original objective function
270.2302 +*
270.2303 +*  This routine computes the current value of the original objective
270.2304 +*  function. */
270.2305 +
270.2306 +static double eval_obj(struct csa *csa)
270.2307 +{     int m = csa->m;
270.2308 +      int n = csa->n;
270.2309 +      double *obj = csa->obj;
270.2310 +      int *head = csa->head;
270.2311 +      double *bbar = csa->bbar;
270.2312 +      int i, j, k;
270.2313 +      double sum;
270.2314 +      sum = obj[0];
270.2315 +      /* walk through the list of basic variables */
270.2316 +      for (i = 1; i <= m; i++)
270.2317 +      {  k = head[i]; /* x[k] = xB[i] */
270.2318 +#ifdef GLP_DEBUG
270.2319 +         xassert(1 <= k && k <= m+n);
270.2320 +#endif
270.2321 +         if (k > m)
270.2322 +            sum += obj[k-m] * bbar[i];
270.2323 +      }
270.2324 +      /* walk through the list of non-basic variables */
270.2325 +      for (j = 1; j <= n; j++)
270.2326 +      {  k = head[m+j]; /* x[k] = xN[j] */
270.2327 +#ifdef GLP_DEBUG
270.2328 +         xassert(1 <= k && k <= m+n);
270.2329 +#endif
270.2330 +         if (k > m)
270.2331 +            sum += obj[k-m] * get_xN(csa, j);
270.2332 +      }
270.2333 +      return sum;
270.2334 +}
270.2335 +
270.2336 +/***********************************************************************
270.2337 +*  display - display the search progress
270.2338 +*
270.2339 +*  This routine displays some information about the search progress
270.2340 +*  that includes:
270.2341 +*
270.2342 +*  the search phase;
270.2343 +*
270.2344 +*  the number of simplex iterations performed by the solver;
270.2345 +*
270.2346 +*  the original objective value;
270.2347 +*
270.2348 +*  the sum of (scaled) primal infeasibilities;
270.2349 +*
270.2350 +*  the number of basic fixed variables. */
270.2351 +
270.2352 +static void display(struct csa *csa, const glp_smcp *parm, int spec)
270.2353 +{     int m = csa->m;
270.2354 +#ifdef GLP_DEBUG
270.2355 +      int n = csa->n;
270.2356 +#endif
270.2357 +      char *type = csa->type;
270.2358 +      double *lb = csa->lb;
270.2359 +      double *ub = csa->ub;
270.2360 +      int phase = csa->phase;
270.2361 +      int *head = csa->head;
270.2362 +      double *bbar = csa->bbar;
270.2363 +      int i, k, cnt;
270.2364 +      double sum;
270.2365 +      if (parm->msg_lev < GLP_MSG_ON) goto skip;
270.2366 +      if (parm->out_dly > 0 &&
270.2367 +         1000.0 * xdifftime(xtime(), csa->tm_beg) < parm->out_dly)
270.2368 +         goto skip;
270.2369 +      if (csa->it_cnt == csa->it_dpy) goto skip;
270.2370 +      if (!spec && csa->it_cnt % parm->out_frq != 0) goto skip;
270.2371 +      /* compute the sum of primal infeasibilities and determine the
270.2372 +         number of basic fixed variables */
270.2373 +      sum = 0.0, cnt = 0;
270.2374 +      for (i = 1; i <= m; i++)
270.2375 +      {  k = head[i]; /* x[k] = xB[i] */
270.2376 +#ifdef GLP_DEBUG
270.2377 +         xassert(1 <= k && k <= m+n);
270.2378 +#endif
270.2379 +         if (type[k] == GLP_LO || type[k] == GLP_DB ||
270.2380 +             type[k] == GLP_FX)
270.2381 +         {  /* x[k] has lower bound */
270.2382 +            if (bbar[i] < lb[k])
270.2383 +               sum += (lb[k] - bbar[i]);
270.2384 +         }
270.2385 +         if (type[k] == GLP_UP || type[k] == GLP_DB ||
270.2386 +             type[k] == GLP_FX)
270.2387 +         {  /* x[k] has upper bound */
270.2388 +            if (bbar[i] > ub[k])
270.2389 +               sum += (bbar[i] - ub[k]);
270.2390 +         }
270.2391 +         if (type[k] == GLP_FX) cnt++;
270.2392 +      }
270.2393 +      xprintf("%c%6d: obj = %17.9e  infeas = %10.3e (%d)\n",
270.2394 +         phase == 1 ? ' ' : '*', csa->it_cnt, eval_obj(csa), sum, cnt);
270.2395 +      csa->it_dpy = csa->it_cnt;
270.2396 +skip: return;
270.2397 +}
270.2398 +
270.2399 +/***********************************************************************
270.2400 +*  store_sol - store basic solution back to the problem object
270.2401 +*
270.2402 +*  This routine stores basic solution components back to the problem
270.2403 +*  object. */
270.2404 +
270.2405 +static void store_sol(struct csa *csa, glp_prob *lp, int p_stat,
270.2406 +      int d_stat, int ray)
270.2407 +{     int m = csa->m;
270.2408 +      int n = csa->n;
270.2409 +      double zeta = csa->zeta;
270.2410 +      int *head = csa->head;
270.2411 +      char *stat = csa->stat;
270.2412 +      double *bbar = csa->bbar;
270.2413 +      double *cbar = csa->cbar;
270.2414 +      int i, j, k;
270.2415 +#ifdef GLP_DEBUG
270.2416 +      xassert(lp->m == m);
270.2417 +      xassert(lp->n == n);
270.2418 +#endif
270.2419 +      /* basis factorization */
270.2420 +#ifdef GLP_DEBUG
270.2421 +      xassert(!lp->valid && lp->bfd == NULL);
270.2422 +      xassert(csa->valid && csa->bfd != NULL);
270.2423 +#endif
270.2424 +      lp->valid = 1, csa->valid = 0;
270.2425 +      lp->bfd = csa->bfd, csa->bfd = NULL;
270.2426 +      memcpy(&lp->head[1], &head[1], m * sizeof(int));
270.2427 +      /* basic solution status */
270.2428 +      lp->pbs_stat = p_stat;
270.2429 +      lp->dbs_stat = d_stat;
270.2430 +      /* objective function value */
270.2431 +      lp->obj_val = eval_obj(csa);
270.2432 +      /* simplex iteration count */
270.2433 +      lp->it_cnt = csa->it_cnt;
270.2434 +      /* unbounded ray */
270.2435 +      lp->some = ray;
270.2436 +      /* basic variables */
270.2437 +      for (i = 1; i <= m; i++)
270.2438 +      {  k = head[i]; /* x[k] = xB[i] */
270.2439 +#ifdef GLP_DEBUG
270.2440 +         xassert(1 <= k && k <= m+n);
270.2441 +#endif
270.2442 +         if (k <= m)
270.2443 +         {  GLPROW *row = lp->row[k];
270.2444 +            row->stat = GLP_BS;
270.2445 +            row->bind = i;
270.2446 +            row->prim = bbar[i] / row->rii;
270.2447 +            row->dual = 0.0;
270.2448 +         }
270.2449 +         else
270.2450 +         {  GLPCOL *col = lp->col[k-m];
270.2451 +            col->stat = GLP_BS;
270.2452 +            col->bind = i;
270.2453 +            col->prim = bbar[i] * col->sjj;
270.2454 +            col->dual = 0.0;
270.2455 +         }
270.2456 +      }
270.2457 +      /* non-basic variables */
270.2458 +      for (j = 1; j <= n; j++)
270.2459 +      {  k = head[m+j]; /* x[k] = xN[j] */
270.2460 +#ifdef GLP_DEBUG
270.2461 +         xassert(1 <= k && k <= m+n);
270.2462 +#endif
270.2463 +         if (k <= m)
270.2464 +         {  GLPROW *row = lp->row[k];
270.2465 +            row->stat = stat[j];
270.2466 +            row->bind = 0;
270.2467 +#if 0
270.2468 +            row->prim = get_xN(csa, j) / row->rii;
270.2469 +#else
270.2470 +            switch (stat[j])
270.2471 +            {  case GLP_NL:
270.2472 +                  row->prim = row->lb; break;
270.2473 +               case GLP_NU:
270.2474 +                  row->prim = row->ub; break;
270.2475 +               case GLP_NF:
270.2476 +                  row->prim = 0.0; break;
270.2477 +               case GLP_NS:
270.2478 +                  row->prim = row->lb; break;
270.2479 +               default:
270.2480 +                  xassert(stat != stat);
270.2481 +            }
270.2482 +#endif
270.2483 +            row->dual = (cbar[j] * row->rii) / zeta;
270.2484 +         }
270.2485 +         else
270.2486 +         {  GLPCOL *col = lp->col[k-m];
270.2487 +            col->stat = stat[j];
270.2488 +            col->bind = 0;
270.2489 +#if 0
270.2490 +            col->prim = get_xN(csa, j) * col->sjj;
270.2491 +#else
270.2492 +            switch (stat[j])
270.2493 +            {  case GLP_NL:
270.2494 +                  col->prim = col->lb; break;
270.2495 +               case GLP_NU:
270.2496 +                  col->prim = col->ub; break;
270.2497 +               case GLP_NF:
270.2498 +                  col->prim = 0.0; break;
270.2499 +               case GLP_NS:
270.2500 +                  col->prim = col->lb; break;
270.2501 +               default:
270.2502 +                  xassert(stat != stat);
270.2503 +            }
270.2504 +#endif
270.2505 +            col->dual = (cbar[j] / col->sjj) / zeta;
270.2506 +         }
270.2507 +      }
270.2508 +      return;
270.2509 +}
270.2510 +
270.2511 +/***********************************************************************
270.2512 +*  free_csa - deallocate common storage area
270.2513 +*
270.2514 +*  This routine frees all the memory allocated to arrays in the common
270.2515 +*  storage area (CSA). */
270.2516 +
270.2517 +static void free_csa(struct csa *csa)
270.2518 +{     xfree(csa->type);
270.2519 +      xfree(csa->lb);
270.2520 +      xfree(csa->ub);
270.2521 +      xfree(csa->coef);
270.2522 +      xfree(csa->obj);
270.2523 +      xfree(csa->A_ptr);
270.2524 +      xfree(csa->A_ind);
270.2525 +      xfree(csa->A_val);
270.2526 +      xfree(csa->head);
270.2527 +      xfree(csa->stat);
270.2528 +      xfree(csa->N_ptr);
270.2529 +      xfree(csa->N_len);
270.2530 +      xfree(csa->N_ind);
270.2531 +      xfree(csa->N_val);
270.2532 +      xfree(csa->bbar);
270.2533 +      xfree(csa->cbar);
270.2534 +      xfree(csa->refsp);
270.2535 +      xfree(csa->gamma);
270.2536 +      xfree(csa->tcol_ind);
270.2537 +      xfree(csa->tcol_vec);
270.2538 +      xfree(csa->trow_ind);
270.2539 +      xfree(csa->trow_vec);
270.2540 +      xfree(csa->work1);
270.2541 +      xfree(csa->work2);
270.2542 +      xfree(csa->work3);
270.2543 +      xfree(csa->work4);
270.2544 +      xfree(csa);
270.2545 +      return;
270.2546 +}
270.2547 +
270.2548 +/***********************************************************************
270.2549 +*  spx_primal - core LP solver based on the primal simplex method
270.2550 +*
270.2551 +*  SYNOPSIS
270.2552 +*
270.2553 +*  #include "glpspx.h"
270.2554 +*  int spx_primal(glp_prob *lp, const glp_smcp *parm);
270.2555 +*
270.2556 +*  DESCRIPTION
270.2557 +*
270.2558 +*  The routine spx_primal is a core LP solver based on the two-phase
270.2559 +*  primal simplex method.
270.2560 +*
270.2561 +*  RETURNS
270.2562 +*
270.2563 +*  0  LP instance has been successfully solved.
270.2564 +*
270.2565 +*  GLP_EITLIM
270.2566 +*     Iteration limit has been exhausted.
270.2567 +*
270.2568 +*  GLP_ETMLIM
270.2569 +*     Time limit has been exhausted.
270.2570 +*
270.2571 +*  GLP_EFAIL
270.2572 +*     The solver failed to solve LP instance. */
270.2573 +
270.2574 +int spx_primal(glp_prob *lp, const glp_smcp *parm)
270.2575 +{     struct csa *csa;
270.2576 +      int binv_st = 2;
270.2577 +      /* status of basis matrix factorization:
270.2578 +         0 - invalid; 1 - just computed; 2 - updated */
270.2579 +      int bbar_st = 0;
270.2580 +      /* status of primal values of basic variables:
270.2581 +         0 - invalid; 1 - just computed; 2 - updated */
270.2582 +      int cbar_st = 0;
270.2583 +      /* status of reduced costs of non-basic variables:
270.2584 +         0 - invalid; 1 - just computed; 2 - updated */
270.2585 +      int rigorous = 0;
270.2586 +      /* rigorous mode flag; this flag is used to enable iterative
270.2587 +         refinement on computing pivot rows and columns of the simplex
270.2588 +         table */
270.2589 +      int check = 0;
270.2590 +      int p_stat, d_stat, ret;
270.2591 +      /* allocate and initialize the common storage area */
270.2592 +      csa = alloc_csa(lp);
270.2593 +      init_csa(csa, lp);
270.2594 +      if (parm->msg_lev >= GLP_MSG_DBG)
270.2595 +         xprintf("Objective scale factor = %g\n", csa->zeta);
270.2596 +loop: /* main loop starts here */
270.2597 +      /* compute factorization of the basis matrix */
270.2598 +      if (binv_st == 0)
270.2599 +      {  ret = invert_B(csa);
270.2600 +         if (ret != 0)
270.2601 +         {  if (parm->msg_lev >= GLP_MSG_ERR)
270.2602 +            {  xprintf("Error: unable to factorize the basis matrix (%d"
270.2603 +                  ")\n", ret);
270.2604 +               xprintf("Sorry, basis recovery procedure not implemented"
270.2605 +                  " yet\n");
270.2606 +            }
270.2607 +            xassert(!lp->valid && lp->bfd == NULL);
270.2608 +            lp->bfd = csa->bfd, csa->bfd = NULL;
270.2609 +            lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
270.2610 +            lp->obj_val = 0.0;
270.2611 +            lp->it_cnt = csa->it_cnt;
270.2612 +            lp->some = 0;
270.2613 +            ret = GLP_EFAIL;
270.2614 +            goto done;
270.2615 +         }
270.2616 +         csa->valid = 1;
270.2617 +         binv_st = 1; /* just computed */
270.2618 +         /* invalidate basic solution components */
270.2619 +         bbar_st = cbar_st = 0;
270.2620 +      }
270.2621 +      /* compute primal values of basic variables */
270.2622 +      if (bbar_st == 0)
270.2623 +      {  eval_bbar(csa);
270.2624 +         bbar_st = 1; /* just computed */
270.2625 +         /* determine the search phase, if not determined yet */
270.2626 +         if (csa->phase == 0)
270.2627 +         {  if (set_aux_obj(csa, parm->tol_bnd) > 0)
270.2628 +            {  /* current basic solution is primal infeasible */
270.2629 +               /* start to minimize the sum of infeasibilities */
270.2630 +               csa->phase = 1;
270.2631 +            }
270.2632 +            else
270.2633 +            {  /* current basic solution is primal feasible */
270.2634 +               /* start to minimize the original objective function */
270.2635 +               set_orig_obj(csa);
270.2636 +               csa->phase = 2;
270.2637 +            }
270.2638 +            xassert(check_stab(csa, parm->tol_bnd) == 0);
270.2639 +            /* working objective coefficients have been changed, so
270.2640 +               invalidate reduced costs */
270.2641 +            cbar_st = 0;
270.2642 +            display(csa, parm, 1);
270.2643 +         }
270.2644 +         /* make sure that the current basic solution remains primal
270.2645 +            feasible (or pseudo feasible on phase I) */
270.2646 +         if (check_stab(csa, parm->tol_bnd))
270.2647 +         {  /* there are excessive bound violations due to round-off
270.2648 +               errors */
270.2649 +            if (parm->msg_lev >= GLP_MSG_ERR)
270.2650 +               xprintf("Warning: numerical instability (primal simplex,"
270.2651 +                  " phase %s)\n", csa->phase == 1 ? "I" : "II");
270.2652 +            /* restart the search */
270.2653 +            csa->phase = 0;
270.2654 +            binv_st = 0;
270.2655 +            rigorous = 5;
270.2656 +            goto loop;
270.2657 +         }
270.2658 +      }
270.2659 +      xassert(csa->phase == 1 || csa->phase == 2);
270.2660 +      /* on phase I we do not need to wait until the current basic
270.2661 +         solution becomes dual feasible; it is sufficient to make sure
270.2662 +         that no basic variable violates its bounds */
270.2663 +      if (csa->phase == 1 && !check_feas(csa, parm->tol_bnd))
270.2664 +      {  /* the current basis is primal feasible; switch to phase II */
270.2665 +         csa->phase = 2;
270.2666 +         set_orig_obj(csa);
270.2667 +         cbar_st = 0;
270.2668 +         display(csa, parm, 1);
270.2669 +      }
270.2670 +      /* compute reduced costs of non-basic variables */
270.2671 +      if (cbar_st == 0)
270.2672 +      {  eval_cbar(csa);
270.2673 +         cbar_st = 1; /* just computed */
270.2674 +      }
270.2675 +      /* redefine the reference space, if required */
270.2676 +      switch (parm->pricing)
270.2677 +      {  case GLP_PT_STD:
270.2678 +            break;
270.2679 +         case GLP_PT_PSE:
270.2680 +            if (csa->refct == 0) reset_refsp(csa);
270.2681 +            break;
270.2682 +         default:
270.2683 +            xassert(parm != parm);
270.2684 +      }
270.2685 +      /* at this point the basis factorization and all basic solution
270.2686 +         components are valid */
270.2687 +      xassert(binv_st && bbar_st && cbar_st);
270.2688 +      /* check accuracy of current basic solution components (only for
270.2689 +         debugging) */
270.2690 +      if (check)
270.2691 +      {  double e_bbar = err_in_bbar(csa);
270.2692 +         double e_cbar = err_in_cbar(csa);
270.2693 +         double e_gamma =
270.2694 +            (parm->pricing == GLP_PT_PSE ? err_in_gamma(csa) : 0.0);
270.2695 +         xprintf("e_bbar = %10.3e; e_cbar = %10.3e; e_gamma = %10.3e\n",
270.2696 +            e_bbar, e_cbar, e_gamma);
270.2697 +         xassert(e_bbar <= 1e-5 && e_cbar <= 1e-5 && e_gamma <= 1e-3);
270.2698 +      }
270.2699 +      /* check if the iteration limit has been exhausted */
270.2700 +      if (parm->it_lim < INT_MAX &&
270.2701 +          csa->it_cnt - csa->it_beg >= parm->it_lim)
270.2702 +      {  if (bbar_st != 1 || csa->phase == 2 && cbar_st != 1)
270.2703 +         {  if (bbar_st != 1) bbar_st = 0;
270.2704 +            if (csa->phase == 2 && cbar_st != 1) cbar_st = 0;
270.2705 +            goto loop;
270.2706 +         }
270.2707 +         display(csa, parm, 1);
270.2708 +         if (parm->msg_lev >= GLP_MSG_ALL)
270.2709 +            xprintf("ITERATION LIMIT EXCEEDED; SEARCH TERMINATED\n");
270.2710 +         switch (csa->phase)
270.2711 +         {  case 1:
270.2712 +               p_stat = GLP_INFEAS;
270.2713 +               set_orig_obj(csa);
270.2714 +               eval_cbar(csa);
270.2715 +               break;
270.2716 +            case 2:
270.2717 +               p_stat = GLP_FEAS;
270.2718 +               break;
270.2719 +            default:
270.2720 +               xassert(csa != csa);
270.2721 +         }
270.2722 +         chuzc(csa, parm->tol_dj);
270.2723 +         d_stat = (csa->q == 0 ? GLP_FEAS : GLP_INFEAS);
270.2724 +         store_sol(csa, lp, p_stat, d_stat, 0);
270.2725 +         ret = GLP_EITLIM;
270.2726 +         goto done;
270.2727 +      }
270.2728 +      /* check if the time limit has been exhausted */
270.2729 +      if (parm->tm_lim < INT_MAX &&
270.2730 +          1000.0 * xdifftime(xtime(), csa->tm_beg) >= parm->tm_lim)
270.2731 +      {  if (bbar_st != 1 || csa->phase == 2 && cbar_st != 1)
270.2732 +         {  if (bbar_st != 1) bbar_st = 0;
270.2733 +            if (csa->phase == 2 && cbar_st != 1) cbar_st = 0;
270.2734 +            goto loop;
270.2735 +         }
270.2736 +         display(csa, parm, 1);
270.2737 +         if (parm->msg_lev >= GLP_MSG_ALL)
270.2738 +            xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
270.2739 +         switch (csa->phase)
270.2740 +         {  case 1:
270.2741 +               p_stat = GLP_INFEAS;
270.2742 +               set_orig_obj(csa);
270.2743 +               eval_cbar(csa);
270.2744 +               break;
270.2745 +            case 2:
270.2746 +               p_stat = GLP_FEAS;
270.2747 +               break;
270.2748 +            default:
270.2749 +               xassert(csa != csa);
270.2750 +         }
270.2751 +         chuzc(csa, parm->tol_dj);
270.2752 +         d_stat = (csa->q == 0 ? GLP_FEAS : GLP_INFEAS);
270.2753 +         store_sol(csa, lp, p_stat, d_stat, 0);
270.2754 +         ret = GLP_ETMLIM;
270.2755 +         goto done;
270.2756 +      }
270.2757 +      /* display the search progress */
270.2758 +      display(csa, parm, 0);
270.2759 +      /* choose non-basic variable xN[q] */
270.2760 +      chuzc(csa, parm->tol_dj);
270.2761 +      if (csa->q == 0)
270.2762 +      {  if (bbar_st != 1 || cbar_st != 1)
270.2763 +         {  if (bbar_st != 1) bbar_st = 0;
270.2764 +            if (cbar_st != 1) cbar_st = 0;
270.2765 +            goto loop;
270.2766 +         }
270.2767 +         display(csa, parm, 1);
270.2768 +         switch (csa->phase)
270.2769 +         {  case 1:
270.2770 +               if (parm->msg_lev >= GLP_MSG_ALL)
270.2771 +                  xprintf("PROBLEM HAS NO FEASIBLE SOLUTION\n");
270.2772 +               p_stat = GLP_NOFEAS;
270.2773 +               set_orig_obj(csa);
270.2774 +               eval_cbar(csa);
270.2775 +               chuzc(csa, parm->tol_dj);
270.2776 +               d_stat = (csa->q == 0 ? GLP_FEAS : GLP_INFEAS);
270.2777 +               break;
270.2778 +            case 2:
270.2779 +               if (parm->msg_lev >= GLP_MSG_ALL)
270.2780 +                  xprintf("OPTIMAL SOLUTION FOUND\n");
270.2781 +               p_stat = d_stat = GLP_FEAS;
270.2782 +               break;
270.2783 +            default:
270.2784 +               xassert(csa != csa);
270.2785 +         }
270.2786 +         store_sol(csa, lp, p_stat, d_stat, 0);
270.2787 +         ret = 0;
270.2788 +         goto done;
270.2789 +      }
270.2790 +      /* compute pivot column of the simplex table */
270.2791 +      eval_tcol(csa);
270.2792 +      if (rigorous) refine_tcol(csa);
270.2793 +      sort_tcol(csa, parm->tol_piv);
270.2794 +      /* check accuracy of the reduced cost of xN[q] */
270.2795 +      {  double d1 = csa->cbar[csa->q]; /* less accurate */
270.2796 +         double d2 = reeval_cost(csa);  /* more accurate */
270.2797 +         xassert(d1 != 0.0);
270.2798 +         if (fabs(d1 - d2) > 1e-5 * (1.0 + fabs(d2)) ||
270.2799 +             !(d1 < 0.0 && d2 < 0.0 || d1 > 0.0 && d2 > 0.0))
270.2800 +         {  if (parm->msg_lev >= GLP_MSG_DBG)
270.2801 +               xprintf("d1 = %.12g; d2 = %.12g\n", d1, d2);
270.2802 +            if (cbar_st != 1 || !rigorous)
270.2803 +            {  if (cbar_st != 1) cbar_st = 0;
270.2804 +               rigorous = 5;
270.2805 +               goto loop;
270.2806 +            }
270.2807 +         }
270.2808 +         /* replace cbar[q] by more accurate value keeping its sign */
270.2809 +         if (d1 > 0.0)
270.2810 +            csa->cbar[csa->q] = (d2 > 0.0 ? d2 : +DBL_EPSILON);
270.2811 +         else
270.2812 +            csa->cbar[csa->q] = (d2 < 0.0 ? d2 : -DBL_EPSILON);
270.2813 +      }
270.2814 +      /* choose basic variable xB[p] */
270.2815 +      switch (parm->r_test)
270.2816 +      {  case GLP_RT_STD:
270.2817 +            chuzr(csa, 0.0);
270.2818 +            break;
270.2819 +         case GLP_RT_HAR:
270.2820 +            chuzr(csa, 0.30 * parm->tol_bnd);
270.2821 +            break;
270.2822 +         default:
270.2823 +            xassert(parm != parm);
270.2824 +      }
270.2825 +      if (csa->p == 0)
270.2826 +      {  if (bbar_st != 1 || cbar_st != 1 || !rigorous)
270.2827 +         {  if (bbar_st != 1) bbar_st = 0;
270.2828 +            if (cbar_st != 1) cbar_st = 0;
270.2829 +            rigorous = 1;
270.2830 +            goto loop;
270.2831 +         }
270.2832 +         display(csa, parm, 1);
270.2833 +         switch (csa->phase)
270.2834 +         {  case 1:
270.2835 +               if (parm->msg_lev >= GLP_MSG_ERR)
270.2836 +                  xprintf("Error: unable to choose basic variable on ph"
270.2837 +                     "ase I\n");
270.2838 +               xassert(!lp->valid && lp->bfd == NULL);
270.2839 +               lp->bfd = csa->bfd, csa->bfd = NULL;
270.2840 +               lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
270.2841 +               lp->obj_val = 0.0;
270.2842 +               lp->it_cnt = csa->it_cnt;
270.2843 +               lp->some = 0;
270.2844 +               ret = GLP_EFAIL;
270.2845 +               break;
270.2846 +            case 2:
270.2847 +               if (parm->msg_lev >= GLP_MSG_ALL)
270.2848 +                  xprintf("PROBLEM HAS UNBOUNDED SOLUTION\n");
270.2849 +               store_sol(csa, lp, GLP_FEAS, GLP_NOFEAS,
270.2850 +                  csa->head[csa->m+csa->q]);
270.2851 +               ret = 0;
270.2852 +               break;
270.2853 +            default:
270.2854 +               xassert(csa != csa);
270.2855 +         }
270.2856 +         goto done;
270.2857 +      }
270.2858 +      /* check if the pivot element is acceptable */
270.2859 +      if (csa->p > 0)
270.2860 +      {  double piv = csa->tcol_vec[csa->p];
270.2861 +         double eps = 1e-5 * (1.0 + 0.01 * csa->tcol_max);
270.2862 +         if (fabs(piv) < eps)
270.2863 +         {  if (parm->msg_lev >= GLP_MSG_DBG)
270.2864 +               xprintf("piv = %.12g; eps = %g\n", piv, eps);
270.2865 +            if (!rigorous)
270.2866 +            {  rigorous = 5;
270.2867 +               goto loop;
270.2868 +            }
270.2869 +         }
270.2870 +      }
270.2871 +      /* now xN[q] and xB[p] have been chosen anyhow */
270.2872 +      /* compute pivot row of the simplex table */
270.2873 +      if (csa->p > 0)
270.2874 +      {  double *rho = csa->work4;
270.2875 +         eval_rho(csa, rho);
270.2876 +         if (rigorous) refine_rho(csa, rho);
270.2877 +         eval_trow(csa, rho);
270.2878 +      }
270.2879 +      /* accuracy check based on the pivot element */
270.2880 +      if (csa->p > 0)
270.2881 +      {  double piv1 = csa->tcol_vec[csa->p]; /* more accurate */
270.2882 +         double piv2 = csa->trow_vec[csa->q]; /* less accurate */
270.2883 +         xassert(piv1 != 0.0);
270.2884 +         if (fabs(piv1 - piv2) > 1e-8 * (1.0 + fabs(piv1)) ||
270.2885 +             !(piv1 > 0.0 && piv2 > 0.0 || piv1 < 0.0 && piv2 < 0.0))
270.2886 +         {  if (parm->msg_lev >= GLP_MSG_DBG)
270.2887 +               xprintf("piv1 = %.12g; piv2 = %.12g\n", piv1, piv2);
270.2888 +            if (binv_st != 1 || !rigorous)
270.2889 +            {  if (binv_st != 1) binv_st = 0;
270.2890 +               rigorous = 5;
270.2891 +               goto loop;
270.2892 +            }
270.2893 +            /* use more accurate version in the pivot row */
270.2894 +            if (csa->trow_vec[csa->q] == 0.0)
270.2895 +            {  csa->trow_nnz++;
270.2896 +               xassert(csa->trow_nnz <= csa->n);
270.2897 +               csa->trow_ind[csa->trow_nnz] = csa->q;
270.2898 +            }
270.2899 +            csa->trow_vec[csa->q] = piv1;
270.2900 +         }
270.2901 +      }
270.2902 +      /* update primal values of basic variables */
270.2903 +      update_bbar(csa);
270.2904 +      bbar_st = 2; /* updated */
270.2905 +      /* update reduced costs of non-basic variables */
270.2906 +      if (csa->p > 0)
270.2907 +      {  update_cbar(csa);
270.2908 +         cbar_st = 2; /* updated */
270.2909 +         /* on phase I objective coefficient of xB[p] in the adjacent
270.2910 +            basis becomes zero */
270.2911 +         if (csa->phase == 1)
270.2912 +         {  int k = csa->head[csa->p]; /* x[k] = xB[p] -> xN[q] */
270.2913 +            csa->cbar[csa->q] -= csa->coef[k];
270.2914 +            csa->coef[k] = 0.0;
270.2915 +         }
270.2916 +      }
270.2917 +      /* update steepest edge coefficients */
270.2918 +      if (csa->p > 0)
270.2919 +      {  switch (parm->pricing)
270.2920 +         {  case GLP_PT_STD:
270.2921 +               break;
270.2922 +            case GLP_PT_PSE:
270.2923 +               if (csa->refct > 0) update_gamma(csa);
270.2924 +               break;
270.2925 +            default:
270.2926 +               xassert(parm != parm);
270.2927 +         }
270.2928 +      }
270.2929 +      /* update factorization of the basis matrix */
270.2930 +      if (csa->p > 0)
270.2931 +      {  ret = update_B(csa, csa->p, csa->head[csa->m+csa->q]);
270.2932 +         if (ret == 0)
270.2933 +            binv_st = 2; /* updated */
270.2934 +         else
270.2935 +         {  csa->valid = 0;
270.2936 +            binv_st = 0; /* invalid */
270.2937 +         }
270.2938 +      }
270.2939 +      /* update matrix N */
270.2940 +      if (csa->p > 0)
270.2941 +      {  del_N_col(csa, csa->q, csa->head[csa->m+csa->q]);
270.2942 +         if (csa->type[csa->head[csa->p]] != GLP_FX)
270.2943 +            add_N_col(csa, csa->q, csa->head[csa->p]);
270.2944 +      }
270.2945 +      /* change the basis header */
270.2946 +      change_basis(csa);
270.2947 +      /* iteration complete */
270.2948 +      csa->it_cnt++;
270.2949 +      if (rigorous > 0) rigorous--;
270.2950 +      goto loop;
270.2951 +done: /* deallocate the common storage area */
270.2952 +      free_csa(csa);
270.2953 +      /* return to the calling program */
270.2954 +      return ret;
270.2955 +}
270.2956 +
270.2957 +/* eof */
   271.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   271.2 +++ b/src/glpspx02.c	Mon Dec 06 13:09:21 2010 +0100
   271.3 @@ -0,0 +1,3077 @@
   271.4 +/* glpspx02.c (dual simplex method) */
   271.5 +
   271.6 +/***********************************************************************
   271.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   271.8 +*
   271.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  271.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  271.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  271.12 +*  E-mail: <mao@gnu.org>.
  271.13 +*
  271.14 +*  GLPK is free software: you can redistribute it and/or modify it
  271.15 +*  under the terms of the GNU General Public License as published by
  271.16 +*  the Free Software Foundation, either version 3 of the License, or
  271.17 +*  (at your option) any later version.
  271.18 +*
  271.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  271.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  271.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  271.22 +*  License for more details.
  271.23 +*
  271.24 +*  You should have received a copy of the GNU General Public License
  271.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  271.26 +***********************************************************************/
  271.27 +
  271.28 +#include "glpspx.h"
  271.29 +
  271.30 +#define GLP_DEBUG 1
  271.31 +
  271.32 +#if 0
  271.33 +#define GLP_LONG_STEP 1
  271.34 +#endif
  271.35 +
  271.36 +struct csa
  271.37 +{     /* common storage area */
  271.38 +      /*--------------------------------------------------------------*/
  271.39 +      /* LP data */
  271.40 +      int m;
  271.41 +      /* number of rows (auxiliary variables), m > 0 */
  271.42 +      int n;
  271.43 +      /* number of columns (structural variables), n > 0 */
  271.44 +      char *type; /* char type[1+m+n]; */
  271.45 +      /* type[0] is not used;
  271.46 +         type[k], 1 <= k <= m+n, is the type of variable x[k]:
  271.47 +         GLP_FR - free variable
  271.48 +         GLP_LO - variable with lower bound
  271.49 +         GLP_UP - variable with upper bound
  271.50 +         GLP_DB - double-bounded variable
  271.51 +         GLP_FX - fixed variable */
  271.52 +      double *lb; /* double lb[1+m+n]; */
  271.53 +      /* lb[0] is not used;
  271.54 +         lb[k], 1 <= k <= m+n, is an lower bound of variable x[k];
  271.55 +         if x[k] has no lower bound, lb[k] is zero */
  271.56 +      double *ub; /* double ub[1+m+n]; */
  271.57 +      /* ub[0] is not used;
  271.58 +         ub[k], 1 <= k <= m+n, is an upper bound of variable x[k];
  271.59 +         if x[k] has no upper bound, ub[k] is zero;
  271.60 +         if x[k] is of fixed type, ub[k] is the same as lb[k] */
  271.61 +      double *coef; /* double coef[1+m+n]; */
  271.62 +      /* coef[0] is not used;
  271.63 +         coef[k], 1 <= k <= m+n, is an objective coefficient at
  271.64 +         variable x[k] */
  271.65 +      /*--------------------------------------------------------------*/
  271.66 +      /* original bounds of variables */
  271.67 +      char *orig_type; /* char orig_type[1+m+n]; */
  271.68 +      double *orig_lb; /* double orig_lb[1+m+n]; */
  271.69 +      double *orig_ub; /* double orig_ub[1+m+n]; */
  271.70 +      /*--------------------------------------------------------------*/
  271.71 +      /* original objective function */
  271.72 +      double *obj; /* double obj[1+n]; */
  271.73 +      /* obj[0] is a constant term of the original objective function;
  271.74 +         obj[j], 1 <= j <= n, is an original objective coefficient at
  271.75 +         structural variable x[m+j] */
  271.76 +      double zeta;
  271.77 +      /* factor used to scale original objective coefficients; its
  271.78 +         sign defines original optimization direction: zeta > 0 means
  271.79 +         minimization, zeta < 0 means maximization */
  271.80 +      /*--------------------------------------------------------------*/
  271.81 +      /* constraint matrix A; it has m rows and n columns and is stored
  271.82 +         by columns */
  271.83 +      int *A_ptr; /* int A_ptr[1+n+1]; */
  271.84 +      /* A_ptr[0] is not used;
  271.85 +         A_ptr[j], 1 <= j <= n, is starting position of j-th column in
  271.86 +         arrays A_ind and A_val; note that A_ptr[1] is always 1;
  271.87 +         A_ptr[n+1] indicates the position after the last element in
  271.88 +         arrays A_ind and A_val */
  271.89 +      int *A_ind; /* int A_ind[A_ptr[n+1]]; */
  271.90 +      /* row indices */
  271.91 +      double *A_val; /* double A_val[A_ptr[n+1]]; */
  271.92 +      /* non-zero element values */
  271.93 +#if 1 /* 06/IV-2009 */
  271.94 +      /* constraint matrix A stored by rows */
  271.95 +      int *AT_ptr; /* int AT_ptr[1+m+1];
  271.96 +      /* AT_ptr[0] is not used;
  271.97 +         AT_ptr[i], 1 <= i <= m, is starting position of i-th row in
  271.98 +         arrays AT_ind and AT_val; note that AT_ptr[1] is always 1;
  271.99 +         AT_ptr[m+1] indicates the position after the last element in
 271.100 +         arrays AT_ind and AT_val */
 271.101 +      int *AT_ind; /* int AT_ind[AT_ptr[m+1]]; */
 271.102 +      /* column indices */
 271.103 +      double *AT_val; /* double AT_val[AT_ptr[m+1]]; */
 271.104 +      /* non-zero element values */
 271.105 +#endif
 271.106 +      /*--------------------------------------------------------------*/
 271.107 +      /* basis header */
 271.108 +      int *head; /* int head[1+m+n]; */
 271.109 +      /* head[0] is not used;
 271.110 +         head[i], 1 <= i <= m, is the ordinal number of basic variable
 271.111 +         xB[i]; head[i] = k means that xB[i] = x[k] and i-th column of
 271.112 +         matrix B is k-th column of matrix (I|-A);
 271.113 +         head[m+j], 1 <= j <= n, is the ordinal number of non-basic
 271.114 +         variable xN[j]; head[m+j] = k means that xN[j] = x[k] and j-th
 271.115 +         column of matrix N is k-th column of matrix (I|-A) */
 271.116 +#if 1 /* 06/IV-2009 */
 271.117 +      int *bind; /* int bind[1+m+n]; */
 271.118 +      /* bind[0] is not used;
 271.119 +         bind[k], 1 <= k <= m+n, is the position of k-th column of the
 271.120 +         matrix (I|-A) in the matrix (B|N); that is, bind[k] = k' means
 271.121 +         that head[k'] = k */
 271.122 +#endif
 271.123 +      char *stat; /* char stat[1+n]; */
 271.124 +      /* stat[0] is not used;
 271.125 +         stat[j], 1 <= j <= n, is the status of non-basic variable
 271.126 +         xN[j], which defines its active bound:
 271.127 +         GLP_NL - lower bound is active
 271.128 +         GLP_NU - upper bound is active
 271.129 +         GLP_NF - free variable
 271.130 +         GLP_NS - fixed variable */
 271.131 +      /*--------------------------------------------------------------*/
 271.132 +      /* matrix B is the basis matrix; it is composed from columns of
 271.133 +         the augmented constraint matrix (I|-A) corresponding to basic
 271.134 +         variables and stored in a factorized (invertable) form */
 271.135 +      int valid;
 271.136 +      /* factorization is valid only if this flag is set */
 271.137 +      BFD *bfd; /* BFD bfd[1:m,1:m]; */
 271.138 +      /* factorized (invertable) form of the basis matrix */
 271.139 +#if 0 /* 06/IV-2009 */
 271.140 +      /*--------------------------------------------------------------*/
 271.141 +      /* matrix N is a matrix composed from columns of the augmented
 271.142 +         constraint matrix (I|-A) corresponding to non-basic variables
 271.143 +         except fixed ones; it is stored by rows and changes every time
 271.144 +         the basis changes */
 271.145 +      int *N_ptr; /* int N_ptr[1+m+1]; */
 271.146 +      /* N_ptr[0] is not used;
 271.147 +         N_ptr[i], 1 <= i <= m, is starting position of i-th row in
 271.148 +         arrays N_ind and N_val; note that N_ptr[1] is always 1;
 271.149 +         N_ptr[m+1] indicates the position after the last element in
 271.150 +         arrays N_ind and N_val */
 271.151 +      int *N_len; /* int N_len[1+m]; */
 271.152 +      /* N_len[0] is not used;
 271.153 +         N_len[i], 1 <= i <= m, is length of i-th row (0 to n) */
 271.154 +      int *N_ind; /* int N_ind[N_ptr[m+1]]; */
 271.155 +      /* column indices */
 271.156 +      double *N_val; /* double N_val[N_ptr[m+1]]; */
 271.157 +      /* non-zero element values */
 271.158 +#endif
 271.159 +      /*--------------------------------------------------------------*/
 271.160 +      /* working parameters */
 271.161 +      int phase;
 271.162 +      /* search phase:
 271.163 +         0 - not determined yet
 271.164 +         1 - search for dual feasible solution
 271.165 +         2 - search for optimal solution */
 271.166 +      glp_long tm_beg;
 271.167 +      /* time value at the beginning of the search */
 271.168 +      int it_beg;
 271.169 +      /* simplex iteration count at the beginning of the search */
 271.170 +      int it_cnt;
 271.171 +      /* simplex iteration count; it increases by one every time the
 271.172 +         basis changes */
 271.173 +      int it_dpy;
 271.174 +      /* simplex iteration count at the most recent display output */
 271.175 +      /*--------------------------------------------------------------*/
 271.176 +      /* basic solution components */
 271.177 +      double *bbar; /* double bbar[1+m]; */
 271.178 +      /* bbar[0] is not used on phase I; on phase II it is the current
 271.179 +         value of the original objective function;
 271.180 +         bbar[i], 1 <= i <= m, is primal value of basic variable xB[i]
 271.181 +         (if xB[i] is free, its primal value is not updated) */
 271.182 +      double *cbar; /* double cbar[1+n]; */
 271.183 +      /* cbar[0] is not used;
 271.184 +         cbar[j], 1 <= j <= n, is reduced cost of non-basic variable
 271.185 +         xN[j] (if xN[j] is fixed, its reduced cost is not updated) */
 271.186 +      /*--------------------------------------------------------------*/
 271.187 +      /* the following pricing technique options may be used:
 271.188 +         GLP_PT_STD - standard ("textbook") pricing;
 271.189 +         GLP_PT_PSE - projected steepest edge;
 271.190 +         GLP_PT_DVX - Devex pricing (not implemented yet);
 271.191 +         in case of GLP_PT_STD the reference space is not used, and all
 271.192 +         steepest edge coefficients are set to 1 */
 271.193 +      int refct;
 271.194 +      /* this count is set to an initial value when the reference space
 271.195 +         is defined and decreases by one every time the basis changes;
 271.196 +         once this count reaches zero, the reference space is redefined
 271.197 +         again */
 271.198 +      char *refsp; /* char refsp[1+m+n]; */
 271.199 +      /* refsp[0] is not used;
 271.200 +         refsp[k], 1 <= k <= m+n, is the flag which means that variable
 271.201 +         x[k] belongs to the current reference space */
 271.202 +      double *gamma; /* double gamma[1+m]; */
 271.203 +      /* gamma[0] is not used;
 271.204 +         gamma[i], 1 <= i <= n, is the steepest edge coefficient for
 271.205 +         basic variable xB[i]; if xB[i] is free, gamma[i] is not used
 271.206 +         and just set to 1 */
 271.207 +      /*--------------------------------------------------------------*/
 271.208 +      /* basic variable xB[p] chosen to leave the basis */
 271.209 +      int p;
 271.210 +      /* index of the basic variable xB[p] chosen, 1 <= p <= m;
 271.211 +         if the set of eligible basic variables is empty (i.e. if the
 271.212 +         current basic solution is primal feasible within a tolerance)
 271.213 +         and thus no variable has been chosen, p is set to 0 */
 271.214 +      double delta;
 271.215 +      /* change of xB[p] in the adjacent basis;
 271.216 +         delta > 0 means that xB[p] violates its lower bound and will
 271.217 +         increase to achieve it in the adjacent basis;
 271.218 +         delta < 0 means that xB[p] violates its upper bound and will
 271.219 +         decrease to achieve it in the adjacent basis */
 271.220 +      /*--------------------------------------------------------------*/
 271.221 +      /* pivot row of the simplex table corresponding to basic variable
 271.222 +         xB[p] chosen is the following vector:
 271.223 +            T' * e[p] = - N' * inv(B') * e[p] = - N' * rho,
 271.224 +         where B' is a matrix transposed to the current basis matrix,
 271.225 +         N' is a matrix, whose rows are columns of the matrix (I|-A)
 271.226 +         corresponding to non-basic non-fixed variables */
 271.227 +      int trow_nnz;
 271.228 +      /* number of non-zero components, 0 <= nnz <= n */
 271.229 +      int *trow_ind; /* int trow_ind[1+n]; */
 271.230 +      /* trow_ind[0] is not used;
 271.231 +         trow_ind[t], 1 <= t <= nnz, is an index of non-zero component,
 271.232 +         i.e. trow_ind[t] = j means that trow_vec[j] != 0 */
 271.233 +      double *trow_vec; /* int trow_vec[1+n]; */
 271.234 +      /* trow_vec[0] is not used;
 271.235 +         trow_vec[j], 1 <= j <= n, is a numeric value of j-th component
 271.236 +         of the row */
 271.237 +      double trow_max;
 271.238 +      /* infinity (maximum) norm of the row (max |trow_vec[j]|) */
 271.239 +      int trow_num;
 271.240 +      /* number of significant non-zero components, which means that:
 271.241 +         |trow_vec[j]| >= eps for j in trow_ind[1,...,num],
 271.242 +         |tcol_vec[j]| <  eps for j in trow_ind[num+1,...,nnz],
 271.243 +         where eps is a pivot tolerance */
 271.244 +      /*--------------------------------------------------------------*/
 271.245 +#ifdef GLP_LONG_STEP /* 07/IV-2009 */
 271.246 +      int nbps;
 271.247 +      /* number of breakpoints, 0 <= nbps <= n */
 271.248 +      struct bkpt
 271.249 +      {     int j;
 271.250 +            /* index of non-basic variable xN[j], 1 <= j <= n */
 271.251 +            double t;
 271.252 +            /* value of dual ray parameter at breakpoint, t >= 0 */
 271.253 +            double dz;
 271.254 +            /* dz = zeta(t = t[k]) - zeta(t = 0) */
 271.255 +      } *bkpt; /* struct bkpt bkpt[1+n]; */
 271.256 +      /* bkpt[0] is not used;
 271.257 +         bkpt[k], 1 <= k <= nbps, is k-th breakpoint of the dual
 271.258 +         objective */
 271.259 +#endif
 271.260 +      /*--------------------------------------------------------------*/
 271.261 +      /* non-basic variable xN[q] chosen to enter the basis */
 271.262 +      int q;
 271.263 +      /* index of the non-basic variable xN[q] chosen, 1 <= q <= n;
 271.264 +         if no variable has been chosen, q is set to 0 */
 271.265 +      double new_dq;
 271.266 +      /* reduced cost of xN[q] in the adjacent basis (it is the change
 271.267 +         of lambdaB[p]) */
 271.268 +      /*--------------------------------------------------------------*/
 271.269 +      /* pivot column of the simplex table corresponding to non-basic
 271.270 +         variable xN[q] chosen is the following vector:
 271.271 +            T * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q],
 271.272 +         where B is the current basis matrix, N[q] is a column of the
 271.273 +         matrix (I|-A) corresponding to xN[q] */
 271.274 +      int tcol_nnz;
 271.275 +      /* number of non-zero components, 0 <= nnz <= m */
 271.276 +      int *tcol_ind; /* int tcol_ind[1+m]; */
 271.277 +      /* tcol_ind[0] is not used;
 271.278 +         tcol_ind[t], 1 <= t <= nnz, is an index of non-zero component,
 271.279 +         i.e. tcol_ind[t] = i means that tcol_vec[i] != 0 */
 271.280 +      double *tcol_vec; /* double tcol_vec[1+m]; */
 271.281 +      /* tcol_vec[0] is not used;
 271.282 +         tcol_vec[i], 1 <= i <= m, is a numeric value of i-th component
 271.283 +         of the column */
 271.284 +      /*--------------------------------------------------------------*/
 271.285 +      /* working arrays */
 271.286 +      double *work1; /* double work1[1+m]; */
 271.287 +      double *work2; /* double work2[1+m]; */
 271.288 +      double *work3; /* double work3[1+m]; */
 271.289 +      double *work4; /* double work4[1+m]; */
 271.290 +};
 271.291 +
 271.292 +static const double kappa = 0.10;
 271.293 +
 271.294 +/***********************************************************************
 271.295 +*  alloc_csa - allocate common storage area
 271.296 +*
 271.297 +*  This routine allocates all arrays in the common storage area (CSA)
 271.298 +*  and returns a pointer to the CSA. */
 271.299 +
 271.300 +static struct csa *alloc_csa(glp_prob *lp)
 271.301 +{     struct csa *csa;
 271.302 +      int m = lp->m;
 271.303 +      int n = lp->n;
 271.304 +      int nnz = lp->nnz;
 271.305 +      csa = xmalloc(sizeof(struct csa));
 271.306 +      xassert(m > 0 && n > 0);
 271.307 +      csa->m = m;
 271.308 +      csa->n = n;
 271.309 +      csa->type = xcalloc(1+m+n, sizeof(char));
 271.310 +      csa->lb = xcalloc(1+m+n, sizeof(double));
 271.311 +      csa->ub = xcalloc(1+m+n, sizeof(double));
 271.312 +      csa->coef = xcalloc(1+m+n, sizeof(double));
 271.313 +      csa->orig_type = xcalloc(1+m+n, sizeof(char));
 271.314 +      csa->orig_lb = xcalloc(1+m+n, sizeof(double));
 271.315 +      csa->orig_ub = xcalloc(1+m+n, sizeof(double));
 271.316 +      csa->obj = xcalloc(1+n, sizeof(double));
 271.317 +      csa->A_ptr = xcalloc(1+n+1, sizeof(int));
 271.318 +      csa->A_ind = xcalloc(1+nnz, sizeof(int));
 271.319 +      csa->A_val = xcalloc(1+nnz, sizeof(double));
 271.320 +#if 1 /* 06/IV-2009 */
 271.321 +      csa->AT_ptr = xcalloc(1+m+1, sizeof(int));
 271.322 +      csa->AT_ind = xcalloc(1+nnz, sizeof(int));
 271.323 +      csa->AT_val = xcalloc(1+nnz, sizeof(double));
 271.324 +#endif
 271.325 +      csa->head = xcalloc(1+m+n, sizeof(int));
 271.326 +#if 1 /* 06/IV-2009 */
 271.327 +      csa->bind = xcalloc(1+m+n, sizeof(int));
 271.328 +#endif
 271.329 +      csa->stat = xcalloc(1+n, sizeof(char));
 271.330 +#if 0 /* 06/IV-2009 */
 271.331 +      csa->N_ptr = xcalloc(1+m+1, sizeof(int));
 271.332 +      csa->N_len = xcalloc(1+m, sizeof(int));
 271.333 +      csa->N_ind = NULL; /* will be allocated later */
 271.334 +      csa->N_val = NULL; /* will be allocated later */
 271.335 +#endif
 271.336 +      csa->bbar = xcalloc(1+m, sizeof(double));
 271.337 +      csa->cbar = xcalloc(1+n, sizeof(double));
 271.338 +      csa->refsp = xcalloc(1+m+n, sizeof(char));
 271.339 +      csa->gamma = xcalloc(1+m, sizeof(double));
 271.340 +      csa->trow_ind = xcalloc(1+n, sizeof(int));
 271.341 +      csa->trow_vec = xcalloc(1+n, sizeof(double));
 271.342 +#ifdef GLP_LONG_STEP /* 07/IV-2009 */
 271.343 +      csa->bkpt = xcalloc(1+n, sizeof(struct bkpt));
 271.344 +#endif
 271.345 +      csa->tcol_ind = xcalloc(1+m, sizeof(int));
 271.346 +      csa->tcol_vec = xcalloc(1+m, sizeof(double));
 271.347 +      csa->work1 = xcalloc(1+m, sizeof(double));
 271.348 +      csa->work2 = xcalloc(1+m, sizeof(double));
 271.349 +      csa->work3 = xcalloc(1+m, sizeof(double));
 271.350 +      csa->work4 = xcalloc(1+m, sizeof(double));
 271.351 +      return csa;
 271.352 +}
 271.353 +
 271.354 +/***********************************************************************
 271.355 +*  init_csa - initialize common storage area
 271.356 +*
 271.357 +*  This routine initializes all data structures in the common storage
 271.358 +*  area (CSA). */
 271.359 +
 271.360 +static void init_csa(struct csa *csa, glp_prob *lp)
 271.361 +{     int m = csa->m;
 271.362 +      int n = csa->n;
 271.363 +      char *type = csa->type;
 271.364 +      double *lb = csa->lb;
 271.365 +      double *ub = csa->ub;
 271.366 +      double *coef = csa->coef;
 271.367 +      char *orig_type = csa->orig_type;
 271.368 +      double *orig_lb = csa->orig_lb;
 271.369 +      double *orig_ub = csa->orig_ub;
 271.370 +      double *obj = csa->obj;
 271.371 +      int *A_ptr = csa->A_ptr;
 271.372 +      int *A_ind = csa->A_ind;
 271.373 +      double *A_val = csa->A_val;
 271.374 +#if 1 /* 06/IV-2009 */
 271.375 +      int *AT_ptr = csa->AT_ptr;
 271.376 +      int *AT_ind = csa->AT_ind;
 271.377 +      double *AT_val = csa->AT_val;
 271.378 +#endif
 271.379 +      int *head = csa->head;
 271.380 +#if 1 /* 06/IV-2009 */
 271.381 +      int *bind = csa->bind;
 271.382 +#endif
 271.383 +      char *stat = csa->stat;
 271.384 +      char *refsp = csa->refsp;
 271.385 +      double *gamma = csa->gamma;
 271.386 +      int i, j, k, loc;
 271.387 +      double cmax;
 271.388 +      /* auxiliary variables */
 271.389 +      for (i = 1; i <= m; i++)
 271.390 +      {  GLPROW *row = lp->row[i];
 271.391 +         type[i] = (char)row->type;
 271.392 +         lb[i] = row->lb * row->rii;
 271.393 +         ub[i] = row->ub * row->rii;
 271.394 +         coef[i] = 0.0;
 271.395 +      }
 271.396 +      /* structural variables */
 271.397 +      for (j = 1; j <= n; j++)
 271.398 +      {  GLPCOL *col = lp->col[j];
 271.399 +         type[m+j] = (char)col->type;
 271.400 +         lb[m+j] = col->lb / col->sjj;
 271.401 +         ub[m+j] = col->ub / col->sjj;
 271.402 +         coef[m+j] = col->coef * col->sjj;
 271.403 +      }
 271.404 +      /* original bounds of variables */
 271.405 +      memcpy(&orig_type[1], &type[1], (m+n) * sizeof(char));
 271.406 +      memcpy(&orig_lb[1], &lb[1], (m+n) * sizeof(double));
 271.407 +      memcpy(&orig_ub[1], &ub[1], (m+n) * sizeof(double));
 271.408 +      /* original objective function */
 271.409 +      obj[0] = lp->c0;
 271.410 +      memcpy(&obj[1], &coef[m+1], n * sizeof(double));
 271.411 +      /* factor used to scale original objective coefficients */
 271.412 +      cmax = 0.0;
 271.413 +      for (j = 1; j <= n; j++)
 271.414 +         if (cmax < fabs(obj[j])) cmax = fabs(obj[j]);
 271.415 +      if (cmax == 0.0) cmax = 1.0;
 271.416 +      switch (lp->dir)
 271.417 +      {  case GLP_MIN:
 271.418 +            csa->zeta = + 1.0 / cmax;
 271.419 +            break;
 271.420 +         case GLP_MAX:
 271.421 +            csa->zeta = - 1.0 / cmax;
 271.422 +            break;
 271.423 +         default:
 271.424 +            xassert(lp != lp);
 271.425 +      }
 271.426 +#if 1
 271.427 +      if (fabs(csa->zeta) < 1.0) csa->zeta *= 1000.0;
 271.428 +#endif
 271.429 +      /* scale working objective coefficients */
 271.430 +      for (j = 1; j <= n; j++) coef[m+j] *= csa->zeta;
 271.431 +      /* matrix A (by columns) */
 271.432 +      loc = 1;
 271.433 +      for (j = 1; j <= n; j++)
 271.434 +      {  GLPAIJ *aij;
 271.435 +         A_ptr[j] = loc;
 271.436 +         for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next)
 271.437 +         {  A_ind[loc] = aij->row->i;
 271.438 +            A_val[loc] = aij->row->rii * aij->val * aij->col->sjj;
 271.439 +            loc++;
 271.440 +         }
 271.441 +      }
 271.442 +      A_ptr[n+1] = loc;
 271.443 +      xassert(loc-1 == lp->nnz);
 271.444 +#if 1 /* 06/IV-2009 */
 271.445 +      /* matrix A (by rows) */
 271.446 +      loc = 1;
 271.447 +      for (i = 1; i <= m; i++)
 271.448 +      {  GLPAIJ *aij;
 271.449 +         AT_ptr[i] = loc;
 271.450 +         for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
 271.451 +         {  AT_ind[loc] = aij->col->j;
 271.452 +            AT_val[loc] = aij->row->rii * aij->val * aij->col->sjj;
 271.453 +            loc++;
 271.454 +         }
 271.455 +      }
 271.456 +      AT_ptr[m+1] = loc;
 271.457 +      xassert(loc-1 == lp->nnz);
 271.458 +#endif
 271.459 +      /* basis header */
 271.460 +      xassert(lp->valid);
 271.461 +      memcpy(&head[1], &lp->head[1], m * sizeof(int));
 271.462 +      k = 0;
 271.463 +      for (i = 1; i <= m; i++)
 271.464 +      {  GLPROW *row = lp->row[i];
 271.465 +         if (row->stat != GLP_BS)
 271.466 +         {  k++;
 271.467 +            xassert(k <= n);
 271.468 +            head[m+k] = i;
 271.469 +            stat[k] = (char)row->stat;
 271.470 +         }
 271.471 +      }
 271.472 +      for (j = 1; j <= n; j++)
 271.473 +      {  GLPCOL *col = lp->col[j];
 271.474 +         if (col->stat != GLP_BS)
 271.475 +         {  k++;
 271.476 +            xassert(k <= n);
 271.477 +            head[m+k] = m + j;
 271.478 +            stat[k] = (char)col->stat;
 271.479 +         }
 271.480 +      }
 271.481 +      xassert(k == n);
 271.482 +#if 1 /* 06/IV-2009 */
 271.483 +      for (k = 1; k <= m+n; k++)
 271.484 +         bind[head[k]] = k;
 271.485 +#endif
 271.486 +      /* factorization of matrix B */
 271.487 +      csa->valid = 1, lp->valid = 0;
 271.488 +      csa->bfd = lp->bfd, lp->bfd = NULL;
 271.489 +#if 0 /* 06/IV-2009 */
 271.490 +      /* matrix N (by rows) */
 271.491 +      alloc_N(csa);
 271.492 +      build_N(csa);
 271.493 +#endif
 271.494 +      /* working parameters */
 271.495 +      csa->phase = 0;
 271.496 +      csa->tm_beg = xtime();
 271.497 +      csa->it_beg = csa->it_cnt = lp->it_cnt;
 271.498 +      csa->it_dpy = -1;
 271.499 +      /* reference space and steepest edge coefficients */
 271.500 +      csa->refct = 0;
 271.501 +      memset(&refsp[1], 0, (m+n) * sizeof(char));
 271.502 +      for (i = 1; i <= m; i++) gamma[i] = 1.0;
 271.503 +      return;
 271.504 +}
 271.505 +
 271.506 +#if 1 /* copied from primal */
 271.507 +/***********************************************************************
 271.508 +*  invert_B - compute factorization of the basis matrix
 271.509 +*
 271.510 +*  This routine computes factorization of the current basis matrix B.
 271.511 +*
 271.512 +*  If the operation is successful, the routine returns zero, otherwise
 271.513 +*  non-zero. */
 271.514 +
 271.515 +static int inv_col(void *info, int i, int ind[], double val[])
 271.516 +{     /* this auxiliary routine returns row indices and numeric values
 271.517 +         of non-zero elements of i-th column of the basis matrix */
 271.518 +      struct csa *csa = info;
 271.519 +      int m = csa->m;
 271.520 +#ifdef GLP_DEBUG
 271.521 +      int n = csa->n;
 271.522 +#endif
 271.523 +      int *A_ptr = csa->A_ptr;
 271.524 +      int *A_ind = csa->A_ind;
 271.525 +      double *A_val = csa->A_val;
 271.526 +      int *head = csa->head;
 271.527 +      int k, len, ptr, t;
 271.528 +#ifdef GLP_DEBUG
 271.529 +      xassert(1 <= i && i <= m);
 271.530 +#endif
 271.531 +      k = head[i]; /* B[i] is k-th column of (I|-A) */
 271.532 +#ifdef GLP_DEBUG
 271.533 +      xassert(1 <= k && k <= m+n);
 271.534 +#endif
 271.535 +      if (k <= m)
 271.536 +      {  /* B[i] is k-th column of submatrix I */
 271.537 +         len = 1;
 271.538 +         ind[1] = k;
 271.539 +         val[1] = 1.0;
 271.540 +      }
 271.541 +      else
 271.542 +      {  /* B[i] is (k-m)-th column of submatrix (-A) */
 271.543 +         ptr = A_ptr[k-m];
 271.544 +         len = A_ptr[k-m+1] - ptr;
 271.545 +         memcpy(&ind[1], &A_ind[ptr], len * sizeof(int));
 271.546 +         memcpy(&val[1], &A_val[ptr], len * sizeof(double));
 271.547 +         for (t = 1; t <= len; t++) val[t] = - val[t];
 271.548 +      }
 271.549 +      return len;
 271.550 +}
 271.551 +
 271.552 +static int invert_B(struct csa *csa)
 271.553 +{     int ret;
 271.554 +      ret = bfd_factorize(csa->bfd, csa->m, NULL, inv_col, csa);
 271.555 +      csa->valid = (ret == 0);
 271.556 +      return ret;
 271.557 +}
 271.558 +#endif
 271.559 +
 271.560 +#if 1 /* copied from primal */
 271.561 +/***********************************************************************
 271.562 +*  update_B - update factorization of the basis matrix
 271.563 +*
 271.564 +*  This routine replaces i-th column of the basis matrix B by k-th
 271.565 +*  column of the augmented constraint matrix (I|-A) and then updates
 271.566 +*  the factorization of B.
 271.567 +*
 271.568 +*  If the factorization has been successfully updated, the routine
 271.569 +*  returns zero, otherwise non-zero. */
 271.570 +
 271.571 +static int update_B(struct csa *csa, int i, int k)
 271.572 +{     int m = csa->m;
 271.573 +#ifdef GLP_DEBUG
 271.574 +      int n = csa->n;
 271.575 +#endif
 271.576 +      int ret;
 271.577 +#ifdef GLP_DEBUG
 271.578 +      xassert(1 <= i && i <= m);
 271.579 +      xassert(1 <= k && k <= m+n);
 271.580 +#endif
 271.581 +      if (k <= m)
 271.582 +      {  /* new i-th column of B is k-th column of I */
 271.583 +         int ind[1+1];
 271.584 +         double val[1+1];
 271.585 +         ind[1] = k;
 271.586 +         val[1] = 1.0;
 271.587 +         xassert(csa->valid);
 271.588 +         ret = bfd_update_it(csa->bfd, i, 0, 1, ind, val);
 271.589 +      }
 271.590 +      else
 271.591 +      {  /* new i-th column of B is (k-m)-th column of (-A) */
 271.592 +         int *A_ptr = csa->A_ptr;
 271.593 +         int *A_ind = csa->A_ind;
 271.594 +         double *A_val = csa->A_val;
 271.595 +         double *val = csa->work1;
 271.596 +         int beg, end, ptr, len;
 271.597 +         beg = A_ptr[k-m];
 271.598 +         end = A_ptr[k-m+1];
 271.599 +         len = 0;
 271.600 +         for (ptr = beg; ptr < end; ptr++)
 271.601 +            val[++len] = - A_val[ptr];
 271.602 +         xassert(csa->valid);
 271.603 +         ret = bfd_update_it(csa->bfd, i, 0, len, &A_ind[beg-1], val);
 271.604 +      }
 271.605 +      csa->valid = (ret == 0);
 271.606 +      return ret;
 271.607 +}
 271.608 +#endif
 271.609 +
 271.610 +#if 1 /* copied from primal */
 271.611 +/***********************************************************************
 271.612 +*  error_ftran - compute residual vector r = h - B * x
 271.613 +*
 271.614 +*  This routine computes the residual vector r = h - B * x, where B is
 271.615 +*  the current basis matrix, h is the vector of right-hand sides, x is
 271.616 +*  the solution vector. */
 271.617 +
 271.618 +static void error_ftran(struct csa *csa, double h[], double x[],
 271.619 +      double r[])
 271.620 +{     int m = csa->m;
 271.621 +#ifdef GLP_DEBUG
 271.622 +      int n = csa->n;
 271.623 +#endif
 271.624 +      int *A_ptr = csa->A_ptr;
 271.625 +      int *A_ind = csa->A_ind;
 271.626 +      double *A_val = csa->A_val;
 271.627 +      int *head = csa->head;
 271.628 +      int i, k, beg, end, ptr;
 271.629 +      double temp;
 271.630 +      /* compute the residual vector:
 271.631 +         r = h - B * x = h - B[1] * x[1] - ... - B[m] * x[m],
 271.632 +         where B[1], ..., B[m] are columns of matrix B */
 271.633 +      memcpy(&r[1], &h[1], m * sizeof(double));
 271.634 +      for (i = 1; i <= m; i++)
 271.635 +      {  temp = x[i];
 271.636 +         if (temp == 0.0) continue;
 271.637 +         k = head[i]; /* B[i] is k-th column of (I|-A) */
 271.638 +#ifdef GLP_DEBUG
 271.639 +         xassert(1 <= k && k <= m+n);
 271.640 +#endif
 271.641 +         if (k <= m)
 271.642 +         {  /* B[i] is k-th column of submatrix I */
 271.643 +            r[k] -= temp;
 271.644 +         }
 271.645 +         else
 271.646 +         {  /* B[i] is (k-m)-th column of submatrix (-A) */
 271.647 +            beg = A_ptr[k-m];
 271.648 +            end = A_ptr[k-m+1];
 271.649 +            for (ptr = beg; ptr < end; ptr++)
 271.650 +               r[A_ind[ptr]] += A_val[ptr] * temp;
 271.651 +         }
 271.652 +      }
 271.653 +      return;
 271.654 +}
 271.655 +#endif
 271.656 +
 271.657 +#if 1 /* copied from primal */
 271.658 +/***********************************************************************
 271.659 +*  refine_ftran - refine solution of B * x = h
 271.660 +*
 271.661 +*  This routine performs one iteration to refine the solution of
 271.662 +*  the system B * x = h, where B is the current basis matrix, h is the
 271.663 +*  vector of right-hand sides, x is the solution vector. */
 271.664 +
 271.665 +static void refine_ftran(struct csa *csa, double h[], double x[])
 271.666 +{     int m = csa->m;
 271.667 +      double *r = csa->work1;
 271.668 +      double *d = csa->work1;
 271.669 +      int i;
 271.670 +      /* compute the residual vector r = h - B * x */
 271.671 +      error_ftran(csa, h, x, r);
 271.672 +      /* compute the correction vector d = inv(B) * r */
 271.673 +      xassert(csa->valid);
 271.674 +      bfd_ftran(csa->bfd, d);
 271.675 +      /* refine the solution vector (new x) = (old x) + d */
 271.676 +      for (i = 1; i <= m; i++) x[i] += d[i];
 271.677 +      return;
 271.678 +}
 271.679 +#endif
 271.680 +
 271.681 +#if 1 /* copied from primal */
 271.682 +/***********************************************************************
 271.683 +*  error_btran - compute residual vector r = h - B'* x
 271.684 +*
 271.685 +*  This routine computes the residual vector r = h - B'* x, where B'
 271.686 +*  is a matrix transposed to the current basis matrix, h is the vector
 271.687 +*  of right-hand sides, x is the solution vector. */
 271.688 +
 271.689 +static void error_btran(struct csa *csa, double h[], double x[],
 271.690 +      double r[])
 271.691 +{     int m = csa->m;
 271.692 +#ifdef GLP_DEBUG
 271.693 +      int n = csa->n;
 271.694 +#endif
 271.695 +      int *A_ptr = csa->A_ptr;
 271.696 +      int *A_ind = csa->A_ind;
 271.697 +      double *A_val = csa->A_val;
 271.698 +      int *head = csa->head;
 271.699 +      int i, k, beg, end, ptr;
 271.700 +      double temp;
 271.701 +      /* compute the residual vector r = b - B'* x */
 271.702 +      for (i = 1; i <= m; i++)
 271.703 +      {  /* r[i] := b[i] - (i-th column of B)'* x */
 271.704 +         k = head[i]; /* B[i] is k-th column of (I|-A) */
 271.705 +#ifdef GLP_DEBUG
 271.706 +         xassert(1 <= k && k <= m+n);
 271.707 +#endif
 271.708 +         temp = h[i];
 271.709 +         if (k <= m)
 271.710 +         {  /* B[i] is k-th column of submatrix I */
 271.711 +            temp -= x[k];
 271.712 +         }
 271.713 +         else
 271.714 +         {  /* B[i] is (k-m)-th column of submatrix (-A) */
 271.715 +            beg = A_ptr[k-m];
 271.716 +            end = A_ptr[k-m+1];
 271.717 +            for (ptr = beg; ptr < end; ptr++)
 271.718 +               temp += A_val[ptr] * x[A_ind[ptr]];
 271.719 +         }
 271.720 +         r[i] = temp;
 271.721 +      }
 271.722 +      return;
 271.723 +}
 271.724 +#endif
 271.725 +
 271.726 +#if 1 /* copied from primal */
 271.727 +/***********************************************************************
 271.728 +*  refine_btran - refine solution of B'* x = h
 271.729 +*
 271.730 +*  This routine performs one iteration to refine the solution of the
 271.731 +*  system B'* x = h, where B' is a matrix transposed to the current
 271.732 +*  basis matrix, h is the vector of right-hand sides, x is the solution
 271.733 +*  vector. */
 271.734 +
 271.735 +static void refine_btran(struct csa *csa, double h[], double x[])
 271.736 +{     int m = csa->m;
 271.737 +      double *r = csa->work1;
 271.738 +      double *d = csa->work1;
 271.739 +      int i;
 271.740 +      /* compute the residual vector r = h - B'* x */
 271.741 +      error_btran(csa, h, x, r);
 271.742 +      /* compute the correction vector d = inv(B') * r */
 271.743 +      xassert(csa->valid);
 271.744 +      bfd_btran(csa->bfd, d);
 271.745 +      /* refine the solution vector (new x) = (old x) + d */
 271.746 +      for (i = 1; i <= m; i++) x[i] += d[i];
 271.747 +      return;
 271.748 +}
 271.749 +#endif
 271.750 +
 271.751 +#if 1 /* copied from primal */
 271.752 +/***********************************************************************
 271.753 +*  get_xN - determine current value of non-basic variable xN[j]
 271.754 +*
 271.755 +*  This routine returns the current value of non-basic variable xN[j],
 271.756 +*  which is a value of its active bound. */
 271.757 +
 271.758 +static double get_xN(struct csa *csa, int j)
 271.759 +{     int m = csa->m;
 271.760 +#ifdef GLP_DEBUG
 271.761 +      int n = csa->n;
 271.762 +#endif
 271.763 +      double *lb = csa->lb;
 271.764 +      double *ub = csa->ub;
 271.765 +      int *head = csa->head;
 271.766 +      char *stat = csa->stat;
 271.767 +      int k;
 271.768 +      double xN;
 271.769 +#ifdef GLP_DEBUG
 271.770 +      xassert(1 <= j && j <= n);
 271.771 +#endif
 271.772 +      k = head[m+j]; /* x[k] = xN[j] */
 271.773 +#ifdef GLP_DEBUG
 271.774 +      xassert(1 <= k && k <= m+n);
 271.775 +#endif
 271.776 +      switch (stat[j])
 271.777 +      {  case GLP_NL:
 271.778 +            /* x[k] is on its lower bound */
 271.779 +            xN = lb[k]; break;
 271.780 +         case GLP_NU:
 271.781 +            /* x[k] is on its upper bound */
 271.782 +            xN = ub[k]; break;
 271.783 +         case GLP_NF:
 271.784 +            /* x[k] is free non-basic variable */
 271.785 +            xN = 0.0; break;
 271.786 +         case GLP_NS:
 271.787 +            /* x[k] is fixed non-basic variable */
 271.788 +            xN = lb[k]; break;
 271.789 +         default:
 271.790 +            xassert(stat != stat);
 271.791 +      }
 271.792 +      return xN;
 271.793 +}
 271.794 +#endif
 271.795 +
 271.796 +#if 1 /* copied from primal */
 271.797 +/***********************************************************************
 271.798 +*  eval_beta - compute primal values of basic variables
 271.799 +*
 271.800 +*  This routine computes current primal values of all basic variables:
 271.801 +*
 271.802 +*     beta = - inv(B) * N * xN,
 271.803 +*
 271.804 +*  where B is the current basis matrix, N is a matrix built of columns
 271.805 +*  of matrix (I|-A) corresponding to non-basic variables, and xN is the
 271.806 +*  vector of current values of non-basic variables. */
 271.807 +
 271.808 +static void eval_beta(struct csa *csa, double beta[])
 271.809 +{     int m = csa->m;
 271.810 +      int n = csa->n;
 271.811 +      int *A_ptr = csa->A_ptr;
 271.812 +      int *A_ind = csa->A_ind;
 271.813 +      double *A_val = csa->A_val;
 271.814 +      int *head = csa->head;
 271.815 +      double *h = csa->work2;
 271.816 +      int i, j, k, beg, end, ptr;
 271.817 +      double xN;
 271.818 +      /* compute the right-hand side vector:
 271.819 +         h := - N * xN = - N[1] * xN[1] - ... - N[n] * xN[n],
 271.820 +         where N[1], ..., N[n] are columns of matrix N */
 271.821 +      for (i = 1; i <= m; i++)
 271.822 +         h[i] = 0.0;
 271.823 +      for (j = 1; j <= n; j++)
 271.824 +      {  k = head[m+j]; /* x[k] = xN[j] */
 271.825 +#ifdef GLP_DEBUG
 271.826 +         xassert(1 <= k && k <= m+n);
 271.827 +#endif
 271.828 +         /* determine current value of xN[j] */
 271.829 +         xN = get_xN(csa, j);
 271.830 +         if (xN == 0.0) continue;
 271.831 +         if (k <= m)
 271.832 +         {  /* N[j] is k-th column of submatrix I */
 271.833 +            h[k] -= xN;
 271.834 +         }
 271.835 +         else
 271.836 +         {  /* N[j] is (k-m)-th column of submatrix (-A) */
 271.837 +            beg = A_ptr[k-m];
 271.838 +            end = A_ptr[k-m+1];
 271.839 +            for (ptr = beg; ptr < end; ptr++)
 271.840 +               h[A_ind[ptr]] += xN * A_val[ptr];
 271.841 +         }
 271.842 +      }
 271.843 +      /* solve system B * beta = h */
 271.844 +      memcpy(&beta[1], &h[1], m * sizeof(double));
 271.845 +      xassert(csa->valid);
 271.846 +      bfd_ftran(csa->bfd, beta);
 271.847 +      /* and refine the solution */
 271.848 +      refine_ftran(csa, h, beta);
 271.849 +      return;
 271.850 +}
 271.851 +#endif
 271.852 +
 271.853 +#if 1 /* copied from primal */
 271.854 +/***********************************************************************
 271.855 +*  eval_pi - compute vector of simplex multipliers
 271.856 +*
 271.857 +*  This routine computes the vector of current simplex multipliers:
 271.858 +*
 271.859 +*     pi = inv(B') * cB,
 271.860 +*
 271.861 +*  where B' is a matrix transposed to the current basis matrix, cB is
 271.862 +*  a subvector of objective coefficients at basic variables. */
 271.863 +
 271.864 +static void eval_pi(struct csa *csa, double pi[])
 271.865 +{     int m = csa->m;
 271.866 +      double *c = csa->coef;
 271.867 +      int *head = csa->head;
 271.868 +      double *cB = csa->work2;
 271.869 +      int i;
 271.870 +      /* construct the right-hand side vector cB */
 271.871 +      for (i = 1; i <= m; i++)
 271.872 +         cB[i] = c[head[i]];
 271.873 +      /* solve system B'* pi = cB */
 271.874 +      memcpy(&pi[1], &cB[1], m * sizeof(double));
 271.875 +      xassert(csa->valid);
 271.876 +      bfd_btran(csa->bfd, pi);
 271.877 +      /* and refine the solution */
 271.878 +      refine_btran(csa, cB, pi);
 271.879 +      return;
 271.880 +}
 271.881 +#endif
 271.882 +
 271.883 +#if 1 /* copied from primal */
 271.884 +/***********************************************************************
 271.885 +*  eval_cost - compute reduced cost of non-basic variable xN[j]
 271.886 +*
 271.887 +*  This routine computes the current reduced cost of non-basic variable
 271.888 +*  xN[j]:
 271.889 +*
 271.890 +*     d[j] = cN[j] - N'[j] * pi,
 271.891 +*
 271.892 +*  where cN[j] is the objective coefficient at variable xN[j], N[j] is
 271.893 +*  a column of the augmented constraint matrix (I|-A) corresponding to
 271.894 +*  xN[j], pi is the vector of simplex multipliers. */
 271.895 +
 271.896 +static double eval_cost(struct csa *csa, double pi[], int j)
 271.897 +{     int m = csa->m;
 271.898 +#ifdef GLP_DEBUG
 271.899 +      int n = csa->n;
 271.900 +#endif
 271.901 +      double *coef = csa->coef;
 271.902 +      int *head = csa->head;
 271.903 +      int k;
 271.904 +      double dj;
 271.905 +#ifdef GLP_DEBUG
 271.906 +      xassert(1 <= j && j <= n);
 271.907 +#endif
 271.908 +      k = head[m+j]; /* x[k] = xN[j] */
 271.909 +#ifdef GLP_DEBUG
 271.910 +      xassert(1 <= k && k <= m+n);
 271.911 +#endif
 271.912 +      dj = coef[k];
 271.913 +      if (k <= m)
 271.914 +      {  /* N[j] is k-th column of submatrix I */
 271.915 +         dj -= pi[k];
 271.916 +      }
 271.917 +      else
 271.918 +      {  /* N[j] is (k-m)-th column of submatrix (-A) */
 271.919 +         int *A_ptr = csa->A_ptr;
 271.920 +         int *A_ind = csa->A_ind;
 271.921 +         double *A_val = csa->A_val;
 271.922 +         int beg, end, ptr;
 271.923 +         beg = A_ptr[k-m];
 271.924 +         end = A_ptr[k-m+1];
 271.925 +         for (ptr = beg; ptr < end; ptr++)
 271.926 +            dj += A_val[ptr] * pi[A_ind[ptr]];
 271.927 +      }
 271.928 +      return dj;
 271.929 +}
 271.930 +#endif
 271.931 +
 271.932 +#if 1 /* copied from primal */
 271.933 +/***********************************************************************
 271.934 +*  eval_bbar - compute and store primal values of basic variables
 271.935 +*
 271.936 +*  This routine computes primal values of all basic variables and then
 271.937 +*  stores them in the solution array. */
 271.938 +
 271.939 +static void eval_bbar(struct csa *csa)
 271.940 +{     eval_beta(csa, csa->bbar);
 271.941 +      return;
 271.942 +}
 271.943 +#endif
 271.944 +
 271.945 +#if 1 /* copied from primal */
 271.946 +/***********************************************************************
 271.947 +*  eval_cbar - compute and store reduced costs of non-basic variables
 271.948 +*
 271.949 +*  This routine computes reduced costs of all non-basic variables and
 271.950 +*  then stores them in the solution array. */
 271.951 +
 271.952 +static void eval_cbar(struct csa *csa)
 271.953 +{
 271.954 +#ifdef GLP_DEBUG
 271.955 +      int m = csa->m;
 271.956 +#endif
 271.957 +      int n = csa->n;
 271.958 +#ifdef GLP_DEBUG
 271.959 +      int *head = csa->head;
 271.960 +#endif
 271.961 +      double *cbar = csa->cbar;
 271.962 +      double *pi = csa->work3;
 271.963 +      int j;
 271.964 +#ifdef GLP_DEBUG
 271.965 +      int k;
 271.966 +#endif
 271.967 +      /* compute simplex multipliers */
 271.968 +      eval_pi(csa, pi);
 271.969 +      /* compute and store reduced costs */
 271.970 +      for (j = 1; j <= n; j++)
 271.971 +      {
 271.972 +#ifdef GLP_DEBUG
 271.973 +         k = head[m+j]; /* x[k] = xN[j] */
 271.974 +         xassert(1 <= k && k <= m+n);
 271.975 +#endif
 271.976 +         cbar[j] = eval_cost(csa, pi, j);
 271.977 +      }
 271.978 +      return;
 271.979 +}
 271.980 +#endif
 271.981 +
 271.982 +/***********************************************************************
 271.983 +*  reset_refsp - reset the reference space
 271.984 +*
 271.985 +*  This routine resets (redefines) the reference space used in the
 271.986 +*  projected steepest edge pricing algorithm. */
 271.987 +
 271.988 +static void reset_refsp(struct csa *csa)
 271.989 +{     int m = csa->m;
 271.990 +      int n = csa->n;
 271.991 +      int *head = csa->head;
 271.992 +      char *refsp = csa->refsp;
 271.993 +      double *gamma = csa->gamma;
 271.994 +      int i, k;
 271.995 +      xassert(csa->refct == 0);
 271.996 +      csa->refct = 1000;
 271.997 +      memset(&refsp[1], 0, (m+n) * sizeof(char));
 271.998 +      for (i = 1; i <= m; i++)
 271.999 +      {  k = head[i]; /* x[k] = xB[i] */
271.1000 +         refsp[k] = 1;
271.1001 +         gamma[i] = 1.0;
271.1002 +      }
271.1003 +      return;
271.1004 +}
271.1005 +
271.1006 +/***********************************************************************
271.1007 +*  eval_gamma - compute steepest edge coefficients
271.1008 +*
271.1009 +*  This routine computes the vector of steepest edge coefficients for
271.1010 +*  all basic variables (except free ones) using its direct definition:
271.1011 +*
271.1012 +*     gamma[i] = eta[i] +  sum   alfa[i,j]^2,  i = 1,...,m,
271.1013 +*                         j in C
271.1014 +*
271.1015 +*  where eta[i] = 1 means that xB[i] is in the current reference space,
271.1016 +*  and 0 otherwise; C is a set of non-basic non-fixed variables xN[j],
271.1017 +*  which are in the current reference space; alfa[i,j] are elements of
271.1018 +*  the current simplex table.
271.1019 +*
271.1020 +*  NOTE: The routine is intended only for debugginig purposes. */
271.1021 +
271.1022 +static void eval_gamma(struct csa *csa, double gamma[])
271.1023 +{     int m = csa->m;
271.1024 +      int n = csa->n;
271.1025 +      char *type = csa->type;
271.1026 +      int *head = csa->head;
271.1027 +      char *refsp = csa->refsp;
271.1028 +      double *alfa = csa->work3;
271.1029 +      double *h = csa->work3;
271.1030 +      int i, j, k;
271.1031 +      /* gamma[i] := eta[i] (or 1, if xB[i] is free) */
271.1032 +      for (i = 1; i <= m; i++)
271.1033 +      {  k = head[i]; /* x[k] = xB[i] */
271.1034 +#ifdef GLP_DEBUG
271.1035 +         xassert(1 <= k && k <= m+n);
271.1036 +#endif
271.1037 +         if (type[k] == GLP_FR)
271.1038 +            gamma[i] = 1.0;
271.1039 +         else
271.1040 +            gamma[i] = (refsp[k] ? 1.0 : 0.0);
271.1041 +      }
271.1042 +      /* compute columns of the current simplex table */
271.1043 +      for (j = 1; j <= n; j++)
271.1044 +      {  k = head[m+j]; /* x[k] = xN[j] */
271.1045 +#ifdef GLP_DEBUG
271.1046 +         xassert(1 <= k && k <= m+n);
271.1047 +#endif
271.1048 +         /* skip column, if xN[j] is not in C */
271.1049 +         if (!refsp[k]) continue;
271.1050 +#ifdef GLP_DEBUG
271.1051 +         /* set C must not contain fixed variables */
271.1052 +         xassert(type[k] != GLP_FX);
271.1053 +#endif
271.1054 +         /* construct the right-hand side vector h = - N[j] */
271.1055 +         for (i = 1; i <= m; i++)
271.1056 +            h[i] = 0.0;
271.1057 +         if (k <= m)
271.1058 +         {  /* N[j] is k-th column of submatrix I */
271.1059 +            h[k] = -1.0;
271.1060 +         }
271.1061 +         else
271.1062 +         {  /* N[j] is (k-m)-th column of submatrix (-A) */
271.1063 +            int *A_ptr = csa->A_ptr;
271.1064 +            int *A_ind = csa->A_ind;
271.1065 +            double *A_val = csa->A_val;
271.1066 +            int beg, end, ptr;
271.1067 +            beg = A_ptr[k-m];
271.1068 +            end = A_ptr[k-m+1];
271.1069 +            for (ptr = beg; ptr < end; ptr++)
271.1070 +               h[A_ind[ptr]] = A_val[ptr];
271.1071 +         }
271.1072 +         /* solve system B * alfa = h */
271.1073 +         xassert(csa->valid);
271.1074 +         bfd_ftran(csa->bfd, alfa);
271.1075 +         /* gamma[i] := gamma[i] + alfa[i,j]^2 */
271.1076 +         for (i = 1; i <= m; i++)
271.1077 +         {  k = head[i]; /* x[k] = xB[i] */
271.1078 +            if (type[k] != GLP_FR)
271.1079 +               gamma[i] += alfa[i] * alfa[i];
271.1080 +         }
271.1081 +      }
271.1082 +      return;
271.1083 +}
271.1084 +
271.1085 +/***********************************************************************
271.1086 +*  chuzr - choose basic variable (row of the simplex table)
271.1087 +*
271.1088 +*  This routine chooses basic variable xB[p] having largest weighted
271.1089 +*  bound violation:
271.1090 +*
271.1091 +*     |r[p]| / sqrt(gamma[p]) = max  |r[i]| / sqrt(gamma[i]),
271.1092 +*                              i in I
271.1093 +*
271.1094 +*            / lB[i] - beta[i], if beta[i] < lB[i]
271.1095 +*            |
271.1096 +*     r[i] = < 0,               if lB[i] <= beta[i] <= uB[i]
271.1097 +*            |
271.1098 +*            \ uB[i] - beta[i], if beta[i] > uB[i]
271.1099 +*
271.1100 +*  where beta[i] is primal value of xB[i] in the current basis, lB[i]
271.1101 +*  and uB[i] are lower and upper bounds of xB[i], I is a subset of
271.1102 +*  eligible basic variables, which significantly violates their bounds,
271.1103 +*  gamma[i] is the steepest edge coefficient.
271.1104 +*
271.1105 +*  If |r[i]| is less than a specified tolerance, xB[i] is not included
271.1106 +*  in I and therefore ignored.
271.1107 +*
271.1108 +*  If I is empty and no variable has been chosen, p is set to 0. */
271.1109 +
271.1110 +static void chuzr(struct csa *csa, double tol_bnd)
271.1111 +{     int m = csa->m;
271.1112 +#ifdef GLP_DEBUG
271.1113 +      int n = csa->n;
271.1114 +#endif
271.1115 +      char *type = csa->type;
271.1116 +      double *lb = csa->lb;
271.1117 +      double *ub = csa->ub;
271.1118 +      int *head = csa->head;
271.1119 +      double *bbar = csa->bbar;
271.1120 +      double *gamma = csa->gamma;
271.1121 +      int i, k, p;
271.1122 +      double delta, best, eps, ri, temp;
271.1123 +      /* nothing is chosen so far */
271.1124 +      p = 0, delta = 0.0, best = 0.0;
271.1125 +      /* look through the list of basic variables */
271.1126 +      for (i = 1; i <= m; i++)
271.1127 +      {  k = head[i]; /* x[k] = xB[i] */
271.1128 +#ifdef GLP_DEBUG
271.1129 +         xassert(1 <= k && k <= m+n);
271.1130 +#endif
271.1131 +         /* determine bound violation ri[i] */
271.1132 +         ri = 0.0;
271.1133 +         if (type[k] == GLP_LO || type[k] == GLP_DB ||
271.1134 +             type[k] == GLP_FX)
271.1135 +         {  /* xB[i] has lower bound */
271.1136 +            eps = tol_bnd * (1.0 + kappa * fabs(lb[k]));
271.1137 +            if (bbar[i] < lb[k] - eps)
271.1138 +            {  /* and significantly violates it */
271.1139 +               ri = lb[k] - bbar[i];
271.1140 +            }
271.1141 +         }
271.1142 +         if (type[k] == GLP_UP || type[k] == GLP_DB ||
271.1143 +             type[k] == GLP_FX)
271.1144 +         {  /* xB[i] has upper bound */
271.1145 +            eps = tol_bnd * (1.0 + kappa * fabs(ub[k]));
271.1146 +            if (bbar[i] > ub[k] + eps)
271.1147 +            {  /* and significantly violates it */
271.1148 +               ri = ub[k] - bbar[i];
271.1149 +            }
271.1150 +         }
271.1151 +         /* if xB[i] is not eligible, skip it */
271.1152 +         if (ri == 0.0) continue;
271.1153 +         /* xB[i] is eligible basic variable; choose one with largest
271.1154 +            weighted bound violation */
271.1155 +#ifdef GLP_DEBUG
271.1156 +         xassert(gamma[i] >= 0.0);
271.1157 +#endif
271.1158 +         temp = gamma[i];
271.1159 +         if (temp < DBL_EPSILON) temp = DBL_EPSILON;
271.1160 +         temp = (ri * ri) / temp;
271.1161 +         if (best < temp)
271.1162 +            p = i, delta = ri, best = temp;
271.1163 +      }
271.1164 +      /* store the index of basic variable xB[p] chosen and its change
271.1165 +         in the adjacent basis */
271.1166 +      csa->p = p;
271.1167 +      csa->delta = delta;
271.1168 +      return;
271.1169 +}
271.1170 +
271.1171 +#if 1 /* copied from primal */
271.1172 +/***********************************************************************
271.1173 +*  eval_rho - compute pivot row of the inverse
271.1174 +*
271.1175 +*  This routine computes the pivot (p-th) row of the inverse inv(B),
271.1176 +*  which corresponds to basic variable xB[p] chosen:
271.1177 +*
271.1178 +*     rho = inv(B') * e[p],
271.1179 +*
271.1180 +*  where B' is a matrix transposed to the current basis matrix, e[p]
271.1181 +*  is unity vector. */
271.1182 +
271.1183 +static void eval_rho(struct csa *csa, double rho[])
271.1184 +{     int m = csa->m;
271.1185 +      int p = csa->p;
271.1186 +      double *e = rho;
271.1187 +      int i;
271.1188 +#ifdef GLP_DEBUG
271.1189 +      xassert(1 <= p && p <= m);
271.1190 +#endif
271.1191 +      /* construct the right-hand side vector e[p] */
271.1192 +      for (i = 1; i <= m; i++)
271.1193 +         e[i] = 0.0;
271.1194 +      e[p] = 1.0;
271.1195 +      /* solve system B'* rho = e[p] */
271.1196 +      xassert(csa->valid);
271.1197 +      bfd_btran(csa->bfd, rho);
271.1198 +      return;
271.1199 +}
271.1200 +#endif
271.1201 +
271.1202 +#if 1 /* copied from primal */
271.1203 +/***********************************************************************
271.1204 +*  refine_rho - refine pivot row of the inverse
271.1205 +*
271.1206 +*  This routine refines the pivot row of the inverse inv(B) assuming
271.1207 +*  that it was previously computed by the routine eval_rho. */
271.1208 +
271.1209 +static void refine_rho(struct csa *csa, double rho[])
271.1210 +{     int m = csa->m;
271.1211 +      int p = csa->p;
271.1212 +      double *e = csa->work3;
271.1213 +      int i;
271.1214 +#ifdef GLP_DEBUG
271.1215 +      xassert(1 <= p && p <= m);
271.1216 +#endif
271.1217 +      /* construct the right-hand side vector e[p] */
271.1218 +      for (i = 1; i <= m; i++)
271.1219 +         e[i] = 0.0;
271.1220 +      e[p] = 1.0;
271.1221 +      /* refine solution of B'* rho = e[p] */
271.1222 +      refine_btran(csa, e, rho);
271.1223 +      return;
271.1224 +}
271.1225 +#endif
271.1226 +
271.1227 +#if 1 /* 06/IV-2009 */
271.1228 +/***********************************************************************
271.1229 +*  eval_trow - compute pivot row of the simplex table
271.1230 +*
271.1231 +*  This routine computes the pivot row of the simplex table, which
271.1232 +*  corresponds to basic variable xB[p] chosen.
271.1233 +*
271.1234 +*  The pivot row is the following vector:
271.1235 +*
271.1236 +*     trow = T'* e[p] = - N'* inv(B') * e[p] = - N' * rho,
271.1237 +*
271.1238 +*  where rho is the pivot row of the inverse inv(B) previously computed
271.1239 +*  by the routine eval_rho.
271.1240 +*
271.1241 +*  Note that elements of the pivot row corresponding to fixed non-basic
271.1242 +*  variables are not computed.
271.1243 +*
271.1244 +*  NOTES
271.1245 +*
271.1246 +*  Computing pivot row of the simplex table is one of the most time
271.1247 +*  consuming operations, and for some instances it may take more than
271.1248 +*  50% of the total solution time.
271.1249 +*
271.1250 +*  In the current implementation there are two routines to compute the
271.1251 +*  pivot row. The routine eval_trow1 computes elements of the pivot row
271.1252 +*  as inner products of columns of the matrix N and the vector rho; it
271.1253 +*  is used when the vector rho is relatively dense. The routine
271.1254 +*  eval_trow2 computes the pivot row as a linear combination of rows of
271.1255 +*  the matrix N; it is used when the vector rho is relatively sparse. */
271.1256 +
271.1257 +static void eval_trow1(struct csa *csa, double rho[])
271.1258 +{     int m = csa->m;
271.1259 +      int n = csa->n;
271.1260 +      int *A_ptr = csa->A_ptr;
271.1261 +      int *A_ind = csa->A_ind;
271.1262 +      double *A_val = csa->A_val;
271.1263 +      int *head = csa->head;
271.1264 +      char *stat = csa->stat;
271.1265 +      int *trow_ind = csa->trow_ind;
271.1266 +      double *trow_vec = csa->trow_vec;
271.1267 +      int j, k, beg, end, ptr, nnz;
271.1268 +      double temp;
271.1269 +      /* compute the pivot row as inner products of columns of the
271.1270 +         matrix N and vector rho: trow[j] = - rho * N[j] */
271.1271 +      nnz = 0;
271.1272 +      for (j = 1; j <= n; j++)
271.1273 +      {  if (stat[j] == GLP_NS)
271.1274 +         {  /* xN[j] is fixed */
271.1275 +            trow_vec[j] = 0.0;
271.1276 +            continue;
271.1277 +         }
271.1278 +         k = head[m+j]; /* x[k] = xN[j] */
271.1279 +         if (k <= m)
271.1280 +         {  /* N[j] is k-th column of submatrix I */
271.1281 +            temp = - rho[k];
271.1282 +         }
271.1283 +         else
271.1284 +         {  /* N[j] is (k-m)-th column of submatrix (-A) */
271.1285 +            beg = A_ptr[k-m], end = A_ptr[k-m+1];
271.1286 +            temp = 0.0;
271.1287 +            for (ptr = beg; ptr < end; ptr++)
271.1288 +               temp += rho[A_ind[ptr]] * A_val[ptr];
271.1289 +         }
271.1290 +         if (temp != 0.0)
271.1291 +            trow_ind[++nnz] = j;
271.1292 +         trow_vec[j] = temp;
271.1293 +      }
271.1294 +      csa->trow_nnz = nnz;
271.1295 +      return;
271.1296 +}
271.1297 +
271.1298 +static void eval_trow2(struct csa *csa, double rho[])
271.1299 +{     int m = csa->m;
271.1300 +      int n = csa->n;
271.1301 +      int *AT_ptr = csa->AT_ptr;
271.1302 +      int *AT_ind = csa->AT_ind;
271.1303 +      double *AT_val = csa->AT_val;
271.1304 +      int *bind = csa->bind;
271.1305 +      char *stat = csa->stat;
271.1306 +      int *trow_ind = csa->trow_ind;
271.1307 +      double *trow_vec = csa->trow_vec;
271.1308 +      int i, j, beg, end, ptr, nnz;
271.1309 +      double temp;
271.1310 +      /* clear the pivot row */
271.1311 +      for (j = 1; j <= n; j++)
271.1312 +         trow_vec[j] = 0.0;
271.1313 +      /* compute the pivot row as a linear combination of rows of the
271.1314 +         matrix N: trow = - rho[1] * N'[1] - ... - rho[m] * N'[m] */
271.1315 +      for (i = 1; i <= m; i++)
271.1316 +      {  temp = rho[i];
271.1317 +         if (temp == 0.0) continue;
271.1318 +         /* trow := trow - rho[i] * N'[i] */
271.1319 +         j = bind[i] - m; /* x[i] = xN[j] */
271.1320 +         if (j >= 1 && stat[j] != GLP_NS)
271.1321 +            trow_vec[j] -= temp;
271.1322 +         beg = AT_ptr[i], end = AT_ptr[i+1];
271.1323 +         for (ptr = beg; ptr < end; ptr++)
271.1324 +         {  j = bind[m + AT_ind[ptr]] - m; /* x[k] = xN[j] */
271.1325 +            if (j >= 1 && stat[j] != GLP_NS)
271.1326 +               trow_vec[j] += temp * AT_val[ptr];
271.1327 +         }
271.1328 +      }
271.1329 +      /* construct sparse pattern of the pivot row */
271.1330 +      nnz = 0;
271.1331 +      for (j = 1; j <= n; j++)
271.1332 +      {  if (trow_vec[j] != 0.0)
271.1333 +            trow_ind[++nnz] = j;
271.1334 +      }
271.1335 +      csa->trow_nnz = nnz;
271.1336 +      return;
271.1337 +}
271.1338 +
271.1339 +static void eval_trow(struct csa *csa, double rho[])
271.1340 +{     int m = csa->m;
271.1341 +      int i, nnz;
271.1342 +      double dens;
271.1343 +      /* determine the density of the vector rho */
271.1344 +      nnz = 0;
271.1345 +      for (i = 1; i <= m; i++)
271.1346 +         if (rho[i] != 0.0) nnz++;
271.1347 +      dens = (double)nnz / (double)m;
271.1348 +      if (dens >= 0.20)
271.1349 +      {  /* rho is relatively dense */
271.1350 +         eval_trow1(csa, rho);
271.1351 +      }
271.1352 +      else
271.1353 +      {  /* rho is relatively sparse */
271.1354 +         eval_trow2(csa, rho);
271.1355 +      }
271.1356 +      return;
271.1357 +}
271.1358 +#endif
271.1359 +
271.1360 +/***********************************************************************
271.1361 +*  sort_trow - sort pivot row of the simplex table
271.1362 +*
271.1363 +*  This routine reorders the list of non-zero elements of the pivot
271.1364 +*  row to put significant elements, whose magnitude is not less than
271.1365 +*  a specified tolerance, in front of the list, and stores the number
271.1366 +*  of significant elements in trow_num. */
271.1367 +
271.1368 +static void sort_trow(struct csa *csa, double tol_piv)
271.1369 +{
271.1370 +#ifdef GLP_DEBUG
271.1371 +      int n = csa->n;
271.1372 +      char *stat = csa->stat;
271.1373 +#endif
271.1374 +      int nnz = csa->trow_nnz;
271.1375 +      int *trow_ind = csa->trow_ind;
271.1376 +      double *trow_vec = csa->trow_vec;
271.1377 +      int j, num, pos;
271.1378 +      double big, eps, temp;
271.1379 +      /* compute infinity (maximum) norm of the row */
271.1380 +      big = 0.0;
271.1381 +      for (pos = 1; pos <= nnz; pos++)
271.1382 +      {
271.1383 +#ifdef GLP_DEBUG
271.1384 +         j = trow_ind[pos];
271.1385 +         xassert(1 <= j && j <= n);
271.1386 +         xassert(stat[j] != GLP_NS);
271.1387 +#endif
271.1388 +         temp = fabs(trow_vec[trow_ind[pos]]);
271.1389 +         if (big < temp) big = temp;
271.1390 +      }
271.1391 +      csa->trow_max = big;
271.1392 +      /* determine absolute pivot tolerance */
271.1393 +      eps = tol_piv * (1.0 + 0.01 * big);
271.1394 +      /* move significant row components to the front of the list */
271.1395 +      for (num = 0; num < nnz; )
271.1396 +      {  j = trow_ind[nnz];
271.1397 +         if (fabs(trow_vec[j]) < eps)
271.1398 +            nnz--;
271.1399 +         else
271.1400 +         {  num++;
271.1401 +            trow_ind[nnz] = trow_ind[num];
271.1402 +            trow_ind[num] = j;
271.1403 +         }
271.1404 +      }
271.1405 +      csa->trow_num = num;
271.1406 +      return;
271.1407 +}
271.1408 +
271.1409 +#ifdef GLP_LONG_STEP /* 07/IV-2009 */
271.1410 +static int ls_func(const void *p1_, const void *p2_)
271.1411 +{     const struct bkpt *p1 = p1_, *p2 = p2_;
271.1412 +      if (p1->t < p2->t) return -1;
271.1413 +      if (p1->t > p2->t) return +1;
271.1414 +      return 0;
271.1415 +}
271.1416 +
271.1417 +static int ls_func1(const void *p1_, const void *p2_)
271.1418 +{     const struct bkpt *p1 = p1_, *p2 = p2_;
271.1419 +      if (p1->dz < p2->dz) return -1;
271.1420 +      if (p1->dz > p2->dz) return +1;
271.1421 +      return 0;
271.1422 +}
271.1423 +
271.1424 +static void long_step(struct csa *csa)
271.1425 +{     int m = csa->m;
271.1426 +#ifdef GLP_DEBUG
271.1427 +      int n = csa->n;
271.1428 +#endif
271.1429 +      char *type = csa->type;
271.1430 +      double *lb = csa->lb;
271.1431 +      double *ub = csa->ub;
271.1432 +      int *head = csa->head;
271.1433 +      char *stat = csa->stat;
271.1434 +      double *cbar = csa->cbar;
271.1435 +      double delta = csa->delta;
271.1436 +      int *trow_ind = csa->trow_ind;
271.1437 +      double *trow_vec = csa->trow_vec;
271.1438 +      int trow_num = csa->trow_num;
271.1439 +      struct bkpt *bkpt = csa->bkpt;
271.1440 +      int j, k, kk, nbps, pos;
271.1441 +      double alfa, s, slope, dzmax;
271.1442 +      /* delta > 0 means that xB[p] violates its lower bound, so to
271.1443 +         increase the dual objective lambdaB[p] must increase;
271.1444 +         delta < 0 means that xB[p] violates its upper bound, so to
271.1445 +         increase the dual objective lambdaB[p] must decrease */
271.1446 +      /* s := sign(delta) */
271.1447 +      s = (delta > 0.0 ? +1.0 : -1.0);
271.1448 +      /* determine breakpoints of the dual objective */
271.1449 +      nbps = 0;
271.1450 +      for (pos = 1; pos <= trow_num; pos++)
271.1451 +      {  j = trow_ind[pos];
271.1452 +#ifdef GLP_DEBUG
271.1453 +         xassert(1 <= j && j <= n);
271.1454 +         xassert(stat[j] != GLP_NS);
271.1455 +#endif
271.1456 +         /* if there is free non-basic variable, switch to the standard
271.1457 +            ratio test */
271.1458 +         if (stat[j] == GLP_NF)
271.1459 +         {  nbps = 0;
271.1460 +            goto done;
271.1461 +         }
271.1462 +         /* lambdaN[j] = ... - alfa * t - ..., where t = s * lambdaB[i]
271.1463 +            is the dual ray parameter, t >= 0 */
271.1464 +         alfa = s * trow_vec[j];
271.1465 +#ifdef GLP_DEBUG
271.1466 +         xassert(alfa != 0.0);
271.1467 +         xassert(stat[j] == GLP_NL || stat[j] == GLP_NU);
271.1468 +#endif
271.1469 +         if (alfa > 0.0 && stat[j] == GLP_NL ||
271.1470 +             alfa < 0.0 && stat[j] == GLP_NU)
271.1471 +         {  /* either lambdaN[j] >= 0 (if stat = GLP_NL) and decreases
271.1472 +               or lambdaN[j] <= 0 (if stat = GLP_NU) and increases; in
271.1473 +               both cases we have a breakpoint */
271.1474 +            nbps++;
271.1475 +#ifdef GLP_DEBUG
271.1476 +            xassert(nbps <= n);
271.1477 +#endif
271.1478 +            bkpt[nbps].j = j;
271.1479 +            bkpt[nbps].t = cbar[j] / alfa;
271.1480 +/*
271.1481 +if (stat[j] == GLP_NL && cbar[j] < 0.0 ||
271.1482 +    stat[j] == GLP_NU && cbar[j] > 0.0)
271.1483 +xprintf("%d %g\n", stat[j], cbar[j]);
271.1484 +*/
271.1485 +            /* if t is negative, replace it by exact zero (see comments
271.1486 +               in the routine chuzc) */
271.1487 +            if (bkpt[nbps].t < 0.0) bkpt[nbps].t = 0.0;
271.1488 +         }
271.1489 +      }
271.1490 +      /* if there are less than two breakpoints, switch to the standard
271.1491 +         ratio test */
271.1492 +      if (nbps < 2)
271.1493 +      {  nbps = 0;
271.1494 +         goto done;
271.1495 +      }
271.1496 +      /* sort breakpoints by ascending the dual ray parameter, t */
271.1497 +      qsort(&bkpt[1], nbps, sizeof(struct bkpt), ls_func);
271.1498 +      /* determine last breakpoint, at which the dual objective still
271.1499 +         greater than at t = 0 */
271.1500 +      dzmax = 0.0;
271.1501 +      slope = fabs(delta); /* initial slope */
271.1502 +      for (kk = 1; kk <= nbps; kk++)
271.1503 +      {  if (kk == 1)
271.1504 +            bkpt[kk].dz =
271.1505 +               0.0 + slope * (bkpt[kk].t - 0.0);
271.1506 +         else
271.1507 +            bkpt[kk].dz =
271.1508 +               bkpt[kk-1].dz + slope * (bkpt[kk].t - bkpt[kk-1].t);
271.1509 +         if (dzmax < bkpt[kk].dz)
271.1510 +            dzmax = bkpt[kk].dz;
271.1511 +         else if (bkpt[kk].dz < 0.05 * (1.0 + dzmax))
271.1512 +         {  nbps = kk - 1;
271.1513 +            break;
271.1514 +         }
271.1515 +         j = bkpt[kk].j;
271.1516 +         k = head[m+j]; /* x[k] = xN[j] */
271.1517 +         if (type[k] == GLP_DB)
271.1518 +            slope -= fabs(trow_vec[j]) * (ub[k] - lb[k]);
271.1519 +         else
271.1520 +         {  nbps = kk;
271.1521 +            break;
271.1522 +         }
271.1523 +      }
271.1524 +      /* if there are less than two breakpoints, switch to the standard
271.1525 +         ratio test */
271.1526 +      if (nbps < 2)
271.1527 +      {  nbps = 0;
271.1528 +         goto done;
271.1529 +      }
271.1530 +      /* sort breakpoints by ascending the dual change, dz */
271.1531 +      qsort(&bkpt[1], nbps, sizeof(struct bkpt), ls_func1);
271.1532 +/*
271.1533 +for (kk = 1; kk <= nbps; kk++)
271.1534 +xprintf("%d; t = %g; dz = %g\n", kk, bkpt[kk].t, bkpt[kk].dz);
271.1535 +*/
271.1536 +done: csa->nbps = nbps;
271.1537 +      return;
271.1538 +}
271.1539 +#endif
271.1540 +
271.1541 +/***********************************************************************
271.1542 +*  chuzc - choose non-basic variable (column of the simplex table)
271.1543 +*
271.1544 +*  This routine chooses non-basic variable xN[q], which being entered
271.1545 +*  in the basis keeps dual feasibility of the basic solution.
271.1546 +*
271.1547 +*  The parameter rtol is a relative tolerance used to relax zero bounds
271.1548 +*  of reduced costs of non-basic variables. If rtol = 0, the routine
271.1549 +*  implements the standard ratio test. Otherwise, if rtol > 0, the
271.1550 +*  routine implements Harris' two-pass ratio test. In the latter case
271.1551 +*  rtol should be about three times less than a tolerance used to check
271.1552 +*  dual feasibility. */
271.1553 +
271.1554 +static void chuzc(struct csa *csa, double rtol)
271.1555 +{
271.1556 +#ifdef GLP_DEBUG
271.1557 +      int m = csa->m;
271.1558 +      int n = csa->n;
271.1559 +#endif
271.1560 +      char *stat = csa->stat;
271.1561 +      double *cbar = csa->cbar;
271.1562 +#ifdef GLP_DEBUG
271.1563 +      int p = csa->p;
271.1564 +#endif
271.1565 +      double delta = csa->delta;
271.1566 +      int *trow_ind = csa->trow_ind;
271.1567 +      double *trow_vec = csa->trow_vec;
271.1568 +      int trow_num = csa->trow_num;
271.1569 +      int j, pos, q;
271.1570 +      double alfa, big, s, t, teta, tmax;
271.1571 +#ifdef GLP_DEBUG
271.1572 +      xassert(1 <= p && p <= m);
271.1573 +#endif
271.1574 +      /* delta > 0 means that xB[p] violates its lower bound and goes
271.1575 +         to it in the adjacent basis, so lambdaB[p] is increasing from
271.1576 +         its lower zero bound;
271.1577 +         delta < 0 means that xB[p] violates its upper bound and goes
271.1578 +         to it in the adjacent basis, so lambdaB[p] is decreasing from
271.1579 +         its upper zero bound */
271.1580 +#ifdef GLP_DEBUG
271.1581 +      xassert(delta != 0.0);
271.1582 +#endif
271.1583 +      /* s := sign(delta) */
271.1584 +      s = (delta > 0.0 ? +1.0 : -1.0);
271.1585 +      /*** FIRST PASS ***/
271.1586 +      /* nothing is chosen so far */
271.1587 +      q = 0, teta = DBL_MAX, big = 0.0;
271.1588 +      /* walk through significant elements of the pivot row */
271.1589 +      for (pos = 1; pos <= trow_num; pos++)
271.1590 +      {  j = trow_ind[pos];
271.1591 +#ifdef GLP_DEBUG
271.1592 +         xassert(1 <= j && j <= n);
271.1593 +#endif
271.1594 +         alfa = s * trow_vec[j];
271.1595 +#ifdef GLP_DEBUG
271.1596 +         xassert(alfa != 0.0);
271.1597 +#endif
271.1598 +         /* lambdaN[j] = ... - alfa * lambdaB[p] - ..., and due to s we
271.1599 +            need to consider only increasing lambdaB[p] */
271.1600 +         if (alfa > 0.0)
271.1601 +         {  /* lambdaN[j] is decreasing */
271.1602 +            if (stat[j] == GLP_NL || stat[j] == GLP_NF)
271.1603 +            {  /* lambdaN[j] has zero lower bound */
271.1604 +               t = (cbar[j] + rtol) / alfa;
271.1605 +            }
271.1606 +            else
271.1607 +            {  /* lambdaN[j] has no lower bound */
271.1608 +               continue;
271.1609 +            }
271.1610 +         }
271.1611 +         else
271.1612 +         {  /* lambdaN[j] is increasing */
271.1613 +            if (stat[j] == GLP_NU || stat[j] == GLP_NF)
271.1614 +            {  /* lambdaN[j] has zero upper bound */
271.1615 +               t = (cbar[j] - rtol) / alfa;
271.1616 +            }
271.1617 +            else
271.1618 +            {  /* lambdaN[j] has no upper bound */
271.1619 +               continue;
271.1620 +            }
271.1621 +         }
271.1622 +         /* t is a change of lambdaB[p], on which lambdaN[j] reaches
271.1623 +            its zero bound (possibly relaxed); since the basic solution
271.1624 +            is assumed to be dual feasible, t has to be non-negative by
271.1625 +            definition; however, it may happen that lambdaN[j] slightly
271.1626 +            (i.e. within a tolerance) violates its zero bound, that
271.1627 +            leads to negative t; in the latter case, if xN[j] is chosen,
271.1628 +            negative t means that lambdaB[p] changes in wrong direction
271.1629 +            that may cause wrong results on updating reduced costs;
271.1630 +            thus, if t is negative, we should replace it by exact zero
271.1631 +            assuming that lambdaN[j] is exactly on its zero bound, and
271.1632 +            violation appears due to round-off errors */
271.1633 +         if (t < 0.0) t = 0.0;
271.1634 +         /* apply minimal ratio test */
271.1635 +         if (teta > t || teta == t && big < fabs(alfa))
271.1636 +            q = j, teta = t, big = fabs(alfa);
271.1637 +      }
271.1638 +      /* the second pass is skipped in the following cases: */
271.1639 +      /* if the standard ratio test is used */
271.1640 +      if (rtol == 0.0) goto done;
271.1641 +      /* if no non-basic variable has been chosen on the first pass */
271.1642 +      if (q == 0) goto done;
271.1643 +      /* if lambdaN[q] prevents lambdaB[p] from any change */
271.1644 +      if (teta == 0.0) goto done;
271.1645 +      /*** SECOND PASS ***/
271.1646 +      /* here tmax is a maximal change of lambdaB[p], on which the
271.1647 +         solution remains dual feasible within a tolerance */
271.1648 +#if 0
271.1649 +      tmax = (1.0 + 10.0 * DBL_EPSILON) * teta;
271.1650 +#else
271.1651 +      tmax = teta;
271.1652 +#endif
271.1653 +      /* nothing is chosen so far */
271.1654 +      q = 0, teta = DBL_MAX, big = 0.0;
271.1655 +      /* walk through significant elements of the pivot row */
271.1656 +      for (pos = 1; pos <= trow_num; pos++)
271.1657 +      {  j = trow_ind[pos];
271.1658 +#ifdef GLP_DEBUG
271.1659 +         xassert(1 <= j && j <= n);
271.1660 +#endif
271.1661 +         alfa = s * trow_vec[j];
271.1662 +#ifdef GLP_DEBUG
271.1663 +         xassert(alfa != 0.0);
271.1664 +#endif
271.1665 +         /* lambdaN[j] = ... - alfa * lambdaB[p] - ..., and due to s we
271.1666 +            need to consider only increasing lambdaB[p] */
271.1667 +         if (alfa > 0.0)
271.1668 +         {  /* lambdaN[j] is decreasing */
271.1669 +            if (stat[j] == GLP_NL || stat[j] == GLP_NF)
271.1670 +            {  /* lambdaN[j] has zero lower bound */
271.1671 +               t = cbar[j] / alfa;
271.1672 +            }
271.1673 +            else
271.1674 +            {  /* lambdaN[j] has no lower bound */
271.1675 +               continue;
271.1676 +            }
271.1677 +         }
271.1678 +         else
271.1679 +         {  /* lambdaN[j] is increasing */
271.1680 +            if (stat[j] == GLP_NU || stat[j] == GLP_NF)
271.1681 +            {  /* lambdaN[j] has zero upper bound */
271.1682 +               t = cbar[j] / alfa;
271.1683 +            }
271.1684 +            else
271.1685 +            {  /* lambdaN[j] has no upper bound */
271.1686 +               continue;
271.1687 +            }
271.1688 +         }
271.1689 +         /* (see comments for the first pass) */
271.1690 +         if (t < 0.0) t = 0.0;
271.1691 +         /* t is a change of lambdaB[p], on which lambdaN[j] reaches
271.1692 +            its zero (lower or upper) bound; if t <= tmax, all reduced
271.1693 +            costs can violate their zero bounds only within relaxation
271.1694 +            tolerance rtol, so we can choose non-basic variable having
271.1695 +            largest influence coefficient to avoid possible numerical
271.1696 +            instability */
271.1697 +         if (t <= tmax && big < fabs(alfa))
271.1698 +            q = j, teta = t, big = fabs(alfa);
271.1699 +      }
271.1700 +      /* something must be chosen on the second pass */
271.1701 +      xassert(q != 0);
271.1702 +done: /* store the index of non-basic variable xN[q] chosen */
271.1703 +      csa->q = q;
271.1704 +      /* store reduced cost of xN[q] in the adjacent basis */
271.1705 +      csa->new_dq = s * teta;
271.1706 +      return;
271.1707 +}
271.1708 +
271.1709 +#if 1 /* copied from primal */
271.1710 +/***********************************************************************
271.1711 +*  eval_tcol - compute pivot column of the simplex table
271.1712 +*
271.1713 +*  This routine computes the pivot column of the simplex table, which
271.1714 +*  corresponds to non-basic variable xN[q] chosen.
271.1715 +*
271.1716 +*  The pivot column is the following vector:
271.1717 +*
271.1718 +*     tcol = T * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q],
271.1719 +*
271.1720 +*  where B is the current basis matrix, N[q] is a column of the matrix
271.1721 +*  (I|-A) corresponding to variable xN[q]. */
271.1722 +
271.1723 +static void eval_tcol(struct csa *csa)
271.1724 +{     int m = csa->m;
271.1725 +#ifdef GLP_DEBUG
271.1726 +      int n = csa->n;
271.1727 +#endif
271.1728 +      int *head = csa->head;
271.1729 +      int q = csa->q;
271.1730 +      int *tcol_ind = csa->tcol_ind;
271.1731 +      double *tcol_vec = csa->tcol_vec;
271.1732 +      double *h = csa->tcol_vec;
271.1733 +      int i, k, nnz;
271.1734 +#ifdef GLP_DEBUG
271.1735 +      xassert(1 <= q && q <= n);
271.1736 +#endif
271.1737 +      k = head[m+q]; /* x[k] = xN[q] */
271.1738 +#ifdef GLP_DEBUG
271.1739 +      xassert(1 <= k && k <= m+n);
271.1740 +#endif
271.1741 +      /* construct the right-hand side vector h = - N[q] */
271.1742 +      for (i = 1; i <= m; i++)
271.1743 +         h[i] = 0.0;
271.1744 +      if (k <= m)
271.1745 +      {  /* N[q] is k-th column of submatrix I */
271.1746 +         h[k] = -1.0;
271.1747 +      }
271.1748 +      else
271.1749 +      {  /* N[q] is (k-m)-th column of submatrix (-A) */
271.1750 +         int *A_ptr = csa->A_ptr;
271.1751 +         int *A_ind = csa->A_ind;
271.1752 +         double *A_val = csa->A_val;
271.1753 +         int beg, end, ptr;
271.1754 +         beg = A_ptr[k-m];
271.1755 +         end = A_ptr[k-m+1];
271.1756 +         for (ptr = beg; ptr < end; ptr++)
271.1757 +            h[A_ind[ptr]] = A_val[ptr];
271.1758 +      }
271.1759 +      /* solve system B * tcol = h */
271.1760 +      xassert(csa->valid);
271.1761 +      bfd_ftran(csa->bfd, tcol_vec);
271.1762 +      /* construct sparse pattern of the pivot column */
271.1763 +      nnz = 0;
271.1764 +      for (i = 1; i <= m; i++)
271.1765 +      {  if (tcol_vec[i] != 0.0)
271.1766 +            tcol_ind[++nnz] = i;
271.1767 +      }
271.1768 +      csa->tcol_nnz = nnz;
271.1769 +      return;
271.1770 +}
271.1771 +#endif
271.1772 +
271.1773 +#if 1 /* copied from primal */
271.1774 +/***********************************************************************
271.1775 +*  refine_tcol - refine pivot column of the simplex table
271.1776 +*
271.1777 +*  This routine refines the pivot column of the simplex table assuming
271.1778 +*  that it was previously computed by the routine eval_tcol. */
271.1779 +
271.1780 +static void refine_tcol(struct csa *csa)
271.1781 +{     int m = csa->m;
271.1782 +#ifdef GLP_DEBUG
271.1783 +      int n = csa->n;
271.1784 +#endif
271.1785 +      int *head = csa->head;
271.1786 +      int q = csa->q;
271.1787 +      int *tcol_ind = csa->tcol_ind;
271.1788 +      double *tcol_vec = csa->tcol_vec;
271.1789 +      double *h = csa->work3;
271.1790 +      int i, k, nnz;
271.1791 +#ifdef GLP_DEBUG
271.1792 +      xassert(1 <= q && q <= n);
271.1793 +#endif
271.1794 +      k = head[m+q]; /* x[k] = xN[q] */
271.1795 +#ifdef GLP_DEBUG
271.1796 +      xassert(1 <= k && k <= m+n);
271.1797 +#endif
271.1798 +      /* construct the right-hand side vector h = - N[q] */
271.1799 +      for (i = 1; i <= m; i++)
271.1800 +         h[i] = 0.0;
271.1801 +      if (k <= m)
271.1802 +      {  /* N[q] is k-th column of submatrix I */
271.1803 +         h[k] = -1.0;
271.1804 +      }
271.1805 +      else
271.1806 +      {  /* N[q] is (k-m)-th column of submatrix (-A) */
271.1807 +         int *A_ptr = csa->A_ptr;
271.1808 +         int *A_ind = csa->A_ind;
271.1809 +         double *A_val = csa->A_val;
271.1810 +         int beg, end, ptr;
271.1811 +         beg = A_ptr[k-m];
271.1812 +         end = A_ptr[k-m+1];
271.1813 +         for (ptr = beg; ptr < end; ptr++)
271.1814 +            h[A_ind[ptr]] = A_val[ptr];
271.1815 +      }
271.1816 +      /* refine solution of B * tcol = h */
271.1817 +      refine_ftran(csa, h, tcol_vec);
271.1818 +      /* construct sparse pattern of the pivot column */
271.1819 +      nnz = 0;
271.1820 +      for (i = 1; i <= m; i++)
271.1821 +      {  if (tcol_vec[i] != 0.0)
271.1822 +            tcol_ind[++nnz] = i;
271.1823 +      }
271.1824 +      csa->tcol_nnz = nnz;
271.1825 +      return;
271.1826 +}
271.1827 +#endif
271.1828 +
271.1829 +/***********************************************************************
271.1830 +*  update_cbar - update reduced costs of non-basic variables
271.1831 +*
271.1832 +*  This routine updates reduced costs of all (except fixed) non-basic
271.1833 +*  variables for the adjacent basis. */
271.1834 +
271.1835 +static void update_cbar(struct csa *csa)
271.1836 +{
271.1837 +#ifdef GLP_DEBUG
271.1838 +      int n = csa->n;
271.1839 +#endif
271.1840 +      double *cbar = csa->cbar;
271.1841 +      int trow_nnz = csa->trow_nnz;
271.1842 +      int *trow_ind = csa->trow_ind;
271.1843 +      double *trow_vec = csa->trow_vec;
271.1844 +      int q = csa->q;
271.1845 +      double new_dq = csa->new_dq;
271.1846 +      int j, pos;
271.1847 +#ifdef GLP_DEBUG
271.1848 +      xassert(1 <= q && q <= n);
271.1849 +#endif
271.1850 +      /* set new reduced cost of xN[q] */
271.1851 +      cbar[q] = new_dq;
271.1852 +      /* update reduced costs of other non-basic variables */
271.1853 +      if (new_dq == 0.0) goto done;
271.1854 +      for (pos = 1; pos <= trow_nnz; pos++)
271.1855 +      {  j = trow_ind[pos];
271.1856 +#ifdef GLP_DEBUG
271.1857 +         xassert(1 <= j && j <= n);
271.1858 +#endif
271.1859 +         if (j != q)
271.1860 +            cbar[j] -= trow_vec[j] * new_dq;
271.1861 +      }
271.1862 +done: return;
271.1863 +}
271.1864 +
271.1865 +/***********************************************************************
271.1866 +*  update_bbar - update values of basic variables
271.1867 +*
271.1868 +*  This routine updates values of all basic variables for the adjacent
271.1869 +*  basis. */
271.1870 +
271.1871 +static void update_bbar(struct csa *csa)
271.1872 +{
271.1873 +#ifdef GLP_DEBUG
271.1874 +      int m = csa->m;
271.1875 +      int n = csa->n;
271.1876 +#endif
271.1877 +      double *bbar = csa->bbar;
271.1878 +      int p = csa->p;
271.1879 +      double delta = csa->delta;
271.1880 +      int q = csa->q;
271.1881 +      int tcol_nnz = csa->tcol_nnz;
271.1882 +      int *tcol_ind = csa->tcol_ind;
271.1883 +      double *tcol_vec = csa->tcol_vec;
271.1884 +      int i, pos;
271.1885 +      double teta;
271.1886 +#ifdef GLP_DEBUG
271.1887 +      xassert(1 <= p && p <= m);
271.1888 +      xassert(1 <= q && q <= n);
271.1889 +#endif
271.1890 +      /* determine the change of xN[q] in the adjacent basis */
271.1891 +#ifdef GLP_DEBUG
271.1892 +      xassert(tcol_vec[p] != 0.0);
271.1893 +#endif
271.1894 +      teta = delta / tcol_vec[p];
271.1895 +      /* set new primal value of xN[q] */
271.1896 +      bbar[p] = get_xN(csa, q) + teta;
271.1897 +      /* update primal values of other basic variables */
271.1898 +      if (teta == 0.0) goto done;
271.1899 +      for (pos = 1; pos <= tcol_nnz; pos++)
271.1900 +      {  i = tcol_ind[pos];
271.1901 +#ifdef GLP_DEBUG
271.1902 +         xassert(1 <= i && i <= m);
271.1903 +#endif
271.1904 +         if (i != p)
271.1905 +            bbar[i] += tcol_vec[i] * teta;
271.1906 +      }
271.1907 +done: return;
271.1908 +}
271.1909 +
271.1910 +/***********************************************************************
271.1911 +*  update_gamma - update steepest edge coefficients
271.1912 +*
271.1913 +*  This routine updates steepest-edge coefficients for the adjacent
271.1914 +*  basis. */
271.1915 +
271.1916 +static void update_gamma(struct csa *csa)
271.1917 +{     int m = csa->m;
271.1918 +#ifdef GLP_DEBUG
271.1919 +      int n = csa->n;
271.1920 +#endif
271.1921 +      char *type = csa->type;
271.1922 +      int *head = csa->head;
271.1923 +      char *refsp = csa->refsp;
271.1924 +      double *gamma = csa->gamma;
271.1925 +      int p = csa->p;
271.1926 +      int trow_nnz = csa->trow_nnz;
271.1927 +      int *trow_ind = csa->trow_ind;
271.1928 +      double *trow_vec = csa->trow_vec;
271.1929 +      int q = csa->q;
271.1930 +      int tcol_nnz = csa->tcol_nnz;
271.1931 +      int *tcol_ind = csa->tcol_ind;
271.1932 +      double *tcol_vec = csa->tcol_vec;
271.1933 +      double *u = csa->work3;
271.1934 +      int i, j, k,pos;
271.1935 +      double gamma_p, eta_p, pivot, t, t1, t2;
271.1936 +#ifdef GLP_DEBUG
271.1937 +      xassert(1 <= p && p <= m);
271.1938 +      xassert(1 <= q && q <= n);
271.1939 +#endif
271.1940 +      /* the basis changes, so decrease the count */
271.1941 +      xassert(csa->refct > 0);
271.1942 +      csa->refct--;
271.1943 +      /* recompute gamma[p] for the current basis more accurately and
271.1944 +         compute auxiliary vector u */
271.1945 +#ifdef GLP_DEBUG
271.1946 +      xassert(type[head[p]] != GLP_FR);
271.1947 +#endif
271.1948 +      gamma_p = eta_p = (refsp[head[p]] ? 1.0 : 0.0);
271.1949 +      for (i = 1; i <= m; i++) u[i] = 0.0;
271.1950 +      for (pos = 1; pos <= trow_nnz; pos++)
271.1951 +      {  j = trow_ind[pos];
271.1952 +#ifdef GLP_DEBUG
271.1953 +         xassert(1 <= j && j <= n);
271.1954 +#endif
271.1955 +         k = head[m+j]; /* x[k] = xN[j] */
271.1956 +#ifdef GLP_DEBUG
271.1957 +         xassert(1 <= k && k <= m+n);
271.1958 +         xassert(type[k] != GLP_FX);
271.1959 +#endif
271.1960 +         if (!refsp[k]) continue;
271.1961 +         t = trow_vec[j];
271.1962 +         gamma_p += t * t;
271.1963 +         /* u := u + N[j] * delta[j] * trow[j] */
271.1964 +         if (k <= m)
271.1965 +         {  /* N[k] = k-j stolbec submatrix I */
271.1966 +            u[k] += t;
271.1967 +         }
271.1968 +         else
271.1969 +         {  /* N[k] = k-m-k stolbec (-A) */
271.1970 +            int *A_ptr = csa->A_ptr;
271.1971 +            int *A_ind = csa->A_ind;
271.1972 +            double *A_val = csa->A_val;
271.1973 +            int beg, end, ptr;
271.1974 +            beg = A_ptr[k-m];
271.1975 +            end = A_ptr[k-m+1];
271.1976 +            for (ptr = beg; ptr < end; ptr++)
271.1977 +               u[A_ind[ptr]] -= t * A_val[ptr];
271.1978 +         }
271.1979 +      }
271.1980 +      xassert(csa->valid);
271.1981 +      bfd_ftran(csa->bfd, u);
271.1982 +      /* update gamma[i] for other basic variables (except xB[p] and
271.1983 +         free variables) */
271.1984 +      pivot = tcol_vec[p];
271.1985 +#ifdef GLP_DEBUG
271.1986 +      xassert(pivot != 0.0);
271.1987 +#endif
271.1988 +      for (pos = 1; pos <= tcol_nnz; pos++)
271.1989 +      {  i = tcol_ind[pos];
271.1990 +#ifdef GLP_DEBUG
271.1991 +         xassert(1 <= i && i <= m);
271.1992 +#endif
271.1993 +         k = head[i];
271.1994 +#ifdef GLP_DEBUG
271.1995 +         xassert(1 <= k && k <= m+n);
271.1996 +#endif
271.1997 +         /* skip xB[p] */
271.1998 +         if (i == p) continue;
271.1999 +         /* skip free basic variable */
271.2000 +         if (type[head[i]] == GLP_FR)
271.2001 +         {
271.2002 +#ifdef GLP_DEBUG
271.2003 +            xassert(gamma[i] == 1.0);
271.2004 +#endif
271.2005 +            continue;
271.2006 +         }
271.2007 +         /* compute gamma[i] for the adjacent basis */
271.2008 +         t = tcol_vec[i] / pivot;
271.2009 +         t1 = gamma[i] + t * t * gamma_p + 2.0 * t * u[i];
271.2010 +         t2 = (refsp[k] ? 1.0 : 0.0) + eta_p * t * t;
271.2011 +         gamma[i] = (t1 >= t2 ? t1 : t2);
271.2012 +         /* (though gamma[i] can be exact zero, because the reference
271.2013 +            space does not include non-basic fixed variables) */
271.2014 +         if (gamma[i] < DBL_EPSILON) gamma[i] = DBL_EPSILON;
271.2015 +      }
271.2016 +      /* compute gamma[p] for the adjacent basis */
271.2017 +      if (type[head[m+q]] == GLP_FR)
271.2018 +         gamma[p] = 1.0;
271.2019 +      else
271.2020 +      {  gamma[p] = gamma_p / (pivot * pivot);
271.2021 +         if (gamma[p] < DBL_EPSILON) gamma[p] = DBL_EPSILON;
271.2022 +      }
271.2023 +      /* if xB[p], which becomes xN[q] in the adjacent basis, is fixed
271.2024 +         and belongs to the reference space, remove it from there, and
271.2025 +         change all gamma's appropriately */
271.2026 +      k = head[p];
271.2027 +      if (type[k] == GLP_FX && refsp[k])
271.2028 +      {  refsp[k] = 0;
271.2029 +         for (pos = 1; pos <= tcol_nnz; pos++)
271.2030 +         {  i = tcol_ind[pos];
271.2031 +            if (i == p)
271.2032 +            {  if (type[head[m+q]] == GLP_FR) continue;
271.2033 +               t = 1.0 / tcol_vec[p];
271.2034 +            }
271.2035 +            else
271.2036 +            {  if (type[head[i]] == GLP_FR) continue;
271.2037 +               t = tcol_vec[i] / tcol_vec[p];
271.2038 +            }
271.2039 +            gamma[i] -= t * t;
271.2040 +            if (gamma[i] < DBL_EPSILON) gamma[i] = DBL_EPSILON;
271.2041 +         }
271.2042 +      }
271.2043 +      return;
271.2044 +}
271.2045 +
271.2046 +#if 1 /* copied from primal */
271.2047 +/***********************************************************************
271.2048 +*  err_in_bbar - compute maximal relative error in primal solution
271.2049 +*
271.2050 +*  This routine returns maximal relative error:
271.2051 +*
271.2052 +*     max |beta[i] - bbar[i]| / (1 + |beta[i]|),
271.2053 +*
271.2054 +*  where beta and bbar are, respectively, directly computed and the
271.2055 +*  current (updated) values of basic variables.
271.2056 +*
271.2057 +*  NOTE: The routine is intended only for debugginig purposes. */
271.2058 +
271.2059 +static double err_in_bbar(struct csa *csa)
271.2060 +{     int m = csa->m;
271.2061 +      double *bbar = csa->bbar;
271.2062 +      int i;
271.2063 +      double e, emax, *beta;
271.2064 +      beta = xcalloc(1+m, sizeof(double));
271.2065 +      eval_beta(csa, beta);
271.2066 +      emax = 0.0;
271.2067 +      for (i = 1; i <= m; i++)
271.2068 +      {  e = fabs(beta[i] - bbar[i]) / (1.0 + fabs(beta[i]));
271.2069 +         if (emax < e) emax = e;
271.2070 +      }
271.2071 +      xfree(beta);
271.2072 +      return emax;
271.2073 +}
271.2074 +#endif
271.2075 +
271.2076 +#if 1 /* copied from primal */
271.2077 +/***********************************************************************
271.2078 +*  err_in_cbar - compute maximal relative error in dual solution
271.2079 +*
271.2080 +*  This routine returns maximal relative error:
271.2081 +*
271.2082 +*     max |cost[j] - cbar[j]| / (1 + |cost[j]|),
271.2083 +*
271.2084 +*  where cost and cbar are, respectively, directly computed and the
271.2085 +*  current (updated) reduced costs of non-basic non-fixed variables.
271.2086 +*
271.2087 +*  NOTE: The routine is intended only for debugginig purposes. */
271.2088 +
271.2089 +static double err_in_cbar(struct csa *csa)
271.2090 +{     int m = csa->m;
271.2091 +      int n = csa->n;
271.2092 +      char *stat = csa->stat;
271.2093 +      double *cbar = csa->cbar;
271.2094 +      int j;
271.2095 +      double e, emax, cost, *pi;
271.2096 +      pi = xcalloc(1+m, sizeof(double));
271.2097 +      eval_pi(csa, pi);
271.2098 +      emax = 0.0;
271.2099 +      for (j = 1; j <= n; j++)
271.2100 +      {  if (stat[j] == GLP_NS) continue;
271.2101 +         cost = eval_cost(csa, pi, j);
271.2102 +         e = fabs(cost - cbar[j]) / (1.0 + fabs(cost));
271.2103 +         if (emax < e) emax = e;
271.2104 +      }
271.2105 +      xfree(pi);
271.2106 +      return emax;
271.2107 +}
271.2108 +#endif
271.2109 +
271.2110 +/***********************************************************************
271.2111 +*  err_in_gamma - compute maximal relative error in steepest edge cff.
271.2112 +*
271.2113 +*  This routine returns maximal relative error:
271.2114 +*
271.2115 +*     max |gamma'[j] - gamma[j]| / (1 + |gamma'[j]),
271.2116 +*
271.2117 +*  where gamma'[j] and gamma[j] are, respectively, directly computed
271.2118 +*  and the current (updated) steepest edge coefficients for non-basic
271.2119 +*  non-fixed variable x[j].
271.2120 +*
271.2121 +*  NOTE: The routine is intended only for debugginig purposes. */
271.2122 +
271.2123 +static double err_in_gamma(struct csa *csa)
271.2124 +{     int m = csa->m;
271.2125 +      char *type = csa->type;
271.2126 +      int *head = csa->head;
271.2127 +      double *gamma = csa->gamma;
271.2128 +      double *exact = csa->work4;
271.2129 +      int i;
271.2130 +      double e, emax, temp;
271.2131 +      eval_gamma(csa, exact);
271.2132 +      emax = 0.0;
271.2133 +      for (i = 1; i <= m; i++)
271.2134 +      {  if (type[head[i]] == GLP_FR)
271.2135 +         {  xassert(gamma[i] == 1.0);
271.2136 +            xassert(exact[i] == 1.0);
271.2137 +            continue;
271.2138 +         }
271.2139 +         temp = exact[i];
271.2140 +         e = fabs(temp - gamma[i]) / (1.0 + fabs(temp));
271.2141 +         if (emax < e) emax = e;
271.2142 +      }
271.2143 +      return emax;
271.2144 +}
271.2145 +
271.2146 +/***********************************************************************
271.2147 +*  change_basis - change basis header
271.2148 +*
271.2149 +*  This routine changes the basis header to make it corresponding to
271.2150 +*  the adjacent basis. */
271.2151 +
271.2152 +static void change_basis(struct csa *csa)
271.2153 +{     int m = csa->m;
271.2154 +#ifdef GLP_DEBUG
271.2155 +      int n = csa->n;
271.2156 +#endif
271.2157 +      char *type = csa->type;
271.2158 +      int *head = csa->head;
271.2159 +#if 1 /* 06/IV-2009 */
271.2160 +      int *bind = csa->bind;
271.2161 +#endif
271.2162 +      char *stat = csa->stat;
271.2163 +      int p = csa->p;
271.2164 +      double delta = csa->delta;
271.2165 +      int q = csa->q;
271.2166 +      int k;
271.2167 +      /* xB[p] leaves the basis, xN[q] enters the basis */
271.2168 +#ifdef GLP_DEBUG
271.2169 +      xassert(1 <= p && p <= m);
271.2170 +      xassert(1 <= q && q <= n);
271.2171 +#endif
271.2172 +      /* xB[p] <-> xN[q] */
271.2173 +      k = head[p], head[p] = head[m+q], head[m+q] = k;
271.2174 +#if 1 /* 06/IV-2009 */
271.2175 +      bind[head[p]] = p, bind[head[m+q]] = m + q;
271.2176 +#endif
271.2177 +      if (type[k] == GLP_FX)
271.2178 +         stat[q] = GLP_NS;
271.2179 +      else if (delta > 0.0)
271.2180 +      {
271.2181 +#ifdef GLP_DEBUG
271.2182 +         xassert(type[k] == GLP_LO || type[k] == GLP_DB);
271.2183 +#endif
271.2184 +         stat[q] = GLP_NL;
271.2185 +      }
271.2186 +      else /* delta < 0.0 */
271.2187 +      {
271.2188 +#ifdef GLP_DEBUG
271.2189 +         xassert(type[k] == GLP_UP || type[k] == GLP_DB);
271.2190 +#endif
271.2191 +         stat[q] = GLP_NU;
271.2192 +      }
271.2193 +      return;
271.2194 +}
271.2195 +
271.2196 +/***********************************************************************
271.2197 +*  check_feas - check dual feasibility of basic solution
271.2198 +*
271.2199 +*  If the current basic solution is dual feasible within a tolerance,
271.2200 +*  this routine returns zero, otherwise it returns non-zero. */
271.2201 +
271.2202 +static int check_feas(struct csa *csa, double tol_dj)
271.2203 +{     int m = csa->m;
271.2204 +      int n = csa->n;
271.2205 +      char *orig_type = csa->orig_type;
271.2206 +      int *head = csa->head;
271.2207 +      double *cbar = csa->cbar;
271.2208 +      int j, k;
271.2209 +      for (j = 1; j <= n; j++)
271.2210 +      {  k = head[m+j]; /* x[k] = xN[j] */
271.2211 +#ifdef GLP_DEBUG
271.2212 +         xassert(1 <= k && k <= m+n);
271.2213 +#endif
271.2214 +         if (cbar[j] < - tol_dj)
271.2215 +            if (orig_type[k] == GLP_LO || orig_type[k] == GLP_FR)
271.2216 +               return 1;
271.2217 +         if (cbar[j] > + tol_dj)
271.2218 +            if (orig_type[k] == GLP_UP || orig_type[k] == GLP_FR)
271.2219 +               return 1;
271.2220 +      }
271.2221 +      return 0;
271.2222 +}
271.2223 +
271.2224 +/***********************************************************************
271.2225 +*  set_aux_bnds - assign auxiliary bounds to variables
271.2226 +*
271.2227 +*  This routine assigns auxiliary bounds to variables to construct an
271.2228 +*  LP problem solved on phase I. */
271.2229 +
271.2230 +static void set_aux_bnds(struct csa *csa)
271.2231 +{     int m = csa->m;
271.2232 +      int n = csa->n;
271.2233 +      char *type = csa->type;
271.2234 +      double *lb = csa->lb;
271.2235 +      double *ub = csa->ub;
271.2236 +      char *orig_type = csa->orig_type;
271.2237 +      int *head = csa->head;
271.2238 +      char *stat = csa->stat;
271.2239 +      double *cbar = csa->cbar;
271.2240 +      int j, k;
271.2241 +      for (k = 1; k <= m+n; k++)
271.2242 +      {  switch (orig_type[k])
271.2243 +         {  case GLP_FR:
271.2244 +#if 0
271.2245 +               type[k] = GLP_DB, lb[k] = -1.0, ub[k] = +1.0;
271.2246 +#else
271.2247 +               /* to force free variables to enter the basis */
271.2248 +               type[k] = GLP_DB, lb[k] = -1e3, ub[k] = +1e3;
271.2249 +#endif
271.2250 +               break;
271.2251 +            case GLP_LO:
271.2252 +               type[k] = GLP_DB, lb[k] = 0.0, ub[k] = +1.0;
271.2253 +               break;
271.2254 +            case GLP_UP:
271.2255 +               type[k] = GLP_DB, lb[k] = -1.0, ub[k] = 0.0;
271.2256 +               break;
271.2257 +            case GLP_DB:
271.2258 +            case GLP_FX:
271.2259 +               type[k] = GLP_FX, lb[k] = ub[k] = 0.0;
271.2260 +               break;
271.2261 +            default:
271.2262 +               xassert(orig_type != orig_type);
271.2263 +         }
271.2264 +      }
271.2265 +      for (j = 1; j <= n; j++)
271.2266 +      {  k = head[m+j]; /* x[k] = xN[j] */
271.2267 +#ifdef GLP_DEBUG
271.2268 +         xassert(1 <= k && k <= m+n);
271.2269 +#endif
271.2270 +         if (type[k] == GLP_FX)
271.2271 +            stat[j] = GLP_NS;
271.2272 +         else if (cbar[j] >= 0.0)
271.2273 +            stat[j] = GLP_NL;
271.2274 +         else
271.2275 +            stat[j] = GLP_NU;
271.2276 +      }
271.2277 +      return;
271.2278 +}
271.2279 +
271.2280 +/***********************************************************************
271.2281 +*  set_orig_bnds - restore original bounds of variables
271.2282 +*
271.2283 +*  This routine restores original types and bounds of variables and
271.2284 +*  determines statuses of non-basic variables assuming that the current
271.2285 +*  basis is dual feasible. */
271.2286 +
271.2287 +static void set_orig_bnds(struct csa *csa)
271.2288 +{     int m = csa->m;
271.2289 +      int n = csa->n;
271.2290 +      char *type = csa->type;
271.2291 +      double *lb = csa->lb;
271.2292 +      double *ub = csa->ub;
271.2293 +      char *orig_type = csa->orig_type;
271.2294 +      double *orig_lb = csa->orig_lb;
271.2295 +      double *orig_ub = csa->orig_ub;
271.2296 +      int *head = csa->head;
271.2297 +      char *stat = csa->stat;
271.2298 +      double *cbar = csa->cbar;
271.2299 +      int j, k;
271.2300 +      memcpy(&type[1], &orig_type[1], (m+n) * sizeof(char));
271.2301 +      memcpy(&lb[1], &orig_lb[1], (m+n) * sizeof(double));
271.2302 +      memcpy(&ub[1], &orig_ub[1], (m+n) * sizeof(double));
271.2303 +      for (j = 1; j <= n; j++)
271.2304 +      {  k = head[m+j]; /* x[k] = xN[j] */
271.2305 +#ifdef GLP_DEBUG
271.2306 +         xassert(1 <= k && k <= m+n);
271.2307 +#endif
271.2308 +         switch (type[k])
271.2309 +         {  case GLP_FR:
271.2310 +               stat[j] = GLP_NF;
271.2311 +               break;
271.2312 +            case GLP_LO:
271.2313 +               stat[j] = GLP_NL;
271.2314 +               break;
271.2315 +            case GLP_UP:
271.2316 +               stat[j] = GLP_NU;
271.2317 +               break;
271.2318 +            case GLP_DB:
271.2319 +               if (cbar[j] >= +DBL_EPSILON)
271.2320 +                  stat[j] = GLP_NL;
271.2321 +               else if (cbar[j] <= -DBL_EPSILON)
271.2322 +                  stat[j] = GLP_NU;
271.2323 +               else if (fabs(lb[k]) <= fabs(ub[k]))
271.2324 +                  stat[j] = GLP_NL;
271.2325 +               else
271.2326 +                  stat[j] = GLP_NU;
271.2327 +               break;
271.2328 +            case GLP_FX:
271.2329 +               stat[j] = GLP_NS;
271.2330 +               break;
271.2331 +            default:
271.2332 +               xassert(type != type);
271.2333 +         }
271.2334 +      }
271.2335 +      return;
271.2336 +}
271.2337 +
271.2338 +/***********************************************************************
271.2339 +*  check_stab - check numerical stability of basic solution
271.2340 +*
271.2341 +*  If the current basic solution is dual feasible within a tolerance,
271.2342 +*  this routine returns zero, otherwise it returns non-zero. */
271.2343 +
271.2344 +static int check_stab(struct csa *csa, double tol_dj)
271.2345 +{     int n = csa->n;
271.2346 +      char *stat = csa->stat;
271.2347 +      double *cbar = csa->cbar;
271.2348 +      int j;
271.2349 +      for (j = 1; j <= n; j++)
271.2350 +      {  if (cbar[j] < - tol_dj)
271.2351 +            if (stat[j] == GLP_NL || stat[j] == GLP_NF) return 1;
271.2352 +         if (cbar[j] > + tol_dj)
271.2353 +            if (stat[j] == GLP_NU || stat[j] == GLP_NF) return 1;
271.2354 +      }
271.2355 +      return 0;
271.2356 +}
271.2357 +
271.2358 +#if 1 /* copied from primal */
271.2359 +/***********************************************************************
271.2360 +*  eval_obj - compute original objective function
271.2361 +*
271.2362 +*  This routine computes the current value of the original objective
271.2363 +*  function. */
271.2364 +
271.2365 +static double eval_obj(struct csa *csa)
271.2366 +{     int m = csa->m;
271.2367 +      int n = csa->n;
271.2368 +      double *obj = csa->obj;
271.2369 +      int *head = csa->head;
271.2370 +      double *bbar = csa->bbar;
271.2371 +      int i, j, k;
271.2372 +      double sum;
271.2373 +      sum = obj[0];
271.2374 +      /* walk through the list of basic variables */
271.2375 +      for (i = 1; i <= m; i++)
271.2376 +      {  k = head[i]; /* x[k] = xB[i] */
271.2377 +#ifdef GLP_DEBUG
271.2378 +         xassert(1 <= k && k <= m+n);
271.2379 +#endif
271.2380 +         if (k > m)
271.2381 +            sum += obj[k-m] * bbar[i];
271.2382 +      }
271.2383 +      /* walk through the list of non-basic variables */
271.2384 +      for (j = 1; j <= n; j++)
271.2385 +      {  k = head[m+j]; /* x[k] = xN[j] */
271.2386 +#ifdef GLP_DEBUG
271.2387 +         xassert(1 <= k && k <= m+n);
271.2388 +#endif
271.2389 +         if (k > m)
271.2390 +            sum += obj[k-m] * get_xN(csa, j);
271.2391 +      }
271.2392 +      return sum;
271.2393 +}
271.2394 +#endif
271.2395 +
271.2396 +/***********************************************************************
271.2397 +*  display - display the search progress
271.2398 +*
271.2399 +*  This routine displays some information about the search progress. */
271.2400 +
271.2401 +static void display(struct csa *csa, const glp_smcp *parm, int spec)
271.2402 +{     int m = csa->m;
271.2403 +      int n = csa->n;
271.2404 +      double *coef = csa->coef;
271.2405 +      char *orig_type = csa->orig_type;
271.2406 +      int *head = csa->head;
271.2407 +      char *stat = csa->stat;
271.2408 +      int phase = csa->phase;
271.2409 +      double *bbar = csa->bbar;
271.2410 +      double *cbar = csa->cbar;
271.2411 +      int i, j, cnt;
271.2412 +      double sum;
271.2413 +      if (parm->msg_lev < GLP_MSG_ON) goto skip;
271.2414 +      if (parm->out_dly > 0 &&
271.2415 +         1000.0 * xdifftime(xtime(), csa->tm_beg) < parm->out_dly)
271.2416 +         goto skip;
271.2417 +      if (csa->it_cnt == csa->it_dpy) goto skip;
271.2418 +      if (!spec && csa->it_cnt % parm->out_frq != 0) goto skip;
271.2419 +      /* compute the sum of dual infeasibilities */
271.2420 +      sum = 0.0;
271.2421 +      if (phase == 1)
271.2422 +      {  for (i = 1; i <= m; i++)
271.2423 +            sum -= coef[head[i]] * bbar[i];
271.2424 +         for (j = 1; j <= n; j++)
271.2425 +            sum -= coef[head[m+j]] * get_xN(csa, j);
271.2426 +      }
271.2427 +      else
271.2428 +      {  for (j = 1; j <= n; j++)
271.2429 +         {  if (cbar[j] < 0.0)
271.2430 +               if (stat[j] == GLP_NL || stat[j] == GLP_NF)
271.2431 +                  sum -= cbar[j];
271.2432 +            if (cbar[j] > 0.0)
271.2433 +               if (stat[j] == GLP_NU || stat[j] == GLP_NF)
271.2434 +                  sum += cbar[j];
271.2435 +         }
271.2436 +      }
271.2437 +      /* determine the number of basic fixed variables */
271.2438 +      cnt = 0;
271.2439 +      for (i = 1; i <= m; i++)
271.2440 +         if (orig_type[head[i]] == GLP_FX) cnt++;
271.2441 +      if (csa->phase == 1)
271.2442 +         xprintf(" %6d: %24s infeas = %10.3e (%d)\n",
271.2443 +            csa->it_cnt, "", sum, cnt);
271.2444 +      else
271.2445 +         xprintf("|%6d: obj = %17.9e  infeas = %10.3e (%d)\n",
271.2446 +            csa->it_cnt, eval_obj(csa), sum, cnt);
271.2447 +      csa->it_dpy = csa->it_cnt;
271.2448 +skip: return;
271.2449 +}
271.2450 +
271.2451 +#if 1 /* copied from primal */
271.2452 +/***********************************************************************
271.2453 +*  store_sol - store basic solution back to the problem object
271.2454 +*
271.2455 +*  This routine stores basic solution components back to the problem
271.2456 +*  object. */
271.2457 +
271.2458 +static void store_sol(struct csa *csa, glp_prob *lp, int p_stat,
271.2459 +      int d_stat, int ray)
271.2460 +{     int m = csa->m;
271.2461 +      int n = csa->n;
271.2462 +      double zeta = csa->zeta;
271.2463 +      int *head = csa->head;
271.2464 +      char *stat = csa->stat;
271.2465 +      double *bbar = csa->bbar;
271.2466 +      double *cbar = csa->cbar;
271.2467 +      int i, j, k;
271.2468 +#ifdef GLP_DEBUG
271.2469 +      xassert(lp->m == m);
271.2470 +      xassert(lp->n == n);
271.2471 +#endif
271.2472 +      /* basis factorization */
271.2473 +#ifdef GLP_DEBUG
271.2474 +      xassert(!lp->valid && lp->bfd == NULL);
271.2475 +      xassert(csa->valid && csa->bfd != NULL);
271.2476 +#endif
271.2477 +      lp->valid = 1, csa->valid = 0;
271.2478 +      lp->bfd = csa->bfd, csa->bfd = NULL;
271.2479 +      memcpy(&lp->head[1], &head[1], m * sizeof(int));
271.2480 +      /* basic solution status */
271.2481 +      lp->pbs_stat = p_stat;
271.2482 +      lp->dbs_stat = d_stat;
271.2483 +      /* objective function value */
271.2484 +      lp->obj_val = eval_obj(csa);
271.2485 +      /* simplex iteration count */
271.2486 +      lp->it_cnt = csa->it_cnt;
271.2487 +      /* unbounded ray */
271.2488 +      lp->some = ray;
271.2489 +      /* basic variables */
271.2490 +      for (i = 1; i <= m; i++)
271.2491 +      {  k = head[i]; /* x[k] = xB[i] */
271.2492 +#ifdef GLP_DEBUG
271.2493 +         xassert(1 <= k && k <= m+n);
271.2494 +#endif
271.2495 +         if (k <= m)
271.2496 +         {  GLPROW *row = lp->row[k];
271.2497 +            row->stat = GLP_BS;
271.2498 +            row->bind = i;
271.2499 +            row->prim = bbar[i] / row->rii;
271.2500 +            row->dual = 0.0;
271.2501 +         }
271.2502 +         else
271.2503 +         {  GLPCOL *col = lp->col[k-m];
271.2504 +            col->stat = GLP_BS;
271.2505 +            col->bind = i;
271.2506 +            col->prim = bbar[i] * col->sjj;
271.2507 +            col->dual = 0.0;
271.2508 +         }
271.2509 +      }
271.2510 +      /* non-basic variables */
271.2511 +      for (j = 1; j <= n; j++)
271.2512 +      {  k = head[m+j]; /* x[k] = xN[j] */
271.2513 +#ifdef GLP_DEBUG
271.2514 +         xassert(1 <= k && k <= m+n);
271.2515 +#endif
271.2516 +         if (k <= m)
271.2517 +         {  GLPROW *row = lp->row[k];
271.2518 +            row->stat = stat[j];
271.2519 +            row->bind = 0;
271.2520 +#if 0
271.2521 +            row->prim = get_xN(csa, j) / row->rii;
271.2522 +#else
271.2523 +            switch (stat[j])
271.2524 +            {  case GLP_NL:
271.2525 +                  row->prim = row->lb; break;
271.2526 +               case GLP_NU:
271.2527 +                  row->prim = row->ub; break;
271.2528 +               case GLP_NF:
271.2529 +                  row->prim = 0.0; break;
271.2530 +               case GLP_NS:
271.2531 +                  row->prim = row->lb; break;
271.2532 +               default:
271.2533 +                  xassert(stat != stat);
271.2534 +            }
271.2535 +#endif
271.2536 +            row->dual = (cbar[j] * row->rii) / zeta;
271.2537 +         }
271.2538 +         else
271.2539 +         {  GLPCOL *col = lp->col[k-m];
271.2540 +            col->stat = stat[j];
271.2541 +            col->bind = 0;
271.2542 +#if 0
271.2543 +            col->prim = get_xN(csa, j) * col->sjj;
271.2544 +#else
271.2545 +            switch (stat[j])
271.2546 +            {  case GLP_NL:
271.2547 +                  col->prim = col->lb; break;
271.2548 +               case GLP_NU:
271.2549 +                  col->prim = col->ub; break;
271.2550 +               case GLP_NF:
271.2551 +                  col->prim = 0.0; break;
271.2552 +               case GLP_NS:
271.2553 +                  col->prim = col->lb; break;
271.2554 +               default:
271.2555 +                  xassert(stat != stat);
271.2556 +            }
271.2557 +#endif
271.2558 +            col->dual = (cbar[j] / col->sjj) / zeta;
271.2559 +         }
271.2560 +      }
271.2561 +      return;
271.2562 +}
271.2563 +#endif
271.2564 +
271.2565 +/***********************************************************************
271.2566 +*  free_csa - deallocate common storage area
271.2567 +*
271.2568 +*  This routine frees all the memory allocated to arrays in the common
271.2569 +*  storage area (CSA). */
271.2570 +
271.2571 +static void free_csa(struct csa *csa)
271.2572 +{     xfree(csa->type);
271.2573 +      xfree(csa->lb);
271.2574 +      xfree(csa->ub);
271.2575 +      xfree(csa->coef);
271.2576 +      xfree(csa->orig_type);
271.2577 +      xfree(csa->orig_lb);
271.2578 +      xfree(csa->orig_ub);
271.2579 +      xfree(csa->obj);
271.2580 +      xfree(csa->A_ptr);
271.2581 +      xfree(csa->A_ind);
271.2582 +      xfree(csa->A_val);
271.2583 +#if 1 /* 06/IV-2009 */
271.2584 +      xfree(csa->AT_ptr);
271.2585 +      xfree(csa->AT_ind);
271.2586 +      xfree(csa->AT_val);
271.2587 +#endif
271.2588 +      xfree(csa->head);
271.2589 +#if 1 /* 06/IV-2009 */
271.2590 +      xfree(csa->bind);
271.2591 +#endif
271.2592 +      xfree(csa->stat);
271.2593 +#if 0 /* 06/IV-2009 */
271.2594 +      xfree(csa->N_ptr);
271.2595 +      xfree(csa->N_len);
271.2596 +      xfree(csa->N_ind);
271.2597 +      xfree(csa->N_val);
271.2598 +#endif
271.2599 +      xfree(csa->bbar);
271.2600 +      xfree(csa->cbar);
271.2601 +      xfree(csa->refsp);
271.2602 +      xfree(csa->gamma);
271.2603 +      xfree(csa->trow_ind);
271.2604 +      xfree(csa->trow_vec);
271.2605 +#ifdef GLP_LONG_STEP /* 07/IV-2009 */
271.2606 +      xfree(csa->bkpt);
271.2607 +#endif
271.2608 +      xfree(csa->tcol_ind);
271.2609 +      xfree(csa->tcol_vec);
271.2610 +      xfree(csa->work1);
271.2611 +      xfree(csa->work2);
271.2612 +      xfree(csa->work3);
271.2613 +      xfree(csa->work4);
271.2614 +      xfree(csa);
271.2615 +      return;
271.2616 +}
271.2617 +
271.2618 +/***********************************************************************
271.2619 +*  spx_dual - core LP solver based on the dual simplex method
271.2620 +*
271.2621 +*  SYNOPSIS
271.2622 +*
271.2623 +*  #include "glpspx.h"
271.2624 +*  int spx_dual(glp_prob *lp, const glp_smcp *parm);
271.2625 +*
271.2626 +*  DESCRIPTION
271.2627 +*
271.2628 +*  The routine spx_dual is a core LP solver based on the two-phase dual
271.2629 +*  simplex method.
271.2630 +*
271.2631 +*  RETURNS
271.2632 +*
271.2633 +*  0  LP instance has been successfully solved.
271.2634 +*
271.2635 +*  GLP_EOBJLL
271.2636 +*     Objective lower limit has been reached (maximization).
271.2637 +*
271.2638 +*  GLP_EOBJUL
271.2639 +*     Objective upper limit has been reached (minimization).
271.2640 +*
271.2641 +*  GLP_EITLIM
271.2642 +*     Iteration limit has been exhausted.
271.2643 +*
271.2644 +*  GLP_ETMLIM
271.2645 +*     Time limit has been exhausted.
271.2646 +*
271.2647 +*  GLP_EFAIL
271.2648 +*     The solver failed to solve LP instance. */
271.2649 +
271.2650 +int spx_dual(glp_prob *lp, const glp_smcp *parm)
271.2651 +{     struct csa *csa;
271.2652 +      int binv_st = 2;
271.2653 +      /* status of basis matrix factorization:
271.2654 +         0 - invalid; 1 - just computed; 2 - updated */
271.2655 +      int bbar_st = 0;
271.2656 +      /* status of primal values of basic variables:
271.2657 +         0 - invalid; 1 - just computed; 2 - updated */
271.2658 +      int cbar_st = 0;
271.2659 +      /* status of reduced costs of non-basic variables:
271.2660 +         0 - invalid; 1 - just computed; 2 - updated */
271.2661 +      int rigorous = 0;
271.2662 +      /* rigorous mode flag; this flag is used to enable iterative
271.2663 +         refinement on computing pivot rows and columns of the simplex
271.2664 +         table */
271.2665 +      int check = 0;
271.2666 +      int p_stat, d_stat, ret;
271.2667 +      /* allocate and initialize the common storage area */
271.2668 +      csa = alloc_csa(lp);
271.2669 +      init_csa(csa, lp);
271.2670 +      if (parm->msg_lev >= GLP_MSG_DBG)
271.2671 +         xprintf("Objective scale factor = %g\n", csa->zeta);
271.2672 +loop: /* main loop starts here */
271.2673 +      /* compute factorization of the basis matrix */
271.2674 +      if (binv_st == 0)
271.2675 +      {  ret = invert_B(csa);
271.2676 +         if (ret != 0)
271.2677 +         {  if (parm->msg_lev >= GLP_MSG_ERR)
271.2678 +            {  xprintf("Error: unable to factorize the basis matrix (%d"
271.2679 +                  ")\n", ret);
271.2680 +               xprintf("Sorry, basis recovery procedure not implemented"
271.2681 +                  " yet\n");
271.2682 +            }
271.2683 +            xassert(!lp->valid && lp->bfd == NULL);
271.2684 +            lp->bfd = csa->bfd, csa->bfd = NULL;
271.2685 +            lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
271.2686 +            lp->obj_val = 0.0;
271.2687 +            lp->it_cnt = csa->it_cnt;
271.2688 +            lp->some = 0;
271.2689 +            ret = GLP_EFAIL;
271.2690 +            goto done;
271.2691 +         }
271.2692 +         csa->valid = 1;
271.2693 +         binv_st = 1; /* just computed */
271.2694 +         /* invalidate basic solution components */
271.2695 +         bbar_st = cbar_st = 0;
271.2696 +      }
271.2697 +      /* compute reduced costs of non-basic variables */
271.2698 +      if (cbar_st == 0)
271.2699 +      {  eval_cbar(csa);
271.2700 +         cbar_st = 1; /* just computed */
271.2701 +         /* determine the search phase, if not determined yet */
271.2702 +         if (csa->phase == 0)
271.2703 +         {  if (check_feas(csa, 0.90 * parm->tol_dj) != 0)
271.2704 +            {  /* current basic solution is dual infeasible */
271.2705 +               /* start searching for dual feasible solution */
271.2706 +               csa->phase = 1;
271.2707 +               set_aux_bnds(csa);
271.2708 +            }
271.2709 +            else
271.2710 +            {  /* current basic solution is dual feasible */
271.2711 +               /* start searching for optimal solution */
271.2712 +               csa->phase = 2;
271.2713 +               set_orig_bnds(csa);
271.2714 +            }
271.2715 +            xassert(check_stab(csa, parm->tol_dj) == 0);
271.2716 +            /* some non-basic double-bounded variables might become
271.2717 +               fixed (on phase I) or vice versa (on phase II) */
271.2718 +#if 0 /* 06/IV-2009 */
271.2719 +            build_N(csa);
271.2720 +#endif
271.2721 +            csa->refct = 0;
271.2722 +            /* bounds of non-basic variables have been changed, so
271.2723 +               invalidate primal values */
271.2724 +            bbar_st = 0;
271.2725 +         }
271.2726 +         /* make sure that the current basic solution remains dual
271.2727 +            feasible */
271.2728 +         if (check_stab(csa, parm->tol_dj) != 0)
271.2729 +         {  if (parm->msg_lev >= GLP_MSG_ERR)
271.2730 +               xprintf("Warning: numerical instability (dual simplex, p"
271.2731 +                  "hase %s)\n", csa->phase == 1 ? "I" : "II");
271.2732 +#if 1
271.2733 +            if (parm->meth == GLP_DUALP)
271.2734 +            {  store_sol(csa, lp, GLP_UNDEF, GLP_UNDEF, 0);
271.2735 +               ret = GLP_EFAIL;
271.2736 +               goto done;
271.2737 +            }
271.2738 +#endif
271.2739 +            /* restart the search */
271.2740 +            csa->phase = 0;
271.2741 +            binv_st = 0;
271.2742 +            rigorous = 5;
271.2743 +            goto loop;
271.2744 +         }
271.2745 +      }
271.2746 +      xassert(csa->phase == 1 || csa->phase == 2);
271.2747 +      /* on phase I we do not need to wait until the current basic
271.2748 +         solution becomes primal feasible; it is sufficient to make
271.2749 +         sure that all reduced costs have correct signs */
271.2750 +      if (csa->phase == 1 && check_feas(csa, parm->tol_dj) == 0)
271.2751 +      {  /* the current basis is dual feasible; switch to phase II */
271.2752 +         display(csa, parm, 1);
271.2753 +         csa->phase = 2;
271.2754 +         if (cbar_st != 1)
271.2755 +         {  eval_cbar(csa);
271.2756 +            cbar_st = 1;
271.2757 +         }
271.2758 +         set_orig_bnds(csa);
271.2759 +#if 0 /* 06/IV-2009 */
271.2760 +         build_N(csa);
271.2761 +#endif
271.2762 +         csa->refct = 0;
271.2763 +         bbar_st = 0;
271.2764 +      }
271.2765 +      /* compute primal values of basic variables */
271.2766 +      if (bbar_st == 0)
271.2767 +      {  eval_bbar(csa);
271.2768 +         if (csa->phase == 2)
271.2769 +            csa->bbar[0] = eval_obj(csa);
271.2770 +         bbar_st = 1; /* just computed */
271.2771 +      }
271.2772 +      /* redefine the reference space, if required */
271.2773 +      switch (parm->pricing)
271.2774 +      {  case GLP_PT_STD:
271.2775 +            break;
271.2776 +         case GLP_PT_PSE:
271.2777 +            if (csa->refct == 0) reset_refsp(csa);
271.2778 +            break;
271.2779 +         default:
271.2780 +            xassert(parm != parm);
271.2781 +      }
271.2782 +      /* at this point the basis factorization and all basic solution
271.2783 +         components are valid */
271.2784 +      xassert(binv_st && bbar_st && cbar_st);
271.2785 +      /* check accuracy of current basic solution components (only for
271.2786 +         debugging) */
271.2787 +      if (check)
271.2788 +      {  double e_bbar = err_in_bbar(csa);
271.2789 +         double e_cbar = err_in_cbar(csa);
271.2790 +         double e_gamma =
271.2791 +            (parm->pricing == GLP_PT_PSE ? err_in_gamma(csa) : 0.0);
271.2792 +         xprintf("e_bbar = %10.3e; e_cbar = %10.3e; e_gamma = %10.3e\n",
271.2793 +            e_bbar, e_cbar, e_gamma);
271.2794 +         xassert(e_bbar <= 1e-5 && e_cbar <= 1e-5 && e_gamma <= 1e-3);
271.2795 +      }
271.2796 +      /* if the objective has to be maximized, check if it has reached
271.2797 +         its lower limit */
271.2798 +      if (csa->phase == 2 && csa->zeta < 0.0 &&
271.2799 +          parm->obj_ll > -DBL_MAX && csa->bbar[0] <= parm->obj_ll)
271.2800 +      {  if (bbar_st != 1 || cbar_st != 1)
271.2801 +         {  if (bbar_st != 1) bbar_st = 0;
271.2802 +            if (cbar_st != 1) cbar_st = 0;
271.2803 +            goto loop;
271.2804 +         }
271.2805 +         display(csa, parm, 1);
271.2806 +         if (parm->msg_lev >= GLP_MSG_ALL)
271.2807 +            xprintf("OBJECTIVE LOWER LIMIT REACHED; SEARCH TERMINATED\n"
271.2808 +               );
271.2809 +         store_sol(csa, lp, GLP_INFEAS, GLP_FEAS, 0);
271.2810 +         ret = GLP_EOBJLL;
271.2811 +         goto done;
271.2812 +      }
271.2813 +      /* if the objective has to be minimized, check if it has reached
271.2814 +         its upper limit */
271.2815 +      if (csa->phase == 2 && csa->zeta > 0.0 &&
271.2816 +          parm->obj_ul < +DBL_MAX && csa->bbar[0] >= parm->obj_ul)
271.2817 +      {  if (bbar_st != 1 || cbar_st != 1)
271.2818 +         {  if (bbar_st != 1) bbar_st = 0;
271.2819 +            if (cbar_st != 1) cbar_st = 0;
271.2820 +            goto loop;
271.2821 +         }
271.2822 +         display(csa, parm, 1);
271.2823 +         if (parm->msg_lev >= GLP_MSG_ALL)
271.2824 +            xprintf("OBJECTIVE UPPER LIMIT REACHED; SEARCH TERMINATED\n"
271.2825 +               );
271.2826 +         store_sol(csa, lp, GLP_INFEAS, GLP_FEAS, 0);
271.2827 +         ret = GLP_EOBJUL;
271.2828 +         goto done;
271.2829 +      }
271.2830 +      /* check if the iteration limit has been exhausted */
271.2831 +      if (parm->it_lim < INT_MAX &&
271.2832 +          csa->it_cnt - csa->it_beg >= parm->it_lim)
271.2833 +      {  if (csa->phase == 2 && bbar_st != 1 || cbar_st != 1)
271.2834 +         {  if (csa->phase == 2 && bbar_st != 1) bbar_st = 0;
271.2835 +            if (cbar_st != 1) cbar_st = 0;
271.2836 +            goto loop;
271.2837 +         }
271.2838 +         display(csa, parm, 1);
271.2839 +         if (parm->msg_lev >= GLP_MSG_ALL)
271.2840 +            xprintf("ITERATION LIMIT EXCEEDED; SEARCH TERMINATED\n");
271.2841 +         switch (csa->phase)
271.2842 +         {  case 1:
271.2843 +               d_stat = GLP_INFEAS;
271.2844 +               set_orig_bnds(csa);
271.2845 +               eval_bbar(csa);
271.2846 +               break;
271.2847 +            case 2:
271.2848 +               d_stat = GLP_FEAS;
271.2849 +               break;
271.2850 +            default:
271.2851 +               xassert(csa != csa);
271.2852 +         }
271.2853 +         store_sol(csa, lp, GLP_INFEAS, d_stat, 0);
271.2854 +         ret = GLP_EITLIM;
271.2855 +         goto done;
271.2856 +      }
271.2857 +      /* check if the time limit has been exhausted */
271.2858 +      if (parm->tm_lim < INT_MAX &&
271.2859 +          1000.0 * xdifftime(xtime(), csa->tm_beg) >= parm->tm_lim)
271.2860 +      {  if (csa->phase == 2 && bbar_st != 1 || cbar_st != 1)
271.2861 +         {  if (csa->phase == 2 && bbar_st != 1) bbar_st = 0;
271.2862 +            if (cbar_st != 1) cbar_st = 0;
271.2863 +            goto loop;
271.2864 +         }
271.2865 +         display(csa, parm, 1);
271.2866 +         if (parm->msg_lev >= GLP_MSG_ALL)
271.2867 +            xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
271.2868 +         switch (csa->phase)
271.2869 +         {  case 1:
271.2870 +               d_stat = GLP_INFEAS;
271.2871 +               set_orig_bnds(csa);
271.2872 +               eval_bbar(csa);
271.2873 +               break;
271.2874 +            case 2:
271.2875 +               d_stat = GLP_FEAS;
271.2876 +               break;
271.2877 +            default:
271.2878 +               xassert(csa != csa);
271.2879 +         }
271.2880 +         store_sol(csa, lp, GLP_INFEAS, d_stat, 0);
271.2881 +         ret = GLP_ETMLIM;
271.2882 +         goto done;
271.2883 +      }
271.2884 +      /* display the search progress */
271.2885 +      display(csa, parm, 0);
271.2886 +      /* choose basic variable xB[p] */
271.2887 +      chuzr(csa, parm->tol_bnd);
271.2888 +      if (csa->p == 0)
271.2889 +      {  if (bbar_st != 1 || cbar_st != 1)
271.2890 +         {  if (bbar_st != 1) bbar_st = 0;
271.2891 +            if (cbar_st != 1) cbar_st = 0;
271.2892 +            goto loop;
271.2893 +         }
271.2894 +         display(csa, parm, 1);
271.2895 +         switch (csa->phase)
271.2896 +         {  case 1:
271.2897 +               if (parm->msg_lev >= GLP_MSG_ALL)
271.2898 +                  xprintf("PROBLEM HAS NO DUAL FEASIBLE SOLUTION\n");
271.2899 +               set_orig_bnds(csa);
271.2900 +               eval_bbar(csa);
271.2901 +               p_stat = GLP_INFEAS, d_stat = GLP_NOFEAS;
271.2902 +               break;
271.2903 +            case 2:
271.2904 +               if (parm->msg_lev >= GLP_MSG_ALL)
271.2905 +                  xprintf("OPTIMAL SOLUTION FOUND\n");
271.2906 +               p_stat = d_stat = GLP_FEAS;
271.2907 +               break;
271.2908 +            default:
271.2909 +               xassert(csa != csa);
271.2910 +         }
271.2911 +         store_sol(csa, lp, p_stat, d_stat, 0);
271.2912 +         ret = 0;
271.2913 +         goto done;
271.2914 +      }
271.2915 +      /* compute pivot row of the simplex table */
271.2916 +      {  double *rho = csa->work4;
271.2917 +         eval_rho(csa, rho);
271.2918 +         if (rigorous) refine_rho(csa, rho);
271.2919 +         eval_trow(csa, rho);
271.2920 +         sort_trow(csa, parm->tol_bnd);
271.2921 +      }
271.2922 +      /* unlike primal simplex there is no need to check accuracy of
271.2923 +         the primal value of xB[p] (which might be computed using the
271.2924 +         pivot row), since bbar is a result of FTRAN */
271.2925 +#ifdef GLP_LONG_STEP /* 07/IV-2009 */
271.2926 +      long_step(csa);
271.2927 +      if (csa->nbps > 0)
271.2928 +      {  csa->q = csa->bkpt[csa->nbps].j;
271.2929 +         if (csa->delta > 0.0)
271.2930 +            csa->new_dq = + csa->bkpt[csa->nbps].t;
271.2931 +         else
271.2932 +            csa->new_dq = - csa->bkpt[csa->nbps].t;
271.2933 +      }
271.2934 +      else
271.2935 +#endif
271.2936 +      /* choose non-basic variable xN[q] */
271.2937 +      switch (parm->r_test)
271.2938 +      {  case GLP_RT_STD:
271.2939 +            chuzc(csa, 0.0);
271.2940 +            break;
271.2941 +         case GLP_RT_HAR:
271.2942 +            chuzc(csa, 0.30 * parm->tol_dj);
271.2943 +            break;
271.2944 +         default:
271.2945 +            xassert(parm != parm);
271.2946 +      }
271.2947 +      if (csa->q == 0)
271.2948 +      {  if (bbar_st != 1 || cbar_st != 1 || !rigorous)
271.2949 +         {  if (bbar_st != 1) bbar_st = 0;
271.2950 +            if (cbar_st != 1) cbar_st = 0;
271.2951 +            rigorous = 1;
271.2952 +            goto loop;
271.2953 +         }
271.2954 +         display(csa, parm, 1);
271.2955 +         switch (csa->phase)
271.2956 +         {  case 1:
271.2957 +               if (parm->msg_lev >= GLP_MSG_ERR)
271.2958 +                  xprintf("Error: unable to choose basic variable on ph"
271.2959 +                     "ase I\n");
271.2960 +               xassert(!lp->valid && lp->bfd == NULL);
271.2961 +               lp->bfd = csa->bfd, csa->bfd = NULL;
271.2962 +               lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
271.2963 +               lp->obj_val = 0.0;
271.2964 +               lp->it_cnt = csa->it_cnt;
271.2965 +               lp->some = 0;
271.2966 +               ret = GLP_EFAIL;
271.2967 +               break;
271.2968 +            case 2:
271.2969 +               if (parm->msg_lev >= GLP_MSG_ALL)
271.2970 +                  xprintf("PROBLEM HAS NO FEASIBLE SOLUTION\n");
271.2971 +               store_sol(csa, lp, GLP_NOFEAS, GLP_FEAS,
271.2972 +                  csa->head[csa->p]);
271.2973 +               ret = 0;
271.2974 +               break;
271.2975 +            default:
271.2976 +               xassert(csa != csa);
271.2977 +         }
271.2978 +         goto done;
271.2979 +      }
271.2980 +      /* check if the pivot element is acceptable */
271.2981 +      {  double piv = csa->trow_vec[csa->q];
271.2982 +         double eps = 1e-5 * (1.0 + 0.01 * csa->trow_max);
271.2983 +         if (fabs(piv) < eps)
271.2984 +         {  if (parm->msg_lev >= GLP_MSG_DBG)
271.2985 +               xprintf("piv = %.12g; eps = %g\n", piv, eps);
271.2986 +            if (!rigorous)
271.2987 +            {  rigorous = 5;
271.2988 +               goto loop;
271.2989 +            }
271.2990 +         }
271.2991 +      }
271.2992 +      /* now xN[q] and xB[p] have been chosen anyhow */
271.2993 +      /* compute pivot column of the simplex table */
271.2994 +      eval_tcol(csa);
271.2995 +      if (rigorous) refine_tcol(csa);
271.2996 +      /* accuracy check based on the pivot element */
271.2997 +      {  double piv1 = csa->tcol_vec[csa->p]; /* more accurate */
271.2998 +         double piv2 = csa->trow_vec[csa->q]; /* less accurate */
271.2999 +         xassert(piv1 != 0.0);
271.3000 +         if (fabs(piv1 - piv2) > 1e-8 * (1.0 + fabs(piv1)) ||
271.3001 +             !(piv1 > 0.0 && piv2 > 0.0 || piv1 < 0.0 && piv2 < 0.0))
271.3002 +         {  if (parm->msg_lev >= GLP_MSG_DBG)
271.3003 +               xprintf("piv1 = %.12g; piv2 = %.12g\n", piv1, piv2);
271.3004 +            if (binv_st != 1 || !rigorous)
271.3005 +            {  if (binv_st != 1) binv_st = 0;
271.3006 +               rigorous = 5;
271.3007 +               goto loop;
271.3008 +            }
271.3009 +            /* (not a good idea; should be revised later) */
271.3010 +            if (csa->tcol_vec[csa->p] == 0.0)
271.3011 +            {  csa->tcol_nnz++;
271.3012 +               xassert(csa->tcol_nnz <= csa->m);
271.3013 +               csa->tcol_ind[csa->tcol_nnz] = csa->p;
271.3014 +            }
271.3015 +            csa->tcol_vec[csa->p] = piv2;
271.3016 +         }
271.3017 +      }
271.3018 +      /* update primal values of basic variables */
271.3019 +#ifdef GLP_LONG_STEP /* 07/IV-2009 */
271.3020 +      if (csa->nbps > 0)
271.3021 +      {  int kk, j, k;
271.3022 +         for (kk = 1; kk < csa->nbps; kk++)
271.3023 +         {  if (csa->bkpt[kk].t >= csa->bkpt[csa->nbps].t) continue;
271.3024 +            j = csa->bkpt[kk].j;
271.3025 +            k = csa->head[csa->m + j];
271.3026 +            xassert(csa->type[k] == GLP_DB);
271.3027 +            if (csa->stat[j] == GLP_NL)
271.3028 +               csa->stat[j] = GLP_NU;
271.3029 +            else
271.3030 +               csa->stat[j] = GLP_NL;
271.3031 +         }
271.3032 +      }
271.3033 +      bbar_st = 0;
271.3034 +#else
271.3035 +      update_bbar(csa);
271.3036 +      if (csa->phase == 2)
271.3037 +         csa->bbar[0] += (csa->cbar[csa->q] / csa->zeta) *
271.3038 +            (csa->delta / csa->tcol_vec[csa->p]);
271.3039 +      bbar_st = 2; /* updated */
271.3040 +#endif
271.3041 +      /* update reduced costs of non-basic variables */
271.3042 +      update_cbar(csa);
271.3043 +      cbar_st = 2; /* updated */
271.3044 +      /* update steepest edge coefficients */
271.3045 +      switch (parm->pricing)
271.3046 +      {  case GLP_PT_STD:
271.3047 +            break;
271.3048 +         case GLP_PT_PSE:
271.3049 +            if (csa->refct > 0) update_gamma(csa);
271.3050 +            break;
271.3051 +         default:
271.3052 +            xassert(parm != parm);
271.3053 +      }
271.3054 +      /* update factorization of the basis matrix */
271.3055 +      ret = update_B(csa, csa->p, csa->head[csa->m+csa->q]);
271.3056 +      if (ret == 0)
271.3057 +         binv_st = 2; /* updated */
271.3058 +      else
271.3059 +      {  csa->valid = 0;
271.3060 +         binv_st = 0; /* invalid */
271.3061 +      }
271.3062 +#if 0 /* 06/IV-2009 */
271.3063 +      /* update matrix N */
271.3064 +      del_N_col(csa, csa->q, csa->head[csa->m+csa->q]);
271.3065 +      if (csa->type[csa->head[csa->p]] != GLP_FX)
271.3066 +         add_N_col(csa, csa->q, csa->head[csa->p]);
271.3067 +#endif
271.3068 +      /* change the basis header */
271.3069 +      change_basis(csa);
271.3070 +      /* iteration complete */
271.3071 +      csa->it_cnt++;
271.3072 +      if (rigorous > 0) rigorous--;
271.3073 +      goto loop;
271.3074 +done: /* deallocate the common storage area */
271.3075 +      free_csa(csa);
271.3076 +      /* return to the calling program */
271.3077 +      return ret;
271.3078 +}
271.3079 +
271.3080 +/* eof */
   272.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   272.2 +++ b/src/glpsql.c	Mon Dec 06 13:09:21 2010 +0100
   272.3 @@ -0,0 +1,1627 @@
   272.4 +/* glpsql.c */
   272.5 +
   272.6 +/***********************************************************************
   272.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   272.8 +*
   272.9 +*  Author: Heinrich Schuchardt <xypron.glpk@gmx.de>.
  272.10 +*
  272.11 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  272.12 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  272.13 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  272.14 +*  E-mail: <mao@gnu.org>.
  272.15 +*
  272.16 +*  GLPK is free software: you can redistribute it and/or modify it
  272.17 +*  under the terms of the GNU General Public License as published by
  272.18 +*  the Free Software Foundation, either version 3 of the License, or
  272.19 +*  (at your option) any later version.
  272.20 +*
  272.21 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  272.22 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  272.23 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  272.24 +*  License for more details.
  272.25 +*
  272.26 +*  You should have received a copy of the GNU General Public License
  272.27 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  272.28 +***********************************************************************/
  272.29 +
  272.30 +#ifdef HAVE_CONFIG_H
  272.31 +#include <config.h>
  272.32 +#endif
  272.33 +
  272.34 +#include "glpmpl.h"
  272.35 +#include "glpsql.h"
  272.36 +
  272.37 +#ifdef ODBC_DLNAME
  272.38 +#define HAVE_ODBC
  272.39 +#define libodbc ODBC_DLNAME
  272.40 +#define h_odbc (get_env_ptr()->h_odbc)
  272.41 +#endif
  272.42 +
  272.43 +#ifdef MYSQL_DLNAME
  272.44 +#define HAVE_MYSQL
  272.45 +#define libmysql MYSQL_DLNAME
  272.46 +#define h_mysql (get_env_ptr()->h_mysql)
  272.47 +#endif
  272.48 +
  272.49 +static void *db_iodbc_open_int(TABDCA *dca, int mode, const char
  272.50 +      **sqllines);
  272.51 +static void *db_mysql_open_int(TABDCA *dca, int mode, const char
  272.52 +      **sqllines);
  272.53 +
  272.54 +/**********************************************************************/
  272.55 +
  272.56 +#if defined(HAVE_ODBC) || defined(HAVE_MYSQL)
  272.57 +
  272.58 +#define SQL_FIELD_MAX 100
  272.59 +/* maximal field count */
  272.60 +
  272.61 +#define SQL_FDLEN_MAX 255
  272.62 +/* maximal field length */
  272.63 +
  272.64 +/***********************************************************************
  272.65 +*  NAME
  272.66 +*
  272.67 +*  args_concat - concatenate arguments
  272.68 +*
  272.69 +*  SYNOPSIS
  272.70 +*
  272.71 +*  static char **args_concat(TABDCA *dca);
  272.72 +*
  272.73 +*  DESCRIPTION
  272.74 +*
  272.75 +*  The arguments passed in dca are SQL statements. A SQL statement may
  272.76 +*  be split over multiple arguments. The last argument of a SQL
  272.77 +*  statement will be terminated with a semilocon. Each SQL statement is
  272.78 +*  merged into a single zero terminated string. Boundaries between
  272.79 +*  arguments are replaced by space.
  272.80 +*
  272.81 +*  RETURNS
  272.82 +*
  272.83 +*  Buffer with SQL statements */
  272.84 +
  272.85 +static char **args_concat(TABDCA *dca)
  272.86 +{
  272.87 +   const char  *arg;
  272.88 +   int          i;
  272.89 +   int          j;
  272.90 +   int          j0;
  272.91 +   int          j1;
  272.92 +   int          len;
  272.93 +   int          lentot;
  272.94 +   int          narg;
  272.95 +   int          nline = 0;
  272.96 +   void        *ret;
  272.97 +   char       **sqllines = NULL;
  272.98 +
  272.99 +   narg = mpl_tab_num_args(dca);
 272.100 +   /* The SQL statements start with argument 3. */
 272.101 +   if (narg < 3)
 272.102 +      return NULL;
 272.103 +   /* Count the SQL statements */
 272.104 +   for (j = 3; j <= narg; j++)
 272.105 +   {
 272.106 +      arg = mpl_tab_get_arg(dca, j);
 272.107 +      len = strlen(arg);
 272.108 +      if (arg[len-1] == ';' || j == narg)
 272.109 +        nline ++;
 272.110 +   }
 272.111 +   /* Allocate string buffer. */
 272.112 +   sqllines = (char **) xmalloc((nline+1) * sizeof(char **));
 272.113 +   /* Join arguments */
 272.114 +   sqllines[0] = NULL;
 272.115 +   j0     = 3;
 272.116 +   i      = 0;
 272.117 +   lentot = 0;
 272.118 +   for (j = 3; j <= narg; j++)
 272.119 +   {
 272.120 +      arg = mpl_tab_get_arg(dca, j);
 272.121 +      len = strlen(arg);
 272.122 +      lentot += len;
 272.123 +      if (arg[len-1] == ';' || j == narg)
 272.124 +      {  /* Join arguments for a single SQL statement */
 272.125 +         sqllines[i] = xmalloc(lentot+1);
 272.126 +         sqllines[i+1] = NULL;
 272.127 +         sqllines[i][0] = 0x00;
 272.128 +         for (j1 = j0; j1 <= j; j1++)
 272.129 +         {  if(j1>j0)
 272.130 +               strcat(sqllines[i], " ");
 272.131 +            strcat(sqllines[i], mpl_tab_get_arg(dca, j1));
 272.132 +         }
 272.133 +         len = strlen(sqllines[i]);
 272.134 +         if (sqllines[i][len-1] == ';')
 272.135 +            sqllines[i][len-1] = 0x00;
 272.136 +         j0 = j+1;
 272.137 +         i++;
 272.138 +         lentot = 0;
 272.139 +      }
 272.140 +   }
 272.141 +   return sqllines;
 272.142 +}
 272.143 +
 272.144 +/***********************************************************************
 272.145 +*  NAME
 272.146 +*
 272.147 +*  free_buffer - free multiline string buffer
 272.148 +*
 272.149 +*  SYNOPSIS
 272.150 +*
 272.151 +*  static void free_buffer(char **buf);
 272.152 +*
 272.153 +*  DESCRIPTION
 272.154 +*
 272.155 +*  buf is a list of strings terminated by NULL.
 272.156 +*  The memory for the strings and for the list is released. */
 272.157 +
 272.158 +static void free_buffer(char **buf)
 272.159 +{  int i;
 272.160 +
 272.161 +   for(i = 0; buf[i] != NULL; i++)
 272.162 +      xfree(buf[i]);
 272.163 +   xfree(buf);
 272.164 +}
 272.165 +
 272.166 +static int db_escaped_string_length(const char* from)
 272.167 +/* length of escaped string */
 272.168 +{
 272.169 +   int         count;
 272.170 +   const char *pointer;
 272.171 +
 272.172 +    for (pointer = from, count = 0; *pointer != (char) '\0'; pointer++,
 272.173 +         count++)
 272.174 +    {
 272.175 +      switch (*pointer)
 272.176 +      {
 272.177 +         case '\'':
 272.178 +            count++;
 272.179 +            break;
 272.180 +      }
 272.181 +    }
 272.182 +
 272.183 +    return count;
 272.184 +}
 272.185 +
 272.186 +static int db_escape_string (char *to, const char *from)
 272.187 +/* escape string*/
 272.188 +{
 272.189 +   const char *source = from;
 272.190 +   char *target = to;
 272.191 +   unsigned int remaining;
 272.192 +
 272.193 +   remaining = strlen(from);
 272.194 +
 272.195 +   if (to == NULL)
 272.196 +     to = (char *) (from + remaining);
 272.197 +
 272.198 +   while (remaining > 0)
 272.199 +   {
 272.200 +      switch (*source)
 272.201 +      {
 272.202 +         case '\'':
 272.203 +            *target = '\'';
 272.204 +            target++;
 272.205 +            *target = '\'';
 272.206 +            break;
 272.207 +
 272.208 +         default:
 272.209 +            *target = *source;
 272.210 +            }
 272.211 +      source++;
 272.212 +      target++;
 272.213 +      remaining--;
 272.214 +      }
 272.215 +
 272.216 +   /* Write the terminating NUL character. */
 272.217 +   *target = '\0';
 272.218 +
 272.219 +   return target - to;
 272.220 +}
 272.221 +
 272.222 +static char *db_generate_select_stmt(TABDCA *dca)
 272.223 +/* generate select statement */
 272.224 +{
 272.225 +   char        *arg;
 272.226 +   char const  *field;
 272.227 +   char        *query;
 272.228 +   int          j;
 272.229 +   int          narg;
 272.230 +   int          nf;
 272.231 +   int          total;
 272.232 +
 272.233 +   total = 50;
 272.234 +   nf = mpl_tab_num_flds(dca);
 272.235 +   narg = mpl_tab_num_args(dca);
 272.236 +   for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
 272.237 +   {
 272.238 +      field = mpl_tab_get_name(dca, j);
 272.239 +      total += strlen(field);
 272.240 +      total += 2;
 272.241 +   }
 272.242 +   arg = (char *) mpl_tab_get_arg(dca, narg);
 272.243 +   total += strlen(arg);
 272.244 +   query = xmalloc( total * sizeof(char));
 272.245 +   strcpy (query, "SELECT ");
 272.246 +   for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
 272.247 +   {
 272.248 +      field = mpl_tab_get_name(dca, j);
 272.249 +      strcat(query, field);
 272.250 +      if ( j < nf )
 272.251 +         strcat(query, ", ");
 272.252 +   }
 272.253 +   strcat(query, " FROM ");
 272.254 +   strcat(query, arg);
 272.255 +   return query;
 272.256 +}
 272.257 +
 272.258 +static char *db_generate_insert_stmt(TABDCA *dca)
 272.259 +/* generate insert statement */
 272.260 +{
 272.261 +   char        *arg;
 272.262 +   char const  *field;
 272.263 +   char        *query;
 272.264 +   int          j;
 272.265 +   int          narg;
 272.266 +   int          nf;
 272.267 +   int          total;
 272.268 +
 272.269 +   total = 50;
 272.270 +   nf = mpl_tab_num_flds(dca);
 272.271 +   narg = mpl_tab_num_args(dca);
 272.272 +   for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
 272.273 +   {
 272.274 +      field = mpl_tab_get_name(dca, j);
 272.275 +      total += strlen(field);
 272.276 +      total += 5;
 272.277 +   }
 272.278 +   arg = (char *) mpl_tab_get_arg(dca, narg);
 272.279 +   total += strlen(arg);
 272.280 +   query = xmalloc( (total+1) * sizeof(char));
 272.281 +   strcpy (query, "INSERT INTO ");
 272.282 +   strcat(query, arg);
 272.283 +   strcat(query, " ( ");
 272.284 +   for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
 272.285 +   {
 272.286 +      field = mpl_tab_get_name(dca, j);
 272.287 +      strcat(query, field);
 272.288 +      if ( j < nf )
 272.289 +         strcat(query, ", ");
 272.290 +   }
 272.291 +   strcat(query, " ) VALUES ( ");
 272.292 +   for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
 272.293 +   {
 272.294 +      strcat(query, "?");
 272.295 +      if ( j < nf )
 272.296 +         strcat(query, ", ");
 272.297 +   }
 272.298 +   strcat(query, " )");
 272.299 +   return query;
 272.300 +}
 272.301 +
 272.302 +#endif
 272.303 +
 272.304 +/**********************************************************************/
 272.305 +
 272.306 +#ifndef HAVE_ODBC
 272.307 +
 272.308 +void *db_iodbc_open(TABDCA *dca, int mode)
 272.309 +{     xassert(dca == dca);
 272.310 +      xassert(mode == mode);
 272.311 +      xprintf("iODBC table driver not supported\n");
 272.312 +      return NULL;
 272.313 +}
 272.314 +
 272.315 +int db_iodbc_read(TABDCA *dca, void *link)
 272.316 +{     xassert(dca != dca);
 272.317 +      xassert(link != link);
 272.318 +      return 0;
 272.319 +}
 272.320 +
 272.321 +int db_iodbc_write(TABDCA *dca, void *link)
 272.322 +{     xassert(dca != dca);
 272.323 +      xassert(link != link);
 272.324 +      return 0;
 272.325 +}
 272.326 +
 272.327 +int db_iodbc_close(TABDCA *dca, void *link)
 272.328 +{     xassert(dca != dca);
 272.329 +      xassert(link != link);
 272.330 +      return 0;
 272.331 +}
 272.332 +
 272.333 +#else
 272.334 +
 272.335 +#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__WOE__)
 272.336 +#include <windows.h>
 272.337 +#endif
 272.338 +
 272.339 +#include <sql.h>
 272.340 +#include <sqlext.h>
 272.341 +
 272.342 +struct db_odbc
 272.343 +{
 272.344 +   int              mode;         /*'R' = Read, 'W' = Write*/
 272.345 +   SQLHDBC          hdbc;         /*connection handle*/
 272.346 +   SQLHENV          henv;         /*environment handle*/
 272.347 +   SQLHSTMT         hstmt;        /*statement handle*/
 272.348 +   SQLSMALLINT      nresultcols;  /* columns in result*/
 272.349 +   SQLULEN          collen[SQL_FIELD_MAX+1];
 272.350 +   SQLLEN           outlen[SQL_FIELD_MAX+1];
 272.351 +   SQLSMALLINT      coltype[SQL_FIELD_MAX+1];
 272.352 +   SQLCHAR          data[SQL_FIELD_MAX+1][SQL_FDLEN_MAX+1];
 272.353 +   SQLCHAR          colname[SQL_FIELD_MAX+1][SQL_FDLEN_MAX+1];
 272.354 +   int              isnumeric[SQL_FIELD_MAX+1];
 272.355 +   int              nf;
 272.356 +   /* number of fields in the csv file */
 272.357 +   int              ref[1+SQL_FIELD_MAX];
 272.358 +   /* ref[k] = k', if k-th field of the csv file corresponds to
 272.359 +      k'-th field in the table statement; if ref[k] = 0, k-th field
 272.360 +      of the csv file is ignored */
 272.361 +   SQLCHAR         *query;
 272.362 +   /* query generated by db_iodbc_open */
 272.363 +};
 272.364 +
 272.365 +SQLRETURN SQL_API dl_SQLAllocHandle (
 272.366 +   SQLSMALLINT           HandleType,
 272.367 +   SQLHANDLE             InputHandle,
 272.368 +   SQLHANDLE            *OutputHandle)
 272.369 +{
 272.370 +      typedef SQLRETURN SQL_API ep_SQLAllocHandle(
 272.371 +         SQLSMALLINT           HandleType,
 272.372 +         SQLHANDLE             InputHandle,
 272.373 +         SQLHANDLE            *OutputHandle);
 272.374 +
 272.375 +      ep_SQLAllocHandle *fn;
 272.376 +      fn = (ep_SQLAllocHandle *) xdlsym(h_odbc, "SQLAllocHandle");
 272.377 +      xassert(fn != NULL);
 272.378 +      return (*fn)(HandleType, InputHandle, OutputHandle);
 272.379 +}
 272.380 +
 272.381 +SQLRETURN SQL_API dl_SQLBindCol (
 272.382 +   SQLHSTMT              StatementHandle,
 272.383 +   SQLUSMALLINT          ColumnNumber,
 272.384 +   SQLSMALLINT           TargetType,
 272.385 +   SQLPOINTER            TargetValue,
 272.386 +   SQLLEN                BufferLength,
 272.387 +   SQLLEN               *StrLen_or_Ind)
 272.388 +{
 272.389 +      typedef SQLRETURN SQL_API ep_SQLBindCol(
 272.390 +         SQLHSTMT              StatementHandle,
 272.391 +         SQLUSMALLINT          ColumnNumber,
 272.392 +         SQLSMALLINT           TargetType,
 272.393 +         SQLPOINTER            TargetValue,
 272.394 +         SQLLEN                BufferLength,
 272.395 +         SQLLEN               *StrLen_or_Ind);
 272.396 +      ep_SQLBindCol *fn;
 272.397 +      fn = (ep_SQLBindCol *) xdlsym(h_odbc, "SQLBindCol");
 272.398 +      xassert(fn != NULL);
 272.399 +      return (*fn)(StatementHandle, ColumnNumber, TargetType,
 272.400 +         TargetValue, BufferLength, StrLen_or_Ind);
 272.401 +}
 272.402 +
 272.403 +SQLRETURN SQL_API dl_SQLCloseCursor (
 272.404 +   SQLHSTMT              StatementHandle)
 272.405 +{
 272.406 +      typedef SQLRETURN SQL_API ep_SQLCloseCursor (
 272.407 +         SQLHSTMT              StatementHandle);
 272.408 +
 272.409 +      ep_SQLCloseCursor *fn;
 272.410 +      fn = (ep_SQLCloseCursor *) xdlsym(h_odbc, "SQLCloseCursor");
 272.411 +      xassert(fn != NULL);
 272.412 +      return (*fn)(StatementHandle);
 272.413 +}
 272.414 +
 272.415 +
 272.416 +SQLRETURN SQL_API dl_SQLDisconnect (
 272.417 +   SQLHDBC               ConnectionHandle)
 272.418 +{
 272.419 +      typedef SQLRETURN SQL_API ep_SQLDisconnect(
 272.420 +         SQLHDBC               ConnectionHandle);
 272.421 +
 272.422 +      ep_SQLDisconnect *fn;
 272.423 +      fn = (ep_SQLDisconnect *) xdlsym(h_odbc, "SQLDisconnect");
 272.424 +      xassert(fn != NULL);
 272.425 +      return (*fn)(ConnectionHandle);
 272.426 +}
 272.427 +
 272.428 +SQLRETURN SQL_API dl_SQLDriverConnect (
 272.429 +   SQLHDBC               hdbc,
 272.430 +   SQLHWND               hwnd,
 272.431 +   SQLCHAR              *szConnStrIn,
 272.432 +   SQLSMALLINT           cbConnStrIn,
 272.433 +   SQLCHAR              *szConnStrOut,
 272.434 +   SQLSMALLINT           cbConnStrOutMax,
 272.435 +   SQLSMALLINT          *pcbConnStrOut,
 272.436 +   SQLUSMALLINT          fDriverCompletion)
 272.437 +{
 272.438 +      typedef SQLRETURN SQL_API ep_SQLDriverConnect(
 272.439 +         SQLHDBC               hdbc,
 272.440 +         SQLHWND               hwnd,
 272.441 +         SQLCHAR             * szConnStrIn,
 272.442 +         SQLSMALLINT           cbConnStrIn,
 272.443 +         SQLCHAR             * szConnStrOut,
 272.444 +         SQLSMALLINT           cbConnStrOutMax,
 272.445 +         SQLSMALLINT         * pcbConnStrOut,
 272.446 +         SQLUSMALLINT          fDriverCompletion);
 272.447 +
 272.448 +      ep_SQLDriverConnect *fn;
 272.449 +      fn = (ep_SQLDriverConnect *) xdlsym(h_odbc, "SQLDriverConnect");
 272.450 +      xassert(fn != NULL);
 272.451 +      return (*fn)(hdbc, hwnd, szConnStrIn, cbConnStrIn, szConnStrOut,
 272.452 +         cbConnStrOutMax, pcbConnStrOut, fDriverCompletion);
 272.453 +}
 272.454 +
 272.455 +SQLRETURN SQL_API dl_SQLEndTran (
 272.456 +   SQLSMALLINT           HandleType,
 272.457 +   SQLHANDLE             Handle,
 272.458 +   SQLSMALLINT           CompletionType)
 272.459 +{
 272.460 +      typedef SQLRETURN SQL_API ep_SQLEndTran (
 272.461 +         SQLSMALLINT           HandleType,
 272.462 +         SQLHANDLE             Handle,
 272.463 +         SQLSMALLINT           CompletionType);
 272.464 +
 272.465 +      ep_SQLEndTran *fn;
 272.466 +      fn = (ep_SQLEndTran *) xdlsym(h_odbc, "SQLEndTran");
 272.467 +      xassert(fn != NULL);
 272.468 +      return (*fn)(HandleType, Handle, CompletionType);
 272.469 +}
 272.470 +
 272.471 +SQLRETURN SQL_API dl_SQLExecDirect (
 272.472 +   SQLHSTMT              StatementHandle,
 272.473 +   SQLCHAR             * StatementText,
 272.474 +   SQLINTEGER            TextLength)
 272.475 +{
 272.476 +      typedef SQLRETURN SQL_API ep_SQLExecDirect (
 272.477 +         SQLHSTMT              StatementHandle,
 272.478 +         SQLCHAR             * StatementText,
 272.479 +         SQLINTEGER            TextLength);
 272.480 +
 272.481 +      ep_SQLExecDirect *fn;
 272.482 +      fn = (ep_SQLExecDirect *) xdlsym(h_odbc, "SQLExecDirect");
 272.483 +      xassert(fn != NULL);
 272.484 +      return (*fn)(StatementHandle, StatementText, TextLength);
 272.485 +}
 272.486 +
 272.487 +SQLRETURN SQL_API dl_SQLFetch (
 272.488 +   SQLHSTMT              StatementHandle)
 272.489 +{
 272.490 +      typedef SQLRETURN SQL_API ep_SQLFetch (
 272.491 +         SQLHSTMT              StatementHandle);
 272.492 +
 272.493 +      ep_SQLFetch *fn;
 272.494 +      fn = (ep_SQLFetch*) xdlsym(h_odbc, "SQLFetch");
 272.495 +      xassert(fn != NULL);
 272.496 +      return (*fn)(StatementHandle);
 272.497 +}
 272.498 +
 272.499 +SQLRETURN SQL_API dl_SQLFreeHandle (
 272.500 +   SQLSMALLINT           HandleType,
 272.501 +   SQLHANDLE             Handle)
 272.502 +{
 272.503 +      typedef SQLRETURN SQL_API ep_SQLFreeHandle (
 272.504 +         SQLSMALLINT           HandleType,
 272.505 +         SQLHANDLE             Handle);
 272.506 +
 272.507 +      ep_SQLFreeHandle *fn;
 272.508 +      fn = (ep_SQLFreeHandle *) xdlsym(h_odbc, "SQLFreeHandle");
 272.509 +      xassert(fn != NULL);
 272.510 +      return (*fn)(HandleType, Handle);
 272.511 +}
 272.512 +
 272.513 +SQLRETURN SQL_API dl_SQLDescribeCol (
 272.514 +   SQLHSTMT              StatementHandle,
 272.515 +   SQLUSMALLINT          ColumnNumber,
 272.516 +   SQLCHAR             * ColumnName,
 272.517 +   SQLSMALLINT           BufferLength,
 272.518 +   SQLSMALLINT         * NameLength,
 272.519 +   SQLSMALLINT         * DataType,
 272.520 +   SQLULEN             * ColumnSize,
 272.521 +   SQLSMALLINT         * DecimalDigits,
 272.522 +   SQLSMALLINT         * Nullable)
 272.523 +{
 272.524 +      typedef SQLRETURN SQL_API ep_SQLDescribeCol (
 272.525 +         SQLHSTMT              StatementHandle,
 272.526 +         SQLUSMALLINT          ColumnNumber,
 272.527 +         SQLCHAR              *ColumnName,
 272.528 +         SQLSMALLINT           BufferLength,
 272.529 +         SQLSMALLINT          *NameLength,
 272.530 +         SQLSMALLINT          *DataType,
 272.531 +         SQLULEN              *ColumnSize,
 272.532 +         SQLSMALLINT          *DecimalDigits,
 272.533 +         SQLSMALLINT          *Nullable);
 272.534 +
 272.535 +      ep_SQLDescribeCol *fn;
 272.536 +      fn = (ep_SQLDescribeCol *) xdlsym(h_odbc, "SQLDescribeCol");
 272.537 +      xassert(fn != NULL);
 272.538 +      return (*fn)(StatementHandle, ColumnNumber, ColumnName,
 272.539 +         BufferLength, NameLength,
 272.540 +         DataType, ColumnSize, DecimalDigits, Nullable);
 272.541 +}
 272.542 +
 272.543 +SQLRETURN SQL_API dl_SQLGetDiagRec (
 272.544 +   SQLSMALLINT           HandleType,
 272.545 +   SQLHANDLE             Handle,
 272.546 +   SQLSMALLINT           RecNumber,
 272.547 +   SQLCHAR              *Sqlstate,
 272.548 +   SQLINTEGER           *NativeError,
 272.549 +   SQLCHAR              *MessageText,
 272.550 +   SQLSMALLINT           BufferLength,
 272.551 +   SQLSMALLINT          *TextLength)
 272.552 +{
 272.553 +      typedef SQLRETURN SQL_API ep_SQLGetDiagRec (
 272.554 +         SQLSMALLINT           HandleType,
 272.555 +         SQLHANDLE             Handle,
 272.556 +         SQLSMALLINT           RecNumber,
 272.557 +         SQLCHAR              *Sqlstate,
 272.558 +         SQLINTEGER           *NativeError,
 272.559 +         SQLCHAR              *MessageText,
 272.560 +         SQLSMALLINT           BufferLength,
 272.561 +         SQLSMALLINT          *TextLength);
 272.562 +
 272.563 +      ep_SQLGetDiagRec *fn;
 272.564 +      fn = (ep_SQLGetDiagRec *) xdlsym(h_odbc, "SQLGetDiagRec");
 272.565 +      xassert(fn != NULL);
 272.566 +      return (*fn)(HandleType, Handle, RecNumber, Sqlstate,
 272.567 +         NativeError, MessageText, BufferLength, TextLength);
 272.568 +}
 272.569 +
 272.570 +SQLRETURN SQL_API dl_SQLGetInfo (
 272.571 +   SQLHDBC               ConnectionHandle,
 272.572 +   SQLUSMALLINT          InfoType,
 272.573 +   SQLPOINTER            InfoValue,
 272.574 +   SQLSMALLINT           BufferLength,
 272.575 +   SQLSMALLINT          *StringLength)
 272.576 +{
 272.577 +      typedef SQLRETURN SQL_API ep_SQLGetInfo (
 272.578 +         SQLHDBC               ConnectionHandle,
 272.579 +         SQLUSMALLINT          InfoType,
 272.580 +         SQLPOINTER            InfoValue,
 272.581 +         SQLSMALLINT           BufferLength,
 272.582 +         SQLSMALLINT          *StringLength);
 272.583 +
 272.584 +      ep_SQLGetInfo *fn;
 272.585 +      fn = (ep_SQLGetInfo *) xdlsym(h_odbc, "SQLGetInfo");
 272.586 +      xassert(fn != NULL);
 272.587 +      return (*fn)(ConnectionHandle, InfoType, InfoValue, BufferLength,
 272.588 +         StringLength);
 272.589 +}
 272.590 +
 272.591 +SQLRETURN SQL_API dl_SQLNumResultCols (
 272.592 +   SQLHSTMT              StatementHandle,
 272.593 +   SQLSMALLINT          *ColumnCount)
 272.594 +{
 272.595 +      typedef SQLRETURN SQL_API ep_SQLNumResultCols (
 272.596 +         SQLHSTMT              StatementHandle,
 272.597 +         SQLSMALLINT          *ColumnCount);
 272.598 +
 272.599 +      ep_SQLNumResultCols *fn;
 272.600 +      fn = (ep_SQLNumResultCols *) xdlsym(h_odbc, "SQLNumResultCols");
 272.601 +      xassert(fn != NULL);
 272.602 +      return (*fn)(StatementHandle, ColumnCount);
 272.603 +}
 272.604 +
 272.605 +SQLRETURN SQL_API dl_SQLSetConnectAttr (
 272.606 +   SQLHDBC               ConnectionHandle,
 272.607 +   SQLINTEGER            Attribute,
 272.608 +   SQLPOINTER            Value,
 272.609 +   SQLINTEGER            StringLength)
 272.610 +{
 272.611 +      typedef SQLRETURN SQL_API ep_SQLSetConnectAttr (
 272.612 +         SQLHDBC               ConnectionHandle,
 272.613 +         SQLINTEGER            Attribute,
 272.614 +         SQLPOINTER            Value,
 272.615 +         SQLINTEGER            StringLength);
 272.616 +
 272.617 +      ep_SQLSetConnectAttr *fn;
 272.618 +     fn = (ep_SQLSetConnectAttr *) xdlsym(h_odbc, "SQLSetConnectAttr");
 272.619 +      xassert(fn != NULL);
 272.620 +      return (*fn)(ConnectionHandle, Attribute, Value, StringLength);
 272.621 +}
 272.622 +
 272.623 +SQLRETURN SQL_API dl_SQLSetEnvAttr (
 272.624 +   SQLHENV               EnvironmentHandle,
 272.625 +   SQLINTEGER            Attribute,
 272.626 +   SQLPOINTER            Value,
 272.627 +   SQLINTEGER            StringLength)
 272.628 +{
 272.629 +      typedef SQLRETURN SQL_API ep_SQLSetEnvAttr (
 272.630 +         SQLHENV               EnvironmentHandle,
 272.631 +         SQLINTEGER            Attribute,
 272.632 +         SQLPOINTER            Value,
 272.633 +         SQLINTEGER            StringLength);
 272.634 +
 272.635 +      ep_SQLSetEnvAttr *fn;
 272.636 +      fn = (ep_SQLSetEnvAttr *) xdlsym(h_odbc, "SQLSetEnvAttr");
 272.637 +      xassert(fn != NULL);
 272.638 +      return (*fn)(EnvironmentHandle, Attribute, Value, StringLength);
 272.639 +}
 272.640 +
 272.641 +static void extract_error(
 272.642 +   char *fn,
 272.643 +   SQLHANDLE handle,
 272.644 +   SQLSMALLINT type);
 272.645 +
 272.646 +static int is_numeric(
 272.647 +    SQLSMALLINT coltype);
 272.648 +
 272.649 +/***********************************************************************
 272.650 +*  NAME
 272.651 +*
 272.652 +*  db_iodbc_open - open connection to ODBC data base
 272.653 +*
 272.654 +*  SYNOPSIS
 272.655 +*
 272.656 +*  #include "glpsql.h"
 272.657 +*  void *db_iodbc_open(TABDCA *dca, int mode);
 272.658 +*
 272.659 +*  DESCRIPTION
 272.660 +*
 272.661 +*  The routine db_iodbc_open opens a connection to an ODBC data base.
 272.662 +*  It then executes the sql statements passed.
 272.663 +*
 272.664 +*  In the case of table read the SELECT statement is executed.
 272.665 +*
 272.666 +*  In the case of table write the INSERT statement is prepared.
 272.667 +*  RETURNS
 272.668 +*
 272.669 +*  The routine returns a pointer to data storage area created. */
 272.670 +void *db_iodbc_open(TABDCA *dca, int mode)
 272.671 +{  void  *ret;
 272.672 +   char **sqllines;
 272.673 +
 272.674 +   sqllines = args_concat(dca);
 272.675 +   if (sqllines == NULL)
 272.676 +   {  xprintf("Missing arguments in table statement.\n"
 272.677 +              "Please, supply table driver, dsn, and query.\n");
 272.678 +      return NULL;
 272.679 +   }
 272.680 +   ret = db_iodbc_open_int(dca, mode, (const char **) sqllines);
 272.681 +   free_buffer(sqllines);
 272.682 +   return ret;
 272.683 +}
 272.684 +
 272.685 +static void *db_iodbc_open_int(TABDCA *dca, int mode, const char
 272.686 +   **sqllines)
 272.687 +{
 272.688 +   struct db_odbc    *sql;
 272.689 +   SQLRETURN          ret;
 272.690 +   SQLCHAR FAR       *dsn;
 272.691 +   SQLCHAR            info[256];
 272.692 +   SQLSMALLINT        colnamelen;
 272.693 +   SQLSMALLINT        nullable;
 272.694 +   SQLSMALLINT        scale;
 272.695 +   const char        *arg;
 272.696 +   int                narg;
 272.697 +   int                i, j;
 272.698 +   int                total;
 272.699 +
 272.700 +   if (libodbc == NULL)
 272.701 +   {
 272.702 +      xprintf("No loader for shared ODBC library available\n");
 272.703 +      return NULL;
 272.704 +   }
 272.705 +
 272.706 +   if (h_odbc == NULL)
 272.707 +   {
 272.708 +      h_odbc = xdlopen(libodbc);
 272.709 +      if (h_odbc == NULL)
 272.710 +      {  xprintf("unable to open library %s\n", libodbc);
 272.711 +         xprintf("%s\n", xerrmsg());
 272.712 +         return NULL;
 272.713 +      }
 272.714 +   }
 272.715 +
 272.716 +   sql = (struct db_odbc *) xmalloc(sizeof(struct db_odbc));
 272.717 +   if (sql == NULL)
 272.718 +         return NULL;
 272.719 +
 272.720 +   sql->mode  = mode;
 272.721 +   sql->hdbc  = NULL;
 272.722 +   sql->henv  = NULL;
 272.723 +   sql->hstmt = NULL;
 272.724 +   sql->query = NULL;
 272.725 +   narg = mpl_tab_num_args(dca);
 272.726 +
 272.727 +   dsn = (SQLCHAR FAR *) mpl_tab_get_arg(dca, 2);
 272.728 +   /* allocate an environment handle */
 272.729 +   ret = dl_SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
 272.730 +      &(sql->henv));
 272.731 +   /* set attribute to enable application to run as ODBC 3.0
 272.732 +      application */
 272.733 +   ret = dl_SQLSetEnvAttr(sql->henv, SQL_ATTR_ODBC_VERSION,
 272.734 +      (void *) SQL_OV_ODBC3, 0);
 272.735 +   /* allocate a connection handle */
 272.736 +   ret = dl_SQLAllocHandle(SQL_HANDLE_DBC, sql->henv, &(sql->hdbc));
 272.737 +   /* connect */
 272.738 +   ret = dl_SQLDriverConnect(sql->hdbc, NULL, dsn, SQL_NTS, NULL, 0,
 272.739 +      NULL, SQL_DRIVER_COMPLETE);
 272.740 +   if (SQL_SUCCEEDED(ret))
 272.741 +   {  /* output information about data base connection */
 272.742 +      xprintf("Connected to ");
 272.743 +      dl_SQLGetInfo(sql->hdbc, SQL_DBMS_NAME, (SQLPOINTER)info,
 272.744 +         sizeof(info), NULL);
 272.745 +      xprintf("%s ", info);
 272.746 +      dl_SQLGetInfo(sql->hdbc, SQL_DBMS_VER, (SQLPOINTER)info,
 272.747 +         sizeof(info), NULL);
 272.748 +      xprintf("%s - ", info);
 272.749 +      dl_SQLGetInfo(sql->hdbc, SQL_DATABASE_NAME, (SQLPOINTER)info,
 272.750 +         sizeof(info), NULL);
 272.751 +      xprintf("%s\n", info);
 272.752 +   }
 272.753 +   else
 272.754 +   {  /* describe error */
 272.755 +      xprintf("Failed to connect\n");
 272.756 +      extract_error("SQLDriverConnect", sql->hdbc, SQL_HANDLE_DBC);
 272.757 +      dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
 272.758 +      dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
 272.759 +      xfree(sql);
 272.760 +      return NULL;
 272.761 +   }
 272.762 +   /* set AUTOCOMMIT on*/
 272.763 +   ret = dl_SQLSetConnectAttr(sql->hdbc, SQL_ATTR_AUTOCOMMIT,
 272.764 +      (SQLPOINTER)SQL_AUTOCOMMIT_ON, 0);
 272.765 +   /* allocate a statement handle */
 272.766 +   ret = dl_SQLAllocHandle(SQL_HANDLE_STMT, sql->hdbc, &(sql->hstmt));
 272.767 +
 272.768 +   /* initialization queries */
 272.769 +   for(j = 0; sqllines[j+1] != NULL; j++)
 272.770 +   {
 272.771 +      sql->query = (SQLCHAR *) sqllines[j];
 272.772 +      xprintf("%s\n", sql->query);
 272.773 +      ret = dl_SQLExecDirect(sql->hstmt, sql->query, SQL_NTS);
 272.774 +      switch (ret)
 272.775 +      {
 272.776 +         case SQL_SUCCESS:
 272.777 +         case SQL_SUCCESS_WITH_INFO:
 272.778 +         case SQL_NO_DATA_FOUND:
 272.779 +            break;
 272.780 +         default:
 272.781 +            xprintf("db_iodbc_open: Query\n\"%s\"\nfailed.\n",
 272.782 +               sql->query);
 272.783 +            extract_error("SQLExecDirect", sql->hstmt, SQL_HANDLE_STMT);
 272.784 +            dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
 272.785 +            dl_SQLDisconnect(sql->hdbc);
 272.786 +            dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
 272.787 +            dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
 272.788 +            xfree(sql);
 272.789 +            return NULL;
 272.790 +      }
 272.791 +      /* commit statement */
 272.792 +      dl_SQLEndTran(SQL_HANDLE_ENV, sql->henv, SQL_COMMIT);
 272.793 +   }
 272.794 +
 272.795 +   if ( sql->mode == 'R' )
 272.796 +   {  sql->nf = mpl_tab_num_flds(dca);
 272.797 +      for(j = 0; sqllines[j] != NULL; j++)
 272.798 +         arg = sqllines[j];
 272.799 +      total = strlen(arg);
 272.800 +      if (total > 7 && 0 == strncmp(arg, "SELECT ", 7))
 272.801 +      {
 272.802 +         total = strlen(arg);
 272.803 +         sql->query = xmalloc( (total+1) * sizeof(char));
 272.804 +         strcpy (sql->query, arg);
 272.805 +      }
 272.806 +      else
 272.807 +      {
 272.808 +         sql->query = db_generate_select_stmt(dca);
 272.809 +      }
 272.810 +      xprintf("%s\n", sql->query);
 272.811 +      if (dl_SQLExecDirect(sql->hstmt, sql->query, SQL_NTS) !=
 272.812 +         SQL_SUCCESS)
 272.813 +      {
 272.814 +         xprintf("db_iodbc_open: Query\n\"%s\"\nfailed.\n", sql->query);
 272.815 +         extract_error("SQLExecDirect", sql->hstmt, SQL_HANDLE_STMT);
 272.816 +         dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
 272.817 +         dl_SQLDisconnect(sql->hdbc);
 272.818 +         dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
 272.819 +         dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
 272.820 +         xfree(sql->query);
 272.821 +            xfree(sql);
 272.822 +         return NULL;
 272.823 +      }
 272.824 +      xfree(sql->query);
 272.825 +      /* determine number of result columns */
 272.826 +      ret = dl_SQLNumResultCols(sql->hstmt, &sql->nresultcols);
 272.827 +      total = sql->nresultcols;
 272.828 +      if (total > SQL_FIELD_MAX)
 272.829 +      {  xprintf("db_iodbc_open: Too many fields (> %d) in query.\n"
 272.830 +            "\"%s\"\n", SQL_FIELD_MAX, sql->query);
 272.831 +         dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
 272.832 +         dl_SQLDisconnect(sql->hdbc);
 272.833 +         dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
 272.834 +         dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
 272.835 +         xfree(sql->query);
 272.836 +         return NULL;
 272.837 +      }
 272.838 +      for (i = 1; i <= total; i++)
 272.839 +      {  /* return a set of attributes for a column */
 272.840 +         ret = dl_SQLDescribeCol(sql->hstmt, (SQLSMALLINT) i,
 272.841 +            sql->colname[i], SQL_FDLEN_MAX,
 272.842 +            &colnamelen, &(sql->coltype[i]), &(sql->collen[i]), &scale,
 272.843 +            &nullable);
 272.844 +         sql->isnumeric[i] = is_numeric(sql->coltype[i]);
 272.845 +         /* bind columns to program vars, converting all types to CHAR*/
 272.846 +         dl_SQLBindCol(sql->hstmt, i, SQL_CHAR, sql->data[i],
 272.847 +            SQL_FDLEN_MAX, &(sql->outlen[i]));
 272.848 +         for (j = sql->nf; j >= 1; j--)
 272.849 +         {  if (strcmp(mpl_tab_get_name(dca, j), sql->colname[i]) == 0)
 272.850 +            break;
 272.851 +         }
 272.852 +         sql->ref[i] = j;
 272.853 +      }
 272.854 +   }
 272.855 +   else if ( sql->mode == 'W' )
 272.856 +   {  for(j = 0; sqllines[j] != NULL; j++)
 272.857 +         arg = sqllines[j];
 272.858 +      if (  NULL != strchr(arg, '?') )
 272.859 +      {
 272.860 +         total = strlen(arg);
 272.861 +         sql->query = xmalloc( (total+1) * sizeof(char));
 272.862 +         strcpy (sql->query, arg);
 272.863 +         }
 272.864 +      else
 272.865 +      {
 272.866 +         sql->query = db_generate_insert_stmt(dca);
 272.867 +      }
 272.868 +      xprintf("%s\n", sql->query);
 272.869 +   }
 272.870 +   return sql;
 272.871 +}
 272.872 +
 272.873 +int db_iodbc_read(TABDCA *dca, void *link)
 272.874 +{
 272.875 +   struct db_odbc  *sql;
 272.876 +   SQLRETURN        ret;
 272.877 +   char             buf[SQL_FDLEN_MAX+1];
 272.878 +   int              i;
 272.879 +   int              len;
 272.880 +   double           num;
 272.881 +
 272.882 +   sql = (struct db_odbc *) link;
 272.883 +
 272.884 +   xassert(sql != NULL);
 272.885 +   xassert(sql->mode == 'R');
 272.886 +
 272.887 +   ret=dl_SQLFetch(sql->hstmt);
 272.888 +   if (ret== SQL_ERROR)
 272.889 +      return -1;
 272.890 +   if (ret== SQL_NO_DATA_FOUND)
 272.891 +      return -1; /*EOF*/
 272.892 +   for (i=1; i <= sql->nresultcols; i++)
 272.893 +   {
 272.894 +      if (sql->ref[i] > 0)
 272.895 +      {
 272.896 +         len = sql->outlen[i];
 272.897 +         if (len != SQL_NULL_DATA)
 272.898 +         {
 272.899 +            if (len > SQL_FDLEN_MAX)
 272.900 +               len = SQL_FDLEN_MAX;
 272.901 +            else if (len < 0)
 272.902 +               len = 0;
 272.903 +            strncpy(buf, (const char *) sql->data[i], len);
 272.904 +            buf[len] = 0x00;
 272.905 +            if (0 != (sql->isnumeric[i]))
 272.906 +            {  strspx(buf); /* remove spaces*/
 272.907 +               if (str2num(buf, &num) != 0)
 272.908 +               {  xprintf("'%s' cannot be converted to a number.\n",
 272.909 +                     buf);
 272.910 +                  return 1;
 272.911 +               }
 272.912 +               mpl_tab_set_num(dca, sql->ref[i], num);
 272.913 +            }
 272.914 +            else
 272.915 +            {  mpl_tab_set_str(dca, sql->ref[i], strtrim(buf));
 272.916 +            }
 272.917 +         }
 272.918 +      }
 272.919 +   }
 272.920 +   return 0;
 272.921 +}
 272.922 +
 272.923 +int db_iodbc_write(TABDCA *dca, void *link)
 272.924 +{
 272.925 +   struct db_odbc  *sql;
 272.926 +   char            *part;
 272.927 +   char            *query;
 272.928 +   char            *template;
 272.929 +   char             num[50];
 272.930 +   int              k;
 272.931 +   int              len;
 272.932 +   int              nf;
 272.933 +
 272.934 +   sql = (struct db_odbc *) link;
 272.935 +   xassert(sql != NULL);
 272.936 +   xassert(sql->mode == 'W');
 272.937 +
 272.938 +   len      = strlen(sql->query);
 272.939 +   template = (char *) xmalloc( (len + 1) * sizeof(char) );
 272.940 +   strcpy(template, sql->query);
 272.941 +
 272.942 +   nf = mpl_tab_num_flds(dca);
 272.943 +   for (k = 1; k <= nf; k++)
 272.944 +   {     switch (mpl_tab_get_type(dca, k))
 272.945 +      {  case 'N':
 272.946 +            len += 20;
 272.947 +            break;
 272.948 +         case 'S':
 272.949 +            len += db_escaped_string_length(mpl_tab_get_str(dca, k));
 272.950 +            len += 2;
 272.951 +            break;
 272.952 +              default:
 272.953 +                        xassert(dca != dca);
 272.954 +         }
 272.955 +   }
 272.956 +   query = xmalloc( (len + 1 ) * sizeof(char) );
 272.957 +   query[0] = 0x00;
 272.958 +   for (k = 1, part = strtok (template, "?"); (part != NULL);
 272.959 +      part = strtok (NULL, "?"), k++)
 272.960 +   {
 272.961 +      if (k > nf) break;
 272.962 +      strcat( query, part );
 272.963 +      switch (mpl_tab_get_type(dca, k))
 272.964 +      {  case 'N':
 272.965 +#if 0 /* 02/XI-2010 by xypron */
 272.966 +            sprintf(num, "%-18g",mpl_tab_get_num(dca, k));
 272.967 +#else
 272.968 +            sprintf(num, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k));
 272.969 +#endif
 272.970 +            strcat( query, num );
 272.971 +            break;
 272.972 +         case 'S':
 272.973 +            strcat( query, "'");
 272.974 +            db_escape_string( query + strlen(query),
 272.975 +               mpl_tab_get_str(dca, k) );
 272.976 +            strcat( query, "'");
 272.977 +            break;
 272.978 +              default:
 272.979 +                        xassert(dca != dca);
 272.980 +         }
 272.981 +   }
 272.982 +   if (part != NULL)
 272.983 +      strcat(query, part);
 272.984 +   if (dl_SQLExecDirect(sql->hstmt, (SQLCHAR *) query, SQL_NTS)
 272.985 +      != SQL_SUCCESS)
 272.986 +   {
 272.987 +      xprintf("db_iodbc_write: Query\n\"%s\"\nfailed.\n", query);
 272.988 +      extract_error("SQLExecDirect", sql->hdbc, SQL_HANDLE_DBC);
 272.989 +      xfree(query);
 272.990 +      xfree(template);
 272.991 +      return 1;
 272.992 +      }
 272.993 +
 272.994 +   xfree(query);
 272.995 +   xfree(template);
 272.996 +   return 0;
 272.997 +}
 272.998 +
 272.999 +int db_iodbc_close(TABDCA *dca, void *link)
272.1000 +{
272.1001 +   struct db_odbc *sql;
272.1002 +
272.1003 +   sql = (struct db_odbc *) link;
272.1004 +   xassert(sql != NULL);
272.1005 +   /* Commit */
272.1006 +   if ( sql->mode == 'W' )
272.1007 +      dl_SQLEndTran(SQL_HANDLE_ENV, sql->henv, SQL_COMMIT);
272.1008 +   if ( sql->mode == 'R' )
272.1009 +      dl_SQLCloseCursor(sql->hstmt);
272.1010 +
272.1011 +   dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
272.1012 +   dl_SQLDisconnect(sql->hdbc);
272.1013 +   dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
272.1014 +   dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
272.1015 +   if ( sql->mode == 'W' )
272.1016 +      xfree(sql->query);
272.1017 +   xfree(sql);
272.1018 +   dca->link = NULL;
272.1019 +   return 0;
272.1020 +}
272.1021 +
272.1022 +static void extract_error(
272.1023 +   char *fn,
272.1024 +   SQLHANDLE handle,
272.1025 +   SQLSMALLINT type)
272.1026 +{
272.1027 +   SQLINTEGER   i = 0;
272.1028 +   SQLINTEGER   native;
272.1029 +   SQLCHAR   state[ 7 ];
272.1030 +   SQLCHAR   text[256];
272.1031 +   SQLSMALLINT  len;
272.1032 +   SQLRETURN    ret;
272.1033 +
272.1034 +   xprintf("\nThe driver reported the following diagnostics whilst "
272.1035 +      "running %s\n", fn);
272.1036 +
272.1037 +   do
272.1038 +   {
272.1039 +      ret = dl_SQLGetDiagRec(type, handle, ++i, state, &native, text,
272.1040 +         sizeof(text), &len );
272.1041 +      if (SQL_SUCCEEDED(ret))
272.1042 +         xprintf("%s:%ld:%ld:%s\n", state, i, native, text);
272.1043 +   }
272.1044 +   while( ret == SQL_SUCCESS );
272.1045 +}
272.1046 +
272.1047 +static int is_numeric(SQLSMALLINT coltype)
272.1048 +{
272.1049 +   int ret = 0;
272.1050 +   switch (coltype)
272.1051 +   {
272.1052 +      case SQL_DECIMAL:
272.1053 +      case SQL_NUMERIC:
272.1054 +      case SQL_SMALLINT:
272.1055 +      case SQL_INTEGER:
272.1056 +      case SQL_REAL:
272.1057 +      case SQL_FLOAT:
272.1058 +      case SQL_DOUBLE:
272.1059 +      case SQL_TINYINT:
272.1060 +      case SQL_BIGINT:
272.1061 +         ret = 1;
272.1062 +         break;
272.1063 +   }
272.1064 +   return ret;
272.1065 +}
272.1066 +
272.1067 +#endif
272.1068 +
272.1069 +/**********************************************************************/
272.1070 +
272.1071 +#ifndef HAVE_MYSQL
272.1072 +
272.1073 +void *db_mysql_open(TABDCA *dca, int mode)
272.1074 +{     xassert(dca == dca);
272.1075 +      xassert(mode == mode);
272.1076 +      xprintf("MySQL table driver not supported\n");
272.1077 +      return NULL;
272.1078 +}
272.1079 +
272.1080 +int db_mysql_read(TABDCA *dca, void *link)
272.1081 +{     xassert(dca != dca);
272.1082 +      xassert(link != link);
272.1083 +      return 0;
272.1084 +}
272.1085 +
272.1086 +int db_mysql_write(TABDCA *dca, void *link)
272.1087 +{     xassert(dca != dca);
272.1088 +      xassert(link != link);
272.1089 +      return 0;
272.1090 +}
272.1091 +
272.1092 +int db_mysql_close(TABDCA *dca, void *link)
272.1093 +{     xassert(dca != dca);
272.1094 +      xassert(link != link);
272.1095 +      return 0;
272.1096 +}
272.1097 +
272.1098 +#else
272.1099 +
272.1100 +#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__WOE__)
272.1101 +#include <windows.h>
272.1102 +#endif
272.1103 +
272.1104 +#ifdef __CYGWIN__
272.1105 +#define byte_defined 1
272.1106 +#endif
272.1107 +
272.1108 +#include <my_global.h>
272.1109 +#include <my_sys.h>
272.1110 +#include <mysql.h>
272.1111 +
272.1112 +struct db_mysql
272.1113 +{
272.1114 +   int              mode;  /*'R' = Read, 'W' = Write*/
272.1115 +   MYSQL           *con;   /*connection*/
272.1116 +   MYSQL_RES       *res;    /*result*/
272.1117 +   int              nf;
272.1118 +   /* number of fields in the csv file */
272.1119 +   int              ref[1+SQL_FIELD_MAX];
272.1120 +   /* ref[k] = k', if k-th field of the csv file corresponds to
272.1121 +      k'-th field in the table statement; if ref[k] = 0, k-th field
272.1122 +      of the csv file is ignored */
272.1123 +   char            *query;
272.1124 +   /* query generated by db_mysql_open */
272.1125 +};
272.1126 +
272.1127 +void STDCALL dl_mysql_close(MYSQL *sock)
272.1128 +{
272.1129 +      typedef void STDCALL ep_mysql_close(MYSQL *sock);
272.1130 +
272.1131 +      ep_mysql_close *fn;
272.1132 +      fn = (ep_mysql_close *) xdlsym(h_mysql, "mysql_close");
272.1133 +      xassert(fn != NULL);
272.1134 +      return (*fn)(sock);
272.1135 +}
272.1136 +
272.1137 +const char * STDCALL dl_mysql_error(MYSQL *mysql)
272.1138 +{
272.1139 +      typedef const char * STDCALL ep_mysql_error(MYSQL *mysql);
272.1140 +
272.1141 +      ep_mysql_error *fn;
272.1142 +      fn = (ep_mysql_error *) xdlsym(h_mysql, "mysql_error");
272.1143 +      xassert(fn != NULL);
272.1144 +      return (*fn)(mysql);
272.1145 +}
272.1146 +
272.1147 +MYSQL_FIELD * STDCALL dl_mysql_fetch_fields(MYSQL_RES *res)
272.1148 +{
272.1149 +      typedef MYSQL_FIELD * STDCALL
272.1150 +         ep_mysql_fetch_fields(MYSQL_RES *res);
272.1151 +
272.1152 +      ep_mysql_fetch_fields *fn;
272.1153 +   fn = (ep_mysql_fetch_fields *) xdlsym(h_mysql, "mysql_fetch_fields");
272.1154 +      xassert(fn != NULL);
272.1155 +      return (*fn)(res);
272.1156 +}
272.1157 +
272.1158 +unsigned long * STDCALL dl_mysql_fetch_lengths(MYSQL_RES *result)
272.1159 +{
272.1160 +      typedef unsigned long * STDCALL
272.1161 +         ep_mysql_fetch_lengths(MYSQL_RES *result);
272.1162 +
272.1163 +      ep_mysql_fetch_lengths *fn;
272.1164 +      fn = (ep_mysql_fetch_lengths *) xdlsym(h_mysql,
272.1165 +         "mysql_fetch_lengths");
272.1166 +      xassert(fn != NULL);
272.1167 +      return (*fn)(result);
272.1168 +}
272.1169 +
272.1170 +MYSQL_ROW STDCALL dl_mysql_fetch_row(MYSQL_RES *result)
272.1171 +{
272.1172 +      typedef MYSQL_ROW STDCALL ep_mysql_fetch_row(MYSQL_RES *result);
272.1173 +
272.1174 +      ep_mysql_fetch_row *fn;
272.1175 +      fn = (ep_mysql_fetch_row *) xdlsym(h_mysql, "mysql_fetch_row");
272.1176 +      xassert(fn != NULL);
272.1177 +      return (*fn)(result);
272.1178 +}
272.1179 +
272.1180 +unsigned int STDCALL dl_mysql_field_count(MYSQL *mysql)
272.1181 +{
272.1182 +      typedef unsigned int STDCALL ep_mysql_field_count(MYSQL *mysql);
272.1183 +
272.1184 +      ep_mysql_field_count *fn;
272.1185 +     fn = (ep_mysql_field_count *) xdlsym(h_mysql, "mysql_field_count");
272.1186 +      xassert(fn != NULL);
272.1187 +      return (*fn)(mysql);
272.1188 +}
272.1189 +
272.1190 +MYSQL * STDCALL dl_mysql_init(MYSQL *mysql)
272.1191 +{
272.1192 +      typedef MYSQL * STDCALL ep_mysql_init(MYSQL *mysql);
272.1193 +
272.1194 +      ep_mysql_init *fn;
272.1195 +      fn = (ep_mysql_init *) xdlsym(h_mysql, "mysql_init");
272.1196 +      xassert(fn != NULL);
272.1197 +      return (*fn)(mysql);
272.1198 +}
272.1199 +
272.1200 +unsigned int STDCALL dl_mysql_num_fields(MYSQL_RES *res)
272.1201 +{
272.1202 +      typedef unsigned int STDCALL ep_mysql_num_fields(MYSQL_RES *res);
272.1203 +
272.1204 +      ep_mysql_num_fields *fn;
272.1205 +      fn = (ep_mysql_num_fields *) xdlsym(h_mysql, "mysql_num_fields");
272.1206 +      xassert(fn != NULL);
272.1207 +      return (*fn)(res);
272.1208 +}
272.1209 +
272.1210 +int STDCALL dl_mysql_query(MYSQL *mysql, const char *q)
272.1211 +{
272.1212 +      typedef int STDCALL ep_mysql_query(MYSQL *mysql, const char *q);
272.1213 +
272.1214 +      ep_mysql_query *fn;
272.1215 +      fn = (ep_mysql_query *) xdlsym(h_mysql, "mysql_query");
272.1216 +      xassert(fn != NULL);
272.1217 +      return (*fn)(mysql, q);
272.1218 +}
272.1219 +
272.1220 +MYSQL * STDCALL dl_mysql_real_connect(MYSQL *mysql, const char *host,
272.1221 +                                           const char *user,
272.1222 +                                           const char *passwd,
272.1223 +                                           const char *db,
272.1224 +                                           unsigned int port,
272.1225 +                                           const char *unix_socket,
272.1226 +                                           unsigned long clientflag)
272.1227 +{
272.1228 +      typedef MYSQL * STDCALL ep_mysql_real_connect(MYSQL *mysql,
272.1229 +            const char *host,
272.1230 +            const char *user,
272.1231 +            const char *passwd,
272.1232 +            const char *db,
272.1233 +            unsigned int port,
272.1234 +            const char *unix_socket,
272.1235 +            unsigned long clientflag);
272.1236 +
272.1237 +      ep_mysql_real_connect *fn;
272.1238 +      fn = (ep_mysql_real_connect *) xdlsym(h_mysql,
272.1239 +         "mysql_real_connect");
272.1240 +      xassert(fn != NULL);
272.1241 +      return (*fn)(mysql, host, user, passwd, db, port, unix_socket,
272.1242 +         clientflag);
272.1243 +}
272.1244 +
272.1245 +MYSQL_RES * STDCALL dl_mysql_use_result(MYSQL *mysql)
272.1246 +{
272.1247 +      typedef MYSQL_RES * STDCALL ep_mysql_use_result(MYSQL *mysql);
272.1248 +      ep_mysql_use_result *fn;
272.1249 +      fn = (ep_mysql_use_result *) xdlsym(h_mysql, "mysql_use_result");
272.1250 +      xassert(fn != NULL);
272.1251 +      return (*fn)(mysql);
272.1252 +}
272.1253 +
272.1254 +/***********************************************************************
272.1255 +*  NAME
272.1256 +*
272.1257 +*  db_mysql_open - open connection to ODBC data base
272.1258 +*
272.1259 +*  SYNOPSIS
272.1260 +*
272.1261 +*  #include "glpsql.h"
272.1262 +*  void *db_mysql_open(TABDCA *dca, int mode);
272.1263 +*
272.1264 +*  DESCRIPTION
272.1265 +*
272.1266 +*  The routine db_mysql_open opens a connection to a MySQL data base.
272.1267 +*  It then executes the sql statements passed.
272.1268 +*
272.1269 +*  In the case of table read the SELECT statement is executed.
272.1270 +*
272.1271 +*  In the case of table write the INSERT statement is prepared.
272.1272 +*  RETURNS
272.1273 +*
272.1274 +*  The routine returns a pointer to data storage area created. */
272.1275 +
272.1276 +void *db_mysql_open(TABDCA *dca, int mode)
272.1277 +{  void  *ret;
272.1278 +   char **sqllines;
272.1279 +
272.1280 +   sqllines = args_concat(dca);
272.1281 +   if (sqllines == NULL)
272.1282 +   {  xprintf("Missing arguments in table statement.\n"
272.1283 +              "Please, supply table driver, dsn, and query.\n");
272.1284 +      return NULL;
272.1285 +   }
272.1286 +   ret = db_mysql_open_int(dca, mode, (const char **) sqllines);
272.1287 +   free_buffer(sqllines);
272.1288 +   return ret;
272.1289 +}
272.1290 +
272.1291 +static void *db_mysql_open_int(TABDCA *dca, int mode, const char
272.1292 +   **sqllines)
272.1293 +{
272.1294 +   struct db_mysql *sql = NULL;
272.1295 +   char            *arg = NULL;
272.1296 +   const char      *field;
272.1297 +   MYSQL_FIELD     *fields;
272.1298 +   char            *keyword;
272.1299 +   char            *value;
272.1300 +   char            *query;
272.1301 +   char            *dsn;
272.1302 +/* "Server=[server_name];Database=[database_name];UID=[username];*/
272.1303 +/* PWD=[password];Port=[port]"*/
272.1304 +   char            *server   = NULL;        /* Server */
272.1305 +   char            *user     = NULL;        /* UID */
272.1306 +   char            *password = NULL;        /* PWD */
272.1307 +   char            *database = NULL;        /* Database */
272.1308 +   unsigned int     port = 0;               /* Port */
272.1309 +   int              narg;
272.1310 +   int              i, j, total;
272.1311 +
272.1312 +   if (libmysql == NULL)
272.1313 +   {
272.1314 +      xprintf("No loader for shared MySQL library available\n");
272.1315 +      return NULL;
272.1316 +   }
272.1317 +
272.1318 +   if (h_mysql == NULL)
272.1319 +   {
272.1320 +      h_mysql = xdlopen(libmysql);
272.1321 +      if (h_mysql == NULL)
272.1322 +      {  xprintf("unable to open library %s\n", libmysql);
272.1323 +         xprintf("%s\n", xerrmsg());
272.1324 +         return NULL;
272.1325 +      }
272.1326 +   }
272.1327 +
272.1328 +   sql = (struct db_mysql *) xmalloc(sizeof(struct db_mysql));
272.1329 +   if (sql == NULL)
272.1330 +         return NULL;
272.1331 +   sql->mode = mode;
272.1332 +   sql->res = NULL;
272.1333 +   sql->query = NULL;
272.1334 +   sql->nf = mpl_tab_num_flds(dca);
272.1335 +
272.1336 +   narg = mpl_tab_num_args(dca);
272.1337 +   if (narg < 3 )
272.1338 +      xprintf("MySQL driver: string list too short \n");
272.1339 +
272.1340 +   /* get connection string*/
272.1341 +   dsn = (char *) mpl_tab_get_arg(dca, 2);
272.1342 +      /* copy connection string*/
272.1343 +   i = strlen(dsn);
272.1344 +   i++;
272.1345 +   arg = xmalloc(i * sizeof(char));
272.1346 +   strcpy(arg, dsn);
272.1347 +   /*tokenize connection string*/
272.1348 +   for (i = 1, keyword = strtok (arg, "="); (keyword != NULL);
272.1349 +      keyword = strtok (NULL, "="), i++)
272.1350 +   {
272.1351 +         value = strtok (NULL, ";");
272.1352 +      if (value==NULL)
272.1353 +         {
272.1354 +            xprintf("db_mysql_open: Missing value for keyword %s\n",
272.1355 +               keyword);
272.1356 +            xfree(arg);
272.1357 +            xfree(sql);
272.1358 +            return NULL;
272.1359 +      }
272.1360 +      if (0 == strcmp(keyword, "Server"))
272.1361 +            server = value;
272.1362 +      else if (0 == strcmp(keyword, "Database"))
272.1363 +             database = value;
272.1364 +      else if (0 == strcmp(keyword, "UID"))
272.1365 +             user = value;
272.1366 +      else if (0 == strcmp(keyword, "PWD"))
272.1367 +             password = value;
272.1368 +      else if (0 == strcmp(keyword, "Port"))
272.1369 +             port = (unsigned int) atol(value);
272.1370 +   }
272.1371 +   /* Connect to database */
272.1372 +   sql->con = dl_mysql_init(NULL);
272.1373 +  if (!dl_mysql_real_connect(sql->con, server, user, password, database,
272.1374 +      port, NULL, 0))
272.1375 +   {
272.1376 +      xprintf("db_mysql_open: Connect failed\n");
272.1377 +      xprintf("%s\n", dl_mysql_error(sql->con));
272.1378 +      xfree(arg);
272.1379 +      xfree(sql);
272.1380 +      return NULL;
272.1381 +   }
272.1382 +   xfree(arg);
272.1383 +
272.1384 +   for(j = 0; sqllines[j+1] != NULL; j++)
272.1385 +   {  query = (char *) sqllines[j];
272.1386 +      xprintf("%s\n", query);
272.1387 +      if (dl_mysql_query(sql->con, query))
272.1388 +      {
272.1389 +         xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query);
272.1390 +         xprintf("%s\n",dl_mysql_error(sql->con));
272.1391 +         dl_mysql_close(sql->con);
272.1392 +         xfree(sql);
272.1393 +         return NULL;
272.1394 +      }
272.1395 +   }
272.1396 +
272.1397 +   if ( sql->mode == 'R' )
272.1398 +   {  sql->nf = mpl_tab_num_flds(dca);
272.1399 +      for(j = 0; sqllines[j] != NULL; j++)
272.1400 +         arg = (char *) sqllines[j];
272.1401 +      total = strlen(arg);
272.1402 +      if (total > 7 && 0 == strncmp(arg, "SELECT ", 7))
272.1403 +      {
272.1404 +         total = strlen(arg);
272.1405 +         query = xmalloc( (total+1) * sizeof(char));
272.1406 +         strcpy (query, arg);
272.1407 +      }
272.1408 +      else
272.1409 +      {
272.1410 +         query = db_generate_select_stmt(dca);
272.1411 +      }
272.1412 +      xprintf("%s\n", query);
272.1413 +      if (dl_mysql_query(sql->con, query))
272.1414 +      {
272.1415 +         xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query);
272.1416 +         xprintf("%s\n",dl_mysql_error(sql->con));
272.1417 +         dl_mysql_close(sql->con);
272.1418 +         xfree(query);
272.1419 +         xfree(sql);
272.1420 +         return NULL;
272.1421 +      }
272.1422 +      xfree(query);
272.1423 +      sql->res = dl_mysql_use_result(sql->con);
272.1424 +      if (sql->res)
272.1425 +      {
272.1426 +         /* create references between query results and table fields*/
272.1427 +         total = dl_mysql_num_fields(sql->res);
272.1428 +         if (total > SQL_FIELD_MAX)
272.1429 +         {  xprintf("db_mysql_open: Too many fields (> %d) in query.\n"
272.1430 +               "\"%s\"\n", SQL_FIELD_MAX, query);
272.1431 +            xprintf("%s\n",dl_mysql_error(sql->con));
272.1432 +            dl_mysql_close(sql->con);
272.1433 +            xfree(query);
272.1434 +                 xfree(sql);
272.1435 +            return NULL;
272.1436 +         }
272.1437 +         fields = dl_mysql_fetch_fields(sql->res);
272.1438 +         for (i = 1; i <= total; i++)
272.1439 +         {
272.1440 +               for (j = sql->nf; j >= 1; j--)
272.1441 +            {
272.1442 +               if (strcmp(mpl_tab_get_name(dca, j), fields[i-1].name)
272.1443 +                  == 0)
272.1444 +               break;
272.1445 +            }
272.1446 +            sql->ref[i] = j;
272.1447 +         }
272.1448 +      }
272.1449 +      else
272.1450 +      {
272.1451 +         if(dl_mysql_field_count(sql->con) == 0)
272.1452 +            {
272.1453 +            xprintf("db_mysql_open: Query was not a SELECT\n\"%s\"\n",
272.1454 +               query);
272.1455 +            xprintf("%s\n",dl_mysql_error(sql->con));
272.1456 +            xfree(query);
272.1457 +            xfree(sql);
272.1458 +            return NULL;
272.1459 +         }
272.1460 +         else
272.1461 +         {
272.1462 +            xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query);
272.1463 +            xprintf("%s\n",dl_mysql_error(sql->con));
272.1464 +            xfree(query);
272.1465 +            xfree(sql);
272.1466 +            return NULL;
272.1467 +         }
272.1468 +      }
272.1469 +   }
272.1470 +   else if ( sql->mode == 'W' )
272.1471 +   {  for(j = 0; sqllines[j] != NULL; j++)
272.1472 +         arg = (char *) sqllines[j];
272.1473 +      if (  NULL != strchr(arg, '?') )
272.1474 +      {
272.1475 +         total = strlen(arg);
272.1476 +         query = xmalloc( (total+1) * sizeof(char));
272.1477 +         strcpy (query, arg);
272.1478 +         }
272.1479 +      else
272.1480 +         query = db_generate_insert_stmt(dca);
272.1481 +      sql->query = query;
272.1482 +      xprintf("%s\n", query);
272.1483 +   }
272.1484 +   return sql;
272.1485 +}
272.1486 +
272.1487 +int db_mysql_read(TABDCA *dca, void *link)
272.1488 +{  struct db_mysql *sql;
272.1489 +   char            buf[255+1];
272.1490 +   char            **row;
272.1491 +   unsigned long   *lengths;
272.1492 +   MYSQL_FIELD     *fields;
272.1493 +   double          num;
272.1494 +   int             len;
272.1495 +   unsigned long   num_fields;
272.1496 +   int             i;
272.1497 +
272.1498 +   sql = (struct db_mysql *) link;
272.1499 +
272.1500 +   xassert(sql != NULL);
272.1501 +   xassert(sql->mode == 'R');
272.1502 +   if (NULL == sql->res)
272.1503 +   {
272.1504 +      xprintf("db_mysql_read: no result set available");
272.1505 +      return 1;
272.1506 +   }
272.1507 +   if (NULL==(row = (char **)dl_mysql_fetch_row(sql->res))) {
272.1508 +       return -1; /*EOF*/
272.1509 +   }
272.1510 +   lengths = dl_mysql_fetch_lengths(sql->res);
272.1511 +   fields = dl_mysql_fetch_fields(sql->res);
272.1512 +   num_fields = dl_mysql_num_fields(sql->res);
272.1513 +   for (i=1; i <= num_fields; i++)
272.1514 +   {
272.1515 +      if (row[i-1] != NULL)
272.1516 +      {  len = (size_t) lengths[i-1];
272.1517 +         if (len > 255)
272.1518 +            len = 255;
272.1519 +         strncpy(buf, (const char *) row[i-1], len);
272.1520 +         buf[len] = 0x00;
272.1521 +         if (0 != (fields[i-1].flags & NUM_FLAG))
272.1522 +         {  strspx(buf); /* remove spaces*/
272.1523 +            if (str2num(buf, &num) != 0)
272.1524 +            {  xprintf("'%s' cannot be converted to a number.\n", buf);
272.1525 +               return 1;
272.1526 +            }
272.1527 +            if (sql->ref[i] > 0)
272.1528 +               mpl_tab_set_num(dca, sql->ref[i], num);
272.1529 +         }
272.1530 +         else
272.1531 +         {  if (sql->ref[i] > 0)
272.1532 +               mpl_tab_set_str(dca, sql->ref[i], strtrim(buf));
272.1533 +         }
272.1534 +      }
272.1535 +   }
272.1536 +   return 0;
272.1537 +}
272.1538 +
272.1539 +int db_mysql_write(TABDCA *dca, void *link)
272.1540 +{
272.1541 +   struct db_mysql *sql;
272.1542 +   char            *part;
272.1543 +   char            *query;
272.1544 +   char            *template;
272.1545 +   char             num[50];
272.1546 +   int              k;
272.1547 +   int              len;
272.1548 +   int              nf;
272.1549 +
272.1550 +   sql = (struct db_mysql *) link;
272.1551 +   xassert(sql != NULL);
272.1552 +   xassert(sql->mode == 'W');
272.1553 +
272.1554 +   len      = strlen(sql->query);
272.1555 +   template = (char *) xmalloc( (len + 1) * sizeof(char) );
272.1556 +   strcpy(template, sql->query);
272.1557 +
272.1558 +   nf = mpl_tab_num_flds(dca);
272.1559 +   for (k = 1; k <= nf; k++)
272.1560 +   {     switch (mpl_tab_get_type(dca, k))
272.1561 +      {  case 'N':
272.1562 +            len += 20;
272.1563 +            break;
272.1564 +         case 'S':
272.1565 +            len += db_escaped_string_length(mpl_tab_get_str(dca, k));
272.1566 +            len += 2;
272.1567 +            break;
272.1568 +              default:
272.1569 +                        xassert(dca != dca);
272.1570 +         }
272.1571 +   }
272.1572 +   query = xmalloc( (len + 1 ) * sizeof(char) );
272.1573 +   query[0] = 0x00;
272.1574 +   for (k = 1, part = strtok (template, "?"); (part != NULL);
272.1575 +      part = strtok (NULL, "?"), k++)
272.1576 +   {
272.1577 +      if (k > nf) break;
272.1578 +      strcat( query, part );
272.1579 +      switch (mpl_tab_get_type(dca, k))
272.1580 +      {  case 'N':
272.1581 +#if 0 /* 02/XI-2010 by xypron */
272.1582 +            sprintf(num, "%-18g",mpl_tab_get_num(dca, k));
272.1583 +#else
272.1584 +            sprintf(num, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k));
272.1585 +#endif
272.1586 +            strcat( query, num );
272.1587 +            break;
272.1588 +         case 'S':
272.1589 +            strcat( query, "'");
272.1590 +            db_escape_string( query + strlen(query),
272.1591 +               mpl_tab_get_str(dca, k) );
272.1592 +            strcat( query, "'");
272.1593 +            break;
272.1594 +              default:
272.1595 +                        xassert(dca != dca);
272.1596 +         }
272.1597 +   }
272.1598 +   if (part != NULL)
272.1599 +      strcat(query, part);
272.1600 +   if (dl_mysql_query(sql->con, query))
272.1601 +   {
272.1602 +      xprintf("db_mysql_write: Query\n\"%s\"\nfailed.\n", query);
272.1603 +      xprintf("%s\n",dl_mysql_error(sql->con));
272.1604 +      xfree(query);
272.1605 +      xfree(template);
272.1606 +      return 1;
272.1607 +      }
272.1608 +
272.1609 +   xfree(query);
272.1610 +   xfree(template);
272.1611 +   return 0;
272.1612 +   }
272.1613 +
272.1614 +int db_mysql_close(TABDCA *dca, void *link)
272.1615 +{
272.1616 +   struct db_mysql *sql;
272.1617 +
272.1618 +   sql = (struct db_mysql *) link;
272.1619 +   xassert(sql != NULL);
272.1620 +   dl_mysql_close(sql->con);
272.1621 +   if ( sql->mode == 'W' )
272.1622 +      xfree(sql->query);
272.1623 +   xfree(sql);
272.1624 +   dca->link = NULL;
272.1625 +   return 0;
272.1626 +}
272.1627 +
272.1628 +#endif
272.1629 +
272.1630 +/* eof */
   273.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   273.2 +++ b/src/glpsql.h	Mon Dec 06 13:09:21 2010 +0100
   273.3 @@ -0,0 +1,64 @@
   273.4 +/* glpsql.h */
   273.5 +
   273.6 +/***********************************************************************
   273.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   273.8 +*
   273.9 +*  Author: Heinrich Schuchardt <heinrich.schuchardt@gmx.de>.
  273.10 +*
  273.11 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  273.12 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  273.13 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  273.14 +*  E-mail: <mao@gnu.org>.
  273.15 +*
  273.16 +*  GLPK is free software: you can redistribute it and/or modify it
  273.17 +*  under the terms of the GNU General Public License as published by
  273.18 +*  the Free Software Foundation, either version 3 of the License, or
  273.19 +*  (at your option) any later version.
  273.20 +*
  273.21 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  273.22 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  273.23 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  273.24 +*  License for more details.
  273.25 +*
  273.26 +*  You should have received a copy of the GNU General Public License
  273.27 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  273.28 +***********************************************************************/
  273.29 +
  273.30 +#ifndef GLPSQL_H
  273.31 +#define GLPSQL_H
  273.32 +
  273.33 +#define db_iodbc_open _glp_db_iodbc_open
  273.34 +void *db_iodbc_open(TABDCA *dca, int mode);
  273.35 +/* open iODBC database connection */
  273.36 +
  273.37 +#define db_iodbc_read _glp_db_iodbc_read
  273.38 +int db_iodbc_read(TABDCA *dca, void *link);
  273.39 +/* read data from iODBC */
  273.40 +
  273.41 +#define db_iodbc_write _glp_db_iodbc_write
  273.42 +int db_iodbc_write(TABDCA *dca, void *link);
  273.43 +/* write data to iODBC */
  273.44 +
  273.45 +#define db_iodbc_close _glp_db_iodbc_close
  273.46 +int db_iodbc_close(TABDCA *dca, void *link);
  273.47 +/* close iODBC database connection */
  273.48 +
  273.49 +#define db_mysql_open _glp_db_mysql_open
  273.50 +void *db_mysql_open(TABDCA *dca, int mode);
  273.51 +/* open MySQL database connection */
  273.52 +
  273.53 +#define db_mysql_read _glp_db_mysql_read
  273.54 +int db_mysql_read(TABDCA *dca, void *link);
  273.55 +/* read data from MySQL */
  273.56 +
  273.57 +#define db_mysql_write _glp_db_mysql_write
  273.58 +int db_mysql_write(TABDCA *dca, void *link);
  273.59 +/* write data to MySQL */
  273.60 +
  273.61 +#define db_mysql_close _glp_db_mysql_close
  273.62 +int db_mysql_close(TABDCA *dca, void *link);
  273.63 +/* close MySQL database connection */
  273.64 +
  273.65 +#endif
  273.66 +
  273.67 +/* eof */
   274.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   274.2 +++ b/src/glpssx.h	Mon Dec 06 13:09:21 2010 +0100
   274.3 @@ -0,0 +1,418 @@
   274.4 +/* glpssx.h (simplex method, bignum arithmetic) */
   274.5 +
   274.6 +/***********************************************************************
   274.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   274.8 +*
   274.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  274.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  274.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  274.12 +*  E-mail: <mao@gnu.org>.
  274.13 +*
  274.14 +*  GLPK is free software: you can redistribute it and/or modify it
  274.15 +*  under the terms of the GNU General Public License as published by
  274.16 +*  the Free Software Foundation, either version 3 of the License, or
  274.17 +*  (at your option) any later version.
  274.18 +*
  274.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  274.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  274.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  274.22 +*  License for more details.
  274.23 +*
  274.24 +*  You should have received a copy of the GNU General Public License
  274.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  274.26 +***********************************************************************/
  274.27 +
  274.28 +#ifndef GLPSSX_H
  274.29 +#define GLPSSX_H
  274.30 +
  274.31 +#include "glpbfx.h"
  274.32 +#include "glpenv.h"
  274.33 +
  274.34 +typedef struct SSX SSX;
  274.35 +
  274.36 +struct SSX
  274.37 +{     /* simplex solver workspace */
  274.38 +/*----------------------------------------------------------------------
  274.39 +// LP PROBLEM DATA
  274.40 +//
  274.41 +// It is assumed that LP problem has the following statement:
  274.42 +//
  274.43 +//    minimize (or maximize)
  274.44 +//
  274.45 +//       z = c[1]*x[1] + ... + c[m+n]*x[m+n] + c[0]                  (1)
  274.46 +//
  274.47 +//    subject to equality constraints
  274.48 +//
  274.49 +//       x[1] - a[1,1]*x[m+1] - ... - a[1,n]*x[m+n] = 0
  274.50 +//
  274.51 +//          .  .  .  .  .  .  .                                      (2)
  274.52 +//
  274.53 +//       x[m] - a[m,1]*x[m+1] + ... - a[m,n]*x[m+n] = 0
  274.54 +//
  274.55 +//    and bounds of variables
  274.56 +//
  274.57 +//         l[1] <= x[1]   <= u[1]
  274.58 +//
  274.59 +//          .  .  .  .  .  .  .                                      (3)
  274.60 +//
  274.61 +//       l[m+n] <= x[m+n] <= u[m+n]
  274.62 +//
  274.63 +// where:
  274.64 +// x[1], ..., x[m]      - auxiliary variables;
  274.65 +// x[m+1], ..., x[m+n]  - structural variables;
  274.66 +// z                    - objective function;
  274.67 +// c[1], ..., c[m+n]    - coefficients of the objective function;
  274.68 +// c[0]                 - constant term of the objective function;
  274.69 +// a[1,1], ..., a[m,n]  - constraint coefficients;
  274.70 +// l[1], ..., l[m+n]    - lower bounds of variables;
  274.71 +// u[1], ..., u[m+n]    - upper bounds of variables.
  274.72 +//
  274.73 +// Bounds of variables can be finite as well as inifinite. Besides,
  274.74 +// lower and upper bounds can be equal to each other. So the following
  274.75 +// five types of variables are possible:
  274.76 +//
  274.77 +//    Bounds of variable      Type of variable
  274.78 +//    -------------------------------------------------
  274.79 +//    -inf <  x[k] <  +inf    Free (unbounded) variable
  274.80 +//    l[k] <= x[k] <  +inf    Variable with lower bound
  274.81 +//    -inf <  x[k] <= u[k]    Variable with upper bound
  274.82 +//    l[k] <= x[k] <= u[k]    Double-bounded variable
  274.83 +//    l[k] =  x[k] =  u[k]    Fixed variable
  274.84 +//
  274.85 +// Using vector-matrix notations the LP problem (1)-(3) can be written
  274.86 +// as follows:
  274.87 +//
  274.88 +//    minimize (or maximize)
  274.89 +//
  274.90 +//       z = c * x + c[0]                                            (4)
  274.91 +//
  274.92 +//    subject to equality constraints
  274.93 +//
  274.94 +//       xR - A * xS = 0                                             (5)
  274.95 +//
  274.96 +//    and bounds of variables
  274.97 +//
  274.98 +//       l <= x <= u                                                 (6)
  274.99 +//
 274.100 +// where:
 274.101 +// xR                   - vector of auxiliary variables;
 274.102 +// xS                   - vector of structural variables;
 274.103 +// x = (xR, xS)         - vector of all variables;
 274.104 +// z                    - objective function;
 274.105 +// c                    - vector of objective coefficients;
 274.106 +// c[0]                 - constant term of the objective function;
 274.107 +// A                    - matrix of constraint coefficients (has m rows
 274.108 +//                        and n columns);
 274.109 +// l                    - vector of lower bounds of variables;
 274.110 +// u                    - vector of upper bounds of variables.
 274.111 +//
 274.112 +// The simplex method makes no difference between auxiliary and
 274.113 +// structural variables, so it is convenient to think the system of
 274.114 +// equality constraints (5) written in a homogeneous form:
 274.115 +//
 274.116 +//    (I | -A) * x = 0,                                              (7)
 274.117 +//
 274.118 +// where (I | -A) is an augmented (m+n)xm constraint matrix, I is mxm
 274.119 +// unity matrix whose columns correspond to auxiliary variables, and A
 274.120 +// is the original mxn constraint matrix whose columns correspond to
 274.121 +// structural variables. Note that only the matrix A is stored.
 274.122 +----------------------------------------------------------------------*/
 274.123 +      int m;
 274.124 +      /* number of rows (auxiliary variables), m > 0 */
 274.125 +      int n;
 274.126 +      /* number of columns (structural variables), n > 0 */
 274.127 +      int *type; /* int type[1+m+n]; */
 274.128 +      /* type[0] is not used;
 274.129 +         type[k], 1 <= k <= m+n, is the type of variable x[k]: */
 274.130 +#define SSX_FR          0     /* free (unbounded) variable */
 274.131 +#define SSX_LO          1     /* variable with lower bound */
 274.132 +#define SSX_UP          2     /* variable with upper bound */
 274.133 +#define SSX_DB          3     /* double-bounded variable */
 274.134 +#define SSX_FX          4     /* fixed variable */
 274.135 +      mpq_t *lb; /* mpq_t lb[1+m+n]; alias: l */
 274.136 +      /* lb[0] is not used;
 274.137 +         lb[k], 1 <= k <= m+n, is an lower bound of variable x[k];
 274.138 +         if x[k] has no lower bound, lb[k] is zero */
 274.139 +      mpq_t *ub; /* mpq_t ub[1+m+n]; alias: u */
 274.140 +      /* ub[0] is not used;
 274.141 +         ub[k], 1 <= k <= m+n, is an upper bound of variable x[k];
 274.142 +         if x[k] has no upper bound, ub[k] is zero;
 274.143 +         if x[k] is of fixed type, ub[k] is equal to lb[k] */
 274.144 +      int dir;
 274.145 +      /* optimization direction (sense of the objective function): */
 274.146 +#define SSX_MIN         0     /* minimization */
 274.147 +#define SSX_MAX         1     /* maximization */
 274.148 +      mpq_t *coef; /* mpq_t coef[1+m+n]; alias: c */
 274.149 +      /* coef[0] is a constant term of the objective function;
 274.150 +         coef[k], 1 <= k <= m+n, is a coefficient of the objective
 274.151 +         function at variable x[k];
 274.152 +         note that auxiliary variables also may have non-zero objective
 274.153 +         coefficients */
 274.154 +      int *A_ptr; /* int A_ptr[1+n+1]; */
 274.155 +      int *A_ind; /* int A_ind[A_ptr[n+1]]; */
 274.156 +      mpq_t *A_val; /* mpq_t A_val[A_ptr[n+1]]; */
 274.157 +      /* constraint matrix A (see (5)) in storage-by-columns format */
 274.158 +/*----------------------------------------------------------------------
 274.159 +// LP BASIS AND CURRENT BASIC SOLUTION
 274.160 +//
 274.161 +// The LP basis is defined by the following partition of the augmented
 274.162 +// constraint matrix (7):
 274.163 +//
 274.164 +//    (B | N) = (I | -A) * Q,                                        (8)
 274.165 +//
 274.166 +// where B is a mxm non-singular basis matrix whose columns correspond
 274.167 +// to basic variables xB, N is a mxn matrix whose columns correspond to
 274.168 +// non-basic variables xN, and Q is a permutation (m+n)x(m+n) matrix.
 274.169 +//
 274.170 +// From (7) and (8) it follows that
 274.171 +//
 274.172 +//    (I | -A) * x = (I | -A) * Q * Q' * x = (B | N) * (xB, xN),
 274.173 +//
 274.174 +// therefore
 274.175 +//
 274.176 +//    (xB, xN) = Q' * x,                                             (9)
 274.177 +//
 274.178 +// where x is the vector of all variables in the original order, xB is
 274.179 +// a vector of basic variables, xN is a vector of non-basic variables,
 274.180 +// Q' = inv(Q) is a matrix transposed to Q.
 274.181 +//
 274.182 +// Current values of non-basic variables xN[j], j = 1, ..., n, are not
 274.183 +// stored; they are defined implicitly by their statuses as follows:
 274.184 +//
 274.185 +//    0,             if xN[j] is free variable
 274.186 +//    lN[j],         if xN[j] is on its lower bound                 (10)
 274.187 +//    uN[j],         if xN[j] is on its upper bound
 274.188 +//    lN[j] = uN[j], if xN[j] is fixed variable
 274.189 +//
 274.190 +// where lN[j] and uN[j] are lower and upper bounds of xN[j].
 274.191 +//
 274.192 +// Current values of basic variables xB[i], i = 1, ..., m, are computed
 274.193 +// as follows:
 274.194 +//
 274.195 +//    beta = - inv(B) * N * xN,                                     (11)
 274.196 +//
 274.197 +// where current values of xN are defined by (10).
 274.198 +//
 274.199 +// Current values of simplex multipliers pi[i], i = 1, ..., m (which
 274.200 +// are values of Lagrange multipliers for equality constraints (7) also
 274.201 +// called shadow prices) are computed as follows:
 274.202 +//
 274.203 +//    pi = inv(B') * cB,                                            (12)
 274.204 +//
 274.205 +// where B' is a matrix transposed to B, cB is a vector of objective
 274.206 +// coefficients at basic variables xB.
 274.207 +//
 274.208 +// Current values of reduced costs d[j], j = 1, ..., n, (which are
 274.209 +// values of Langrange multipliers for active inequality constraints
 274.210 +// corresponding to non-basic variables) are computed as follows:
 274.211 +//
 274.212 +//    d = cN - N' * pi,                                             (13)
 274.213 +//
 274.214 +// where N' is a matrix transposed to N, cN is a vector of objective
 274.215 +// coefficients at non-basic variables xN.
 274.216 +----------------------------------------------------------------------*/
 274.217 +      int *stat; /* int stat[1+m+n]; */
 274.218 +      /* stat[0] is not used;
 274.219 +         stat[k], 1 <= k <= m+n, is the status of variable x[k]: */
 274.220 +#define SSX_BS          0     /* basic variable */
 274.221 +#define SSX_NL          1     /* non-basic variable on lower bound */
 274.222 +#define SSX_NU          2     /* non-basic variable on upper bound */
 274.223 +#define SSX_NF          3     /* non-basic free variable */
 274.224 +#define SSX_NS          4     /* non-basic fixed variable */
 274.225 +      int *Q_row; /* int Q_row[1+m+n]; */
 274.226 +      /* matrix Q in row-like format;
 274.227 +         Q_row[0] is not used;
 274.228 +         Q_row[i] = j means that q[i,j] = 1 */
 274.229 +      int *Q_col; /* int Q_col[1+m+n]; */
 274.230 +      /* matrix Q in column-like format;
 274.231 +         Q_col[0] is not used;
 274.232 +         Q_col[j] = i means that q[i,j] = 1 */
 274.233 +      /* if k-th column of the matrix (I | A) is k'-th column of the
 274.234 +         matrix (B | N), then Q_row[k] = k' and Q_col[k'] = k;
 274.235 +         if x[k] is xB[i], then Q_row[k] = i and Q_col[i] = k;
 274.236 +         if x[k] is xN[j], then Q_row[k] = m+j and Q_col[m+j] = k */
 274.237 +      BFX *binv;
 274.238 +      /* invertable form of the basis matrix B */
 274.239 +      mpq_t *bbar; /* mpq_t bbar[1+m]; alias: beta */
 274.240 +      /* bbar[0] is a value of the objective function;
 274.241 +         bbar[i], 1 <= i <= m, is a value of basic variable xB[i] */
 274.242 +      mpq_t *pi; /* mpq_t pi[1+m]; */
 274.243 +      /* pi[0] is not used;
 274.244 +         pi[i], 1 <= i <= m, is a simplex multiplier corresponding to
 274.245 +         i-th row (equality constraint) */
 274.246 +      mpq_t *cbar; /* mpq_t cbar[1+n]; alias: d */
 274.247 +      /* cbar[0] is not used;
 274.248 +         cbar[j], 1 <= j <= n, is a reduced cost of non-basic variable
 274.249 +         xN[j] */
 274.250 +/*----------------------------------------------------------------------
 274.251 +// SIMPLEX TABLE
 274.252 +//
 274.253 +// Due to (8) and (9) the system of equality constraints (7) for the
 274.254 +// current basis can be written as follows:
 274.255 +//
 274.256 +//    xB = A~ * xN,                                                 (14)
 274.257 +//
 274.258 +// where
 274.259 +//
 274.260 +//    A~ = - inv(B) * N                                             (15)
 274.261 +//
 274.262 +// is a mxn matrix called the simplex table.
 274.263 +//
 274.264 +// The revised simplex method uses only two components of A~, namely,
 274.265 +// pivot column corresponding to non-basic variable xN[q] chosen to
 274.266 +// enter the basis, and pivot row corresponding to basic variable xB[p]
 274.267 +// chosen to leave the basis.
 274.268 +//
 274.269 +// Pivot column alfa_q is q-th column of A~, so
 274.270 +//
 274.271 +//    alfa_q = A~ * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q],   (16)
 274.272 +//
 274.273 +// where N[q] is q-th column of the matrix N.
 274.274 +//
 274.275 +// Pivot row alfa_p is p-th row of A~ or, equivalently, p-th column of
 274.276 +// A~', a matrix transposed to A~, so
 274.277 +//
 274.278 +//    alfa_p = A~' * e[p] = - N' * inv(B') * e[p] = - N' * rho_p,   (17)
 274.279 +//
 274.280 +// where (*)' means transposition, and
 274.281 +//
 274.282 +//    rho_p = inv(B') * e[p],                                       (18)
 274.283 +//
 274.284 +// is p-th column of inv(B') or, that is the same, p-th row of inv(B).
 274.285 +----------------------------------------------------------------------*/
 274.286 +      int p;
 274.287 +      /* number of basic variable xB[p], 1 <= p <= m, chosen to leave
 274.288 +         the basis */
 274.289 +      mpq_t *rho; /* mpq_t rho[1+m]; */
 274.290 +      /* p-th row of the inverse inv(B); see (18) */
 274.291 +      mpq_t *ap; /* mpq_t ap[1+n]; */
 274.292 +      /* p-th row of the simplex table; see (17) */
 274.293 +      int q;
 274.294 +      /* number of non-basic variable xN[q], 1 <= q <= n, chosen to
 274.295 +         enter the basis */
 274.296 +      mpq_t *aq; /* mpq_t aq[1+m]; */
 274.297 +      /* q-th column of the simplex table; see (16) */
 274.298 +/*--------------------------------------------------------------------*/
 274.299 +      int q_dir;
 274.300 +      /* direction in which non-basic variable xN[q] should change on
 274.301 +         moving to the adjacent vertex of the polyhedron:
 274.302 +         +1 means that xN[q] increases
 274.303 +         -1 means that xN[q] decreases */
 274.304 +      int p_stat;
 274.305 +      /* non-basic status which should be assigned to basic variable
 274.306 +         xB[p] when it has left the basis and become xN[q] */
 274.307 +      mpq_t delta;
 274.308 +      /* actual change of xN[q] in the adjacent basis (it has the same
 274.309 +         sign as q_dir) */
 274.310 +/*--------------------------------------------------------------------*/
 274.311 +      int it_lim;
 274.312 +      /* simplex iterations limit; if this value is positive, it is
 274.313 +         decreased by one each time when one simplex iteration has been
 274.314 +         performed, and reaching zero value signals the solver to stop
 274.315 +         the search; negative value means no iterations limit */
 274.316 +      int it_cnt;
 274.317 +      /* simplex iterations count; this count is increased by one each
 274.318 +         time when one simplex iteration has been performed */
 274.319 +      double tm_lim;
 274.320 +      /* searching time limit, in seconds; if this value is positive,
 274.321 +         it is decreased each time when one simplex iteration has been
 274.322 +         performed by the amount of time spent for the iteration, and
 274.323 +         reaching zero value signals the solver to stop the search;
 274.324 +         negative value means no time limit */
 274.325 +      double out_frq;
 274.326 +      /* output frequency, in seconds; this parameter specifies how
 274.327 +         frequently the solver sends information about the progress of
 274.328 +         the search to the standard output */
 274.329 +      glp_long tm_beg;
 274.330 +      /* starting time of the search, in seconds; the total time of the
 274.331 +         search is the difference between xtime() and tm_beg */
 274.332 +      glp_long tm_lag;
 274.333 +      /* the most recent time, in seconds, at which the progress of the
 274.334 +         the search was displayed */
 274.335 +};
 274.336 +
 274.337 +#define ssx_create            _glp_ssx_create
 274.338 +#define ssx_factorize         _glp_ssx_factorize
 274.339 +#define ssx_get_xNj           _glp_ssx_get_xNj
 274.340 +#define ssx_eval_bbar         _glp_ssx_eval_bbar
 274.341 +#define ssx_eval_pi           _glp_ssx_eval_pi
 274.342 +#define ssx_eval_dj           _glp_ssx_eval_dj
 274.343 +#define ssx_eval_cbar         _glp_ssx_eval_cbar
 274.344 +#define ssx_eval_rho          _glp_ssx_eval_rho
 274.345 +#define ssx_eval_row          _glp_ssx_eval_row
 274.346 +#define ssx_eval_col          _glp_ssx_eval_col
 274.347 +#define ssx_chuzc             _glp_ssx_chuzc
 274.348 +#define ssx_chuzr             _glp_ssx_chuzr
 274.349 +#define ssx_update_bbar       _glp_ssx_update_bbar
 274.350 +#define ssx_update_pi         _glp_ssx_update_pi
 274.351 +#define ssx_update_cbar       _glp_ssx_update_cbar
 274.352 +#define ssx_change_basis      _glp_ssx_change_basis
 274.353 +#define ssx_delete            _glp_ssx_delete
 274.354 +
 274.355 +#define ssx_phase_I           _glp_ssx_phase_I
 274.356 +#define ssx_phase_II          _glp_ssx_phase_II
 274.357 +#define ssx_driver            _glp_ssx_driver
 274.358 +
 274.359 +SSX *ssx_create(int m, int n, int nnz);
 274.360 +/* create simplex solver workspace */
 274.361 +
 274.362 +int ssx_factorize(SSX *ssx);
 274.363 +/* factorize the current basis matrix */
 274.364 +
 274.365 +void ssx_get_xNj(SSX *ssx, int j, mpq_t x);
 274.366 +/* determine value of non-basic variable */
 274.367 +
 274.368 +void ssx_eval_bbar(SSX *ssx);
 274.369 +/* compute values of basic variables */
 274.370 +
 274.371 +void ssx_eval_pi(SSX *ssx);
 274.372 +/* compute values of simplex multipliers */
 274.373 +
 274.374 +void ssx_eval_dj(SSX *ssx, int j, mpq_t dj);
 274.375 +/* compute reduced cost of non-basic variable */
 274.376 +
 274.377 +void ssx_eval_cbar(SSX *ssx);
 274.378 +/* compute reduced costs of all non-basic variables */
 274.379 +
 274.380 +void ssx_eval_rho(SSX *ssx);
 274.381 +/* compute p-th row of the inverse */
 274.382 +
 274.383 +void ssx_eval_row(SSX *ssx);
 274.384 +/* compute pivot row of the simplex table */
 274.385 +
 274.386 +void ssx_eval_col(SSX *ssx);
 274.387 +/* compute pivot column of the simplex table */
 274.388 +
 274.389 +void ssx_chuzc(SSX *ssx);
 274.390 +/* choose pivot column */
 274.391 +
 274.392 +void ssx_chuzr(SSX *ssx);
 274.393 +/* choose pivot row */
 274.394 +
 274.395 +void ssx_update_bbar(SSX *ssx);
 274.396 +/* update values of basic variables */
 274.397 +
 274.398 +void ssx_update_pi(SSX *ssx);
 274.399 +/* update simplex multipliers */
 274.400 +
 274.401 +void ssx_update_cbar(SSX *ssx);
 274.402 +/* update reduced costs of non-basic variables */
 274.403 +
 274.404 +void ssx_change_basis(SSX *ssx);
 274.405 +/* change current basis to adjacent one */
 274.406 +
 274.407 +void ssx_delete(SSX *ssx);
 274.408 +/* delete simplex solver workspace */
 274.409 +
 274.410 +int ssx_phase_I(SSX *ssx);
 274.411 +/* find primal feasible solution */
 274.412 +
 274.413 +int ssx_phase_II(SSX *ssx);
 274.414 +/* find optimal solution */
 274.415 +
 274.416 +int ssx_driver(SSX *ssx);
 274.417 +/* base driver to exact simplex method */
 274.418 +
 274.419 +#endif
 274.420 +
 274.421 +/* eof */
   275.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   275.2 +++ b/src/glpssx01.c	Mon Dec 06 13:09:21 2010 +0100
   275.3 @@ -0,0 +1,839 @@
   275.4 +/* glpssx01.c */
   275.5 +
   275.6 +/***********************************************************************
   275.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   275.8 +*
   275.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  275.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  275.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  275.12 +*  E-mail: <mao@gnu.org>.
  275.13 +*
  275.14 +*  GLPK is free software: you can redistribute it and/or modify it
  275.15 +*  under the terms of the GNU General Public License as published by
  275.16 +*  the Free Software Foundation, either version 3 of the License, or
  275.17 +*  (at your option) any later version.
  275.18 +*
  275.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  275.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  275.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  275.22 +*  License for more details.
  275.23 +*
  275.24 +*  You should have received a copy of the GNU General Public License
  275.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  275.26 +***********************************************************************/
  275.27 +
  275.28 +#include "glpenv.h"
  275.29 +#include "glpssx.h"
  275.30 +#define xfault xerror
  275.31 +
  275.32 +/*----------------------------------------------------------------------
  275.33 +// ssx_create - create simplex solver workspace.
  275.34 +//
  275.35 +// This routine creates the workspace used by simplex solver routines,
  275.36 +// and returns a pointer to it.
  275.37 +//
  275.38 +// Parameters m, n, and nnz specify, respectively, the number of rows,
  275.39 +// columns, and non-zero constraint coefficients.
  275.40 +//
  275.41 +// This routine only allocates the memory for the workspace components,
  275.42 +// so the workspace needs to be saturated by data. */
  275.43 +
  275.44 +SSX *ssx_create(int m, int n, int nnz)
  275.45 +{     SSX *ssx;
  275.46 +      int i, j, k;
  275.47 +      if (m < 1)
  275.48 +         xfault("ssx_create: m = %d; invalid number of rows\n", m);
  275.49 +      if (n < 1)
  275.50 +         xfault("ssx_create: n = %d; invalid number of columns\n", n);
  275.51 +      if (nnz < 0)
  275.52 +         xfault("ssx_create: nnz = %d; invalid number of non-zero const"
  275.53 +            "raint coefficients\n", nnz);
  275.54 +      ssx = xmalloc(sizeof(SSX));
  275.55 +      ssx->m = m;
  275.56 +      ssx->n = n;
  275.57 +      ssx->type = xcalloc(1+m+n, sizeof(int));
  275.58 +      ssx->lb = xcalloc(1+m+n, sizeof(mpq_t));
  275.59 +      for (k = 1; k <= m+n; k++) mpq_init(ssx->lb[k]);
  275.60 +      ssx->ub = xcalloc(1+m+n, sizeof(mpq_t));
  275.61 +      for (k = 1; k <= m+n; k++) mpq_init(ssx->ub[k]);
  275.62 +      ssx->coef = xcalloc(1+m+n, sizeof(mpq_t));
  275.63 +      for (k = 0; k <= m+n; k++) mpq_init(ssx->coef[k]);
  275.64 +      ssx->A_ptr = xcalloc(1+n+1, sizeof(int));
  275.65 +      ssx->A_ptr[n+1] = nnz+1;
  275.66 +      ssx->A_ind = xcalloc(1+nnz, sizeof(int));
  275.67 +      ssx->A_val = xcalloc(1+nnz, sizeof(mpq_t));
  275.68 +      for (k = 1; k <= nnz; k++) mpq_init(ssx->A_val[k]);
  275.69 +      ssx->stat = xcalloc(1+m+n, sizeof(int));
  275.70 +      ssx->Q_row = xcalloc(1+m+n, sizeof(int));
  275.71 +      ssx->Q_col = xcalloc(1+m+n, sizeof(int));
  275.72 +      ssx->binv = bfx_create_binv();
  275.73 +      ssx->bbar = xcalloc(1+m, sizeof(mpq_t));
  275.74 +      for (i = 0; i <= m; i++) mpq_init(ssx->bbar[i]);
  275.75 +      ssx->pi = xcalloc(1+m, sizeof(mpq_t));
  275.76 +      for (i = 1; i <= m; i++) mpq_init(ssx->pi[i]);
  275.77 +      ssx->cbar = xcalloc(1+n, sizeof(mpq_t));
  275.78 +      for (j = 1; j <= n; j++) mpq_init(ssx->cbar[j]);
  275.79 +      ssx->rho = xcalloc(1+m, sizeof(mpq_t));
  275.80 +      for (i = 1; i <= m; i++) mpq_init(ssx->rho[i]);
  275.81 +      ssx->ap = xcalloc(1+n, sizeof(mpq_t));
  275.82 +      for (j = 1; j <= n; j++) mpq_init(ssx->ap[j]);
  275.83 +      ssx->aq = xcalloc(1+m, sizeof(mpq_t));
  275.84 +      for (i = 1; i <= m; i++) mpq_init(ssx->aq[i]);
  275.85 +      mpq_init(ssx->delta);
  275.86 +      return ssx;
  275.87 +}
  275.88 +
  275.89 +/*----------------------------------------------------------------------
  275.90 +// ssx_factorize - factorize the current basis matrix.
  275.91 +//
  275.92 +// This routine computes factorization of the current basis matrix B
  275.93 +// and returns the singularity flag. If the matrix B is non-singular,
  275.94 +// the flag is zero, otherwise non-zero. */
  275.95 +
  275.96 +static int basis_col(void *info, int j, int ind[], mpq_t val[])
  275.97 +{     /* this auxiliary routine provides row indices and numeric values
  275.98 +         of non-zero elements in j-th column of the matrix B */
  275.99 +      SSX *ssx = info;
 275.100 +      int m = ssx->m;
 275.101 +      int n = ssx->n;
 275.102 +      int *A_ptr = ssx->A_ptr;
 275.103 +      int *A_ind = ssx->A_ind;
 275.104 +      mpq_t *A_val = ssx->A_val;
 275.105 +      int *Q_col = ssx->Q_col;
 275.106 +      int k, len, ptr;
 275.107 +      xassert(1 <= j && j <= m);
 275.108 +      k = Q_col[j]; /* x[k] = xB[j] */
 275.109 +      xassert(1 <= k && k <= m+n);
 275.110 +      /* j-th column of the matrix B is k-th column of the augmented
 275.111 +         constraint matrix (I | -A) */
 275.112 +      if (k <= m)
 275.113 +      {  /* it is a column of the unity matrix I */
 275.114 +         len = 1, ind[1] = k, mpq_set_si(val[1], 1, 1);
 275.115 +      }
 275.116 +      else
 275.117 +      {  /* it is a column of the original constraint matrix -A */
 275.118 +         len = 0;
 275.119 +         for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
 275.120 +         {  len++;
 275.121 +            ind[len] = A_ind[ptr];
 275.122 +            mpq_neg(val[len], A_val[ptr]);
 275.123 +         }
 275.124 +      }
 275.125 +      return len;
 275.126 +}
 275.127 +
 275.128 +int ssx_factorize(SSX *ssx)
 275.129 +{     int ret;
 275.130 +      ret = bfx_factorize(ssx->binv, ssx->m, basis_col, ssx);
 275.131 +      return ret;
 275.132 +}
 275.133 +
 275.134 +/*----------------------------------------------------------------------
 275.135 +// ssx_get_xNj - determine value of non-basic variable.
 275.136 +//
 275.137 +// This routine determines the value of non-basic variable xN[j] in the
 275.138 +// current basic solution defined as follows:
 275.139 +//
 275.140 +//    0,             if xN[j] is free variable
 275.141 +//    lN[j],         if xN[j] is on its lower bound
 275.142 +//    uN[j],         if xN[j] is on its upper bound
 275.143 +//    lN[j] = uN[j], if xN[j] is fixed variable
 275.144 +//
 275.145 +// where lN[j] and uN[j] are lower and upper bounds of xN[j]. */
 275.146 +
 275.147 +void ssx_get_xNj(SSX *ssx, int j, mpq_t x)
 275.148 +{     int m = ssx->m;
 275.149 +      int n = ssx->n;
 275.150 +      mpq_t *lb = ssx->lb;
 275.151 +      mpq_t *ub = ssx->ub;
 275.152 +      int *stat = ssx->stat;
 275.153 +      int *Q_col = ssx->Q_col;
 275.154 +      int k;
 275.155 +      xassert(1 <= j && j <= n);
 275.156 +      k = Q_col[m+j]; /* x[k] = xN[j] */
 275.157 +      xassert(1 <= k && k <= m+n);
 275.158 +      switch (stat[k])
 275.159 +      {  case SSX_NL:
 275.160 +            /* xN[j] is on its lower bound */
 275.161 +            mpq_set(x, lb[k]); break;
 275.162 +         case SSX_NU:
 275.163 +            /* xN[j] is on its upper bound */
 275.164 +            mpq_set(x, ub[k]); break;
 275.165 +         case SSX_NF:
 275.166 +            /* xN[j] is free variable */
 275.167 +            mpq_set_si(x, 0, 1); break;
 275.168 +         case SSX_NS:
 275.169 +            /* xN[j] is fixed variable */
 275.170 +            mpq_set(x, lb[k]); break;
 275.171 +         default:
 275.172 +            xassert(stat != stat);
 275.173 +      }
 275.174 +      return;
 275.175 +}
 275.176 +
 275.177 +/*----------------------------------------------------------------------
 275.178 +// ssx_eval_bbar - compute values of basic variables.
 275.179 +//
 275.180 +// This routine computes values of basic variables xB in the current
 275.181 +// basic solution as follows:
 275.182 +//
 275.183 +//    beta = - inv(B) * N * xN,
 275.184 +//
 275.185 +// where B is the basis matrix, N is the matrix of non-basic columns,
 275.186 +// xN is a vector of current values of non-basic variables. */
 275.187 +
 275.188 +void ssx_eval_bbar(SSX *ssx)
 275.189 +{     int m = ssx->m;
 275.190 +      int n = ssx->n;
 275.191 +      mpq_t *coef = ssx->coef;
 275.192 +      int *A_ptr = ssx->A_ptr;
 275.193 +      int *A_ind = ssx->A_ind;
 275.194 +      mpq_t *A_val = ssx->A_val;
 275.195 +      int *Q_col = ssx->Q_col;
 275.196 +      mpq_t *bbar = ssx->bbar;
 275.197 +      int i, j, k, ptr;
 275.198 +      mpq_t x, temp;
 275.199 +      mpq_init(x);
 275.200 +      mpq_init(temp);
 275.201 +      /* bbar := 0 */
 275.202 +      for (i = 1; i <= m; i++)
 275.203 +         mpq_set_si(bbar[i], 0, 1);
 275.204 +      /* bbar := - N * xN = - N[1] * xN[1] - ... - N[n] * xN[n] */
 275.205 +      for (j = 1; j <= n; j++)
 275.206 +      {  ssx_get_xNj(ssx, j, x);
 275.207 +         if (mpq_sgn(x) == 0) continue;
 275.208 +         k = Q_col[m+j]; /* x[k] = xN[j] */
 275.209 +         if (k <= m)
 275.210 +         {  /* N[j] is a column of the unity matrix I */
 275.211 +            mpq_sub(bbar[k], bbar[k], x);
 275.212 +         }
 275.213 +         else
 275.214 +         {  /* N[j] is a column of the original constraint matrix -A */
 275.215 +            for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
 275.216 +            {  mpq_mul(temp, A_val[ptr], x);
 275.217 +               mpq_add(bbar[A_ind[ptr]], bbar[A_ind[ptr]], temp);
 275.218 +            }
 275.219 +         }
 275.220 +      }
 275.221 +      /* bbar := inv(B) * bbar */
 275.222 +      bfx_ftran(ssx->binv, bbar, 0);
 275.223 +#if 1
 275.224 +      /* compute value of the objective function */
 275.225 +      /* bbar[0] := c[0] */
 275.226 +      mpq_set(bbar[0], coef[0]);
 275.227 +      /* bbar[0] := bbar[0] + sum{i in B} cB[i] * xB[i] */
 275.228 +      for (i = 1; i <= m; i++)
 275.229 +      {  k = Q_col[i]; /* x[k] = xB[i] */
 275.230 +         if (mpq_sgn(coef[k]) == 0) continue;
 275.231 +         mpq_mul(temp, coef[k], bbar[i]);
 275.232 +         mpq_add(bbar[0], bbar[0], temp);
 275.233 +      }
 275.234 +      /* bbar[0] := bbar[0] + sum{j in N} cN[j] * xN[j] */
 275.235 +      for (j = 1; j <= n; j++)
 275.236 +      {  k = Q_col[m+j]; /* x[k] = xN[j] */
 275.237 +         if (mpq_sgn(coef[k]) == 0) continue;
 275.238 +         ssx_get_xNj(ssx, j, x);
 275.239 +         mpq_mul(temp, coef[k], x);
 275.240 +         mpq_add(bbar[0], bbar[0], temp);
 275.241 +      }
 275.242 +#endif
 275.243 +      mpq_clear(x);
 275.244 +      mpq_clear(temp);
 275.245 +      return;
 275.246 +}
 275.247 +
 275.248 +/*----------------------------------------------------------------------
 275.249 +// ssx_eval_pi - compute values of simplex multipliers.
 275.250 +//
 275.251 +// This routine computes values of simplex multipliers (shadow prices)
 275.252 +// pi in the current basic solution as follows:
 275.253 +//
 275.254 +//    pi = inv(B') * cB,
 275.255 +//
 275.256 +// where B' is a matrix transposed to the basis matrix B, cB is a vector
 275.257 +// of objective coefficients at basic variables xB. */
 275.258 +
 275.259 +void ssx_eval_pi(SSX *ssx)
 275.260 +{     int m = ssx->m;
 275.261 +      mpq_t *coef = ssx->coef;
 275.262 +      int *Q_col = ssx->Q_col;
 275.263 +      mpq_t *pi = ssx->pi;
 275.264 +      int i;
 275.265 +      /* pi := cB */
 275.266 +      for (i = 1; i <= m; i++) mpq_set(pi[i], coef[Q_col[i]]);
 275.267 +      /* pi := inv(B') * cB */
 275.268 +      bfx_btran(ssx->binv, pi);
 275.269 +      return;
 275.270 +}
 275.271 +
 275.272 +/*----------------------------------------------------------------------
 275.273 +// ssx_eval_dj - compute reduced cost of non-basic variable.
 275.274 +//
 275.275 +// This routine computes reduced cost d[j] of non-basic variable xN[j]
 275.276 +// in the current basic solution as follows:
 275.277 +//
 275.278 +//    d[j] = cN[j] - N[j] * pi,
 275.279 +//
 275.280 +// where cN[j] is an objective coefficient at xN[j], N[j] is a column
 275.281 +// of the augmented constraint matrix (I | -A) corresponding to xN[j],
 275.282 +// pi is the vector of simplex multipliers (shadow prices). */
 275.283 +
 275.284 +void ssx_eval_dj(SSX *ssx, int j, mpq_t dj)
 275.285 +{     int m = ssx->m;
 275.286 +      int n = ssx->n;
 275.287 +      mpq_t *coef = ssx->coef;
 275.288 +      int *A_ptr = ssx->A_ptr;
 275.289 +      int *A_ind = ssx->A_ind;
 275.290 +      mpq_t *A_val = ssx->A_val;
 275.291 +      int *Q_col = ssx->Q_col;
 275.292 +      mpq_t *pi = ssx->pi;
 275.293 +      int k, ptr, end;
 275.294 +      mpq_t temp;
 275.295 +      mpq_init(temp);
 275.296 +      xassert(1 <= j && j <= n);
 275.297 +      k = Q_col[m+j]; /* x[k] = xN[j] */
 275.298 +      xassert(1 <= k && k <= m+n);
 275.299 +      /* j-th column of the matrix N is k-th column of the augmented
 275.300 +         constraint matrix (I | -A) */
 275.301 +      if (k <= m)
 275.302 +      {  /* it is a column of the unity matrix I */
 275.303 +         mpq_sub(dj, coef[k], pi[k]);
 275.304 +      }
 275.305 +      else
 275.306 +      {  /* it is a column of the original constraint matrix -A */
 275.307 +         mpq_set(dj, coef[k]);
 275.308 +         for (ptr = A_ptr[k-m], end = A_ptr[k-m+1]; ptr < end; ptr++)
 275.309 +         {  mpq_mul(temp, A_val[ptr], pi[A_ind[ptr]]);
 275.310 +            mpq_add(dj, dj, temp);
 275.311 +         }
 275.312 +      }
 275.313 +      mpq_clear(temp);
 275.314 +      return;
 275.315 +}
 275.316 +
 275.317 +/*----------------------------------------------------------------------
 275.318 +// ssx_eval_cbar - compute reduced costs of all non-basic variables.
 275.319 +//
 275.320 +// This routine computes the vector of reduced costs pi in the current
 275.321 +// basic solution for all non-basic variables, including fixed ones. */
 275.322 +
 275.323 +void ssx_eval_cbar(SSX *ssx)
 275.324 +{     int n = ssx->n;
 275.325 +      mpq_t *cbar = ssx->cbar;
 275.326 +      int j;
 275.327 +      for (j = 1; j <= n; j++)
 275.328 +         ssx_eval_dj(ssx, j, cbar[j]);
 275.329 +      return;
 275.330 +}
 275.331 +
 275.332 +/*----------------------------------------------------------------------
 275.333 +// ssx_eval_rho - compute p-th row of the inverse.
 275.334 +//
 275.335 +// This routine computes p-th row of the matrix inv(B), where B is the
 275.336 +// current basis matrix.
 275.337 +//
 275.338 +// p-th row of the inverse is computed using the following formula:
 275.339 +//
 275.340 +//    rho = inv(B') * e[p],
 275.341 +//
 275.342 +// where B' is a matrix transposed to B, e[p] is a unity vector, which
 275.343 +// contains one in p-th position. */
 275.344 +
 275.345 +void ssx_eval_rho(SSX *ssx)
 275.346 +{     int m = ssx->m;
 275.347 +      int p = ssx->p;
 275.348 +      mpq_t *rho = ssx->rho;
 275.349 +      int i;
 275.350 +      xassert(1 <= p && p <= m);
 275.351 +      /* rho := 0 */
 275.352 +      for (i = 1; i <= m; i++) mpq_set_si(rho[i], 0, 1);
 275.353 +      /* rho := e[p] */
 275.354 +      mpq_set_si(rho[p], 1, 1);
 275.355 +      /* rho := inv(B') * rho */
 275.356 +      bfx_btran(ssx->binv, rho);
 275.357 +      return;
 275.358 +}
 275.359 +
 275.360 +/*----------------------------------------------------------------------
 275.361 +// ssx_eval_row - compute pivot row of the simplex table.
 275.362 +//
 275.363 +// This routine computes p-th (pivot) row of the current simplex table
 275.364 +// A~ = - inv(B) * N using the following formula:
 275.365 +//
 275.366 +//    A~[p] = - N' * inv(B') * e[p] = - N' * rho[p],
 275.367 +//
 275.368 +// where N' is a matrix transposed to the matrix N, rho[p] is p-th row
 275.369 +// of the inverse inv(B). */
 275.370 +
 275.371 +void ssx_eval_row(SSX *ssx)
 275.372 +{     int m = ssx->m;
 275.373 +      int n = ssx->n;
 275.374 +      int *A_ptr = ssx->A_ptr;
 275.375 +      int *A_ind = ssx->A_ind;
 275.376 +      mpq_t *A_val = ssx->A_val;
 275.377 +      int *Q_col = ssx->Q_col;
 275.378 +      mpq_t *rho = ssx->rho;
 275.379 +      mpq_t *ap = ssx->ap;
 275.380 +      int j, k, ptr;
 275.381 +      mpq_t temp;
 275.382 +      mpq_init(temp);
 275.383 +      for (j = 1; j <= n; j++)
 275.384 +      {  /* ap[j] := - N'[j] * rho (inner product) */
 275.385 +         k = Q_col[m+j]; /* x[k] = xN[j] */
 275.386 +         if (k <= m)
 275.387 +            mpq_neg(ap[j], rho[k]);
 275.388 +         else
 275.389 +         {  mpq_set_si(ap[j], 0, 1);
 275.390 +            for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
 275.391 +            {  mpq_mul(temp, A_val[ptr], rho[A_ind[ptr]]);
 275.392 +               mpq_add(ap[j], ap[j], temp);
 275.393 +            }
 275.394 +         }
 275.395 +      }
 275.396 +      mpq_clear(temp);
 275.397 +      return;
 275.398 +}
 275.399 +
 275.400 +/*----------------------------------------------------------------------
 275.401 +// ssx_eval_col - compute pivot column of the simplex table.
 275.402 +//
 275.403 +// This routine computes q-th (pivot) column of the current simplex
 275.404 +// table A~ = - inv(B) * N using the following formula:
 275.405 +//
 275.406 +//    A~[q] = - inv(B) * N[q],
 275.407 +//
 275.408 +// where N[q] is q-th column of the matrix N corresponding to chosen
 275.409 +// non-basic variable xN[q]. */
 275.410 +
 275.411 +void ssx_eval_col(SSX *ssx)
 275.412 +{     int m = ssx->m;
 275.413 +      int n = ssx->n;
 275.414 +      int *A_ptr = ssx->A_ptr;
 275.415 +      int *A_ind = ssx->A_ind;
 275.416 +      mpq_t *A_val = ssx->A_val;
 275.417 +      int *Q_col = ssx->Q_col;
 275.418 +      int q = ssx->q;
 275.419 +      mpq_t *aq = ssx->aq;
 275.420 +      int i, k, ptr;
 275.421 +      xassert(1 <= q && q <= n);
 275.422 +      /* aq := 0 */
 275.423 +      for (i = 1; i <= m; i++) mpq_set_si(aq[i], 0, 1);
 275.424 +      /* aq := N[q] */
 275.425 +      k = Q_col[m+q]; /* x[k] = xN[q] */
 275.426 +      if (k <= m)
 275.427 +      {  /* N[q] is a column of the unity matrix I */
 275.428 +         mpq_set_si(aq[k], 1, 1);
 275.429 +      }
 275.430 +      else
 275.431 +      {  /* N[q] is a column of the original constraint matrix -A */
 275.432 +         for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
 275.433 +            mpq_neg(aq[A_ind[ptr]], A_val[ptr]);
 275.434 +      }
 275.435 +      /* aq := inv(B) * aq */
 275.436 +      bfx_ftran(ssx->binv, aq, 1);
 275.437 +      /* aq := - aq */
 275.438 +      for (i = 1; i <= m; i++) mpq_neg(aq[i], aq[i]);
 275.439 +      return;
 275.440 +}
 275.441 +
 275.442 +/*----------------------------------------------------------------------
 275.443 +// ssx_chuzc - choose pivot column.
 275.444 +//
 275.445 +// This routine chooses non-basic variable xN[q] whose reduced cost
 275.446 +// indicates possible improving of the objective function to enter it
 275.447 +// in the basis.
 275.448 +//
 275.449 +// Currently the standard (textbook) pricing is used, i.e. that
 275.450 +// non-basic variable is preferred which has greatest reduced cost (in
 275.451 +// magnitude).
 275.452 +//
 275.453 +// If xN[q] has been chosen, the routine stores its number q and also
 275.454 +// sets the flag q_dir that indicates direction in which xN[q] has to
 275.455 +// change (+1 means increasing, -1 means decreasing).
 275.456 +//
 275.457 +// If the choice cannot be made, because the current basic solution is
 275.458 +// dual feasible, the routine sets the number q to 0. */
 275.459 +
 275.460 +void ssx_chuzc(SSX *ssx)
 275.461 +{     int m = ssx->m;
 275.462 +      int n = ssx->n;
 275.463 +      int dir = (ssx->dir == SSX_MIN ? +1 : -1);
 275.464 +      int *Q_col = ssx->Q_col;
 275.465 +      int *stat = ssx->stat;
 275.466 +      mpq_t *cbar = ssx->cbar;
 275.467 +      int j, k, s, q, q_dir;
 275.468 +      double best, temp;
 275.469 +      /* nothing is chosen so far */
 275.470 +      q = 0, q_dir = 0, best = 0.0;
 275.471 +      /* look through the list of non-basic variables */
 275.472 +      for (j = 1; j <= n; j++)
 275.473 +      {  k = Q_col[m+j]; /* x[k] = xN[j] */
 275.474 +         s = dir * mpq_sgn(cbar[j]);
 275.475 +         if ((stat[k] == SSX_NF || stat[k] == SSX_NL) && s < 0 ||
 275.476 +             (stat[k] == SSX_NF || stat[k] == SSX_NU) && s > 0)
 275.477 +         {  /* reduced cost of xN[j] indicates possible improving of
 275.478 +               the objective function */
 275.479 +            temp = fabs(mpq_get_d(cbar[j]));
 275.480 +            xassert(temp != 0.0);
 275.481 +            if (q == 0 || best < temp)
 275.482 +               q = j, q_dir = - s, best = temp;
 275.483 +         }
 275.484 +      }
 275.485 +      ssx->q = q, ssx->q_dir = q_dir;
 275.486 +      return;
 275.487 +}
 275.488 +
 275.489 +/*----------------------------------------------------------------------
 275.490 +// ssx_chuzr - choose pivot row.
 275.491 +//
 275.492 +// This routine looks through elements of q-th column of the simplex
 275.493 +// table and chooses basic variable xB[p] which should leave the basis.
 275.494 +//
 275.495 +// The choice is based on the standard (textbook) ratio test.
 275.496 +//
 275.497 +// If xB[p] has been chosen, the routine stores its number p and also
 275.498 +// sets its non-basic status p_stat which should be assigned to xB[p]
 275.499 +// when it has left the basis and become xN[q].
 275.500 +//
 275.501 +// Special case p < 0 means that xN[q] is double-bounded variable and
 275.502 +// it reaches its opposite bound before any basic variable does that,
 275.503 +// so the current basis remains unchanged.
 275.504 +//
 275.505 +// If the choice cannot be made, because xN[q] can infinitely change in
 275.506 +// the feasible direction, the routine sets the number p to 0. */
 275.507 +
 275.508 +void ssx_chuzr(SSX *ssx)
 275.509 +{     int m = ssx->m;
 275.510 +      int n = ssx->n;
 275.511 +      int *type = ssx->type;
 275.512 +      mpq_t *lb = ssx->lb;
 275.513 +      mpq_t *ub = ssx->ub;
 275.514 +      int *Q_col = ssx->Q_col;
 275.515 +      mpq_t *bbar = ssx->bbar;
 275.516 +      int q = ssx->q;
 275.517 +      mpq_t *aq = ssx->aq;
 275.518 +      int q_dir = ssx->q_dir;
 275.519 +      int i, k, s, t, p, p_stat;
 275.520 +      mpq_t teta, temp;
 275.521 +      mpq_init(teta);
 275.522 +      mpq_init(temp);
 275.523 +      xassert(1 <= q && q <= n);
 275.524 +      xassert(q_dir == +1 || q_dir == -1);
 275.525 +      /* nothing is chosen so far */
 275.526 +      p = 0, p_stat = 0;
 275.527 +      /* look through the list of basic variables */
 275.528 +      for (i = 1; i <= m; i++)
 275.529 +      {  s = q_dir * mpq_sgn(aq[i]);
 275.530 +         if (s < 0)
 275.531 +         {  /* xB[i] decreases */
 275.532 +            k = Q_col[i]; /* x[k] = xB[i] */
 275.533 +            t = type[k];
 275.534 +            if (t == SSX_LO || t == SSX_DB || t == SSX_FX)
 275.535 +            {  /* xB[i] has finite lower bound */
 275.536 +               mpq_sub(temp, bbar[i], lb[k]);
 275.537 +               mpq_div(temp, temp, aq[i]);
 275.538 +               mpq_abs(temp, temp);
 275.539 +               if (p == 0 || mpq_cmp(teta, temp) > 0)
 275.540 +               {  p = i;
 275.541 +                  p_stat = (t == SSX_FX ? SSX_NS : SSX_NL);
 275.542 +                  mpq_set(teta, temp);
 275.543 +               }
 275.544 +            }
 275.545 +         }
 275.546 +         else if (s > 0)
 275.547 +         {  /* xB[i] increases */
 275.548 +            k = Q_col[i]; /* x[k] = xB[i] */
 275.549 +            t = type[k];
 275.550 +            if (t == SSX_UP || t == SSX_DB || t == SSX_FX)
 275.551 +            {  /* xB[i] has finite upper bound */
 275.552 +               mpq_sub(temp, bbar[i], ub[k]);
 275.553 +               mpq_div(temp, temp, aq[i]);
 275.554 +               mpq_abs(temp, temp);
 275.555 +               if (p == 0 || mpq_cmp(teta, temp) > 0)
 275.556 +               {  p = i;
 275.557 +                  p_stat = (t == SSX_FX ? SSX_NS : SSX_NU);
 275.558 +                  mpq_set(teta, temp);
 275.559 +               }
 275.560 +            }
 275.561 +         }
 275.562 +         /* if something has been chosen and the ratio test indicates
 275.563 +            exact degeneracy, the search can be finished */
 275.564 +         if (p != 0 && mpq_sgn(teta) == 0) break;
 275.565 +      }
 275.566 +      /* if xN[q] is double-bounded, check if it can reach its opposite
 275.567 +         bound before any basic variable */
 275.568 +      k = Q_col[m+q]; /* x[k] = xN[q] */
 275.569 +      if (type[k] == SSX_DB)
 275.570 +      {  mpq_sub(temp, ub[k], lb[k]);
 275.571 +         if (p == 0 || mpq_cmp(teta, temp) > 0)
 275.572 +         {  p = -1;
 275.573 +            p_stat = -1;
 275.574 +            mpq_set(teta, temp);
 275.575 +         }
 275.576 +      }
 275.577 +      ssx->p = p;
 275.578 +      ssx->p_stat = p_stat;
 275.579 +      /* if xB[p] has been chosen, determine its actual change in the
 275.580 +         adjacent basis (it has the same sign as q_dir) */
 275.581 +      if (p != 0)
 275.582 +      {  xassert(mpq_sgn(teta) >= 0);
 275.583 +         if (q_dir > 0)
 275.584 +            mpq_set(ssx->delta, teta);
 275.585 +         else
 275.586 +            mpq_neg(ssx->delta, teta);
 275.587 +      }
 275.588 +      mpq_clear(teta);
 275.589 +      mpq_clear(temp);
 275.590 +      return;
 275.591 +}
 275.592 +
 275.593 +/*----------------------------------------------------------------------
 275.594 +// ssx_update_bbar - update values of basic variables.
 275.595 +//
 275.596 +// This routine recomputes the current values of basic variables for
 275.597 +// the adjacent basis.
 275.598 +//
 275.599 +// The simplex table for the current basis is the following:
 275.600 +//
 275.601 +//    xB[i] = sum{j in 1..n} alfa[i,j] * xN[q],  i = 1,...,m
 275.602 +//
 275.603 +// therefore
 275.604 +//
 275.605 +//    delta xB[i] = alfa[i,q] * delta xN[q],  i = 1,...,m
 275.606 +//
 275.607 +// where delta xN[q] = xN.new[q] - xN[q] is the change of xN[q] in the
 275.608 +// adjacent basis, and delta xB[i] = xB.new[i] - xB[i] is the change of
 275.609 +// xB[i]. This gives formulae for recomputing values of xB[i]:
 275.610 +//
 275.611 +//    xB.new[p] = xN[q] + delta xN[q]
 275.612 +//
 275.613 +// (because xN[q] becomes xB[p] in the adjacent basis), and
 275.614 +//
 275.615 +//    xB.new[i] = xB[i] + alfa[i,q] * delta xN[q],  i != p
 275.616 +//
 275.617 +// for other basic variables. */
 275.618 +
 275.619 +void ssx_update_bbar(SSX *ssx)
 275.620 +{     int m = ssx->m;
 275.621 +      int n = ssx->n;
 275.622 +      mpq_t *bbar = ssx->bbar;
 275.623 +      mpq_t *cbar = ssx->cbar;
 275.624 +      int p = ssx->p;
 275.625 +      int q = ssx->q;
 275.626 +      mpq_t *aq = ssx->aq;
 275.627 +      int i;
 275.628 +      mpq_t temp;
 275.629 +      mpq_init(temp);
 275.630 +      xassert(1 <= q && q <= n);
 275.631 +      if (p < 0)
 275.632 +      {  /* xN[q] is double-bounded and goes to its opposite bound */
 275.633 +         /* nop */;
 275.634 +      }
 275.635 +      else
 275.636 +      {  /* xN[q] becomes xB[p] in the adjacent basis */
 275.637 +         /* xB.new[p] = xN[q] + delta xN[q] */
 275.638 +         xassert(1 <= p && p <= m);
 275.639 +         ssx_get_xNj(ssx, q, temp);
 275.640 +         mpq_add(bbar[p], temp, ssx->delta);
 275.641 +      }
 275.642 +      /* update values of other basic variables depending on xN[q] */
 275.643 +      for (i = 1; i <= m; i++)
 275.644 +      {  if (i == p) continue;
 275.645 +         /* xB.new[i] = xB[i] + alfa[i,q] * delta xN[q] */
 275.646 +         if (mpq_sgn(aq[i]) == 0) continue;
 275.647 +         mpq_mul(temp, aq[i], ssx->delta);
 275.648 +         mpq_add(bbar[i], bbar[i], temp);
 275.649 +      }
 275.650 +#if 1
 275.651 +      /* update value of the objective function */
 275.652 +      /* z.new = z + d[q] * delta xN[q] */
 275.653 +      mpq_mul(temp, cbar[q], ssx->delta);
 275.654 +      mpq_add(bbar[0], bbar[0], temp);
 275.655 +#endif
 275.656 +      mpq_clear(temp);
 275.657 +      return;
 275.658 +}
 275.659 +
 275.660 +/*----------------------------------------------------------------------
 275.661 +-- ssx_update_pi - update simplex multipliers.
 275.662 +--
 275.663 +-- This routine recomputes the vector of simplex multipliers for the
 275.664 +-- adjacent basis. */
 275.665 +
 275.666 +void ssx_update_pi(SSX *ssx)
 275.667 +{     int m = ssx->m;
 275.668 +      int n = ssx->n;
 275.669 +      mpq_t *pi = ssx->pi;
 275.670 +      mpq_t *cbar = ssx->cbar;
 275.671 +      int p = ssx->p;
 275.672 +      int q = ssx->q;
 275.673 +      mpq_t *aq = ssx->aq;
 275.674 +      mpq_t *rho = ssx->rho;
 275.675 +      int i;
 275.676 +      mpq_t new_dq, temp;
 275.677 +      mpq_init(new_dq);
 275.678 +      mpq_init(temp);
 275.679 +      xassert(1 <= p && p <= m);
 275.680 +      xassert(1 <= q && q <= n);
 275.681 +      /* compute d[q] in the adjacent basis */
 275.682 +      mpq_div(new_dq, cbar[q], aq[p]);
 275.683 +      /* update the vector of simplex multipliers */
 275.684 +      for (i = 1; i <= m; i++)
 275.685 +      {  if (mpq_sgn(rho[i]) == 0) continue;
 275.686 +         mpq_mul(temp, new_dq, rho[i]);
 275.687 +         mpq_sub(pi[i], pi[i], temp);
 275.688 +      }
 275.689 +      mpq_clear(new_dq);
 275.690 +      mpq_clear(temp);
 275.691 +      return;
 275.692 +}
 275.693 +
 275.694 +/*----------------------------------------------------------------------
 275.695 +// ssx_update_cbar - update reduced costs of non-basic variables.
 275.696 +//
 275.697 +// This routine recomputes the vector of reduced costs of non-basic
 275.698 +// variables for the adjacent basis. */
 275.699 +
 275.700 +void ssx_update_cbar(SSX *ssx)
 275.701 +{     int m = ssx->m;
 275.702 +      int n = ssx->n;
 275.703 +      mpq_t *cbar = ssx->cbar;
 275.704 +      int p = ssx->p;
 275.705 +      int q = ssx->q;
 275.706 +      mpq_t *ap = ssx->ap;
 275.707 +      int j;
 275.708 +      mpq_t temp;
 275.709 +      mpq_init(temp);
 275.710 +      xassert(1 <= p && p <= m);
 275.711 +      xassert(1 <= q && q <= n);
 275.712 +      /* compute d[q] in the adjacent basis */
 275.713 +      /* d.new[q] = d[q] / alfa[p,q] */
 275.714 +      mpq_div(cbar[q], cbar[q], ap[q]);
 275.715 +      /* update reduced costs of other non-basic variables */
 275.716 +      for (j = 1; j <= n; j++)
 275.717 +      {  if (j == q) continue;
 275.718 +         /* d.new[j] = d[j] - (alfa[p,j] / alfa[p,q]) * d[q] */
 275.719 +         if (mpq_sgn(ap[j]) == 0) continue;
 275.720 +         mpq_mul(temp, ap[j], cbar[q]);
 275.721 +         mpq_sub(cbar[j], cbar[j], temp);
 275.722 +      }
 275.723 +      mpq_clear(temp);
 275.724 +      return;
 275.725 +}
 275.726 +
 275.727 +/*----------------------------------------------------------------------
 275.728 +// ssx_change_basis - change current basis to adjacent one.
 275.729 +//
 275.730 +// This routine changes the current basis to the adjacent one swapping
 275.731 +// basic variable xB[p] and non-basic variable xN[q]. */
 275.732 +
 275.733 +void ssx_change_basis(SSX *ssx)
 275.734 +{     int m = ssx->m;
 275.735 +      int n = ssx->n;
 275.736 +      int *type = ssx->type;
 275.737 +      int *stat = ssx->stat;
 275.738 +      int *Q_row = ssx->Q_row;
 275.739 +      int *Q_col = ssx->Q_col;
 275.740 +      int p = ssx->p;
 275.741 +      int q = ssx->q;
 275.742 +      int p_stat = ssx->p_stat;
 275.743 +      int k, kp, kq;
 275.744 +      if (p < 0)
 275.745 +      {  /* special case: xN[q] goes to its opposite bound */
 275.746 +         xassert(1 <= q && q <= n);
 275.747 +         k = Q_col[m+q]; /* x[k] = xN[q] */
 275.748 +         xassert(type[k] == SSX_DB);
 275.749 +         switch (stat[k])
 275.750 +         {  case SSX_NL:
 275.751 +               stat[k] = SSX_NU;
 275.752 +               break;
 275.753 +            case SSX_NU:
 275.754 +               stat[k] = SSX_NL;
 275.755 +               break;
 275.756 +            default:
 275.757 +               xassert(stat != stat);
 275.758 +         }
 275.759 +      }
 275.760 +      else
 275.761 +      {  /* xB[p] leaves the basis, xN[q] enters the basis */
 275.762 +         xassert(1 <= p && p <= m);
 275.763 +         xassert(1 <= q && q <= n);
 275.764 +         kp = Q_col[p];   /* x[kp] = xB[p] */
 275.765 +         kq = Q_col[m+q]; /* x[kq] = xN[q] */
 275.766 +         /* check non-basic status of xB[p] which becomes xN[q] */
 275.767 +         switch (type[kp])
 275.768 +         {  case SSX_FR:
 275.769 +               xassert(p_stat == SSX_NF);
 275.770 +               break;
 275.771 +            case SSX_LO:
 275.772 +               xassert(p_stat == SSX_NL);
 275.773 +               break;
 275.774 +            case SSX_UP:
 275.775 +               xassert(p_stat == SSX_NU);
 275.776 +               break;
 275.777 +            case SSX_DB:
 275.778 +               xassert(p_stat == SSX_NL || p_stat == SSX_NU);
 275.779 +               break;
 275.780 +            case SSX_FX:
 275.781 +               xassert(p_stat == SSX_NS);
 275.782 +               break;
 275.783 +            default:
 275.784 +               xassert(type != type);
 275.785 +         }
 275.786 +         /* swap xB[p] and xN[q] */
 275.787 +         stat[kp] = (char)p_stat, stat[kq] = SSX_BS;
 275.788 +         Q_row[kp] = m+q, Q_row[kq] = p;
 275.789 +         Q_col[p] = kq, Q_col[m+q] = kp;
 275.790 +         /* update factorization of the basis matrix */
 275.791 +         if (bfx_update(ssx->binv, p))
 275.792 +         {  if (ssx_factorize(ssx))
 275.793 +               xassert(("Internal error: basis matrix is singular", 0));
 275.794 +         }
 275.795 +      }
 275.796 +      return;
 275.797 +}
 275.798 +
 275.799 +/*----------------------------------------------------------------------
 275.800 +// ssx_delete - delete simplex solver workspace.
 275.801 +//
 275.802 +// This routine deletes the simplex solver workspace freeing all the
 275.803 +// memory allocated to this object. */
 275.804 +
 275.805 +void ssx_delete(SSX *ssx)
 275.806 +{     int m = ssx->m;
 275.807 +      int n = ssx->n;
 275.808 +      int nnz = ssx->A_ptr[n+1]-1;
 275.809 +      int i, j, k;
 275.810 +      xfree(ssx->type);
 275.811 +      for (k = 1; k <= m+n; k++) mpq_clear(ssx->lb[k]);
 275.812 +      xfree(ssx->lb);
 275.813 +      for (k = 1; k <= m+n; k++) mpq_clear(ssx->ub[k]);
 275.814 +      xfree(ssx->ub);
 275.815 +      for (k = 0; k <= m+n; k++) mpq_clear(ssx->coef[k]);
 275.816 +      xfree(ssx->coef);
 275.817 +      xfree(ssx->A_ptr);
 275.818 +      xfree(ssx->A_ind);
 275.819 +      for (k = 1; k <= nnz; k++) mpq_clear(ssx->A_val[k]);
 275.820 +      xfree(ssx->A_val);
 275.821 +      xfree(ssx->stat);
 275.822 +      xfree(ssx->Q_row);
 275.823 +      xfree(ssx->Q_col);
 275.824 +      bfx_delete_binv(ssx->binv);
 275.825 +      for (i = 0; i <= m; i++) mpq_clear(ssx->bbar[i]);
 275.826 +      xfree(ssx->bbar);
 275.827 +      for (i = 1; i <= m; i++) mpq_clear(ssx->pi[i]);
 275.828 +      xfree(ssx->pi);
 275.829 +      for (j = 1; j <= n; j++) mpq_clear(ssx->cbar[j]);
 275.830 +      xfree(ssx->cbar);
 275.831 +      for (i = 1; i <= m; i++) mpq_clear(ssx->rho[i]);
 275.832 +      xfree(ssx->rho);
 275.833 +      for (j = 1; j <= n; j++) mpq_clear(ssx->ap[j]);
 275.834 +      xfree(ssx->ap);
 275.835 +      for (i = 1; i <= m; i++) mpq_clear(ssx->aq[i]);
 275.836 +      xfree(ssx->aq);
 275.837 +      mpq_clear(ssx->delta);
 275.838 +      xfree(ssx);
 275.839 +      return;
 275.840 +}
 275.841 +
 275.842 +/* eof */
   276.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   276.2 +++ b/src/glpssx02.c	Mon Dec 06 13:09:21 2010 +0100
   276.3 @@ -0,0 +1,479 @@
   276.4 +/* glpssx02.c */
   276.5 +
   276.6 +/***********************************************************************
   276.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   276.8 +*
   276.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  276.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  276.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  276.12 +*  E-mail: <mao@gnu.org>.
  276.13 +*
  276.14 +*  GLPK is free software: you can redistribute it and/or modify it
  276.15 +*  under the terms of the GNU General Public License as published by
  276.16 +*  the Free Software Foundation, either version 3 of the License, or
  276.17 +*  (at your option) any later version.
  276.18 +*
  276.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  276.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  276.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  276.22 +*  License for more details.
  276.23 +*
  276.24 +*  You should have received a copy of the GNU General Public License
  276.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  276.26 +***********************************************************************/
  276.27 +
  276.28 +#include "glpenv.h"
  276.29 +#include "glpssx.h"
  276.30 +
  276.31 +static void show_progress(SSX *ssx, int phase)
  276.32 +{     /* this auxiliary routine displays information about progress of
  276.33 +         the search */
  276.34 +      int i, def = 0;
  276.35 +      for (i = 1; i <= ssx->m; i++)
  276.36 +         if (ssx->type[ssx->Q_col[i]] == SSX_FX) def++;
  276.37 +      xprintf("%s%6d:   %s = %22.15g   (%d)\n", phase == 1 ? " " : "*",
  276.38 +         ssx->it_cnt, phase == 1 ? "infsum" : "objval",
  276.39 +         mpq_get_d(ssx->bbar[0]), def);
  276.40 +#if 0
  276.41 +      ssx->tm_lag = utime();
  276.42 +#else
  276.43 +      ssx->tm_lag = xtime();
  276.44 +#endif
  276.45 +      return;
  276.46 +}
  276.47 +
  276.48 +/*----------------------------------------------------------------------
  276.49 +// ssx_phase_I - find primal feasible solution.
  276.50 +//
  276.51 +// This routine implements phase I of the primal simplex method.
  276.52 +//
  276.53 +// On exit the routine returns one of the following codes:
  276.54 +//
  276.55 +// 0 - feasible solution found;
  276.56 +// 1 - problem has no feasible solution;
  276.57 +// 2 - iterations limit exceeded;
  276.58 +// 3 - time limit exceeded.
  276.59 +----------------------------------------------------------------------*/
  276.60 +
  276.61 +int ssx_phase_I(SSX *ssx)
  276.62 +{     int m = ssx->m;
  276.63 +      int n = ssx->n;
  276.64 +      int *type = ssx->type;
  276.65 +      mpq_t *lb = ssx->lb;
  276.66 +      mpq_t *ub = ssx->ub;
  276.67 +      mpq_t *coef = ssx->coef;
  276.68 +      int *A_ptr = ssx->A_ptr;
  276.69 +      int *A_ind = ssx->A_ind;
  276.70 +      mpq_t *A_val = ssx->A_val;
  276.71 +      int *Q_col = ssx->Q_col;
  276.72 +      mpq_t *bbar = ssx->bbar;
  276.73 +      mpq_t *pi = ssx->pi;
  276.74 +      mpq_t *cbar = ssx->cbar;
  276.75 +      int *orig_type, orig_dir;
  276.76 +      mpq_t *orig_lb, *orig_ub, *orig_coef;
  276.77 +      int i, k, ret;
  276.78 +      /* save components of the original LP problem, which are changed
  276.79 +         by the routine */
  276.80 +      orig_type = xcalloc(1+m+n, sizeof(int));
  276.81 +      orig_lb = xcalloc(1+m+n, sizeof(mpq_t));
  276.82 +      orig_ub = xcalloc(1+m+n, sizeof(mpq_t));
  276.83 +      orig_coef = xcalloc(1+m+n, sizeof(mpq_t));
  276.84 +      for (k = 1; k <= m+n; k++)
  276.85 +      {  orig_type[k] = type[k];
  276.86 +         mpq_init(orig_lb[k]);
  276.87 +         mpq_set(orig_lb[k], lb[k]);
  276.88 +         mpq_init(orig_ub[k]);
  276.89 +         mpq_set(orig_ub[k], ub[k]);
  276.90 +      }
  276.91 +      orig_dir = ssx->dir;
  276.92 +      for (k = 0; k <= m+n; k++)
  276.93 +      {  mpq_init(orig_coef[k]);
  276.94 +         mpq_set(orig_coef[k], coef[k]);
  276.95 +      }
  276.96 +      /* build an artificial basic solution, which is primal feasible,
  276.97 +         and also build an auxiliary objective function to minimize the
  276.98 +         sum of infeasibilities for the original problem */
  276.99 +      ssx->dir = SSX_MIN;
 276.100 +      for (k = 0; k <= m+n; k++) mpq_set_si(coef[k], 0, 1);
 276.101 +      mpq_set_si(bbar[0], 0, 1);
 276.102 +      for (i = 1; i <= m; i++)
 276.103 +      {  int t;
 276.104 +         k = Q_col[i]; /* x[k] = xB[i] */
 276.105 +         t = type[k];
 276.106 +         if (t == SSX_LO || t == SSX_DB || t == SSX_FX)
 276.107 +         {  /* in the original problem x[k] has lower bound */
 276.108 +            if (mpq_cmp(bbar[i], lb[k]) < 0)
 276.109 +            {  /* which is violated */
 276.110 +               type[k] = SSX_UP;
 276.111 +               mpq_set(ub[k], lb[k]);
 276.112 +               mpq_set_si(lb[k], 0, 1);
 276.113 +               mpq_set_si(coef[k], -1, 1);
 276.114 +               mpq_add(bbar[0], bbar[0], ub[k]);
 276.115 +               mpq_sub(bbar[0], bbar[0], bbar[i]);
 276.116 +            }
 276.117 +         }
 276.118 +         if (t == SSX_UP || t == SSX_DB || t == SSX_FX)
 276.119 +         {  /* in the original problem x[k] has upper bound */
 276.120 +            if (mpq_cmp(bbar[i], ub[k]) > 0)
 276.121 +            {  /* which is violated */
 276.122 +               type[k] = SSX_LO;
 276.123 +               mpq_set(lb[k], ub[k]);
 276.124 +               mpq_set_si(ub[k], 0, 1);
 276.125 +               mpq_set_si(coef[k], +1, 1);
 276.126 +               mpq_add(bbar[0], bbar[0], bbar[i]);
 276.127 +               mpq_sub(bbar[0], bbar[0], lb[k]);
 276.128 +            }
 276.129 +         }
 276.130 +      }
 276.131 +      /* now the initial basic solution should be primal feasible due
 276.132 +         to changes of bounds of some basic variables, which turned to
 276.133 +         implicit artifical variables */
 276.134 +      /* compute simplex multipliers and reduced costs */
 276.135 +      ssx_eval_pi(ssx);
 276.136 +      ssx_eval_cbar(ssx);
 276.137 +      /* display initial progress of the search */
 276.138 +      show_progress(ssx, 1);
 276.139 +      /* main loop starts here */
 276.140 +      for (;;)
 276.141 +      {  /* display current progress of the search */
 276.142 +#if 0
 276.143 +         if (utime() - ssx->tm_lag >= ssx->out_frq - 0.001)
 276.144 +#else
 276.145 +         if (xdifftime(xtime(), ssx->tm_lag) >= ssx->out_frq - 0.001)
 276.146 +#endif
 276.147 +            show_progress(ssx, 1);
 276.148 +         /* we do not need to wait until all artificial variables have
 276.149 +            left the basis */
 276.150 +         if (mpq_sgn(bbar[0]) == 0)
 276.151 +         {  /* the sum of infeasibilities is zero, therefore the current
 276.152 +               solution is primal feasible for the original problem */
 276.153 +            ret = 0;
 276.154 +            break;
 276.155 +         }
 276.156 +         /* check if the iterations limit has been exhausted */
 276.157 +         if (ssx->it_lim == 0)
 276.158 +         {  ret = 2;
 276.159 +            break;
 276.160 +         }
 276.161 +         /* check if the time limit has been exhausted */
 276.162 +#if 0
 276.163 +         if (ssx->tm_lim >= 0.0 && ssx->tm_lim <= utime() - ssx->tm_beg)
 276.164 +#else
 276.165 +         if (ssx->tm_lim >= 0.0 &&
 276.166 +             ssx->tm_lim <= xdifftime(xtime(), ssx->tm_beg))
 276.167 +#endif
 276.168 +         {  ret = 3;
 276.169 +            break;
 276.170 +         }
 276.171 +         /* choose non-basic variable xN[q] */
 276.172 +         ssx_chuzc(ssx);
 276.173 +         /* if xN[q] cannot be chosen, the sum of infeasibilities is
 276.174 +            minimal but non-zero; therefore the original problem has no
 276.175 +            primal feasible solution */
 276.176 +         if (ssx->q == 0)
 276.177 +         {  ret = 1;
 276.178 +            break;
 276.179 +         }
 276.180 +         /* compute q-th column of the simplex table */
 276.181 +         ssx_eval_col(ssx);
 276.182 +         /* choose basic variable xB[p] */
 276.183 +         ssx_chuzr(ssx);
 276.184 +         /* the sum of infeasibilities cannot be negative, therefore
 276.185 +            the auxiliary lp problem cannot have unbounded solution */
 276.186 +         xassert(ssx->p != 0);
 276.187 +         /* update values of basic variables */
 276.188 +         ssx_update_bbar(ssx);
 276.189 +         if (ssx->p > 0)
 276.190 +         {  /* compute p-th row of the inverse inv(B) */
 276.191 +            ssx_eval_rho(ssx);
 276.192 +            /* compute p-th row of the simplex table */
 276.193 +            ssx_eval_row(ssx);
 276.194 +            xassert(mpq_cmp(ssx->aq[ssx->p], ssx->ap[ssx->q]) == 0);
 276.195 +            /* update simplex multipliers */
 276.196 +            ssx_update_pi(ssx);
 276.197 +            /* update reduced costs of non-basic variables */
 276.198 +            ssx_update_cbar(ssx);
 276.199 +         }
 276.200 +         /* xB[p] is leaving the basis; if it is implicit artificial
 276.201 +            variable, the corresponding residual vanishes; therefore
 276.202 +            bounds of this variable should be restored to the original
 276.203 +            values */
 276.204 +         if (ssx->p > 0)
 276.205 +         {  k = Q_col[ssx->p]; /* x[k] = xB[p] */
 276.206 +            if (type[k] != orig_type[k])
 276.207 +            {  /* x[k] is implicit artificial variable */
 276.208 +               type[k] = orig_type[k];
 276.209 +               mpq_set(lb[k], orig_lb[k]);
 276.210 +               mpq_set(ub[k], orig_ub[k]);
 276.211 +               xassert(ssx->p_stat == SSX_NL || ssx->p_stat == SSX_NU);
 276.212 +               ssx->p_stat = (ssx->p_stat == SSX_NL ? SSX_NU : SSX_NL);
 276.213 +               if (type[k] == SSX_FX) ssx->p_stat = SSX_NS;
 276.214 +               /* nullify the objective coefficient at x[k] */
 276.215 +               mpq_set_si(coef[k], 0, 1);
 276.216 +               /* since coef[k] has been changed, we need to compute
 276.217 +                  new reduced cost of x[k], which it will have in the
 276.218 +                  adjacent basis */
 276.219 +               /* the formula d[j] = cN[j] - pi' * N[j] is used (note
 276.220 +                  that the vector pi is not changed, because it depends
 276.221 +                  on objective coefficients at basic variables, but in
 276.222 +                  the adjacent basis, for which the vector pi has been
 276.223 +                  just recomputed, x[k] is non-basic) */
 276.224 +               if (k <= m)
 276.225 +               {  /* x[k] is auxiliary variable */
 276.226 +                  mpq_neg(cbar[ssx->q], pi[k]);
 276.227 +               }
 276.228 +               else
 276.229 +               {  /* x[k] is structural variable */
 276.230 +                  int ptr;
 276.231 +                  mpq_t temp;
 276.232 +                  mpq_init(temp);
 276.233 +                  mpq_set_si(cbar[ssx->q], 0, 1);
 276.234 +                  for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
 276.235 +                  {  mpq_mul(temp, pi[A_ind[ptr]], A_val[ptr]);
 276.236 +                     mpq_add(cbar[ssx->q], cbar[ssx->q], temp);
 276.237 +                  }
 276.238 +                  mpq_clear(temp);
 276.239 +               }
 276.240 +            }
 276.241 +         }
 276.242 +         /* jump to the adjacent vertex of the polyhedron */
 276.243 +         ssx_change_basis(ssx);
 276.244 +         /* one simplex iteration has been performed */
 276.245 +         if (ssx->it_lim > 0) ssx->it_lim--;
 276.246 +         ssx->it_cnt++;
 276.247 +      }
 276.248 +      /* display final progress of the search */
 276.249 +      show_progress(ssx, 1);
 276.250 +      /* restore components of the original problem, which were changed
 276.251 +         by the routine */
 276.252 +      for (k = 1; k <= m+n; k++)
 276.253 +      {  type[k] = orig_type[k];
 276.254 +         mpq_set(lb[k], orig_lb[k]);
 276.255 +         mpq_clear(orig_lb[k]);
 276.256 +         mpq_set(ub[k], orig_ub[k]);
 276.257 +         mpq_clear(orig_ub[k]);
 276.258 +      }
 276.259 +      ssx->dir = orig_dir;
 276.260 +      for (k = 0; k <= m+n; k++)
 276.261 +      {  mpq_set(coef[k], orig_coef[k]);
 276.262 +         mpq_clear(orig_coef[k]);
 276.263 +      }
 276.264 +      xfree(orig_type);
 276.265 +      xfree(orig_lb);
 276.266 +      xfree(orig_ub);
 276.267 +      xfree(orig_coef);
 276.268 +      /* return to the calling program */
 276.269 +      return ret;
 276.270 +}
 276.271 +
 276.272 +/*----------------------------------------------------------------------
 276.273 +// ssx_phase_II - find optimal solution.
 276.274 +//
 276.275 +// This routine implements phase II of the primal simplex method.
 276.276 +//
 276.277 +// On exit the routine returns one of the following codes:
 276.278 +//
 276.279 +// 0 - optimal solution found;
 276.280 +// 1 - problem has unbounded solution;
 276.281 +// 2 - iterations limit exceeded;
 276.282 +// 3 - time limit exceeded.
 276.283 +----------------------------------------------------------------------*/
 276.284 +
 276.285 +int ssx_phase_II(SSX *ssx)
 276.286 +{     int ret;
 276.287 +      /* display initial progress of the search */
 276.288 +      show_progress(ssx, 2);
 276.289 +      /* main loop starts here */
 276.290 +      for (;;)
 276.291 +      {  /* display current progress of the search */
 276.292 +#if 0
 276.293 +         if (utime() - ssx->tm_lag >= ssx->out_frq - 0.001)
 276.294 +#else
 276.295 +         if (xdifftime(xtime(), ssx->tm_lag) >= ssx->out_frq - 0.001)
 276.296 +#endif
 276.297 +            show_progress(ssx, 2);
 276.298 +         /* check if the iterations limit has been exhausted */
 276.299 +         if (ssx->it_lim == 0)
 276.300 +         {  ret = 2;
 276.301 +            break;
 276.302 +         }
 276.303 +         /* check if the time limit has been exhausted */
 276.304 +#if 0
 276.305 +         if (ssx->tm_lim >= 0.0 && ssx->tm_lim <= utime() - ssx->tm_beg)
 276.306 +#else
 276.307 +         if (ssx->tm_lim >= 0.0 &&
 276.308 +             ssx->tm_lim <= xdifftime(xtime(), ssx->tm_beg))
 276.309 +#endif
 276.310 +         {  ret = 3;
 276.311 +            break;
 276.312 +         }
 276.313 +         /* choose non-basic variable xN[q] */
 276.314 +         ssx_chuzc(ssx);
 276.315 +         /* if xN[q] cannot be chosen, the current basic solution is
 276.316 +            dual feasible and therefore optimal */
 276.317 +         if (ssx->q == 0)
 276.318 +         {  ret = 0;
 276.319 +            break;
 276.320 +         }
 276.321 +         /* compute q-th column of the simplex table */
 276.322 +         ssx_eval_col(ssx);
 276.323 +         /* choose basic variable xB[p] */
 276.324 +         ssx_chuzr(ssx);
 276.325 +         /* if xB[p] cannot be chosen, the problem has no dual feasible
 276.326 +            solution (i.e. unbounded) */
 276.327 +         if (ssx->p == 0)
 276.328 +         {  ret = 1;
 276.329 +            break;
 276.330 +         }
 276.331 +         /* update values of basic variables */
 276.332 +         ssx_update_bbar(ssx);
 276.333 +         if (ssx->p > 0)
 276.334 +         {  /* compute p-th row of the inverse inv(B) */
 276.335 +            ssx_eval_rho(ssx);
 276.336 +            /* compute p-th row of the simplex table */
 276.337 +            ssx_eval_row(ssx);
 276.338 +            xassert(mpq_cmp(ssx->aq[ssx->p], ssx->ap[ssx->q]) == 0);
 276.339 +#if 0
 276.340 +            /* update simplex multipliers */
 276.341 +            ssx_update_pi(ssx);
 276.342 +#endif
 276.343 +            /* update reduced costs of non-basic variables */
 276.344 +            ssx_update_cbar(ssx);
 276.345 +         }
 276.346 +         /* jump to the adjacent vertex of the polyhedron */
 276.347 +         ssx_change_basis(ssx);
 276.348 +         /* one simplex iteration has been performed */
 276.349 +         if (ssx->it_lim > 0) ssx->it_lim--;
 276.350 +         ssx->it_cnt++;
 276.351 +      }
 276.352 +      /* display final progress of the search */
 276.353 +      show_progress(ssx, 2);
 276.354 +      /* return to the calling program */
 276.355 +      return ret;
 276.356 +}
 276.357 +
 276.358 +/*----------------------------------------------------------------------
 276.359 +// ssx_driver - base driver to exact simplex method.
 276.360 +//
 276.361 +// This routine is a base driver to a version of the primal simplex
 276.362 +// method using exact (bignum) arithmetic.
 276.363 +//
 276.364 +// On exit the routine returns one of the following codes:
 276.365 +//
 276.366 +// 0 - optimal solution found;
 276.367 +// 1 - problem has no feasible solution;
 276.368 +// 2 - problem has unbounded solution;
 276.369 +// 3 - iterations limit exceeded (phase I);
 276.370 +// 4 - iterations limit exceeded (phase II);
 276.371 +// 5 - time limit exceeded (phase I);
 276.372 +// 6 - time limit exceeded (phase II);
 276.373 +// 7 - initial basis matrix is exactly singular.
 276.374 +----------------------------------------------------------------------*/
 276.375 +
 276.376 +int ssx_driver(SSX *ssx)
 276.377 +{     int m = ssx->m;
 276.378 +      int *type = ssx->type;
 276.379 +      mpq_t *lb = ssx->lb;
 276.380 +      mpq_t *ub = ssx->ub;
 276.381 +      int *Q_col = ssx->Q_col;
 276.382 +      mpq_t *bbar = ssx->bbar;
 276.383 +      int i, k, ret;
 276.384 +      ssx->tm_beg = xtime();
 276.385 +      /* factorize the initial basis matrix */
 276.386 +      if (ssx_factorize(ssx))
 276.387 +      {  xprintf("Initial basis matrix is singular\n");
 276.388 +         ret = 7;
 276.389 +         goto done;
 276.390 +      }
 276.391 +      /* compute values of basic variables */
 276.392 +      ssx_eval_bbar(ssx);
 276.393 +      /* check if the initial basic solution is primal feasible */
 276.394 +      for (i = 1; i <= m; i++)
 276.395 +      {  int t;
 276.396 +         k = Q_col[i]; /* x[k] = xB[i] */
 276.397 +         t = type[k];
 276.398 +         if (t == SSX_LO || t == SSX_DB || t == SSX_FX)
 276.399 +         {  /* x[k] has lower bound */
 276.400 +            if (mpq_cmp(bbar[i], lb[k]) < 0)
 276.401 +            {  /* which is violated */
 276.402 +               break;
 276.403 +            }
 276.404 +         }
 276.405 +         if (t == SSX_UP || t == SSX_DB || t == SSX_FX)
 276.406 +         {  /* x[k] has upper bound */
 276.407 +            if (mpq_cmp(bbar[i], ub[k]) > 0)
 276.408 +            {  /* which is violated */
 276.409 +               break;
 276.410 +            }
 276.411 +         }
 276.412 +      }
 276.413 +      if (i > m)
 276.414 +      {  /* no basic variable violates its bounds */
 276.415 +         ret = 0;
 276.416 +         goto skip;
 276.417 +      }
 276.418 +      /* phase I: find primal feasible solution */
 276.419 +      ret = ssx_phase_I(ssx);
 276.420 +      switch (ret)
 276.421 +      {  case 0:
 276.422 +            ret = 0;
 276.423 +            break;
 276.424 +         case 1:
 276.425 +            xprintf("PROBLEM HAS NO FEASIBLE SOLUTION\n");
 276.426 +            ret = 1;
 276.427 +            break;
 276.428 +         case 2:
 276.429 +            xprintf("ITERATIONS LIMIT EXCEEDED; SEARCH TERMINATED\n");
 276.430 +            ret = 3;
 276.431 +            break;
 276.432 +         case 3:
 276.433 +            xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
 276.434 +            ret = 5;
 276.435 +            break;
 276.436 +         default:
 276.437 +            xassert(ret != ret);
 276.438 +      }
 276.439 +      /* compute values of basic variables (actually only the objective
 276.440 +         value needs to be computed) */
 276.441 +      ssx_eval_bbar(ssx);
 276.442 +skip: /* compute simplex multipliers */
 276.443 +      ssx_eval_pi(ssx);
 276.444 +      /* compute reduced costs of non-basic variables */
 276.445 +      ssx_eval_cbar(ssx);
 276.446 +      /* if phase I failed, do not start phase II */
 276.447 +      if (ret != 0) goto done;
 276.448 +      /* phase II: find optimal solution */
 276.449 +      ret = ssx_phase_II(ssx);
 276.450 +      switch (ret)
 276.451 +      {  case 0:
 276.452 +            xprintf("OPTIMAL SOLUTION FOUND\n");
 276.453 +            ret = 0;
 276.454 +            break;
 276.455 +         case 1:
 276.456 +            xprintf("PROBLEM HAS UNBOUNDED SOLUTION\n");
 276.457 +            ret = 2;
 276.458 +            break;
 276.459 +         case 2:
 276.460 +            xprintf("ITERATIONS LIMIT EXCEEDED; SEARCH TERMINATED\n");
 276.461 +            ret = 4;
 276.462 +            break;
 276.463 +         case 3:
 276.464 +            xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
 276.465 +            ret = 6;
 276.466 +            break;
 276.467 +         default:
 276.468 +            xassert(ret != ret);
 276.469 +      }
 276.470 +done: /* decrease the time limit by the spent amount of time */
 276.471 +      if (ssx->tm_lim >= 0.0)
 276.472 +#if 0
 276.473 +      {  ssx->tm_lim -= utime() - ssx->tm_beg;
 276.474 +#else
 276.475 +      {  ssx->tm_lim -= xdifftime(xtime(), ssx->tm_beg);
 276.476 +#endif
 276.477 +         if (ssx->tm_lim < 0.0) ssx->tm_lim = 0.0;
 276.478 +      }
 276.479 +      return ret;
 276.480 +}
 276.481 +
 276.482 +/* eof */
   277.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   277.2 +++ b/src/glpstd.h	Mon Dec 06 13:09:21 2010 +0100
   277.3 @@ -0,0 +1,43 @@
   277.4 +/* glpstd.h (standard C headers) */
   277.5 +
   277.6 +/***********************************************************************
   277.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   277.8 +*
   277.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  277.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  277.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  277.12 +*  E-mail: <mao@gnu.org>.
  277.13 +*
  277.14 +*  GLPK is free software: you can redistribute it and/or modify it
  277.15 +*  under the terms of the GNU General Public License as published by
  277.16 +*  the Free Software Foundation, either version 3 of the License, or
  277.17 +*  (at your option) any later version.
  277.18 +*
  277.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  277.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  277.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  277.22 +*  License for more details.
  277.23 +*
  277.24 +*  You should have received a copy of the GNU General Public License
  277.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  277.26 +***********************************************************************/
  277.27 +
  277.28 +#ifndef GLPSTD_H
  277.29 +#define GLPSTD_H
  277.30 +
  277.31 +#include <ctype.h>
  277.32 +#include <errno.h>
  277.33 +#include <float.h>
  277.34 +#include <limits.h>
  277.35 +#include <math.h>
  277.36 +#include <setjmp.h>
  277.37 +#include <stdarg.h>
  277.38 +#include <stddef.h>
  277.39 +#include <stdio.h>
  277.40 +#include <stdlib.h>
  277.41 +#include <string.h>
  277.42 +#include <time.h>
  277.43 +
  277.44 +#endif
  277.45 +
  277.46 +/* eof */
   278.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   278.2 +++ b/src/glptsp.c	Mon Dec 06 13:09:21 2010 +0100
   278.3 @@ -0,0 +1,667 @@
   278.4 +/* glptsp.c */
   278.5 +
   278.6 +/***********************************************************************
   278.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   278.8 +*
   278.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  278.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  278.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  278.12 +*  E-mail: <mao@gnu.org>.
  278.13 +*
  278.14 +*  GLPK is free software: you can redistribute it and/or modify it
  278.15 +*  under the terms of the GNU General Public License as published by
  278.16 +*  the Free Software Foundation, either version 3 of the License, or
  278.17 +*  (at your option) any later version.
  278.18 +*
  278.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  278.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  278.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  278.22 +*  License for more details.
  278.23 +*
  278.24 +*  You should have received a copy of the GNU General Public License
  278.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  278.26 +***********************************************************************/
  278.27 +
  278.28 +#define _GLPSTD_ERRNO
  278.29 +#define _GLPSTD_STDIO
  278.30 +#include "glpenv.h"
  278.31 +#include "glptsp.h"
  278.32 +#define xfault xerror
  278.33 +
  278.34 +/*----------------------------------------------------------------------
  278.35 +-- tsp_read_data - read TSP instance data.
  278.36 +--
  278.37 +-- *Synopsis*
  278.38 +--
  278.39 +-- #include "glptsp.h"
  278.40 +-- TSP *tsp_read_data(char *fname);
  278.41 +--
  278.42 +-- *Description*
  278.43 +--
  278.44 +-- The routine tsp_read_data reads a TSP (or related problem) instance
  278.45 +-- data from the text file, whose name is the character string fname.
  278.46 +--
  278.47 +-- For detailed description of the format recognized by the routine see
  278.48 +-- the report: G.Reinelt, TSPLIB 95.
  278.49 +--
  278.50 +-- *Returns*
  278.51 +--
  278.52 +-- If no error occurred, the routine tsp_read_data returns a pointer to
  278.53 +-- the TSP instance data block, which contains loaded data. In the case
  278.54 +-- of error the routine prints an error message and returns NULL. */
  278.55 +
  278.56 +struct dsa
  278.57 +{     /* dynamic storage area used by the routine tsp_read_data */
  278.58 +      char *fname;
  278.59 +      /* name of the input text file */
  278.60 +      FILE *fp;
  278.61 +      /* stream assigned to the input text file */
  278.62 +      int seqn;
  278.63 +      /* line sequential number */
  278.64 +      int c;
  278.65 +      /* current character */
  278.66 +      char token[255+1];
  278.67 +      /* current token */
  278.68 +};
  278.69 +
  278.70 +static int get_char(struct dsa *dsa)
  278.71 +{     dsa->c = fgetc(dsa->fp);
  278.72 +      if (ferror(dsa->fp))
  278.73 +      {  xprintf("%s:%d: read error - %s\n",
  278.74 +            dsa->fname, dsa->seqn, strerror(errno));
  278.75 +         return 1;
  278.76 +      }
  278.77 +      if (feof(dsa->fp))
  278.78 +         dsa->c = EOF;
  278.79 +      else if (dsa->c == '\n')
  278.80 +         dsa->seqn++;
  278.81 +      else if (isspace(dsa->c))
  278.82 +         dsa->c = ' ';
  278.83 +      else if (iscntrl(dsa->c))
  278.84 +      {  xprintf("%s:%d: invalid control character 0x%02X\n",
  278.85 +            dsa->fname, dsa->seqn, dsa->c);
  278.86 +         return 1;
  278.87 +      }
  278.88 +      return 0;
  278.89 +}
  278.90 +
  278.91 +static int skip_spaces(struct dsa *dsa, int across)
  278.92 +{     while (dsa->c == ' ' || (across && dsa->c == '\n'))
  278.93 +         if (get_char(dsa)) return 1;
  278.94 +      return 0;
  278.95 +}
  278.96 +
  278.97 +static int scan_keyword(struct dsa *dsa)
  278.98 +{     int len = 0;
  278.99 +      if (skip_spaces(dsa, 0)) return 1;
 278.100 +      dsa->token[0] = '\0';
 278.101 +      while (isalnum(dsa->c) || dsa->c == '_')
 278.102 +      {  if (len == 31)
 278.103 +         {  xprintf("%s:%d: keyword `%s...' too long\n", dsa->fname,
 278.104 +               dsa->seqn, dsa->token);
 278.105 +            return 1;
 278.106 +         }
 278.107 +         dsa->token[len++] = (char)dsa->c, dsa->token[len] = '\0';
 278.108 +         if (get_char(dsa)) return 1;
 278.109 +      }
 278.110 +      if (len == 0)
 278.111 +      {  xprintf("%s:%d: missing keyword\n", dsa->fname, dsa->seqn);
 278.112 +         return 1;
 278.113 +      }
 278.114 +      return 0;
 278.115 +}
 278.116 +
 278.117 +static int check_colon(struct dsa *dsa)
 278.118 +{     if (skip_spaces(dsa, 0)) return 1;
 278.119 +      if (dsa->c != ':')
 278.120 +      {  xprintf("%s:%d: missing colon after `%s'\n", dsa->fname,
 278.121 +            dsa->seqn, dsa->token);
 278.122 +         return 1;
 278.123 +      }
 278.124 +      if (get_char(dsa)) return 1;
 278.125 +      return 0;
 278.126 +}
 278.127 +
 278.128 +static int scan_token(struct dsa *dsa, int across)
 278.129 +{     int len = 0;
 278.130 +      if (skip_spaces(dsa, across)) return 1;
 278.131 +      dsa->token[0] = '\0';
 278.132 +      while (!(dsa->c == EOF || dsa->c == '\n' || dsa->c == ' '))
 278.133 +      {  if (len == 255)
 278.134 +         {  dsa->token[31] = '\0';
 278.135 +            xprintf("%s:%d: token `%s...' too long\n", dsa->fname,
 278.136 +               dsa->seqn, dsa->token);
 278.137 +            return 1;
 278.138 +         }
 278.139 +         dsa->token[len++] = (char)dsa->c, dsa->token[len] = '\0';
 278.140 +         if (get_char(dsa)) return 1;
 278.141 +      }
 278.142 +      return 0;
 278.143 +}
 278.144 +
 278.145 +static int check_newline(struct dsa *dsa)
 278.146 +{     if (skip_spaces(dsa, 0)) return 1;
 278.147 +      if (!(dsa->c == EOF || dsa->c == '\n'))
 278.148 +      {  xprintf("%s:%d: extra symbols detected\n", dsa->fname,
 278.149 +            dsa->seqn);
 278.150 +         return 1;
 278.151 +      }
 278.152 +      if (get_char(dsa)) return 1;
 278.153 +      return 0;
 278.154 +}
 278.155 +
 278.156 +static int scan_comment(struct dsa *dsa)
 278.157 +{     int len = 0;
 278.158 +      if (skip_spaces(dsa, 0)) return 1;
 278.159 +      dsa->token[0] = '\0';
 278.160 +      while (!(dsa->c == EOF || dsa->c == '\n'))
 278.161 +      {  if (len == 255)
 278.162 +         {  xprintf("%s:%d: comment too long\n", dsa->fname, dsa->seqn)
 278.163 +               ;
 278.164 +            return 1;
 278.165 +         }
 278.166 +         dsa->token[len++] = (char)dsa->c, dsa->token[len] = '\0';
 278.167 +         if (get_char(dsa)) return 1;
 278.168 +      }
 278.169 +      return 0;
 278.170 +}
 278.171 +
 278.172 +static int scan_integer(struct dsa *dsa, int across, int *val)
 278.173 +{     if (scan_token(dsa, across)) return 1;
 278.174 +      if (strlen(dsa->token) == 0)
 278.175 +      {  xprintf("%s:%d: missing integer\n", dsa->fname, dsa->seqn);
 278.176 +         return 1;
 278.177 +      }
 278.178 +      if (str2int(dsa->token, val))
 278.179 +      {  xprintf("%s:%d: integer `%s' invalid\n", dsa->fname, dsa->seqn
 278.180 +            , dsa->token);
 278.181 +         return 1;
 278.182 +      }
 278.183 +      return 0;
 278.184 +}
 278.185 +
 278.186 +static int scan_number(struct dsa *dsa, int across, double *val)
 278.187 +{     if (scan_token(dsa, across)) return 1;
 278.188 +      if (strlen(dsa->token) == 0)
 278.189 +      {  xprintf("%s:%d: missing number\n", dsa->fname, dsa->seqn);
 278.190 +         return 1;
 278.191 +      }
 278.192 +      if (str2num(dsa->token, val))
 278.193 +      {  xprintf("%s:%d: number `%s' invalid\n", dsa->fname, dsa->seqn,
 278.194 +            dsa->token);
 278.195 +         return 1;
 278.196 +      }
 278.197 +      return 0;
 278.198 +}
 278.199 +
 278.200 +TSP *tsp_read_data(char *fname)
 278.201 +{     struct dsa _dsa, *dsa = &_dsa;
 278.202 +      TSP *tsp = NULL;
 278.203 +      dsa->fname = fname;
 278.204 +      xprintf("tsp_read_data: reading TSP data from `%s'...\n",
 278.205 +         dsa->fname);
 278.206 +      dsa->fp = fopen(dsa->fname, "r");
 278.207 +      if (dsa->fp == NULL)
 278.208 +      {  xprintf("tsp_read_data: unable to open `%s' - %s\n",
 278.209 +            dsa->fname, strerror(errno));
 278.210 +         goto fail;
 278.211 +      }
 278.212 +      tsp = xmalloc(sizeof(TSP));
 278.213 +      tsp->name = NULL;
 278.214 +      tsp->type = TSP_UNDEF;
 278.215 +      tsp->comment = NULL;
 278.216 +      tsp->dimension = 0;
 278.217 +      tsp->edge_weight_type = TSP_UNDEF;
 278.218 +      tsp->edge_weight_format = TSP_UNDEF;
 278.219 +      tsp->display_data_type = TSP_UNDEF;
 278.220 +      tsp->node_x_coord = NULL;
 278.221 +      tsp->node_y_coord = NULL;
 278.222 +      tsp->dply_x_coord = NULL;
 278.223 +      tsp->dply_y_coord = NULL;
 278.224 +      tsp->tour = NULL;
 278.225 +      tsp->edge_weight = NULL;
 278.226 +      dsa->seqn = 1;
 278.227 +      if (get_char(dsa)) goto fail;
 278.228 +loop: if (scan_keyword(dsa)) goto fail;
 278.229 +      if (strcmp(dsa->token, "NAME") == 0)
 278.230 +      {  if (tsp->name != NULL)
 278.231 +         {  xprintf("%s:%d: NAME entry multiply defined\n", dsa->fname,
 278.232 +               dsa->seqn);
 278.233 +            goto fail;
 278.234 +         }
 278.235 +         if (check_colon(dsa)) goto fail;
 278.236 +         if (scan_token(dsa, 0)) goto fail;
 278.237 +         if (strlen(dsa->token) == 0)
 278.238 +         {  xprintf("%s:%d: NAME entry incomplete\n", dsa->fname,
 278.239 +               dsa->seqn);
 278.240 +            goto fail;
 278.241 +         }
 278.242 +         tsp->name = xmalloc(strlen(dsa->token) + 1);
 278.243 +         strcpy(tsp->name, dsa->token);
 278.244 +         xprintf("tsp_read_data: NAME: %s\n", tsp->name);
 278.245 +         if (check_newline(dsa)) goto fail;
 278.246 +      }
 278.247 +      else if (strcmp(dsa->token, "TYPE") == 0)
 278.248 +      {  if (tsp->type != TSP_UNDEF)
 278.249 +         {  xprintf("%s:%d: TYPE entry multiply defined\n", dsa->fname,
 278.250 +               dsa->seqn);
 278.251 +            goto fail;
 278.252 +         }
 278.253 +         if (check_colon(dsa)) goto fail;
 278.254 +         if (scan_keyword(dsa)) goto fail;
 278.255 +         if (strcmp(dsa->token, "TSP") == 0)
 278.256 +            tsp->type = TSP_TSP;
 278.257 +         else if (strcmp(dsa->token, "ATSP") == 0)
 278.258 +            tsp->type = TSP_ATSP;
 278.259 +         else if (strcmp(dsa->token, "TOUR") == 0)
 278.260 +            tsp->type = TSP_TOUR;
 278.261 +         else
 278.262 +         {  xprintf("%s:%d: data type `%s' not recognized\n",
 278.263 +               dsa->fname, dsa->seqn, dsa->token);
 278.264 +            goto fail;
 278.265 +         }
 278.266 +         xprintf("tsp_read_data: TYPE: %s\n", dsa->token);
 278.267 +         if (check_newline(dsa)) goto fail;
 278.268 +      }
 278.269 +      else if (strcmp(dsa->token, "COMMENT") == 0)
 278.270 +      {  if (tsp->comment != NULL)
 278.271 +         {  xprintf("%s:%d: COMMENT entry multiply defined\n",
 278.272 +               dsa->fname, dsa->seqn);
 278.273 +            goto fail;
 278.274 +         }
 278.275 +         if (check_colon(dsa)) goto fail;
 278.276 +         if (scan_comment(dsa)) goto fail;
 278.277 +         tsp->comment = xmalloc(strlen(dsa->token) + 1);
 278.278 +         strcpy(tsp->comment, dsa->token);
 278.279 +         xprintf("tsp_read_data: COMMENT: %s\n", tsp->comment);
 278.280 +         if (check_newline(dsa)) goto fail;
 278.281 +      }
 278.282 +      else if (strcmp(dsa->token, "DIMENSION") == 0)
 278.283 +      {  if (tsp->dimension != 0)
 278.284 +         {  xprintf("%s:%d: DIMENSION entry multiply defined\n",
 278.285 +               dsa->fname, dsa->seqn);
 278.286 +            goto fail;
 278.287 +         }
 278.288 +         if (check_colon(dsa)) goto fail;
 278.289 +         if (scan_integer(dsa, 0, &tsp->dimension)) goto fail;
 278.290 +         if (tsp->dimension < 1)
 278.291 +         {  xprintf("%s:%d: invalid dimension\n", dsa->fname,
 278.292 +               dsa->seqn);
 278.293 +            goto fail;
 278.294 +         }
 278.295 +         xprintf("tsp_read_data: DIMENSION: %d\n", tsp->dimension);
 278.296 +         if (check_newline(dsa)) goto fail;
 278.297 +      }
 278.298 +      else if (strcmp(dsa->token, "EDGE_WEIGHT_TYPE") == 0)
 278.299 +      {  if (tsp->edge_weight_type != TSP_UNDEF)
 278.300 +         {  xprintf("%s:%d: EDGE_WEIGHT_TYPE entry multiply defined\n",
 278.301 +               dsa->fname, dsa->seqn);
 278.302 +            goto fail;
 278.303 +         }
 278.304 +         if (check_colon(dsa)) goto fail;
 278.305 +         if (scan_keyword(dsa)) goto fail;
 278.306 +         if (strcmp(dsa->token, "GEO") == 0)
 278.307 +            tsp->edge_weight_type = TSP_GEO;
 278.308 +         else if (strcmp(dsa->token, "EUC_2D") == 0)
 278.309 +            tsp->edge_weight_type = TSP_EUC_2D;
 278.310 +         else if (strcmp(dsa->token, "ATT") == 0)
 278.311 +            tsp->edge_weight_type = TSP_ATT;
 278.312 +         else if (strcmp(dsa->token, "EXPLICIT") == 0)
 278.313 +            tsp->edge_weight_type = TSP_EXPLICIT;
 278.314 +         else if (strcmp(dsa->token, "CEIL_2D") == 0)
 278.315 +            tsp->edge_weight_type = TSP_CEIL_2D;
 278.316 +         else
 278.317 +         {  xprintf("%s:%d: edge weight type `%s' not recognized\n",
 278.318 +               dsa->fname, dsa->seqn, dsa->token);
 278.319 +            goto fail;
 278.320 +         }
 278.321 +         xprintf("tsp_read_data: EDGE_WEIGHT_TYPE: %s\n", dsa->token);
 278.322 +         if (check_newline(dsa)) goto fail;
 278.323 +      }
 278.324 +      else if (strcmp(dsa->token, "EDGE_WEIGHT_FORMAT") == 0)
 278.325 +      {  if (tsp->edge_weight_format != TSP_UNDEF)
 278.326 +         {  xprintf(
 278.327 +               "%s:%d: EDGE_WEIGHT_FORMAT entry multiply defined\n",
 278.328 +               dsa->fname, dsa->seqn);
 278.329 +            goto fail;
 278.330 +         }
 278.331 +         if (check_colon(dsa)) goto fail;
 278.332 +         if (scan_keyword(dsa)) goto fail;
 278.333 +         if (strcmp(dsa->token, "UPPER_ROW") == 0)
 278.334 +            tsp->edge_weight_format = TSP_UPPER_ROW;
 278.335 +         else if (strcmp(dsa->token, "FULL_MATRIX") == 0)
 278.336 +            tsp->edge_weight_format = TSP_FULL_MATRIX;
 278.337 +         else if (strcmp(dsa->token, "FUNCTION") == 0)
 278.338 +            tsp->edge_weight_format = TSP_FUNCTION;
 278.339 +         else if (strcmp(dsa->token, "LOWER_DIAG_ROW") == 0)
 278.340 +            tsp->edge_weight_format = TSP_LOWER_DIAG_ROW;
 278.341 +         else
 278.342 +         {  xprintf("%s:%d: edge weight format `%s' not recognized\n",
 278.343 +               dsa->fname, dsa->seqn, dsa->token);
 278.344 +            goto fail;
 278.345 +         }
 278.346 +         xprintf("tsp_read_data: EDGE_WEIGHT_FORMAT: %s\n", dsa->token);
 278.347 +         if (check_newline(dsa)) goto fail;
 278.348 +      }
 278.349 +      else if (strcmp(dsa->token, "DISPLAY_DATA_TYPE") == 0)
 278.350 +      {  if (tsp->display_data_type != TSP_UNDEF)
 278.351 +         {  xprintf("%s:%d: DISPLAY_DATA_TYPE entry multiply defined\n",
 278.352 +               dsa->fname, dsa->seqn);
 278.353 +            goto fail;
 278.354 +         }
 278.355 +         if (check_colon(dsa)) goto fail;
 278.356 +         if (scan_keyword(dsa)) goto fail;
 278.357 +         if (strcmp(dsa->token, "COORD_DISPLAY") == 0)
 278.358 +            tsp->display_data_type = TSP_COORD_DISPLAY;
 278.359 +         else if (strcmp(dsa->token, "TWOD_DISPLAY") == 0)
 278.360 +            tsp->display_data_type = TSP_TWOD_DISPLAY;
 278.361 +         else
 278.362 +         {  xprintf("%s:%d: display data type `%s' not recognized\n",
 278.363 +               dsa->fname, dsa->seqn, dsa->token);
 278.364 +            goto fail;
 278.365 +         }
 278.366 +         xprintf("tsp_read_data: DISPLAY_DATA_TYPE: %s\n", dsa->token);
 278.367 +         if (check_newline(dsa)) goto fail;
 278.368 +      }
 278.369 +      else if (strcmp(dsa->token, "NODE_COORD_SECTION") == 0)
 278.370 +      {  int n = tsp->dimension, k, node;
 278.371 +         if (n == 0)
 278.372 +         {  xprintf("%s:%d: DIMENSION entry not specified\n",
 278.373 +               dsa->fname, dsa->seqn);
 278.374 +            goto fail;
 278.375 +         }
 278.376 +         if (tsp->node_x_coord != NULL)
 278.377 +         {  xprintf("%s:%d: NODE_COORD_SECTION multiply specified\n",
 278.378 +               dsa->fname, dsa->seqn);
 278.379 +            goto fail;
 278.380 +         }
 278.381 +         if (check_newline(dsa)) goto fail;
 278.382 +         tsp->node_x_coord = xcalloc(1+n, sizeof(double));
 278.383 +         tsp->node_y_coord = xcalloc(1+n, sizeof(double));
 278.384 +         for (node = 1; node <= n; node++)
 278.385 +            tsp->node_x_coord[node] = tsp->node_y_coord[node] = DBL_MAX;
 278.386 +         for (k = 1; k <= n; k++)
 278.387 +         {  if (scan_integer(dsa, 0, &node)) goto fail;
 278.388 +            if (!(1 <= node && node <= n))
 278.389 +            {  xprintf("%s:%d: invalid node number %d\n", dsa->fname,
 278.390 +                  dsa->seqn, node);
 278.391 +               goto fail;
 278.392 +            }
 278.393 +            if (tsp->node_x_coord[node] != DBL_MAX)
 278.394 +            {  xprintf("%s:%d: node number %d multiply specified\n",
 278.395 +                  dsa->fname, dsa->seqn, node);
 278.396 +               goto fail;
 278.397 +            }
 278.398 +            if (scan_number(dsa, 0, &tsp->node_x_coord[node]))
 278.399 +               goto fail;
 278.400 +            if (scan_number(dsa, 0, &tsp->node_y_coord[node]))
 278.401 +               goto fail;
 278.402 +            if (check_newline(dsa)) goto fail;
 278.403 +         }
 278.404 +      }
 278.405 +      else if (strcmp(dsa->token, "DISPLAY_DATA_SECTION") == 0)
 278.406 +      {  int n = tsp->dimension, k, node;
 278.407 +         if (n == 0)
 278.408 +         {  xprintf("%s:%d: DIMENSION entry not specified\n",
 278.409 +               dsa->fname, dsa->seqn);
 278.410 +            goto fail;
 278.411 +         }
 278.412 +         if (tsp->dply_x_coord != NULL)
 278.413 +         {  xprintf("%s:%d: DISPLAY_DATA_SECTION multiply specified\n",
 278.414 +               dsa->fname, dsa->seqn);
 278.415 +            goto fail;
 278.416 +         }
 278.417 +         if (check_newline(dsa)) goto fail;
 278.418 +         tsp->dply_x_coord = xcalloc(1+n, sizeof(double));
 278.419 +         tsp->dply_y_coord = xcalloc(1+n, sizeof(double));
 278.420 +         for (node = 1; node <= n; node++)
 278.421 +            tsp->dply_x_coord[node] = tsp->dply_y_coord[node] = DBL_MAX;
 278.422 +         for (k = 1; k <= n; k++)
 278.423 +         {  if (scan_integer(dsa, 0, &node)) goto fail;
 278.424 +            if (!(1 <= node && node <= n))
 278.425 +            {  xprintf("%s:%d: invalid node number %d\n", dsa->fname,
 278.426 +                  dsa->seqn, node);
 278.427 +               goto fail;
 278.428 +            }
 278.429 +            if (tsp->dply_x_coord[node] != DBL_MAX)
 278.430 +            {  xprintf("%s:%d: node number %d multiply specified\n",
 278.431 +                  dsa->fname, dsa->seqn, node);
 278.432 +               goto fail;
 278.433 +            }
 278.434 +            if (scan_number(dsa, 0, &tsp->dply_x_coord[node]))
 278.435 +               goto fail;
 278.436 +            if (scan_number(dsa, 0, &tsp->dply_y_coord[node]))
 278.437 +               goto fail;
 278.438 +            if (check_newline(dsa)) goto fail;
 278.439 +         }
 278.440 +      }
 278.441 +      else if (strcmp(dsa->token, "TOUR_SECTION") == 0)
 278.442 +      {  int n = tsp->dimension, k, node;
 278.443 +         if (n == 0)
 278.444 +         {  xprintf("%s:%d: DIMENSION entry not specified\n",
 278.445 +               dsa->fname, dsa->seqn);
 278.446 +            goto fail;
 278.447 +         }
 278.448 +         if (tsp->tour != NULL)
 278.449 +         {  xprintf("%s:%d: TOUR_SECTION multiply specified\n",
 278.450 +               dsa->fname, dsa->seqn);
 278.451 +            goto fail;
 278.452 +         }
 278.453 +         if (check_newline(dsa)) goto fail;
 278.454 +         tsp->tour = xcalloc(1+n, sizeof(int));
 278.455 +         for (k = 1; k <= n; k++)
 278.456 +         {  if (scan_integer(dsa, 1, &node)) goto fail;
 278.457 +            if (!(1 <= node && node <= n))
 278.458 +            {  xprintf("%s:%d: invalid node number %d\n", dsa->fname,
 278.459 +                  dsa->seqn, node);
 278.460 +               goto fail;
 278.461 +            }
 278.462 +            tsp->tour[k] = node;
 278.463 +         }
 278.464 +         if (scan_integer(dsa, 1, &node)) goto fail;
 278.465 +         if (node != -1)
 278.466 +         {  xprintf("%s:%d: extra node(s) detected\n", dsa->fname,
 278.467 +               dsa->seqn);
 278.468 +            goto fail;
 278.469 +         }
 278.470 +         if (check_newline(dsa)) goto fail;
 278.471 +      }
 278.472 +      else if (strcmp(dsa->token, "EDGE_WEIGHT_SECTION") == 0)
 278.473 +      {  int n = tsp->dimension, i, j, temp;
 278.474 +         if (n == 0)
 278.475 +         {  xprintf("%s:%d: DIMENSION entry not specified\n",
 278.476 +               dsa->fname, dsa->seqn);
 278.477 +            goto fail;
 278.478 +         }
 278.479 +         if (tsp->edge_weight_format == TSP_UNDEF)
 278.480 +         {  xprintf("%s:%d: EDGE_WEIGHT_FORMAT entry not specified\n",
 278.481 +               dsa->fname, dsa->seqn);
 278.482 +            goto fail;
 278.483 +         }
 278.484 +         if (tsp->edge_weight != NULL)
 278.485 +         {  xprintf("%s:%d: EDGE_WEIGHT_SECTION multiply specified\n",
 278.486 +               dsa->fname, dsa->seqn);
 278.487 +            goto fail;
 278.488 +         }
 278.489 +         if (check_newline(dsa)) goto fail;
 278.490 +         tsp->edge_weight = xcalloc(1+n*n, sizeof(int));
 278.491 +         switch (tsp->edge_weight_format)
 278.492 +         {  case TSP_FULL_MATRIX:
 278.493 +               for (i = 1; i <= n; i++)
 278.494 +               {  for (j = 1; j <= n; j++)
 278.495 +                  {  if (scan_integer(dsa, 1, &temp)) goto fail;
 278.496 +                     tsp->edge_weight[(i - 1) * n + j] = temp;
 278.497 +                  }
 278.498 +               }
 278.499 +               break;
 278.500 +            case TSP_UPPER_ROW:
 278.501 +               for (i = 1; i <= n; i++)
 278.502 +               {  tsp->edge_weight[(i - 1) * n + i] = 0;
 278.503 +                  for (j = i + 1; j <= n; j++)
 278.504 +                  {  if (scan_integer(dsa, 1, &temp)) goto fail;
 278.505 +                     tsp->edge_weight[(i - 1) * n + j] = temp;
 278.506 +                     tsp->edge_weight[(j - 1) * n + i] = temp;
 278.507 +                  }
 278.508 +               }
 278.509 +               break;
 278.510 +            case TSP_LOWER_DIAG_ROW:
 278.511 +               for (i = 1; i <= n; i++)
 278.512 +               {  for (j = 1; j <= i; j++)
 278.513 +                  {  if (scan_integer(dsa, 1, &temp)) goto fail;
 278.514 +                     tsp->edge_weight[(i - 1) * n + j] = temp;
 278.515 +                     tsp->edge_weight[(j - 1) * n + i] = temp;
 278.516 +                  }
 278.517 +               }
 278.518 +               break;
 278.519 +            default:
 278.520 +               goto fail;
 278.521 +         }
 278.522 +         if (check_newline(dsa)) goto fail;
 278.523 +      }
 278.524 +      else if (strcmp(dsa->token, "EOF") == 0)
 278.525 +      {  if (check_newline(dsa)) goto fail;
 278.526 +         goto done;
 278.527 +      }
 278.528 +      else
 278.529 +      {  xprintf("%s:%d: keyword `%s' not recognized\n", dsa->fname,
 278.530 +            dsa->seqn, dsa->token);
 278.531 +         goto fail;
 278.532 +      }
 278.533 +      goto loop;
 278.534 +done: xprintf("tsp_read_data: %d lines were read\n", dsa->seqn-1);
 278.535 +      fclose(dsa->fp);
 278.536 +      return tsp;
 278.537 +fail: if (tsp != NULL)
 278.538 +      {  if (tsp->name != NULL) xfree(tsp->name);
 278.539 +         if (tsp->comment != NULL) xfree(tsp->comment);
 278.540 +         if (tsp->node_x_coord != NULL) xfree(tsp->node_x_coord);
 278.541 +         if (tsp->node_y_coord != NULL) xfree(tsp->node_y_coord);
 278.542 +         if (tsp->dply_x_coord != NULL) xfree(tsp->dply_x_coord);
 278.543 +         if (tsp->dply_y_coord != NULL) xfree(tsp->dply_y_coord);
 278.544 +         if (tsp->tour != NULL) xfree(tsp->tour);
 278.545 +         if (tsp->edge_weight != NULL) xfree(tsp->edge_weight);
 278.546 +         xfree(tsp);
 278.547 +      }
 278.548 +      if (dsa->fp != NULL) fclose(dsa->fp);
 278.549 +      return NULL;
 278.550 +}
 278.551 +
 278.552 +/*----------------------------------------------------------------------
 278.553 +-- tsp_free_data - free TSP instance data.
 278.554 +--
 278.555 +-- *Synopsis*
 278.556 +--
 278.557 +-- #include "glptsp.h"
 278.558 +-- void tsp_free_data(TSP *tsp);
 278.559 +--
 278.560 +-- *Description*
 278.561 +--
 278.562 +-- The routine tsp_free_data frees all the memory allocated to the TSP
 278.563 +-- instance data block, which the parameter tsp points to. */
 278.564 +
 278.565 +void tsp_free_data(TSP *tsp)
 278.566 +{     if (tsp->name != NULL) xfree(tsp->name);
 278.567 +      if (tsp->comment != NULL) xfree(tsp->comment);
 278.568 +      if (tsp->node_x_coord != NULL) xfree(tsp->node_x_coord);
 278.569 +      if (tsp->node_y_coord != NULL) xfree(tsp->node_y_coord);
 278.570 +      if (tsp->dply_x_coord != NULL) xfree(tsp->dply_x_coord);
 278.571 +      if (tsp->dply_y_coord != NULL) xfree(tsp->dply_y_coord);
 278.572 +      if (tsp->tour != NULL) xfree(tsp->tour);
 278.573 +      if (tsp->edge_weight != NULL) xfree(tsp->edge_weight);
 278.574 +      xfree(tsp);
 278.575 +      return;
 278.576 +}
 278.577 +
 278.578 +/*----------------------------------------------------------------------
 278.579 +-- tsp_distance - compute distance between two nodes.
 278.580 +--
 278.581 +-- *Synopsis*
 278.582 +--
 278.583 +-- #include "glptsp.h"
 278.584 +-- int tsp_distance(TSP *tsp, int i, int j);
 278.585 +--
 278.586 +-- *Description*
 278.587 +--
 278.588 +-- The routine tsp_distance computes the distance between i-th and j-th
 278.589 +-- nodes for the TSP instance, which tsp points to.
 278.590 +--
 278.591 +-- *Returns*
 278.592 +--
 278.593 +-- The routine tsp_distance returns the computed distance. */
 278.594 +
 278.595 +#define nint(x) ((int)((x) + 0.5))
 278.596 +
 278.597 +static double rad(double x)
 278.598 +{     /* convert input coordinate to longitude/latitude, in radians */
 278.599 +      double pi = 3.141592, deg, min;
 278.600 +      deg = (int)x;
 278.601 +      min = x - deg;
 278.602 +      return pi * (deg + 5.0 * min / 3.0) / 180.0;
 278.603 +}
 278.604 +
 278.605 +int tsp_distance(TSP *tsp, int i, int j)
 278.606 +{     int n = tsp->dimension, dij;
 278.607 +      if (!(tsp->type == TSP_TSP || tsp->type == TSP_ATSP))
 278.608 +         xfault("tsp_distance: invalid TSP instance\n");
 278.609 +      if (!(1 <= i && i <= n && 1 <= j && j <= n))
 278.610 +         xfault("tsp_distance: node number out of range\n");
 278.611 +      switch (tsp->edge_weight_type)
 278.612 +      {  case TSP_UNDEF:
 278.613 +            xfault("tsp_distance: edge weight type not specified\n");
 278.614 +         case TSP_EXPLICIT:
 278.615 +            if (tsp->edge_weight == NULL)
 278.616 +               xfault("tsp_distance: edge weights not specified\n");
 278.617 +            dij = tsp->edge_weight[(i - 1) * n + j];
 278.618 +            break;
 278.619 +         case TSP_EUC_2D:
 278.620 +            if (tsp->node_x_coord == NULL || tsp->node_y_coord == NULL)
 278.621 +               xfault("tsp_distance: node coordinates not specified\n");
 278.622 +            {  double xd, yd;
 278.623 +               xd = tsp->node_x_coord[i] - tsp->node_x_coord[j];
 278.624 +               yd = tsp->node_y_coord[i] - tsp->node_y_coord[j];
 278.625 +               dij = nint(sqrt(xd * xd + yd * yd));
 278.626 +            }
 278.627 +            break;
 278.628 +         case TSP_CEIL_2D:
 278.629 +            if (tsp->node_x_coord == NULL || tsp->node_y_coord == NULL)
 278.630 +               xfault("tsp_distance: node coordinates not specified\n");
 278.631 +            {  double xd, yd;
 278.632 +               xd = tsp->node_x_coord[i] - tsp->node_x_coord[j];
 278.633 +               yd = tsp->node_y_coord[i] - tsp->node_y_coord[j];
 278.634 +               dij = (int)ceil(sqrt(xd * xd + yd * yd));
 278.635 +            }
 278.636 +            break;
 278.637 +         case TSP_GEO:
 278.638 +            if (tsp->node_x_coord == NULL || tsp->node_y_coord == NULL)
 278.639 +               xfault("tsp_distance: node coordinates not specified\n");
 278.640 +            {  double rrr = 6378.388;
 278.641 +               double latitude_i = rad(tsp->node_x_coord[i]);
 278.642 +               double latitude_j = rad(tsp->node_x_coord[j]);
 278.643 +               double longitude_i = rad(tsp->node_y_coord[i]);
 278.644 +               double longitude_j = rad(tsp->node_y_coord[j]);
 278.645 +               double q1 = cos(longitude_i - longitude_j);
 278.646 +               double q2 = cos(latitude_i - latitude_j);
 278.647 +               double q3 = cos(latitude_i + latitude_j);
 278.648 +               dij = (int)(rrr * acos(0.5 * ((1.0 + q1) * q2 -
 278.649 +                  (1.0 - q1) *q3)) + 1.0);
 278.650 +            }
 278.651 +            break;
 278.652 +         case TSP_ATT:
 278.653 +            if (tsp->node_x_coord == NULL || tsp->node_y_coord == NULL)
 278.654 +               xfault("tsp_distance: node coordinates not specified\n");
 278.655 +            {  int tij;
 278.656 +               double xd, yd, rij;
 278.657 +               xd = tsp->node_x_coord[i] - tsp->node_x_coord[j];
 278.658 +               yd = tsp->node_y_coord[i] - tsp->node_y_coord[j];
 278.659 +               rij = sqrt((xd * xd + yd * yd) / 10.0);
 278.660 +               tij = nint(rij);
 278.661 +               if (tij < rij) dij = tij + 1; else dij = tij;
 278.662 +            }
 278.663 +            break;
 278.664 +         default:
 278.665 +            xassert(tsp->edge_weight_type != tsp->edge_weight_type);
 278.666 +      }
 278.667 +      return dij;
 278.668 +}
 278.669 +
 278.670 +/* eof */
   279.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   279.2 +++ b/src/glptsp.h	Mon Dec 06 13:09:21 2010 +0100
   279.3 @@ -0,0 +1,104 @@
   279.4 +/* glptsp.h (TSP format) */
   279.5 +
   279.6 +/***********************************************************************
   279.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
   279.8 +*
   279.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  279.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  279.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  279.12 +*  E-mail: <mao@gnu.org>.
  279.13 +*
  279.14 +*  GLPK is free software: you can redistribute it and/or modify it
  279.15 +*  under the terms of the GNU General Public License as published by
  279.16 +*  the Free Software Foundation, either version 3 of the License, or
  279.17 +*  (at your option) any later version.
  279.18 +*
  279.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
  279.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  279.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  279.22 +*  License for more details.
  279.23 +*
  279.24 +*  You should have received a copy of the GNU General Public License
  279.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  279.26 +***********************************************************************/
  279.27 +
  279.28 +#ifndef GLPTSP_H
  279.29 +#define GLPTSP_H
  279.30 +
  279.31 +typedef struct TSP TSP;
  279.32 +
  279.33 +struct TSP
  279.34 +{     /* TSP (or related problem) instance in the format described in
  279.35 +         the report [G.Reinelt, TSPLIB 95] */
  279.36 +      /*--------------------------------------------------------------*/
  279.37 +      /* the specification part */
  279.38 +      char *name;
  279.39 +      /* identifies the data file */
  279.40 +      int type;
  279.41 +      /* specifies the type of data: */
  279.42 +#define TSP_UNDEF             0  /* undefined */
  279.43 +#define TSP_TSP               1  /* symmetric TSP */
  279.44 +#define TSP_ATSP              2  /* asymmetric TSP */
  279.45 +#define TSP_TOUR              3  /* collection of tours */
  279.46 +      char *comment;
  279.47 +      /* additional comments (usually the name of the contributor or
  279.48 +         creator of the problem instance is given here) */
  279.49 +      int dimension;
  279.50 +      /* for a TSP or ATSP, the dimension is the number of its nodes
  279.51 +         for a TOUR it is the dimension of the corresponding problem */
  279.52 +      int edge_weight_type;
  279.53 +      /* specifies how the edge weights (or distances) are given: */
  279.54 +#define TSP_UNDEF             0  /* undefined */
  279.55 +#define TSP_EXPLICIT          1  /* listed explicitly */
  279.56 +#define TSP_EUC_2D            2  /* Eucl. distances in 2-D */
  279.57 +#define TSP_CEIL_2D           3  /* Eucl. distances in 2-D rounded up */
  279.58 +#define TSP_GEO               4  /* geographical distances */
  279.59 +#define TSP_ATT               5  /* special distance function */
  279.60 +      int edge_weight_format;
  279.61 +      /* describes the format of the edge weights if they are given
  279.62 +         explicitly: */
  279.63 +#define TSP_UNDEF             0  /* undefined */
  279.64 +#define TSP_FUNCTION          1  /* given by a function */
  279.65 +#define TSP_FULL_MATRIX       2  /* given by a full matrix */
  279.66 +#define TSP_UPPER_ROW         3  /* upper triangulat matrix (row-wise
  279.67 +                                    without diagonal entries) */
  279.68 +#define TSP_LOWER_DIAG_ROW    4  /* lower triangular matrix (row-wise
  279.69 +                                    including diagonal entries) */
  279.70 +      int display_data_type;
  279.71 +      /* specifies how a graphical display of the nodes can be
  279.72 +         obtained: */
  279.73 +#define TSP_UNDEF             0  /* undefined */
  279.74 +#define TSP_COORD_DISPLAY     1  /* display is generated from the node
  279.75 +                                    coordinates */
  279.76 +#define TSP_TWOD_DISPLAY      2  /* explicit coordinates in 2-D are
  279.77 +                                    given */
  279.78 +      /*--------------------------------------------------------------*/
  279.79 +      /* data part */
  279.80 +      /* NODE_COORD_SECTION: */
  279.81 +      double *node_x_coord; /* double node_x_coord[1+dimension]; */
  279.82 +      double *node_y_coord; /* double node_y_coord[1+dimension]; */
  279.83 +      /* DISPLAY_DATA_SECTION: */
  279.84 +      double *dply_x_coord; /* double dply_x_coord[1+dimension]; */
  279.85 +      double *dply_y_coord; /* double dply_y_coord[1+dimension]; */
  279.86 +      /* TOUR_SECTION: */
  279.87 +      int *tour; /* int tour[1+dimension]; */
  279.88 +      /* EDGE_WEIGHT_SECTION: */
  279.89 +      int *edge_weight; /* int edge_weight[1+dimension*dimension]; */
  279.90 +};
  279.91 +
  279.92 +#define tsp_read_data         _glp_tsp_read_data
  279.93 +#define tsp_free_data         _glp_tsp_free_data
  279.94 +#define tsp_distance          _glp_tsp_distance
  279.95 +
  279.96 +TSP *tsp_read_data(char *fname);
  279.97 +/* read TSP instance data */
  279.98 +
  279.99 +void tsp_free_data(TSP *tsp);
 279.100 +/* free TSP instance data */
 279.101 +
 279.102 +int tsp_distance(TSP *tsp, int i, int j);
 279.103 +/* compute distance between two nodes */
 279.104 +
 279.105 +#endif
 279.106 +
 279.107 +/* eof */
   280.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   280.2 +++ b/w32/Build_GLPK_with_VC10.bat	Mon Dec 06 13:09:21 2010 +0100
   280.3 @@ -0,0 +1,11 @@
   280.4 +rem Build GLPK with Microsoft Visual Studio Express 2010
   280.5 +
   280.6 +rem NOTE: Make sure that HOME variable specifies correct path
   280.7 +set HOME="C:\Program Files\Microsoft Visual Studio 10.0\VC"
   280.8 +
   280.9 +call %HOME%\vcvarsall.bat x86
  280.10 +copy config_VC config.h
  280.11 +%HOME%\bin\nmake.exe /f Makefile_VC
  280.12 +%HOME%\bin\nmake.exe /f Makefile_VC check
  280.13 +
  280.14 +pause
   281.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   281.2 +++ b/w32/Build_GLPK_with_VC10_DLL.bat	Mon Dec 06 13:09:21 2010 +0100
   281.3 @@ -0,0 +1,11 @@
   281.4 +rem Build GLPK DLL with Microsoft Visual Studio Express 2010
   281.5 +
   281.6 +rem NOTE: Make sure that HOME variable specifies correct path
   281.7 +set HOME="C:\Program Files\Microsoft Visual Studio 10.0\VC"
   281.8 +
   281.9 +call %HOME%\vcvarsall.bat x86
  281.10 +copy config_VC config.h
  281.11 +%HOME%\bin\nmake.exe /f Makefile_VC_DLL
  281.12 +%HOME%\bin\nmake.exe /f Makefile_VC_DLL check
  281.13 +
  281.14 +pause
   282.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   282.2 +++ b/w32/Build_GLPK_with_VC9.bat	Mon Dec 06 13:09:21 2010 +0100
   282.3 @@ -0,0 +1,11 @@
   282.4 +rem Build GLPK with Microsoft Visual Studio Express 2008
   282.5 +
   282.6 +rem NOTE: Make sure that HOME variable specifies correct path
   282.7 +set HOME="C:\Program Files\Microsoft Visual Studio 9.0\VC"
   282.8 +
   282.9 +call %HOME%\bin\vcvars32.bat
  282.10 +copy config_VC config.h
  282.11 +%HOME%\bin\nmake.exe /f Makefile_VC
  282.12 +%HOME%\bin\nmake.exe /f Makefile_VC check
  282.13 +
  282.14 +pause
   283.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   283.2 +++ b/w32/Build_GLPK_with_VC9_DLL.bat	Mon Dec 06 13:09:21 2010 +0100
   283.3 @@ -0,0 +1,11 @@
   283.4 +rem Build GLPK DLL with Microsoft Visual Studio Express 2008
   283.5 +
   283.6 +rem NOTE: Make sure that HOME variable specifies correct path
   283.7 +set HOME="C:\Program Files\Microsoft Visual Studio 9.0\VC"
   283.8 +
   283.9 +call %HOME%\bin\vcvars32.bat
  283.10 +copy config_VC config.h
  283.11 +%HOME%\bin\nmake.exe /f Makefile_VC_DLL
  283.12 +%HOME%\bin\nmake.exe /f Makefile_VC_DLL check
  283.13 +
  283.14 +pause
   284.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   284.2 +++ b/w32/Makefile_VC	Mon Dec 06 13:09:21 2010 +0100
   284.3 @@ -0,0 +1,132 @@
   284.4 +# Build GLPK with Microsoft Visual Studio Express
   284.5 +
   284.6 +CFLAGS = /I. /I..\include /I..\src /I..\src\amd /I..\src\colamd \
   284.7 +        /DHAVE_CONFIG_H /D_CRT_SECURE_NO_WARNINGS /nologo /W3 /O2
   284.8 +
   284.9 +OBJSET = \
  284.10 +..\src\glpapi01.obj \
  284.11 +..\src\glpapi02.obj \
  284.12 +..\src\glpapi03.obj \
  284.13 +..\src\glpapi04.obj \
  284.14 +..\src\glpapi05.obj \
  284.15 +..\src\glpapi06.obj \
  284.16 +..\src\glpapi07.obj \
  284.17 +..\src\glpapi08.obj \
  284.18 +..\src\glpapi09.obj \
  284.19 +..\src\glpapi10.obj \
  284.20 +..\src\glpapi11.obj \
  284.21 +..\src\glpapi12.obj \
  284.22 +..\src\glpapi13.obj \
  284.23 +..\src\glpapi14.obj \
  284.24 +..\src\glpapi15.obj \
  284.25 +..\src\glpapi16.obj \
  284.26 +..\src\glpapi17.obj \
  284.27 +..\src\glpapi18.obj \
  284.28 +..\src\glpapi19.obj \
  284.29 +..\src\glpavl.obj \
  284.30 +..\src\glpbfd.obj \
  284.31 +..\src\glpbfx.obj \
  284.32 +..\src\glpcpx.obj \
  284.33 +..\src\glpdmp.obj \
  284.34 +..\src\glpdmx.obj \
  284.35 +..\src\glpenv01.obj \
  284.36 +..\src\glpenv02.obj \
  284.37 +..\src\glpenv03.obj \
  284.38 +..\src\glpenv04.obj \
  284.39 +..\src\glpenv05.obj \
  284.40 +..\src\glpenv06.obj \
  284.41 +..\src\glpenv07.obj \
  284.42 +..\src\glpenv08.obj \
  284.43 +..\src\glpfhv.obj \
  284.44 +..\src\glpgmp.obj \
  284.45 +..\src\glphbm.obj \
  284.46 +..\src\glpini01.obj \
  284.47 +..\src\glpini02.obj \
  284.48 +..\src\glpios01.obj \
  284.49 +..\src\glpios02.obj \
  284.50 +..\src\glpios03.obj \
  284.51 +..\src\glpios04.obj \
  284.52 +..\src\glpios05.obj \
  284.53 +..\src\glpios06.obj \
  284.54 +..\src\glpios07.obj \
  284.55 +..\src\glpios08.obj \
  284.56 +..\src\glpios09.obj \
  284.57 +..\src\glpios10.obj \
  284.58 +..\src\glpios11.obj \
  284.59 +..\src\glpios12.obj \
  284.60 +..\src\glpipm.obj \
  284.61 +..\src\glplib01.obj \
  284.62 +..\src\glplib02.obj \
  284.63 +..\src\glplib03.obj \
  284.64 +..\src\glplpf.obj \
  284.65 +..\src\glplpx01.obj \
  284.66 +..\src\glplpx02.obj \
  284.67 +..\src\glplpx03.obj \
  284.68 +..\src\glpluf.obj \
  284.69 +..\src\glplux.obj \
  284.70 +..\src\glpmat.obj \
  284.71 +..\src\glpmpl01.obj \
  284.72 +..\src\glpmpl02.obj \
  284.73 +..\src\glpmpl03.obj \
  284.74 +..\src\glpmpl04.obj \
  284.75 +..\src\glpmpl05.obj \
  284.76 +..\src\glpmpl06.obj \
  284.77 +..\src\glpmps.obj \
  284.78 +..\src\glpnet01.obj \
  284.79 +..\src\glpnet02.obj \
  284.80 +..\src\glpnet03.obj \
  284.81 +..\src\glpnet04.obj \
  284.82 +..\src\glpnet05.obj \
  284.83 +..\src\glpnet06.obj \
  284.84 +..\src\glpnet07.obj \
  284.85 +..\src\glpnet08.obj \
  284.86 +..\src\glpnet09.obj \
  284.87 +..\src\glpnpp01.obj \
  284.88 +..\src\glpnpp02.obj \
  284.89 +..\src\glpnpp03.obj \
  284.90 +..\src\glpnpp04.obj \
  284.91 +..\src\glpnpp05.obj \
  284.92 +..\src\glpqmd.obj \
  284.93 +..\src\glprgr.obj \
  284.94 +..\src\glprng01.obj \
  284.95 +..\src\glprng02.obj \
  284.96 +..\src\glpscf.obj \
  284.97 +..\src\glpscl.obj \
  284.98 +..\src\glpsdf.obj \
  284.99 +..\src\glpspm.obj \
 284.100 +..\src\glpspx01.obj \
 284.101 +..\src\glpspx02.obj \
 284.102 +..\src\glpsql.obj \
 284.103 +..\src\glpssx01.obj \
 284.104 +..\src\glpssx02.obj \
 284.105 +..\src\glptsp.obj \
 284.106 +..\src\amd\amd_1.obj \
 284.107 +..\src\amd\amd_2.obj \
 284.108 +..\src\amd\amd_aat.obj \
 284.109 +..\src\amd\amd_control.obj \
 284.110 +..\src\amd\amd_defaults.obj \
 284.111 +..\src\amd\amd_dump.obj \
 284.112 +..\src\amd\amd_info.obj \
 284.113 +..\src\amd\amd_order.obj \
 284.114 +..\src\amd\amd_post_tree.obj \
 284.115 +..\src\amd\amd_postorder.obj \
 284.116 +..\src\amd\amd_preprocess.obj \
 284.117 +..\src\amd\amd_valid.obj \
 284.118 +..\src\colamd\colamd.obj
 284.119 +
 284.120 +.c.obj:
 284.121 +        cl.exe $(CFLAGS) /Fo$*.obj /c $*.c
 284.122 +
 284.123 +all: glpk.lib glpsol.exe
 284.124 +
 284.125 +glpk.lib: $(OBJSET)
 284.126 +        lib.exe /out:glpk.lib ..\src\*.obj ..\src\amd\*.obj \
 284.127 +                ..\src\colamd\*.obj
 284.128 +
 284.129 +glpsol.exe: ..\examples\glpsol.obj glpk.lib
 284.130 +        cl.exe $(CFLAGS) /Feglpsol.exe ..\examples\glpsol.obj \
 284.131 +                glpk.lib
 284.132 +
 284.133 +check: glpsol.exe
 284.134 +        .\glpsol.exe --version
 284.135 +        .\glpsol.exe --mps ..\examples\plan.mps
   285.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   285.2 +++ b/w32/Makefile_VC_DLL	Mon Dec 06 13:09:21 2010 +0100
   285.3 @@ -0,0 +1,132 @@
   285.4 +# Build GLPK DLL with Microsoft Visual Studio Express
   285.5 +
   285.6 +CFLAGS = /I. /I..\include /I..\src /I..\src\amd /I..\src\colamd \
   285.7 +        /DHAVE_CONFIG_H /D_CRT_SECURE_NO_WARNINGS /nologo /W3 /O2
   285.8 +
   285.9 +OBJSET = \
  285.10 +..\src\glpapi01.obj \
  285.11 +..\src\glpapi02.obj \
  285.12 +..\src\glpapi03.obj \
  285.13 +..\src\glpapi04.obj \
  285.14 +..\src\glpapi05.obj \
  285.15 +..\src\glpapi06.obj \
  285.16 +..\src\glpapi07.obj \
  285.17 +..\src\glpapi08.obj \
  285.18 +..\src\glpapi09.obj \
  285.19 +..\src\glpapi10.obj \
  285.20 +..\src\glpapi11.obj \
  285.21 +..\src\glpapi12.obj \
  285.22 +..\src\glpapi13.obj \
  285.23 +..\src\glpapi14.obj \
  285.24 +..\src\glpapi15.obj \
  285.25 +..\src\glpapi16.obj \
  285.26 +..\src\glpapi17.obj \
  285.27 +..\src\glpapi18.obj \
  285.28 +..\src\glpapi19.obj \
  285.29 +..\src\glpavl.obj \
  285.30 +..\src\glpbfd.obj \
  285.31 +..\src\glpbfx.obj \
  285.32 +..\src\glpcpx.obj \
  285.33 +..\src\glpdmp.obj \
  285.34 +..\src\glpdmx.obj \
  285.35 +..\src\glpenv01.obj \
  285.36 +..\src\glpenv02.obj \
  285.37 +..\src\glpenv03.obj \
  285.38 +..\src\glpenv04.obj \
  285.39 +..\src\glpenv05.obj \
  285.40 +..\src\glpenv06.obj \
  285.41 +..\src\glpenv07.obj \
  285.42 +..\src\glpenv08.obj \
  285.43 +..\src\glpfhv.obj \
  285.44 +..\src\glpgmp.obj \
  285.45 +..\src\glphbm.obj \
  285.46 +..\src\glpini01.obj \
  285.47 +..\src\glpini02.obj \
  285.48 +..\src\glpios01.obj \
  285.49 +..\src\glpios02.obj \
  285.50 +..\src\glpios03.obj \
  285.51 +..\src\glpios04.obj \
  285.52 +..\src\glpios05.obj \
  285.53 +..\src\glpios06.obj \
  285.54 +..\src\glpios07.obj \
  285.55 +..\src\glpios08.obj \
  285.56 +..\src\glpios09.obj \
  285.57 +..\src\glpios10.obj \
  285.58 +..\src\glpios11.obj \
  285.59 +..\src\glpios12.obj \
  285.60 +..\src\glpipm.obj \
  285.61 +..\src\glplib01.obj \
  285.62 +..\src\glplib02.obj \
  285.63 +..\src\glplib03.obj \
  285.64 +..\src\glplpf.obj \
  285.65 +..\src\glplpx01.obj \
  285.66 +..\src\glplpx02.obj \
  285.67 +..\src\glplpx03.obj \
  285.68 +..\src\glpluf.obj \
  285.69 +..\src\glplux.obj \
  285.70 +..\src\glpmat.obj \
  285.71 +..\src\glpmpl01.obj \
  285.72 +..\src\glpmpl02.obj \
  285.73 +..\src\glpmpl03.obj \
  285.74 +..\src\glpmpl04.obj \
  285.75 +..\src\glpmpl05.obj \
  285.76 +..\src\glpmpl06.obj \
  285.77 +..\src\glpmps.obj \
  285.78 +..\src\glpnet01.obj \
  285.79 +..\src\glpnet02.obj \
  285.80 +..\src\glpnet03.obj \
  285.81 +..\src\glpnet04.obj \
  285.82 +..\src\glpnet05.obj \
  285.83 +..\src\glpnet06.obj \
  285.84 +..\src\glpnet07.obj \
  285.85 +..\src\glpnet08.obj \
  285.86 +..\src\glpnet09.obj \
  285.87 +..\src\glpnpp01.obj \
  285.88 +..\src\glpnpp02.obj \
  285.89 +..\src\glpnpp03.obj \
  285.90 +..\src\glpnpp04.obj \
  285.91 +..\src\glpnpp05.obj \
  285.92 +..\src\glpqmd.obj \
  285.93 +..\src\glprgr.obj \
  285.94 +..\src\glprng01.obj \
  285.95 +..\src\glprng02.obj \
  285.96 +..\src\glpscf.obj \
  285.97 +..\src\glpscl.obj \
  285.98 +..\src\glpsdf.obj \
  285.99 +..\src\glpspm.obj \
 285.100 +..\src\glpspx01.obj \
 285.101 +..\src\glpspx02.obj \
 285.102 +..\src\glpsql.obj \
 285.103 +..\src\glpssx01.obj \
 285.104 +..\src\glpssx02.obj \
 285.105 +..\src\glptsp.obj \
 285.106 +..\src\amd\amd_1.obj \
 285.107 +..\src\amd\amd_2.obj \
 285.108 +..\src\amd\amd_aat.obj \
 285.109 +..\src\amd\amd_control.obj \
 285.110 +..\src\amd\amd_defaults.obj \
 285.111 +..\src\amd\amd_dump.obj \
 285.112 +..\src\amd\amd_info.obj \
 285.113 +..\src\amd\amd_order.obj \
 285.114 +..\src\amd\amd_post_tree.obj \
 285.115 +..\src\amd\amd_postorder.obj \
 285.116 +..\src\amd\amd_preprocess.obj \
 285.117 +..\src\amd\amd_valid.obj \
 285.118 +..\src\colamd\colamd.obj
 285.119 +
 285.120 +.c.obj:
 285.121 +        cl.exe $(CFLAGS) /Fo$*.obj /c $*.c
 285.122 +
 285.123 +all: glpk_4_45.dll glpsol.exe
 285.124 +
 285.125 +glpk_4_45.dll: $(OBJSET)
 285.126 +        cl.exe $(CFLAGS) /LD /Feglpk_4_45.dll ..\src\*.obj \
 285.127 +                ..\src\amd\*.obj ..\src\colamd\*.obj glpk_4_45.def
 285.128 +
 285.129 +glpsol.exe: ..\examples\glpsol.obj glpk_4_45.dll
 285.130 +        cl.exe $(CFLAGS) /Feglpsol.exe ..\examples\glpsol.obj \
 285.131 +                glpk_4_45.lib
 285.132 +
 285.133 +check: glpsol.exe
 285.134 +        .\glpsol.exe --version
 285.135 +        .\glpsol.exe --mps ..\examples\plan.mps
   286.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   286.2 +++ b/w32/config_VC	Mon Dec 06 13:09:21 2010 +0100
   286.3 @@ -0,0 +1,13 @@
   286.4 +/* GLPK configuration file (Microsoft Visual Studio Express) */
   286.5 +
   286.6 +#define __WOE__ 1
   286.7 +
   286.8 +#define ODBC_DLNAME "odbc32.dll"
   286.9 +/* ODBC shared library name if this feature is enabled */
  286.10 +
  286.11 +#if 0
  286.12 +#define MYSQL_DLNAME "libmysql.dll"
  286.13 +/* MySQL shared library name if this feature is enabled */
  286.14 +#endif
  286.15 +
  286.16 +/* eof */
   287.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   287.2 +++ b/w32/glpk_4_45.def	Mon Dec 06 13:09:21 2010 +0100
   287.3 @@ -0,0 +1,1062 @@
   287.4 +LIBRARY glpk_4_45
   287.5 +VERSION 4.45
   287.6 +DESCRIPTION "GNU Linear Programming Kit"
   287.7 +EXPORTS
   287.8 +;; from amd_1 ;;
   287.9 + _glp_amd_1
  287.10 +;; from amd_2 ;;
  287.11 + _glp_amd_2
  287.12 +;; from amd_aat ;;
  287.13 + _glp_amd_aat
  287.14 +;; from amd_control ;;
  287.15 + _glp_amd_control
  287.16 +;; from amd_defaults ;;
  287.17 + _glp_amd_defaults
  287.18 +;; from amd_dump ;;
  287.19 +;; from amd_info ;;
  287.20 + _glp_amd_info
  287.21 +;; from amd_order ;;
  287.22 + _glp_amd_order
  287.23 +;; from amd_post_tree ;;
  287.24 + _glp_amd_post_tree
  287.25 +;; from amd_postorder ;;
  287.26 + _glp_amd_postorder
  287.27 +;; from amd_preprocess ;;
  287.28 + _glp_amd_preprocess
  287.29 +;; from amd_valid ;;
  287.30 + _glp_amd_valid
  287.31 +;; from colamd ;;
  287.32 + _glp_colamd
  287.33 + _glp_colamd_recommended
  287.34 + _glp_colamd_report
  287.35 + _glp_colamd_set_defaults
  287.36 + _glp_symamd
  287.37 + _glp_symamd_report
  287.38 +;; from glpapi01 ;;
  287.39 + glp_add_cols
  287.40 + glp_add_rows
  287.41 + glp_check_dup
  287.42 + glp_copy_prob
  287.43 + glp_create_prob
  287.44 + glp_del_cols
  287.45 + glp_del_rows
  287.46 + glp_delete_prob
  287.47 + glp_erase_prob
  287.48 + glp_load_matrix
  287.49 + glp_set_col_bnds
  287.50 + glp_set_col_name
  287.51 + glp_set_mat_col
  287.52 + glp_set_mat_row
  287.53 + glp_set_obj_coef
  287.54 + glp_set_obj_dir
  287.55 + glp_set_obj_name
  287.56 + glp_set_prob_name
  287.57 + glp_set_row_bnds
  287.58 + glp_set_row_name
  287.59 + glp_sort_matrix
  287.60 +;; from glpapi02 ;;
  287.61 + glp_get_col_lb
  287.62 + glp_get_col_name
  287.63 + glp_get_col_type
  287.64 + glp_get_col_ub
  287.65 + glp_get_mat_col
  287.66 + glp_get_mat_row
  287.67 + glp_get_num_cols
  287.68 + glp_get_num_nz
  287.69 + glp_get_num_rows
  287.70 + glp_get_obj_coef
  287.71 + glp_get_obj_dir
  287.72 + glp_get_obj_name
  287.73 + glp_get_prob_name
  287.74 + glp_get_row_lb
  287.75 + glp_get_row_name
  287.76 + glp_get_row_type
  287.77 + glp_get_row_ub
  287.78 +;; from glpapi03 ;;
  287.79 + glp_create_index
  287.80 + glp_delete_index
  287.81 + glp_find_col
  287.82 + glp_find_row
  287.83 +;; from glpapi04 ;;
  287.84 + glp_get_rii
  287.85 + glp_get_sjj
  287.86 + glp_set_rii
  287.87 + glp_set_sjj
  287.88 + glp_unscale_prob
  287.89 +;; from glpapi05 ;;
  287.90 + glp_set_col_stat
  287.91 + glp_set_row_stat
  287.92 + glp_std_basis
  287.93 +;; from glpapi06 ;;
  287.94 + glp_get_col_dual
  287.95 + glp_get_col_prim
  287.96 + glp_get_col_stat
  287.97 + glp_get_dual_stat
  287.98 + glp_get_obj_val
  287.99 + glp_get_prim_stat
 287.100 + glp_get_row_dual
 287.101 + glp_get_row_prim
 287.102 + glp_get_row_stat
 287.103 + glp_get_status
 287.104 + glp_get_unbnd_ray
 287.105 + glp_init_smcp
 287.106 + glp_simplex
 287.107 +;; from glpapi07 ;;
 287.108 + glp_exact
 287.109 +;; from glpapi08 ;;
 287.110 + glp_init_iptcp
 287.111 + glp_interior
 287.112 + glp_ipt_col_dual
 287.113 + glp_ipt_col_prim
 287.114 + glp_ipt_obj_val
 287.115 + glp_ipt_row_dual
 287.116 + glp_ipt_row_prim
 287.117 + glp_ipt_status
 287.118 +;; from glpapi09 ;;
 287.119 + glp_get_col_kind
 287.120 + glp_get_num_bin
 287.121 + glp_get_num_int
 287.122 + glp_init_iocp
 287.123 + glp_intopt
 287.124 + glp_mip_col_val
 287.125 + glp_mip_obj_val
 287.126 + glp_mip_row_val
 287.127 + glp_mip_status
 287.128 + glp_set_col_kind
 287.129 +;; from glpapi10 ;;
 287.130 + _glp_check_kkt
 287.131 +;; from glpapi11 ;;
 287.132 + glp_print_ipt
 287.133 + glp_print_mip
 287.134 + glp_print_ranges
 287.135 + glp_print_sol
 287.136 + glp_read_ipt
 287.137 + glp_read_mip
 287.138 + glp_read_sol
 287.139 + glp_write_ipt
 287.140 + glp_write_mip
 287.141 + glp_write_sol
 287.142 +;; from glpapi12 ;;
 287.143 + _glp_analyze_row
 287.144 + glp_analyze_bound
 287.145 + glp_analyze_coef
 287.146 + glp_bf_exists
 287.147 + glp_bf_updated
 287.148 + glp_btran
 287.149 + glp_dual_rtest
 287.150 + glp_eval_tab_col
 287.151 + glp_eval_tab_row
 287.152 + glp_factorize
 287.153 + glp_ftran
 287.154 + glp_get_bfcp
 287.155 + glp_get_bhead
 287.156 + glp_get_col_bind
 287.157 + glp_get_row_bind
 287.158 + glp_prim_rtest
 287.159 + glp_set_bfcp
 287.160 + glp_transform_col
 287.161 + glp_transform_row
 287.162 + glp_warm_up
 287.163 +;; from glpapi13 ;;
 287.164 + glp_ios_add_row
 287.165 + glp_ios_best_node
 287.166 + glp_ios_branch_upon
 287.167 + glp_ios_can_branch
 287.168 + glp_ios_clear_pool
 287.169 + glp_ios_curr_node
 287.170 + glp_ios_del_row
 287.171 + glp_ios_get_prob
 287.172 + glp_ios_heur_sol
 287.173 + glp_ios_mip_gap
 287.174 + glp_ios_next_node
 287.175 + glp_ios_node_bound
 287.176 + glp_ios_node_data
 287.177 + glp_ios_node_level
 287.178 + glp_ios_pool_size
 287.179 + glp_ios_prev_node
 287.180 + glp_ios_reason
 287.181 + glp_ios_row_attr
 287.182 + glp_ios_select_node
 287.183 + glp_ios_terminate
 287.184 + glp_ios_tree_size
 287.185 + glp_ios_up_node
 287.186 +;; from glpapi14 ;;
 287.187 + _glp_mpl_init_rand
 287.188 + glp_mpl_alloc_wksp
 287.189 + glp_mpl_build_prob
 287.190 + glp_mpl_free_wksp
 287.191 + glp_mpl_generate
 287.192 + glp_mpl_postsolve
 287.193 + glp_mpl_read_data
 287.194 + glp_mpl_read_model
 287.195 +;; from glpapi15 ;;
 287.196 + glp_add_arc
 287.197 + glp_add_vertices
 287.198 + glp_create_graph
 287.199 + glp_create_v_index
 287.200 + glp_del_arc
 287.201 + glp_del_vertices
 287.202 + glp_delete_graph
 287.203 + glp_delete_v_index
 287.204 + glp_erase_graph
 287.205 + glp_find_vertex
 287.206 + glp_read_graph
 287.207 + glp_set_graph_name
 287.208 + glp_set_vertex_name
 287.209 + glp_write_graph
 287.210 +;; from glpapi16 ;;
 287.211 + glp_strong_comp
 287.212 + glp_top_sort
 287.213 + glp_weak_comp
 287.214 +;; from glpapi17 ;;
 287.215 + glp_asnprob_hall
 287.216 + glp_asnprob_lp
 287.217 + glp_asnprob_okalg
 287.218 + glp_check_asnprob
 287.219 + glp_cpp
 287.220 + glp_maxflow_ffalg
 287.221 + glp_maxflow_lp
 287.222 + glp_mincost_lp
 287.223 + glp_mincost_okalg
 287.224 +;; from glpapi18 ;;
 287.225 + glp_wclique_exact
 287.226 +;; from glpapi19 ;;
 287.227 + glp_main
 287.228 +;; from glpavl ;;
 287.229 + _glp_avl_create_tree
 287.230 + _glp_avl_delete_node
 287.231 + _glp_avl_delete_tree
 287.232 + _glp_avl_find_node
 287.233 + _glp_avl_get_node_link
 287.234 + _glp_avl_get_node_type
 287.235 + _glp_avl_insert_node
 287.236 + _glp_avl_set_node_link
 287.237 + _glp_avl_set_node_type
 287.238 + _glp_avl_strcmp
 287.239 +;; from glpbfd ;;
 287.240 + _glp_bfd_btran
 287.241 + _glp_bfd_create_it
 287.242 + _glp_bfd_delete_it
 287.243 + _glp_bfd_factorize
 287.244 + _glp_bfd_ftran
 287.245 + _glp_bfd_get_count
 287.246 + _glp_bfd_set_parm
 287.247 + _glp_bfd_update_it
 287.248 +;; from glpbfx ;;
 287.249 + _glp_bfx_btran
 287.250 + _glp_bfx_create_binv
 287.251 + _glp_bfx_delete_binv
 287.252 + _glp_bfx_factorize
 287.253 + _glp_bfx_ftran
 287.254 + _glp_bfx_update
 287.255 +;; from glpcpx ;;
 287.256 + glp_init_cpxcp
 287.257 + glp_read_lp
 287.258 + glp_write_lp
 287.259 +;; from glpdmp ;;
 287.260 + _glp_dmp_create_pool
 287.261 + _glp_dmp_delete_pool
 287.262 + _glp_dmp_free_atom
 287.263 + _glp_dmp_get_atom
 287.264 + _glp_dmp_in_use
 287.265 +;; from glpdmx ;;
 287.266 + glp_read_asnprob
 287.267 + glp_read_ccdata
 287.268 + glp_read_maxflow
 287.269 + glp_read_mincost
 287.270 + glp_read_prob
 287.271 + glp_write_asnprob
 287.272 + glp_write_ccdata
 287.273 + glp_write_maxflow
 287.274 + glp_write_mincost
 287.275 + glp_write_prob
 287.276 +;; from glpenv01 ;;
 287.277 + _glp_get_env_ptr
 287.278 + glp_free_env
 287.279 + glp_init_env
 287.280 + glp_version
 287.281 +;; from glpenv02 ;;
 287.282 + _glp_tls_get_ptr
 287.283 + _glp_tls_set_ptr
 287.284 +;; from glpenv03 ;;
 287.285 + glp_close_tee
 287.286 + glp_open_tee
 287.287 + glp_printf
 287.288 + glp_term_hook
 287.289 + glp_term_out
 287.290 + glp_vprintf
 287.291 +;; from glpenv04 ;;
 287.292 + glp_assert_
 287.293 + glp_error_
 287.294 + glp_error_hook
 287.295 +;; from glpenv05 ;;
 287.296 + glp_calloc
 287.297 + glp_free
 287.298 + glp_malloc
 287.299 + glp_mem_limit
 287.300 + glp_mem_usage
 287.301 +;; from glpenv06 ;;
 287.302 + glp_difftime
 287.303 + glp_time
 287.304 +;; from glpenv07 ;;
 287.305 + _glp_lib_err_msg
 287.306 + _glp_lib_xerrmsg
 287.307 + _glp_lib_xfclose
 287.308 + _glp_lib_xfeof
 287.309 + _glp_lib_xferror
 287.310 + _glp_lib_xfflush
 287.311 + _glp_lib_xfgetc
 287.312 + _glp_lib_xfopen
 287.313 + _glp_lib_xfprintf
 287.314 + _glp_lib_xfputc
 287.315 +;; from glpenv08 ;;
 287.316 + _glp_xdlclose
 287.317 + _glp_xdlopen
 287.318 + _glp_xdlsym
 287.319 +;; from glpfhv ;;
 287.320 + _glp_fhv_btran
 287.321 + _glp_fhv_create_it
 287.322 + _glp_fhv_delete_it
 287.323 + _glp_fhv_factorize
 287.324 + _glp_fhv_ftran
 287.325 + _glp_fhv_h_solve
 287.326 + _glp_fhv_update_it
 287.327 +;; from glpgmp ;;
 287.328 + _glp_gmp_free_atom
 287.329 + _glp_gmp_free_mem
 287.330 + _glp_gmp_get_atom
 287.331 + _glp_gmp_get_work
 287.332 + _glp_gmp_pool_count
 287.333 + _glp_mpq_abs
 287.334 + _glp_mpq_add
 287.335 + _glp_mpq_canonicalize
 287.336 + _glp_mpq_clear
 287.337 + _glp_mpq_cmp
 287.338 + _glp_mpq_div
 287.339 + _glp_mpq_get_d
 287.340 + _glp_mpq_init
 287.341 + _glp_mpq_mul
 287.342 + _glp_mpq_neg
 287.343 + _glp_mpq_out_str
 287.344 + _glp_mpq_set
 287.345 + _glp_mpq_set_d
 287.346 + _glp_mpq_set_si
 287.347 + _glp_mpq_sgn
 287.348 + _glp_mpq_sub
 287.349 + _glp_mpz_abs
 287.350 + _glp_mpz_add
 287.351 + _glp_mpz_clear
 287.352 + _glp_mpz_cmp
 287.353 + _glp_mpz_div
 287.354 + _glp_mpz_gcd
 287.355 + _glp_mpz_get_d
 287.356 + _glp_mpz_get_d_2exp
 287.357 + _glp_mpz_init
 287.358 + _glp_mpz_mul
 287.359 + _glp_mpz_neg
 287.360 + _glp_mpz_out_str
 287.361 + _glp_mpz_set
 287.362 + _glp_mpz_set_si
 287.363 + _glp_mpz_sgn
 287.364 + _glp_mpz_sub
 287.365 + _glp_mpz_swap
 287.366 +;; from glphbm ;;
 287.367 + _glp_hbm_free_mat
 287.368 + _glp_hbm_read_mat
 287.369 +;; from glpini01 ;;
 287.370 + glp_adv_basis
 287.371 +;; from glpini02 ;;
 287.372 + glp_cpx_basis
 287.373 +;; from glpios01 ;;
 287.374 + _glp_ios_add_row
 287.375 + _glp_ios_best_node
 287.376 + _glp_ios_clear_pool
 287.377 + _glp_ios_clone_node
 287.378 + _glp_ios_create_pool
 287.379 + _glp_ios_create_tree
 287.380 + _glp_ios_del_row
 287.381 + _glp_ios_delete_node
 287.382 + _glp_ios_delete_pool
 287.383 + _glp_ios_delete_tree
 287.384 + _glp_ios_eval_degrad
 287.385 + _glp_ios_find_row
 287.386 + _glp_ios_freeze_node
 287.387 + _glp_ios_is_hopeful
 287.388 + _glp_ios_relative_gap
 287.389 + _glp_ios_revive_node
 287.390 + _glp_ios_round_bound
 287.391 + _glp_ios_solve_node
 287.392 +;; from glpios02 ;;
 287.393 + _glp_ios_preprocess_node
 287.394 +;; from glpios03 ;;
 287.395 + _glp_ios_driver
 287.396 +;; from glpios04 ;;
 287.397 + _glp_ios_check_vec
 287.398 + _glp_ios_clean_vec
 287.399 + _glp_ios_clear_vec
 287.400 + _glp_ios_copy_vec
 287.401 + _glp_ios_create_vec
 287.402 + _glp_ios_delete_vec
 287.403 + _glp_ios_get_vj
 287.404 + _glp_ios_linear_comb
 287.405 + _glp_ios_set_vj
 287.406 +;; from glpios05 ;;
 287.407 + _glp_ios_gmi_gen
 287.408 +;; from glpios06 ;;
 287.409 + _glp_ios_mir_gen
 287.410 + _glp_ios_mir_init
 287.411 + _glp_ios_mir_term
 287.412 +;; from glpios07 ;;
 287.413 + _glp_ios_cov_gen
 287.414 +;; from glpios08 ;;
 287.415 + _glp_ios_clq_gen
 287.416 + _glp_ios_clq_init
 287.417 + _glp_ios_clq_term
 287.418 +;; from glpios09 ;;
 287.419 + _glp_ios_choose_var
 287.420 + _glp_ios_pcost_branch
 287.421 + _glp_ios_pcost_free
 287.422 + _glp_ios_pcost_init
 287.423 + _glp_ios_pcost_update
 287.424 +;; from glpios10 ;;
 287.425 + _glp_ios_feas_pump
 287.426 +;; from glpios11 ;;
 287.427 + _glp_ios_process_cuts
 287.428 +;; from glpios12 ;;
 287.429 + _glp_ios_choose_node
 287.430 +;; from glpipm ;;
 287.431 + _glp_ipm_solve
 287.432 +;; from glplib01 ;;
 287.433 + _glp_lib_bigdiv
 287.434 + _glp_lib_bigmul
 287.435 +;; from glplib02 ;;
 287.436 + _glp_lib_xladd
 287.437 + _glp_lib_xlcmp
 287.438 + _glp_lib_xldiv
 287.439 + _glp_lib_xlmul
 287.440 + _glp_lib_xlneg
 287.441 + _glp_lib_xlset
 287.442 + _glp_lib_xlsub
 287.443 + _glp_lib_xltoa
 287.444 + _glp_lib_xltod
 287.445 +;; from glplib03 ;;
 287.446 + _glp_lib_fp2rat
 287.447 + _glp_lib_gcd
 287.448 + _glp_lib_gcdn
 287.449 + _glp_lib_jdate
 287.450 + _glp_lib_jday
 287.451 + _glp_lib_lcm
 287.452 + _glp_lib_lcmn
 287.453 + _glp_lib_round2n
 287.454 + _glp_lib_str2int
 287.455 + _glp_lib_str2num
 287.456 + _glp_lib_strrev
 287.457 + _glp_lib_strspx
 287.458 + _glp_lib_strtrim
 287.459 +;; from glplpf ;;
 287.460 + _glp_lpf_btran
 287.461 + _glp_lpf_create_it
 287.462 + _glp_lpf_delete_it
 287.463 + _glp_lpf_factorize
 287.464 + _glp_lpf_ftran
 287.465 + _glp_lpf_update_it
 287.466 +;; from glplpx01 ;;
 287.467 + _glp_lpx_add_cols
 287.468 + _glp_lpx_add_rows
 287.469 + _glp_lpx_adv_basis
 287.470 + _glp_lpx_check_int
 287.471 + _glp_lpx_check_kkt
 287.472 + _glp_lpx_cpx_basis
 287.473 + _glp_lpx_create_index
 287.474 + _glp_lpx_create_prob
 287.475 + _glp_lpx_del_cols
 287.476 + _glp_lpx_del_rows
 287.477 + _glp_lpx_delete_index
 287.478 + _glp_lpx_delete_prob
 287.479 + _glp_lpx_dual_ratio_test
 287.480 + _glp_lpx_eval_tab_col
 287.481 + _glp_lpx_eval_tab_row
 287.482 + _glp_lpx_exact
 287.483 + _glp_lpx_find_col
 287.484 + _glp_lpx_find_row
 287.485 + _glp_lpx_get_class
 287.486 + _glp_lpx_get_col_bnds
 287.487 + _glp_lpx_get_col_dual
 287.488 + _glp_lpx_get_col_info
 287.489 + _glp_lpx_get_col_kind
 287.490 + _glp_lpx_get_col_lb
 287.491 + _glp_lpx_get_col_name
 287.492 + _glp_lpx_get_col_prim
 287.493 + _glp_lpx_get_col_stat
 287.494 + _glp_lpx_get_col_type
 287.495 + _glp_lpx_get_col_ub
 287.496 + _glp_lpx_get_dual_stat
 287.497 + _glp_lpx_get_int_parm
 287.498 + _glp_lpx_get_mat_col
 287.499 + _glp_lpx_get_mat_row
 287.500 + _glp_lpx_get_num_bin
 287.501 + _glp_lpx_get_num_cols
 287.502 + _glp_lpx_get_num_int
 287.503 + _glp_lpx_get_num_nz
 287.504 + _glp_lpx_get_num_rows
 287.505 + _glp_lpx_get_obj_coef
 287.506 + _glp_lpx_get_obj_dir
 287.507 + _glp_lpx_get_obj_name
 287.508 + _glp_lpx_get_obj_val
 287.509 + _glp_lpx_get_prim_stat
 287.510 + _glp_lpx_get_prob_name
 287.511 + _glp_lpx_get_ray_info
 287.512 + _glp_lpx_get_real_parm
 287.513 + _glp_lpx_get_row_bnds
 287.514 + _glp_lpx_get_row_dual
 287.515 + _glp_lpx_get_row_info
 287.516 + _glp_lpx_get_row_lb
 287.517 + _glp_lpx_get_row_name
 287.518 + _glp_lpx_get_row_prim
 287.519 + _glp_lpx_get_row_stat
 287.520 + _glp_lpx_get_row_type
 287.521 + _glp_lpx_get_row_ub
 287.522 + _glp_lpx_get_status
 287.523 + _glp_lpx_integer
 287.524 + _glp_lpx_interior
 287.525 + _glp_lpx_intopt
 287.526 + _glp_lpx_ipt_col_dual
 287.527 + _glp_lpx_ipt_col_prim
 287.528 + _glp_lpx_ipt_obj_val
 287.529 + _glp_lpx_ipt_row_dual
 287.530 + _glp_lpx_ipt_row_prim
 287.531 + _glp_lpx_ipt_status
 287.532 + _glp_lpx_is_b_avail
 287.533 + _glp_lpx_load_matrix
 287.534 + _glp_lpx_main
 287.535 + _glp_lpx_mip_col_val
 287.536 + _glp_lpx_mip_obj_val
 287.537 + _glp_lpx_mip_row_val
 287.538 + _glp_lpx_mip_status
 287.539 + _glp_lpx_prim_ratio_test
 287.540 + _glp_lpx_print_ips
 287.541 + _glp_lpx_print_mip
 287.542 + _glp_lpx_print_prob
 287.543 + _glp_lpx_print_sens_bnds
 287.544 + _glp_lpx_print_sol
 287.545 + _glp_lpx_read_bas
 287.546 + _glp_lpx_read_cpxlp
 287.547 + _glp_lpx_read_freemps
 287.548 + _glp_lpx_read_model
 287.549 + _glp_lpx_read_mps
 287.550 + _glp_lpx_reset_parms
 287.551 + _glp_lpx_scale_prob
 287.552 + _glp_lpx_set_class
 287.553 + _glp_lpx_set_col_bnds
 287.554 + _glp_lpx_set_col_kind
 287.555 + _glp_lpx_set_col_name
 287.556 + _glp_lpx_set_col_stat
 287.557 + _glp_lpx_set_int_parm
 287.558 + _glp_lpx_set_mat_col
 287.559 + _glp_lpx_set_mat_row
 287.560 + _glp_lpx_set_obj_coef
 287.561 + _glp_lpx_set_obj_dir
 287.562 + _glp_lpx_set_obj_name
 287.563 + _glp_lpx_set_prob_name
 287.564 + _glp_lpx_set_real_parm
 287.565 + _glp_lpx_set_row_bnds
 287.566 + _glp_lpx_set_row_name
 287.567 + _glp_lpx_set_row_stat
 287.568 + _glp_lpx_simplex
 287.569 + _glp_lpx_std_basis
 287.570 + _glp_lpx_transform_col
 287.571 + _glp_lpx_transform_row
 287.572 + _glp_lpx_unscale_prob
 287.573 + _glp_lpx_warm_up
 287.574 + _glp_lpx_write_bas
 287.575 + _glp_lpx_write_cpxlp
 287.576 + _glp_lpx_write_freemps
 287.577 + _glp_lpx_write_mps
 287.578 +;; from glplpx02 ;;
 287.579 + _glp_put_mip_soln
 287.580 + _glp_put_solution
 287.581 +;; from glplpx03 ;;
 287.582 + _glp_lpx_write_pb
 287.583 +;; from glpluf ;;
 287.584 + _glp_luf_a_solve
 287.585 + _glp_luf_create_it
 287.586 + _glp_luf_defrag_sva
 287.587 + _glp_luf_delete_it
 287.588 + _glp_luf_enlarge_col
 287.589 + _glp_luf_enlarge_row
 287.590 + _glp_luf_f_solve
 287.591 + _glp_luf_factorize
 287.592 + _glp_luf_v_solve
 287.593 +;; from glplux ;;
 287.594 + _glp_lux_create
 287.595 + _glp_lux_decomp
 287.596 + _glp_lux_delete
 287.597 + _glp_lux_f_solve
 287.598 + _glp_lux_solve
 287.599 + _glp_lux_v_solve
 287.600 +;; from glpmat ;;
 287.601 + _glp_mat_adat_numeric
 287.602 + _glp_mat_adat_symbolic
 287.603 + _glp_mat_amd_order1
 287.604 + _glp_mat_check_fvs
 287.605 + _glp_mat_check_pattern
 287.606 + _glp_mat_chol_numeric
 287.607 + _glp_mat_chol_symbolic
 287.608 + _glp_mat_min_degree
 287.609 + _glp_mat_symamd_ord
 287.610 + _glp_mat_transpose
 287.611 + _glp_mat_u_solve
 287.612 + _glp_mat_ut_solve
 287.613 +;; from glpmpl01 ;;
 287.614 + _glp_mpl_append_block
 287.615 + _glp_mpl_append_char
 287.616 + _glp_mpl_append_slot
 287.617 + _glp_mpl_arg_list_len
 287.618 + _glp_mpl_branched_expression
 287.619 + _glp_mpl_check_statement
 287.620 + _glp_mpl_close_scope
 287.621 + _glp_mpl_constraint_statement
 287.622 + _glp_mpl_create_arg_list
 287.623 + _glp_mpl_create_block
 287.624 + _glp_mpl_create_domain
 287.625 + _glp_mpl_display_statement
 287.626 + _glp_mpl_domain_arity
 287.627 + _glp_mpl_elemset_argument
 287.628 + _glp_mpl_end_statement
 287.629 + _glp_mpl_enter_context
 287.630 + _glp_mpl_error_dimension
 287.631 + _glp_mpl_error_following
 287.632 + _glp_mpl_error_preceding
 287.633 + _glp_mpl_expand_arg_list
 287.634 + _glp_mpl_expression_0
 287.635 + _glp_mpl_expression_1
 287.636 + _glp_mpl_expression_10
 287.637 + _glp_mpl_expression_11
 287.638 + _glp_mpl_expression_12
 287.639 + _glp_mpl_expression_13
 287.640 + _glp_mpl_expression_2
 287.641 + _glp_mpl_expression_3
 287.642 + _glp_mpl_expression_4
 287.643 + _glp_mpl_expression_5
 287.644 + _glp_mpl_expression_6
 287.645 + _glp_mpl_expression_7
 287.646 + _glp_mpl_expression_8
 287.647 + _glp_mpl_expression_9
 287.648 + _glp_mpl_expression_list
 287.649 + _glp_mpl_for_statement
 287.650 + _glp_mpl_function_reference
 287.651 + _glp_mpl_get_char
 287.652 + _glp_mpl_get_token
 287.653 + _glp_mpl_indexing_expression
 287.654 + _glp_mpl_is_keyword
 287.655 + _glp_mpl_is_reserved
 287.656 + _glp_mpl_iterated_expression
 287.657 + _glp_mpl_literal_set
 287.658 + _glp_mpl_make_binary
 287.659 + _glp_mpl_make_code
 287.660 + _glp_mpl_make_ternary
 287.661 + _glp_mpl_make_unary
 287.662 + _glp_mpl_model_section
 287.663 + _glp_mpl_numeric_argument
 287.664 + _glp_mpl_numeric_literal
 287.665 + _glp_mpl_object_reference
 287.666 + _glp_mpl_objective_statement
 287.667 + _glp_mpl_parameter_statement
 287.668 + _glp_mpl_primary_expression
 287.669 + _glp_mpl_print_context
 287.670 + _glp_mpl_printf_statement
 287.671 + _glp_mpl_set_expression
 287.672 + _glp_mpl_set_statement
 287.673 + _glp_mpl_simple_statement
 287.674 + _glp_mpl_solve_statement
 287.675 + _glp_mpl_string_literal
 287.676 + _glp_mpl_subscript_list
 287.677 + _glp_mpl_symbolic_argument
 287.678 + _glp_mpl_table_statement
 287.679 + _glp_mpl_unget_token
 287.680 + _glp_mpl_variable_statement
 287.681 +;; from glpmpl02 ;;
 287.682 + _glp_mpl_create_slice
 287.683 + _glp_mpl_data_section
 287.684 + _glp_mpl_delete_slice
 287.685 + _glp_mpl_expand_slice
 287.686 + _glp_mpl_fake_slice
 287.687 + _glp_mpl_is_literal
 287.688 + _glp_mpl_is_number
 287.689 + _glp_mpl_is_symbol
 287.690 + _glp_mpl_matrix_format
 287.691 + _glp_mpl_parameter_data
 287.692 + _glp_mpl_plain_format
 287.693 + _glp_mpl_read_number
 287.694 + _glp_mpl_read_slice
 287.695 + _glp_mpl_read_symbol
 287.696 + _glp_mpl_read_value
 287.697 + _glp_mpl_select_parameter
 287.698 + _glp_mpl_select_set
 287.699 + _glp_mpl_set_data
 287.700 + _glp_mpl_set_default
 287.701 + _glp_mpl_simple_format
 287.702 + _glp_mpl_slice_arity
 287.703 + _glp_mpl_slice_dimen
 287.704 + _glp_mpl_tabbing_format
 287.705 + _glp_mpl_tabular_format
 287.706 +;; from glpmpl03 ;;
 287.707 + _glp_mpl_add_member
 287.708 + _glp_mpl_add_tuple
 287.709 + _glp_mpl_arelset_member
 287.710 + _glp_mpl_arelset_size
 287.711 + _glp_mpl_assign_dummy_index
 287.712 + _glp_mpl_build_subtuple
 287.713 + _glp_mpl_check_elem_set
 287.714 + _glp_mpl_check_then_add
 287.715 + _glp_mpl_check_value_num
 287.716 + _glp_mpl_check_value_sym
 287.717 + _glp_mpl_clean_check
 287.718 + _glp_mpl_clean_code
 287.719 + _glp_mpl_clean_constraint
 287.720 + _glp_mpl_clean_display
 287.721 + _glp_mpl_clean_domain
 287.722 + _glp_mpl_clean_for
 287.723 + _glp_mpl_clean_parameter
 287.724 + _glp_mpl_clean_printf
 287.725 + _glp_mpl_clean_set
 287.726 + _glp_mpl_clean_statement
 287.727 + _glp_mpl_clean_table
 287.728 + _glp_mpl_clean_variable
 287.729 + _glp_mpl_compare_strings
 287.730 + _glp_mpl_compare_symbols
 287.731 + _glp_mpl_compare_tuples
 287.732 + _glp_mpl_concat_symbols
 287.733 + _glp_mpl_constant_term
 287.734 + _glp_mpl_copy_elemset
 287.735 + _glp_mpl_copy_formula
 287.736 + _glp_mpl_copy_string
 287.737 + _glp_mpl_copy_symbol
 287.738 + _glp_mpl_copy_tuple
 287.739 + _glp_mpl_create_arelset
 287.740 + _glp_mpl_create_array
 287.741 + _glp_mpl_create_elemset
 287.742 + _glp_mpl_create_string
 287.743 + _glp_mpl_create_symbol_num
 287.744 + _glp_mpl_create_symbol_str
 287.745 + _glp_mpl_create_tuple
 287.746 + _glp_mpl_delete_array
 287.747 + _glp_mpl_delete_elemset
 287.748 + _glp_mpl_delete_formula
 287.749 + _glp_mpl_delete_string
 287.750 + _glp_mpl_delete_symbol
 287.751 + _glp_mpl_delete_tuple
 287.752 + _glp_mpl_delete_value
 287.753 + _glp_mpl_enter_domain_block
 287.754 + _glp_mpl_eval_elemset
 287.755 + _glp_mpl_eval_formula
 287.756 + _glp_mpl_eval_logical
 287.757 + _glp_mpl_eval_member_con
 287.758 + _glp_mpl_eval_member_num
 287.759 + _glp_mpl_eval_member_set
 287.760 + _glp_mpl_eval_member_sym
 287.761 + _glp_mpl_eval_member_var
 287.762 + _glp_mpl_eval_numeric
 287.763 + _glp_mpl_eval_symbolic
 287.764 + _glp_mpl_eval_tuple
 287.765 + _glp_mpl_eval_whole_con
 287.766 + _glp_mpl_eval_whole_par
 287.767 + _glp_mpl_eval_whole_set
 287.768 + _glp_mpl_eval_whole_var
 287.769 + _glp_mpl_eval_within_domain
 287.770 + _glp_mpl_execute_check
 287.771 + _glp_mpl_execute_display
 287.772 + _glp_mpl_execute_for
 287.773 + _glp_mpl_execute_printf
 287.774 + _glp_mpl_execute_statement
 287.775 + _glp_mpl_execute_table
 287.776 + _glp_mpl_expand_tuple
 287.777 + _glp_mpl_fetch_string
 287.778 + _glp_mpl_find_member
 287.779 + _glp_mpl_find_tuple
 287.780 + _glp_mpl_format_symbol
 287.781 + _glp_mpl_format_tuple
 287.782 + _glp_mpl_fp_add
 287.783 + _glp_mpl_fp_atan
 287.784 + _glp_mpl_fp_atan2
 287.785 + _glp_mpl_fp_cos
 287.786 + _glp_mpl_fp_div
 287.787 + _glp_mpl_fp_exp
 287.788 + _glp_mpl_fp_idiv
 287.789 + _glp_mpl_fp_irand224
 287.790 + _glp_mpl_fp_less
 287.791 + _glp_mpl_fp_log
 287.792 + _glp_mpl_fp_log10
 287.793 + _glp_mpl_fp_mod
 287.794 + _glp_mpl_fp_mul
 287.795 + _glp_mpl_fp_normal
 287.796 + _glp_mpl_fp_normal01
 287.797 + _glp_mpl_fp_power
 287.798 + _glp_mpl_fp_round
 287.799 + _glp_mpl_fp_sin
 287.800 + _glp_mpl_fp_sqrt
 287.801 + _glp_mpl_fp_sub
 287.802 + _glp_mpl_fp_trunc
 287.803 + _glp_mpl_fp_uniform01
 287.804 + _glp_mpl_free_dca
 287.805 + _glp_mpl_get_domain_tuple
 287.806 + _glp_mpl_is_member
 287.807 + _glp_mpl_linear_comb
 287.808 + _glp_mpl_loop_within_domain
 287.809 + _glp_mpl_out_of_domain
 287.810 + _glp_mpl_reduce_terms
 287.811 + _glp_mpl_remove_constant
 287.812 + _glp_mpl_set_cross
 287.813 + _glp_mpl_set_diff
 287.814 + _glp_mpl_set_inter
 287.815 + _glp_mpl_set_symdiff
 287.816 + _glp_mpl_set_union
 287.817 + _glp_mpl_single_variable
 287.818 + _glp_mpl_tab_get_arg
 287.819 + _glp_mpl_tab_get_name
 287.820 + _glp_mpl_tab_get_num
 287.821 + _glp_mpl_tab_get_str
 287.822 + _glp_mpl_tab_get_type
 287.823 + _glp_mpl_tab_num_args
 287.824 + _glp_mpl_tab_num_flds
 287.825 + _glp_mpl_tab_set_num
 287.826 + _glp_mpl_tab_set_str
 287.827 + _glp_mpl_take_member_con
 287.828 + _glp_mpl_take_member_num
 287.829 + _glp_mpl_take_member_set
 287.830 + _glp_mpl_take_member_sym
 287.831 + _glp_mpl_take_member_var
 287.832 + _glp_mpl_tuple_dimen
 287.833 + _glp_mpl_uniform
 287.834 + _glp_mpl_update_dummy_indices
 287.835 +;; from glpmpl04 ;;
 287.836 + _glp_mpl_alloc_content
 287.837 + _glp_mpl_build_problem
 287.838 + _glp_mpl_clean_model
 287.839 + _glp_mpl_close_input
 287.840 + _glp_mpl_error
 287.841 + _glp_mpl_flush_output
 287.842 + _glp_mpl_generate
 287.843 + _glp_mpl_generate_model
 287.844 + _glp_mpl_get_col_bnds
 287.845 + _glp_mpl_get_col_kind
 287.846 + _glp_mpl_get_col_name
 287.847 + _glp_mpl_get_mat_row
 287.848 + _glp_mpl_get_num_cols
 287.849 + _glp_mpl_get_num_rows
 287.850 + _glp_mpl_get_prob_name
 287.851 + _glp_mpl_get_row_bnds
 287.852 + _glp_mpl_get_row_c0
 287.853 + _glp_mpl_get_row_kind
 287.854 + _glp_mpl_get_row_name
 287.855 + _glp_mpl_has_solve_stmt
 287.856 + _glp_mpl_initialize
 287.857 + _glp_mpl_open_input
 287.858 + _glp_mpl_open_output
 287.859 + _glp_mpl_postsolve
 287.860 + _glp_mpl_postsolve_model
 287.861 + _glp_mpl_put_col_soln
 287.862 + _glp_mpl_put_row_soln
 287.863 + _glp_mpl_read_char
 287.864 + _glp_mpl_read_data
 287.865 + _glp_mpl_read_model
 287.866 + _glp_mpl_terminate
 287.867 + _glp_mpl_warning
 287.868 + _glp_mpl_write_char
 287.869 + _glp_mpl_write_text
 287.870 +;; from glpmpl05 ;;
 287.871 + _glp_mpl_fn_gmtime
 287.872 + _glp_mpl_fn_str2time
 287.873 + _glp_mpl_fn_time2str
 287.874 +;; from glpmpl06 ;;
 287.875 + _glp_mpl_tab_drv_close
 287.876 + _glp_mpl_tab_drv_open
 287.877 + _glp_mpl_tab_drv_read
 287.878 + _glp_mpl_tab_drv_write
 287.879 +;; from glpmps ;;
 287.880 + glp_init_mpscp
 287.881 + glp_read_mps
 287.882 + glp_write_mps
 287.883 +;; from glpnet01 ;;
 287.884 + _glp_mc21a
 287.885 +;; from glpnet02 ;;
 287.886 + _glp_mc13d
 287.887 +;; from glpnet03 ;;
 287.888 + glp_netgen
 287.889 +;; from glpnet04 ;;
 287.890 + glp_gridgen
 287.891 +;; from glpnet05 ;;
 287.892 + glp_rmfgen
 287.893 +;; from glpnet06 ;;
 287.894 + _glp_okalg
 287.895 +;; from glpnet07 ;;
 287.896 + _glp_ffalg
 287.897 +;; from glpnet08 ;;
 287.898 + _glp_wclique
 287.899 +;; from glpnet09 ;;
 287.900 + _glp_kellerman
 287.901 +;; from glpnpp01 ;;
 287.902 + _glp_npp_activate_col
 287.903 + _glp_npp_activate_row
 287.904 + _glp_npp_add_aij
 287.905 + _glp_npp_add_col
 287.906 + _glp_npp_add_row
 287.907 + _glp_npp_build_prob
 287.908 + _glp_npp_col_nnz
 287.909 + _glp_npp_create_wksp
 287.910 + _glp_npp_deactivate_col
 287.911 + _glp_npp_deactivate_row
 287.912 + _glp_npp_del_aij
 287.913 + _glp_npp_del_col
 287.914 + _glp_npp_del_row
 287.915 + _glp_npp_delete_wksp
 287.916 + _glp_npp_erase_row
 287.917 + _glp_npp_insert_col
 287.918 + _glp_npp_insert_row
 287.919 + _glp_npp_load_prob
 287.920 + _glp_npp_postprocess
 287.921 + _glp_npp_push_tse
 287.922 + _glp_npp_remove_col
 287.923 + _glp_npp_remove_row
 287.924 + _glp_npp_row_nnz
 287.925 + _glp_npp_unload_sol
 287.926 +;; from glpnpp02 ;;
 287.927 + _glp_npp_dbnd_col
 287.928 + _glp_npp_fixed_col
 287.929 + _glp_npp_free_col
 287.930 + _glp_npp_free_row
 287.931 + _glp_npp_geq_row
 287.932 + _glp_npp_lbnd_col
 287.933 + _glp_npp_leq_row
 287.934 + _glp_npp_make_equality
 287.935 + _glp_npp_make_fixed
 287.936 + _glp_npp_ubnd_col
 287.937 +;; from glpnpp03 ;;
 287.938 + _glp_npp_analyze_row
 287.939 + _glp_npp_empty_col
 287.940 + _glp_npp_empty_row
 287.941 + _glp_npp_eq_doublet
 287.942 + _glp_npp_eq_singlet
 287.943 + _glp_npp_forcing_row
 287.944 + _glp_npp_implied_bounds
 287.945 + _glp_npp_implied_free
 287.946 + _glp_npp_implied_lower
 287.947 + _glp_npp_implied_slack
 287.948 + _glp_npp_implied_upper
 287.949 + _glp_npp_implied_value
 287.950 + _glp_npp_inactive_bound
 287.951 + _glp_npp_ineq_singlet
 287.952 +;; from glpnpp04 ;;
 287.953 + _glp_npp_binarize_prob
 287.954 + _glp_npp_hidden_covering
 287.955 + _glp_npp_hidden_packing
 287.956 + _glp_npp_implied_packing
 287.957 + _glp_npp_is_covering
 287.958 + _glp_npp_is_packing
 287.959 + _glp_npp_is_partitioning
 287.960 + _glp_npp_reduce_ineq_coef
 287.961 +;; from glpnpp05 ;;
 287.962 + _glp_npp_clean_prob
 287.963 + _glp_npp_improve_bounds
 287.964 + _glp_npp_integer
 287.965 + _glp_npp_process_col
 287.966 + _glp_npp_process_prob
 287.967 + _glp_npp_process_row
 287.968 + _glp_npp_simplex
 287.969 +;; from glpqmd ;;
 287.970 + _glp_qmd_genqmd
 287.971 + _glp_qmd_qmdmrg
 287.972 + _glp_qmd_qmdqt
 287.973 + _glp_qmd_qmdrch
 287.974 + _glp_qmd_qmdupd
 287.975 +;; from glprgr ;;
 287.976 + _glp_rgr_write_bmp16
 287.977 +;; from glprng01 ;;
 287.978 + _glp_rng_create_rand
 287.979 + _glp_rng_delete_rand
 287.980 + _glp_rng_init_rand
 287.981 + _glp_rng_next_rand
 287.982 + _glp_rng_unif_rand
 287.983 +;; from glprng02 ;;
 287.984 + _glp_rng_unif_01
 287.985 + _glp_rng_uniform
 287.986 +;; from glpscf ;;
 287.987 + _glp_scf_create_it
 287.988 + _glp_scf_delete_it
 287.989 + _glp_scf_reset_it
 287.990 + _glp_scf_solve_it
 287.991 + _glp_scf_update_exp
 287.992 +;; from glpscl ;;
 287.993 + glp_scale_prob
 287.994 +;; from glpsdf ;;
 287.995 + glp_sdf_close_file
 287.996 + glp_sdf_error
 287.997 + glp_sdf_line
 287.998 + glp_sdf_open_file
 287.999 + glp_sdf_read_int
287.1000 + glp_sdf_read_item
287.1001 + glp_sdf_read_num
287.1002 + glp_sdf_read_text
287.1003 + glp_sdf_set_jump
287.1004 + glp_sdf_warning
287.1005 +;; from glpspm ;;
287.1006 + _glp_spm_add_mat
287.1007 + _glp_spm_add_num
287.1008 + _glp_spm_add_sym
287.1009 + _glp_spm_check_per
287.1010 + _glp_spm_count_nnz
287.1011 + _glp_spm_create_mat
287.1012 + _glp_spm_create_per
287.1013 + _glp_spm_delete_mat
287.1014 + _glp_spm_delete_per
287.1015 + _glp_spm_drop_zeros
287.1016 + _glp_spm_mul_mat
287.1017 + _glp_spm_mul_num
287.1018 + _glp_spm_mul_sym
287.1019 + _glp_spm_new_elem
287.1020 + _glp_spm_read_hbm
287.1021 + _glp_spm_read_mat
287.1022 + _glp_spm_show_mat
287.1023 + _glp_spm_test_mat_d
287.1024 + _glp_spm_test_mat_e
287.1025 + _glp_spm_transpose
287.1026 + _glp_spm_write_mat
287.1027 +;; from glpspx01 ;;
287.1028 + _glp_spx_primal
287.1029 +;; from glpspx02 ;;
287.1030 + _glp_spx_dual
287.1031 +;; from glpsql ;;
287.1032 + _glp_db_iodbc_close
287.1033 + _glp_db_iodbc_open
287.1034 + _glp_db_iodbc_read
287.1035 + _glp_db_iodbc_write
287.1036 + _glp_db_mysql_close
287.1037 + _glp_db_mysql_open
287.1038 + _glp_db_mysql_read
287.1039 + _glp_db_mysql_write
287.1040 +;; from glpssx01 ;;
287.1041 + _glp_ssx_change_basis
287.1042 + _glp_ssx_chuzc
287.1043 + _glp_ssx_chuzr
287.1044 + _glp_ssx_create
287.1045 + _glp_ssx_delete
287.1046 + _glp_ssx_eval_bbar
287.1047 + _glp_ssx_eval_cbar
287.1048 + _glp_ssx_eval_col
287.1049 + _glp_ssx_eval_dj
287.1050 + _glp_ssx_eval_pi
287.1051 + _glp_ssx_eval_rho
287.1052 + _glp_ssx_eval_row
287.1053 + _glp_ssx_factorize
287.1054 + _glp_ssx_get_xNj
287.1055 + _glp_ssx_update_bbar
287.1056 + _glp_ssx_update_cbar
287.1057 + _glp_ssx_update_pi
287.1058 +;; from glpssx02 ;;
287.1059 + _glp_ssx_driver
287.1060 + _glp_ssx_phase_I
287.1061 + _glp_ssx_phase_II
287.1062 +;; from glptsp ;;
287.1063 + _glp_tsp_distance
287.1064 + _glp_tsp_free_data
287.1065 + _glp_tsp_read_data
   288.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   288.2 +++ b/w32/readme.txt	Mon Dec 06 13:09:21 2010 +0100
   288.3 @@ -0,0 +1,24 @@
   288.4 +This directory contains batch files and other stuff which you can use
   288.5 +to build GLPK for 32-bit Windows with the native C/C++ compilers.
   288.6 +
   288.7 +Before running the batch file do the following:
   288.8 +
   288.9 +1. Make sure that you have installed the compiler you are going to use
  288.10 +   to build GLPK.
  288.11 +
  288.12 +2. Look into corresponding batch file (just right-click it and choose
  288.13 +   'Edit' in the popup menu; DO NOT choose 'Open'). Make sure that HOME
  288.14 +   variable specifies correct path to the compiler directory; if not,
  288.15 +   make necessary changes.
  288.16 +
  288.17 +To run the batch file just double-click it and wait a bit while the
  288.18 +Make utility does its job. The message 'OPTIMAL SOLUTION FOUND' in the
  288.19 +MS-DOS window means that all is OK. If you do not see it, something is
  288.20 +wrong.
  288.21 +
  288.22 +Once GLPK has been successfully built, there must appear two files in
  288.23 +this directory:
  288.24 +
  288.25 +glpk.lib, which is the GLPK object library, and
  288.26 +
  288.27 +glpsol.exe, which is the stand-alone GLPK LP/MIP solver.
   289.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   289.2 +++ b/w64/Build_GLPK_with_VC10.bat	Mon Dec 06 13:09:21 2010 +0100
   289.3 @@ -0,0 +1,11 @@
   289.4 +rem Build GLPK with Microsoft Visual Studio Express 2010
   289.5 +
   289.6 +rem NOTE: Make sure that HOME variable specifies correct path
   289.7 +set HOME="C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC"
   289.8 +
   289.9 +call %HOME%\vcvarsall.bat x64
  289.10 +copy config_VC config.h
  289.11 +%HOME%\bin\nmake.exe /f Makefile_VC
  289.12 +%HOME%\bin\nmake.exe /f Makefile_VC check
  289.13 +
  289.14 +pause
   290.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   290.2 +++ b/w64/Build_GLPK_with_VC10_DLL.bat	Mon Dec 06 13:09:21 2010 +0100
   290.3 @@ -0,0 +1,11 @@
   290.4 +rem Build GLPK DLL with Microsoft Visual Studio Express 2010
   290.5 +
   290.6 +rem NOTE: Make sure that HOME variable specifies correct path
   290.7 +set HOME="C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC"
   290.8 +
   290.9 +call %HOME%\vcvarsall.bat x64
  290.10 +copy config_VC config.h
  290.11 +%HOME%\bin\nmake.exe /f Makefile_VC_DLL
  290.12 +%HOME%\bin\nmake.exe /f Makefile_VC_DLL check
  290.13 +
  290.14 +pause
   291.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   291.2 +++ b/w64/Build_GLPK_with_VC9.bat	Mon Dec 06 13:09:21 2010 +0100
   291.3 @@ -0,0 +1,11 @@
   291.4 +rem Build GLPK with Microsoft Visual Studio Express 2008
   291.5 +
   291.6 +rem NOTE: Make sure that HOME variable specifies correct path
   291.7 +set HOME="C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC"
   291.8 +
   291.9 +call %HOME%\bin\vcvars64.bat
  291.10 +copy config_VC config.h
  291.11 +%HOME%\bin\nmake.exe /f Makefile_VC
  291.12 +%HOME%\bin\nmake.exe /f Makefile_VC check
  291.13 +
  291.14 +pause
   292.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   292.2 +++ b/w64/Build_GLPK_with_VC9_DLL.bat	Mon Dec 06 13:09:21 2010 +0100
   292.3 @@ -0,0 +1,11 @@
   292.4 +rem Build GLPK DLL with Microsoft Visual Studio Express 2008
   292.5 +
   292.6 +rem NOTE: Make sure that HOME variable specifies correct path
   292.7 +set HOME="C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC"
   292.8 +
   292.9 +call %HOME%\bin\vcvars64.bat
  292.10 +copy config_VC config.h
  292.11 +%HOME%\bin\nmake.exe /f Makefile_VC_DLL
  292.12 +%HOME%\bin\nmake.exe /f Makefile_VC_DLL check
  292.13 +
  292.14 +pause
   293.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   293.2 +++ b/w64/config_VC	Mon Dec 06 13:09:21 2010 +0100
   293.3 @@ -0,0 +1,13 @@
   293.4 +/* GLPK configuration file (Microsoft Visual Studio Express) */
   293.5 +
   293.6 +#define __WOE__ 1
   293.7 +
   293.8 +#define ODBC_DLNAME "odbc32.dll"
   293.9 +/* ODBC shared library name if this feature is enabled */
  293.10 +
  293.11 +#if 0
  293.12 +#define MYSQL_DLNAME "libmysql.dll"
  293.13 +/* MySQL shared library name if this feature is enabled */
  293.14 +#endif
  293.15 +
  293.16 +/* eof */
   294.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   294.2 +++ b/w64/glpk_4_45.def	Mon Dec 06 13:09:21 2010 +0100
   294.3 @@ -0,0 +1,1062 @@
   294.4 +LIBRARY glpk_4_45
   294.5 +VERSION 4.45
   294.6 +DESCRIPTION "GNU Linear Programming Kit"
   294.7 +EXPORTS
   294.8 +;; from amd_1 ;;
   294.9 + _glp_amd_1
  294.10 +;; from amd_2 ;;
  294.11 + _glp_amd_2
  294.12 +;; from amd_aat ;;
  294.13 + _glp_amd_aat
  294.14 +;; from amd_control ;;
  294.15 + _glp_amd_control
  294.16 +;; from amd_defaults ;;
  294.17 + _glp_amd_defaults
  294.18 +;; from amd_dump ;;
  294.19 +;; from amd_info ;;
  294.20 + _glp_amd_info
  294.21 +;; from amd_order ;;
  294.22 + _glp_amd_order
  294.23 +;; from amd_post_tree ;;
  294.24 + _glp_amd_post_tree
  294.25 +;; from amd_postorder ;;
  294.26 + _glp_amd_postorder
  294.27 +;; from amd_preprocess ;;
  294.28 + _glp_amd_preprocess
  294.29 +;; from amd_valid ;;
  294.30 + _glp_amd_valid
  294.31 +;; from colamd ;;
  294.32 + _glp_colamd
  294.33 + _glp_colamd_recommended
  294.34 + _glp_colamd_report
  294.35 + _glp_colamd_set_defaults
  294.36 + _glp_symamd
  294.37 + _glp_symamd_report
  294.38 +;; from glpapi01 ;;
  294.39 + glp_add_cols
  294.40 + glp_add_rows
  294.41 + glp_check_dup
  294.42 + glp_copy_prob
  294.43 + glp_create_prob
  294.44 + glp_del_cols
  294.45 + glp_del_rows
  294.46 + glp_delete_prob
  294.47 + glp_erase_prob
  294.48 + glp_load_matrix
  294.49 + glp_set_col_bnds
  294.50 + glp_set_col_name
  294.51 + glp_set_mat_col
  294.52 + glp_set_mat_row
  294.53 + glp_set_obj_coef
  294.54 + glp_set_obj_dir
  294.55 + glp_set_obj_name
  294.56 + glp_set_prob_name
  294.57 + glp_set_row_bnds
  294.58 + glp_set_row_name
  294.59 + glp_sort_matrix
  294.60 +;; from glpapi02 ;;
  294.61 + glp_get_col_lb
  294.62 + glp_get_col_name
  294.63 + glp_get_col_type
  294.64 + glp_get_col_ub
  294.65 + glp_get_mat_col
  294.66 + glp_get_mat_row
  294.67 + glp_get_num_cols
  294.68 + glp_get_num_nz
  294.69 + glp_get_num_rows
  294.70 + glp_get_obj_coef
  294.71 + glp_get_obj_dir
  294.72 + glp_get_obj_name
  294.73 + glp_get_prob_name
  294.74 + glp_get_row_lb
  294.75 + glp_get_row_name
  294.76 + glp_get_row_type
  294.77 + glp_get_row_ub
  294.78 +;; from glpapi03 ;;
  294.79 + glp_create_index
  294.80 + glp_delete_index
  294.81 + glp_find_col
  294.82 + glp_find_row
  294.83 +;; from glpapi04 ;;
  294.84 + glp_get_rii
  294.85 + glp_get_sjj
  294.86 + glp_set_rii
  294.87 + glp_set_sjj
  294.88 + glp_unscale_prob
  294.89 +;; from glpapi05 ;;
  294.90 + glp_set_col_stat
  294.91 + glp_set_row_stat
  294.92 + glp_std_basis
  294.93 +;; from glpapi06 ;;
  294.94 + glp_get_col_dual
  294.95 + glp_get_col_prim
  294.96 + glp_get_col_stat
  294.97 + glp_get_dual_stat
  294.98 + glp_get_obj_val
  294.99 + glp_get_prim_stat
 294.100 + glp_get_row_dual
 294.101 + glp_get_row_prim
 294.102 + glp_get_row_stat
 294.103 + glp_get_status
 294.104 + glp_get_unbnd_ray
 294.105 + glp_init_smcp
 294.106 + glp_simplex
 294.107 +;; from glpapi07 ;;
 294.108 + glp_exact
 294.109 +;; from glpapi08 ;;
 294.110 + glp_init_iptcp
 294.111 + glp_interior
 294.112 + glp_ipt_col_dual
 294.113 + glp_ipt_col_prim
 294.114 + glp_ipt_obj_val
 294.115 + glp_ipt_row_dual
 294.116 + glp_ipt_row_prim
 294.117 + glp_ipt_status
 294.118 +;; from glpapi09 ;;
 294.119 + glp_get_col_kind
 294.120 + glp_get_num_bin
 294.121 + glp_get_num_int
 294.122 + glp_init_iocp
 294.123 + glp_intopt
 294.124 + glp_mip_col_val
 294.125 + glp_mip_obj_val
 294.126 + glp_mip_row_val
 294.127 + glp_mip_status
 294.128 + glp_set_col_kind
 294.129 +;; from glpapi10 ;;
 294.130 + _glp_check_kkt
 294.131 +;; from glpapi11 ;;
 294.132 + glp_print_ipt
 294.133 + glp_print_mip
 294.134 + glp_print_ranges
 294.135 + glp_print_sol
 294.136 + glp_read_ipt
 294.137 + glp_read_mip
 294.138 + glp_read_sol
 294.139 + glp_write_ipt
 294.140 + glp_write_mip
 294.141 + glp_write_sol
 294.142 +;; from glpapi12 ;;
 294.143 + _glp_analyze_row
 294.144 + glp_analyze_bound
 294.145 + glp_analyze_coef
 294.146 + glp_bf_exists
 294.147 + glp_bf_updated
 294.148 + glp_btran
 294.149 + glp_dual_rtest
 294.150 + glp_eval_tab_col
 294.151 + glp_eval_tab_row
 294.152 + glp_factorize
 294.153 + glp_ftran
 294.154 + glp_get_bfcp
 294.155 + glp_get_bhead
 294.156 + glp_get_col_bind
 294.157 + glp_get_row_bind
 294.158 + glp_prim_rtest
 294.159 + glp_set_bfcp
 294.160 + glp_transform_col
 294.161 + glp_transform_row
 294.162 + glp_warm_up
 294.163 +;; from glpapi13 ;;
 294.164 + glp_ios_add_row
 294.165 + glp_ios_best_node
 294.166 + glp_ios_branch_upon
 294.167 + glp_ios_can_branch
 294.168 + glp_ios_clear_pool
 294.169 + glp_ios_curr_node
 294.170 + glp_ios_del_row
 294.171 + glp_ios_get_prob
 294.172 + glp_ios_heur_sol
 294.173 + glp_ios_mip_gap
 294.174 + glp_ios_next_node
 294.175 + glp_ios_node_bound
 294.176 + glp_ios_node_data
 294.177 + glp_ios_node_level
 294.178 + glp_ios_pool_size
 294.179 + glp_ios_prev_node
 294.180 + glp_ios_reason
 294.181 + glp_ios_row_attr
 294.182 + glp_ios_select_node
 294.183 + glp_ios_terminate
 294.184 + glp_ios_tree_size
 294.185 + glp_ios_up_node
 294.186 +;; from glpapi14 ;;
 294.187 + _glp_mpl_init_rand
 294.188 + glp_mpl_alloc_wksp
 294.189 + glp_mpl_build_prob
 294.190 + glp_mpl_free_wksp
 294.191 + glp_mpl_generate
 294.192 + glp_mpl_postsolve
 294.193 + glp_mpl_read_data
 294.194 + glp_mpl_read_model
 294.195 +;; from glpapi15 ;;
 294.196 + glp_add_arc
 294.197 + glp_add_vertices
 294.198 + glp_create_graph
 294.199 + glp_create_v_index
 294.200 + glp_del_arc
 294.201 + glp_del_vertices
 294.202 + glp_delete_graph
 294.203 + glp_delete_v_index
 294.204 + glp_erase_graph
 294.205 + glp_find_vertex
 294.206 + glp_read_graph
 294.207 + glp_set_graph_name
 294.208 + glp_set_vertex_name
 294.209 + glp_write_graph
 294.210 +;; from glpapi16 ;;
 294.211 + glp_strong_comp
 294.212 + glp_top_sort
 294.213 + glp_weak_comp
 294.214 +;; from glpapi17 ;;
 294.215 + glp_asnprob_hall
 294.216 + glp_asnprob_lp
 294.217 + glp_asnprob_okalg
 294.218 + glp_check_asnprob
 294.219 + glp_cpp
 294.220 + glp_maxflow_ffalg
 294.221 + glp_maxflow_lp
 294.222 + glp_mincost_lp
 294.223 + glp_mincost_okalg
 294.224 +;; from glpapi18 ;;
 294.225 + glp_wclique_exact
 294.226 +;; from glpapi19 ;;
 294.227 + glp_main
 294.228 +;; from glpavl ;;
 294.229 + _glp_avl_create_tree
 294.230 + _glp_avl_delete_node
 294.231 + _glp_avl_delete_tree
 294.232 + _glp_avl_find_node
 294.233 + _glp_avl_get_node_link
 294.234 + _glp_avl_get_node_type
 294.235 + _glp_avl_insert_node
 294.236 + _glp_avl_set_node_link
 294.237 + _glp_avl_set_node_type
 294.238 + _glp_avl_strcmp
 294.239 +;; from glpbfd ;;
 294.240 + _glp_bfd_btran
 294.241 + _glp_bfd_create_it
 294.242 + _glp_bfd_delete_it
 294.243 + _glp_bfd_factorize
 294.244 + _glp_bfd_ftran
 294.245 + _glp_bfd_get_count
 294.246 + _glp_bfd_set_parm
 294.247 + _glp_bfd_update_it
 294.248 +;; from glpbfx ;;
 294.249 + _glp_bfx_btran
 294.250 + _glp_bfx_create_binv
 294.251 + _glp_bfx_delete_binv
 294.252 + _glp_bfx_factorize
 294.253 + _glp_bfx_ftran
 294.254 + _glp_bfx_update
 294.255 +;; from glpcpx ;;
 294.256 + glp_init_cpxcp
 294.257 + glp_read_lp
 294.258 + glp_write_lp
 294.259 +;; from glpdmp ;;
 294.260 + _glp_dmp_create_pool
 294.261 + _glp_dmp_delete_pool
 294.262 + _glp_dmp_free_atom
 294.263 + _glp_dmp_get_atom
 294.264 + _glp_dmp_in_use
 294.265 +;; from glpdmx ;;
 294.266 + glp_read_asnprob
 294.267 + glp_read_ccdata
 294.268 + glp_read_maxflow
 294.269 + glp_read_mincost
 294.270 + glp_read_prob
 294.271 + glp_write_asnprob
 294.272 + glp_write_ccdata
 294.273 + glp_write_maxflow
 294.274 + glp_write_mincost
 294.275 + glp_write_prob
 294.276 +;; from glpenv01 ;;
 294.277 + _glp_get_env_ptr
 294.278 + glp_free_env
 294.279 + glp_init_env
 294.280 + glp_version
 294.281 +;; from glpenv02 ;;
 294.282 + _glp_tls_get_ptr
 294.283 + _glp_tls_set_ptr
 294.284 +;; from glpenv03 ;;
 294.285 + glp_close_tee
 294.286 + glp_open_tee
 294.287 + glp_printf
 294.288 + glp_term_hook
 294.289 + glp_term_out
 294.290 + glp_vprintf
 294.291 +;; from glpenv04 ;;
 294.292 + glp_assert_
 294.293 + glp_error_
 294.294 + glp_error_hook
 294.295 +;; from glpenv05 ;;
 294.296 + glp_calloc
 294.297 + glp_free
 294.298 + glp_malloc
 294.299 + glp_mem_limit
 294.300 + glp_mem_usage
 294.301 +;; from glpenv06 ;;
 294.302 + glp_difftime
 294.303 + glp_time
 294.304 +;; from glpenv07 ;;
 294.305 + _glp_lib_err_msg
 294.306 + _glp_lib_xerrmsg
 294.307 + _glp_lib_xfclose
 294.308 + _glp_lib_xfeof
 294.309 + _glp_lib_xferror
 294.310 + _glp_lib_xfflush
 294.311 + _glp_lib_xfgetc
 294.312 + _glp_lib_xfopen
 294.313 + _glp_lib_xfprintf
 294.314 + _glp_lib_xfputc
 294.315 +;; from glpenv08 ;;
 294.316 + _glp_xdlclose
 294.317 + _glp_xdlopen
 294.318 + _glp_xdlsym
 294.319 +;; from glpfhv ;;
 294.320 + _glp_fhv_btran
 294.321 + _glp_fhv_create_it
 294.322 + _glp_fhv_delete_it
 294.323 + _glp_fhv_factorize
 294.324 + _glp_fhv_ftran
 294.325 + _glp_fhv_h_solve
 294.326 + _glp_fhv_update_it
 294.327 +;; from glpgmp ;;
 294.328 + _glp_gmp_free_atom
 294.329 + _glp_gmp_free_mem
 294.330 + _glp_gmp_get_atom
 294.331 + _glp_gmp_get_work
 294.332 + _glp_gmp_pool_count
 294.333 + _glp_mpq_abs
 294.334 + _glp_mpq_add
 294.335 + _glp_mpq_canonicalize
 294.336 + _glp_mpq_clear
 294.337 + _glp_mpq_cmp
 294.338 + _glp_mpq_div
 294.339 + _glp_mpq_get_d
 294.340 + _glp_mpq_init
 294.341 + _glp_mpq_mul
 294.342 + _glp_mpq_neg
 294.343 + _glp_mpq_out_str
 294.344 + _glp_mpq_set
 294.345 + _glp_mpq_set_d
 294.346 + _glp_mpq_set_si
 294.347 + _glp_mpq_sgn
 294.348 + _glp_mpq_sub
 294.349 + _glp_mpz_abs
 294.350 + _glp_mpz_add
 294.351 + _glp_mpz_clear
 294.352 + _glp_mpz_cmp
 294.353 + _glp_mpz_div
 294.354 + _glp_mpz_gcd
 294.355 + _glp_mpz_get_d
 294.356 + _glp_mpz_get_d_2exp
 294.357 + _glp_mpz_init
 294.358 + _glp_mpz_mul
 294.359 + _glp_mpz_neg
 294.360 + _glp_mpz_out_str
 294.361 + _glp_mpz_set
 294.362 + _glp_mpz_set_si
 294.363 + _glp_mpz_sgn
 294.364 + _glp_mpz_sub
 294.365 + _glp_mpz_swap
 294.366 +;; from glphbm ;;
 294.367 + _glp_hbm_free_mat
 294.368 + _glp_hbm_read_mat
 294.369 +;; from glpini01 ;;
 294.370 + glp_adv_basis
 294.371 +;; from glpini02 ;;
 294.372 + glp_cpx_basis
 294.373 +;; from glpios01 ;;
 294.374 + _glp_ios_add_row
 294.375 + _glp_ios_best_node
 294.376 + _glp_ios_clear_pool
 294.377 + _glp_ios_clone_node
 294.378 + _glp_ios_create_pool
 294.379 + _glp_ios_create_tree
 294.380 + _glp_ios_del_row
 294.381 + _glp_ios_delete_node
 294.382 + _glp_ios_delete_pool
 294.383 + _glp_ios_delete_tree
 294.384 + _glp_ios_eval_degrad
 294.385 + _glp_ios_find_row
 294.386 + _glp_ios_freeze_node
 294.387 + _glp_ios_is_hopeful
 294.388 + _glp_ios_relative_gap
 294.389 + _glp_ios_revive_node
 294.390 + _glp_ios_round_bound
 294.391 + _glp_ios_solve_node
 294.392 +;; from glpios02 ;;
 294.393 + _glp_ios_preprocess_node
 294.394 +;; from glpios03 ;;
 294.395 + _glp_ios_driver
 294.396 +;; from glpios04 ;;
 294.397 + _glp_ios_check_vec
 294.398 + _glp_ios_clean_vec
 294.399 + _glp_ios_clear_vec
 294.400 + _glp_ios_copy_vec
 294.401 + _glp_ios_create_vec
 294.402 + _glp_ios_delete_vec
 294.403 + _glp_ios_get_vj
 294.404 + _glp_ios_linear_comb
 294.405 + _glp_ios_set_vj
 294.406 +;; from glpios05 ;;
 294.407 + _glp_ios_gmi_gen
 294.408 +;; from glpios06 ;;
 294.409 + _glp_ios_mir_gen
 294.410 + _glp_ios_mir_init
 294.411 + _glp_ios_mir_term
 294.412 +;; from glpios07 ;;
 294.413 + _glp_ios_cov_gen
 294.414 +;; from glpios08 ;;
 294.415 + _glp_ios_clq_gen
 294.416 + _glp_ios_clq_init
 294.417 + _glp_ios_clq_term
 294.418 +;; from glpios09 ;;
 294.419 + _glp_ios_choose_var
 294.420 + _glp_ios_pcost_branch
 294.421 + _glp_ios_pcost_free
 294.422 + _glp_ios_pcost_init
 294.423 + _glp_ios_pcost_update
 294.424 +;; from glpios10 ;;
 294.425 + _glp_ios_feas_pump
 294.426 +;; from glpios11 ;;
 294.427 + _glp_ios_process_cuts
 294.428 +;; from glpios12 ;;
 294.429 + _glp_ios_choose_node
 294.430 +;; from glpipm ;;
 294.431 + _glp_ipm_solve
 294.432 +;; from glplib01 ;;
 294.433 + _glp_lib_bigdiv
 294.434 + _glp_lib_bigmul
 294.435 +;; from glplib02 ;;
 294.436 + _glp_lib_xladd
 294.437 + _glp_lib_xlcmp
 294.438 + _glp_lib_xldiv
 294.439 + _glp_lib_xlmul
 294.440 + _glp_lib_xlneg
 294.441 + _glp_lib_xlset
 294.442 + _glp_lib_xlsub
 294.443 + _glp_lib_xltoa
 294.444 + _glp_lib_xltod
 294.445 +;; from glplib03 ;;
 294.446 + _glp_lib_fp2rat
 294.447 + _glp_lib_gcd
 294.448 + _glp_lib_gcdn
 294.449 + _glp_lib_jdate
 294.450 + _glp_lib_jday
 294.451 + _glp_lib_lcm
 294.452 + _glp_lib_lcmn
 294.453 + _glp_lib_round2n
 294.454 + _glp_lib_str2int
 294.455 + _glp_lib_str2num
 294.456 + _glp_lib_strrev
 294.457 + _glp_lib_strspx
 294.458 + _glp_lib_strtrim
 294.459 +;; from glplpf ;;
 294.460 + _glp_lpf_btran
 294.461 + _glp_lpf_create_it
 294.462 + _glp_lpf_delete_it
 294.463 + _glp_lpf_factorize
 294.464 + _glp_lpf_ftran
 294.465 + _glp_lpf_update_it
 294.466 +;; from glplpx01 ;;
 294.467 + _glp_lpx_add_cols
 294.468 + _glp_lpx_add_rows
 294.469 + _glp_lpx_adv_basis
 294.470 + _glp_lpx_check_int
 294.471 + _glp_lpx_check_kkt
 294.472 + _glp_lpx_cpx_basis
 294.473 + _glp_lpx_create_index
 294.474 + _glp_lpx_create_prob
 294.475 + _glp_lpx_del_cols
 294.476 + _glp_lpx_del_rows
 294.477 + _glp_lpx_delete_index
 294.478 + _glp_lpx_delete_prob
 294.479 + _glp_lpx_dual_ratio_test
 294.480 + _glp_lpx_eval_tab_col
 294.481 + _glp_lpx_eval_tab_row
 294.482 + _glp_lpx_exact
 294.483 + _glp_lpx_find_col
 294.484 + _glp_lpx_find_row
 294.485 + _glp_lpx_get_class
 294.486 + _glp_lpx_get_col_bnds
 294.487 + _glp_lpx_get_col_dual
 294.488 + _glp_lpx_get_col_info
 294.489 + _glp_lpx_get_col_kind
 294.490 + _glp_lpx_get_col_lb
 294.491 + _glp_lpx_get_col_name
 294.492 + _glp_lpx_get_col_prim
 294.493 + _glp_lpx_get_col_stat
 294.494 + _glp_lpx_get_col_type
 294.495 + _glp_lpx_get_col_ub
 294.496 + _glp_lpx_get_dual_stat
 294.497 + _glp_lpx_get_int_parm
 294.498 + _glp_lpx_get_mat_col
 294.499 + _glp_lpx_get_mat_row
 294.500 + _glp_lpx_get_num_bin
 294.501 + _glp_lpx_get_num_cols
 294.502 + _glp_lpx_get_num_int
 294.503 + _glp_lpx_get_num_nz
 294.504 + _glp_lpx_get_num_rows
 294.505 + _glp_lpx_get_obj_coef
 294.506 + _glp_lpx_get_obj_dir
 294.507 + _glp_lpx_get_obj_name
 294.508 + _glp_lpx_get_obj_val
 294.509 + _glp_lpx_get_prim_stat
 294.510 + _glp_lpx_get_prob_name
 294.511 + _glp_lpx_get_ray_info
 294.512 + _glp_lpx_get_real_parm
 294.513 + _glp_lpx_get_row_bnds
 294.514 + _glp_lpx_get_row_dual
 294.515 + _glp_lpx_get_row_info
 294.516 + _glp_lpx_get_row_lb
 294.517 + _glp_lpx_get_row_name
 294.518 + _glp_lpx_get_row_prim
 294.519 + _glp_lpx_get_row_stat
 294.520 + _glp_lpx_get_row_type
 294.521 + _glp_lpx_get_row_ub
 294.522 + _glp_lpx_get_status
 294.523 + _glp_lpx_integer
 294.524 + _glp_lpx_interior
 294.525 + _glp_lpx_intopt
 294.526 + _glp_lpx_ipt_col_dual
 294.527 + _glp_lpx_ipt_col_prim
 294.528 + _glp_lpx_ipt_obj_val
 294.529 + _glp_lpx_ipt_row_dual
 294.530 + _glp_lpx_ipt_row_prim
 294.531 + _glp_lpx_ipt_status
 294.532 + _glp_lpx_is_b_avail
 294.533 + _glp_lpx_load_matrix
 294.534 + _glp_lpx_main
 294.535 + _glp_lpx_mip_col_val
 294.536 + _glp_lpx_mip_obj_val
 294.537 + _glp_lpx_mip_row_val
 294.538 + _glp_lpx_mip_status
 294.539 + _glp_lpx_prim_ratio_test
 294.540 + _glp_lpx_print_ips
 294.541 + _glp_lpx_print_mip
 294.542 + _glp_lpx_print_prob
 294.543 + _glp_lpx_print_sens_bnds
 294.544 + _glp_lpx_print_sol
 294.545 + _glp_lpx_read_bas
 294.546 + _glp_lpx_read_cpxlp
 294.547 + _glp_lpx_read_freemps
 294.548 + _glp_lpx_read_model
 294.549 + _glp_lpx_read_mps
 294.550 + _glp_lpx_reset_parms
 294.551 + _glp_lpx_scale_prob
 294.552 + _glp_lpx_set_class
 294.553 + _glp_lpx_set_col_bnds
 294.554 + _glp_lpx_set_col_kind
 294.555 + _glp_lpx_set_col_name
 294.556 + _glp_lpx_set_col_stat
 294.557 + _glp_lpx_set_int_parm
 294.558 + _glp_lpx_set_mat_col
 294.559 + _glp_lpx_set_mat_row
 294.560 + _glp_lpx_set_obj_coef
 294.561 + _glp_lpx_set_obj_dir
 294.562 + _glp_lpx_set_obj_name
 294.563 + _glp_lpx_set_prob_name
 294.564 + _glp_lpx_set_real_parm
 294.565 + _glp_lpx_set_row_bnds
 294.566 + _glp_lpx_set_row_name
 294.567 + _glp_lpx_set_row_stat
 294.568 + _glp_lpx_simplex
 294.569 + _glp_lpx_std_basis
 294.570 + _glp_lpx_transform_col
 294.571 + _glp_lpx_transform_row
 294.572 + _glp_lpx_unscale_prob
 294.573 + _glp_lpx_warm_up
 294.574 + _glp_lpx_write_bas
 294.575 + _glp_lpx_write_cpxlp
 294.576 + _glp_lpx_write_freemps
 294.577 + _glp_lpx_write_mps
 294.578 +;; from glplpx02 ;;
 294.579 + _glp_put_mip_soln
 294.580 + _glp_put_solution
 294.581 +;; from glplpx03 ;;
 294.582 + _glp_lpx_write_pb
 294.583 +;; from glpluf ;;
 294.584 + _glp_luf_a_solve
 294.585 + _glp_luf_create_it
 294.586 + _glp_luf_defrag_sva
 294.587 + _glp_luf_delete_it
 294.588 + _glp_luf_enlarge_col
 294.589 + _glp_luf_enlarge_row
 294.590 + _glp_luf_f_solve
 294.591 + _glp_luf_factorize
 294.592 + _glp_luf_v_solve
 294.593 +;; from glplux ;;
 294.594 + _glp_lux_create
 294.595 + _glp_lux_decomp
 294.596 + _glp_lux_delete
 294.597 + _glp_lux_f_solve
 294.598 + _glp_lux_solve
 294.599 + _glp_lux_v_solve
 294.600 +;; from glpmat ;;
 294.601 + _glp_mat_adat_numeric
 294.602 + _glp_mat_adat_symbolic
 294.603 + _glp_mat_amd_order1
 294.604 + _glp_mat_check_fvs
 294.605 + _glp_mat_check_pattern
 294.606 + _glp_mat_chol_numeric
 294.607 + _glp_mat_chol_symbolic
 294.608 + _glp_mat_min_degree
 294.609 + _glp_mat_symamd_ord
 294.610 + _glp_mat_transpose
 294.611 + _glp_mat_u_solve
 294.612 + _glp_mat_ut_solve
 294.613 +;; from glpmpl01 ;;
 294.614 + _glp_mpl_append_block
 294.615 + _glp_mpl_append_char
 294.616 + _glp_mpl_append_slot
 294.617 + _glp_mpl_arg_list_len
 294.618 + _glp_mpl_branched_expression
 294.619 + _glp_mpl_check_statement
 294.620 + _glp_mpl_close_scope
 294.621 + _glp_mpl_constraint_statement
 294.622 + _glp_mpl_create_arg_list
 294.623 + _glp_mpl_create_block
 294.624 + _glp_mpl_create_domain
 294.625 + _glp_mpl_display_statement
 294.626 + _glp_mpl_domain_arity
 294.627 + _glp_mpl_elemset_argument
 294.628 + _glp_mpl_end_statement
 294.629 + _glp_mpl_enter_context
 294.630 + _glp_mpl_error_dimension
 294.631 + _glp_mpl_error_following
 294.632 + _glp_mpl_error_preceding
 294.633 + _glp_mpl_expand_arg_list
 294.634 + _glp_mpl_expression_0
 294.635 + _glp_mpl_expression_1
 294.636 + _glp_mpl_expression_10
 294.637 + _glp_mpl_expression_11
 294.638 + _glp_mpl_expression_12
 294.639 + _glp_mpl_expression_13
 294.640 + _glp_mpl_expression_2
 294.641 + _glp_mpl_expression_3
 294.642 + _glp_mpl_expression_4
 294.643 + _glp_mpl_expression_5
 294.644 + _glp_mpl_expression_6
 294.645 + _glp_mpl_expression_7
 294.646 + _glp_mpl_expression_8
 294.647 + _glp_mpl_expression_9
 294.648 + _glp_mpl_expression_list
 294.649 + _glp_mpl_for_statement
 294.650 + _glp_mpl_function_reference
 294.651 + _glp_mpl_get_char
 294.652 + _glp_mpl_get_token
 294.653 + _glp_mpl_indexing_expression
 294.654 + _glp_mpl_is_keyword
 294.655 + _glp_mpl_is_reserved
 294.656 + _glp_mpl_iterated_expression
 294.657 + _glp_mpl_literal_set
 294.658 + _glp_mpl_make_binary
 294.659 + _glp_mpl_make_code
 294.660 + _glp_mpl_make_ternary
 294.661 + _glp_mpl_make_unary
 294.662 + _glp_mpl_model_section
 294.663 + _glp_mpl_numeric_argument
 294.664 + _glp_mpl_numeric_literal
 294.665 + _glp_mpl_object_reference
 294.666 + _glp_mpl_objective_statement
 294.667 + _glp_mpl_parameter_statement
 294.668 + _glp_mpl_primary_expression
 294.669 + _glp_mpl_print_context
 294.670 + _glp_mpl_printf_statement
 294.671 + _glp_mpl_set_expression
 294.672 + _glp_mpl_set_statement
 294.673 + _glp_mpl_simple_statement
 294.674 + _glp_mpl_solve_statement
 294.675 + _glp_mpl_string_literal
 294.676 + _glp_mpl_subscript_list
 294.677 + _glp_mpl_symbolic_argument
 294.678 + _glp_mpl_table_statement
 294.679 + _glp_mpl_unget_token
 294.680 + _glp_mpl_variable_statement
 294.681 +;; from glpmpl02 ;;
 294.682 + _glp_mpl_create_slice
 294.683 + _glp_mpl_data_section
 294.684 + _glp_mpl_delete_slice
 294.685 + _glp_mpl_expand_slice
 294.686 + _glp_mpl_fake_slice
 294.687 + _glp_mpl_is_literal
 294.688 + _glp_mpl_is_number
 294.689 + _glp_mpl_is_symbol
 294.690 + _glp_mpl_matrix_format
 294.691 + _glp_mpl_parameter_data
 294.692 + _glp_mpl_plain_format
 294.693 + _glp_mpl_read_number
 294.694 + _glp_mpl_read_slice
 294.695 + _glp_mpl_read_symbol
 294.696 + _glp_mpl_read_value
 294.697 + _glp_mpl_select_parameter
 294.698 + _glp_mpl_select_set
 294.699 + _glp_mpl_set_data
 294.700 + _glp_mpl_set_default
 294.701 + _glp_mpl_simple_format
 294.702 + _glp_mpl_slice_arity
 294.703 + _glp_mpl_slice_dimen
 294.704 + _glp_mpl_tabbing_format
 294.705 + _glp_mpl_tabular_format
 294.706 +;; from glpmpl03 ;;
 294.707 + _glp_mpl_add_member
 294.708 + _glp_mpl_add_tuple
 294.709 + _glp_mpl_arelset_member
 294.710 + _glp_mpl_arelset_size
 294.711 + _glp_mpl_assign_dummy_index
 294.712 + _glp_mpl_build_subtuple
 294.713 + _glp_mpl_check_elem_set
 294.714 + _glp_mpl_check_then_add
 294.715 + _glp_mpl_check_value_num
 294.716 + _glp_mpl_check_value_sym
 294.717 + _glp_mpl_clean_check
 294.718 + _glp_mpl_clean_code
 294.719 + _glp_mpl_clean_constraint
 294.720 + _glp_mpl_clean_display
 294.721 + _glp_mpl_clean_domain
 294.722 + _glp_mpl_clean_for
 294.723 + _glp_mpl_clean_parameter
 294.724 + _glp_mpl_clean_printf
 294.725 + _glp_mpl_clean_set
 294.726 + _glp_mpl_clean_statement
 294.727 + _glp_mpl_clean_table
 294.728 + _glp_mpl_clean_variable
 294.729 + _glp_mpl_compare_strings
 294.730 + _glp_mpl_compare_symbols
 294.731 + _glp_mpl_compare_tuples
 294.732 + _glp_mpl_concat_symbols
 294.733 + _glp_mpl_constant_term
 294.734 + _glp_mpl_copy_elemset
 294.735 + _glp_mpl_copy_formula
 294.736 + _glp_mpl_copy_string
 294.737 + _glp_mpl_copy_symbol
 294.738 + _glp_mpl_copy_tuple
 294.739 + _glp_mpl_create_arelset
 294.740 + _glp_mpl_create_array
 294.741 + _glp_mpl_create_elemset
 294.742 + _glp_mpl_create_string
 294.743 + _glp_mpl_create_symbol_num
 294.744 + _glp_mpl_create_symbol_str
 294.745 + _glp_mpl_create_tuple
 294.746 + _glp_mpl_delete_array
 294.747 + _glp_mpl_delete_elemset
 294.748 + _glp_mpl_delete_formula
 294.749 + _glp_mpl_delete_string
 294.750 + _glp_mpl_delete_symbol
 294.751 + _glp_mpl_delete_tuple
 294.752 + _glp_mpl_delete_value
 294.753 + _glp_mpl_enter_domain_block
 294.754 + _glp_mpl_eval_elemset
 294.755 + _glp_mpl_eval_formula
 294.756 + _glp_mpl_eval_logical
 294.757 + _glp_mpl_eval_member_con
 294.758 + _glp_mpl_eval_member_num
 294.759 + _glp_mpl_eval_member_set
 294.760 + _glp_mpl_eval_member_sym
 294.761 + _glp_mpl_eval_member_var
 294.762 + _glp_mpl_eval_numeric
 294.763 + _glp_mpl_eval_symbolic
 294.764 + _glp_mpl_eval_tuple
 294.765 + _glp_mpl_eval_whole_con
 294.766 + _glp_mpl_eval_whole_par
 294.767 + _glp_mpl_eval_whole_set
 294.768 + _glp_mpl_eval_whole_var
 294.769 + _glp_mpl_eval_within_domain
 294.770 + _glp_mpl_execute_check
 294.771 + _glp_mpl_execute_display
 294.772 + _glp_mpl_execute_for
 294.773 + _glp_mpl_execute_printf
 294.774 + _glp_mpl_execute_statement
 294.775 + _glp_mpl_execute_table
 294.776 + _glp_mpl_expand_tuple
 294.777 + _glp_mpl_fetch_string
 294.778 + _glp_mpl_find_member
 294.779 + _glp_mpl_find_tuple
 294.780 + _glp_mpl_format_symbol
 294.781 + _glp_mpl_format_tuple
 294.782 + _glp_mpl_fp_add
 294.783 + _glp_mpl_fp_atan
 294.784 + _glp_mpl_fp_atan2
 294.785 + _glp_mpl_fp_cos
 294.786 + _glp_mpl_fp_div
 294.787 + _glp_mpl_fp_exp
 294.788 + _glp_mpl_fp_idiv
 294.789 + _glp_mpl_fp_irand224
 294.790 + _glp_mpl_fp_less
 294.791 + _glp_mpl_fp_log
 294.792 + _glp_mpl_fp_log10
 294.793 + _glp_mpl_fp_mod
 294.794 + _glp_mpl_fp_mul
 294.795 + _glp_mpl_fp_normal
 294.796 + _glp_mpl_fp_normal01
 294.797 + _glp_mpl_fp_power
 294.798 + _glp_mpl_fp_round
 294.799 + _glp_mpl_fp_sin
 294.800 + _glp_mpl_fp_sqrt
 294.801 + _glp_mpl_fp_sub
 294.802 + _glp_mpl_fp_trunc
 294.803 + _glp_mpl_fp_uniform01
 294.804 + _glp_mpl_free_dca
 294.805 + _glp_mpl_get_domain_tuple
 294.806 + _glp_mpl_is_member
 294.807 + _glp_mpl_linear_comb
 294.808 + _glp_mpl_loop_within_domain
 294.809 + _glp_mpl_out_of_domain
 294.810 + _glp_mpl_reduce_terms
 294.811 + _glp_mpl_remove_constant
 294.812 + _glp_mpl_set_cross
 294.813 + _glp_mpl_set_diff
 294.814 + _glp_mpl_set_inter
 294.815 + _glp_mpl_set_symdiff
 294.816 + _glp_mpl_set_union
 294.817 + _glp_mpl_single_variable
 294.818 + _glp_mpl_tab_get_arg
 294.819 + _glp_mpl_tab_get_name
 294.820 + _glp_mpl_tab_get_num
 294.821 + _glp_mpl_tab_get_str
 294.822 + _glp_mpl_tab_get_type
 294.823 + _glp_mpl_tab_num_args
 294.824 + _glp_mpl_tab_num_flds
 294.825 + _glp_mpl_tab_set_num
 294.826 + _glp_mpl_tab_set_str
 294.827 + _glp_mpl_take_member_con
 294.828 + _glp_mpl_take_member_num
 294.829 + _glp_mpl_take_member_set
 294.830 + _glp_mpl_take_member_sym
 294.831 + _glp_mpl_take_member_var
 294.832 + _glp_mpl_tuple_dimen
 294.833 + _glp_mpl_uniform
 294.834 + _glp_mpl_update_dummy_indices
 294.835 +;; from glpmpl04 ;;
 294.836 + _glp_mpl_alloc_content
 294.837 + _glp_mpl_build_problem
 294.838 + _glp_mpl_clean_model
 294.839 + _glp_mpl_close_input
 294.840 + _glp_mpl_error
 294.841 + _glp_mpl_flush_output
 294.842 + _glp_mpl_generate
 294.843 + _glp_mpl_generate_model
 294.844 + _glp_mpl_get_col_bnds
 294.845 + _glp_mpl_get_col_kind
 294.846 + _glp_mpl_get_col_name
 294.847 + _glp_mpl_get_mat_row
 294.848 + _glp_mpl_get_num_cols
 294.849 + _glp_mpl_get_num_rows
 294.850 + _glp_mpl_get_prob_name
 294.851 + _glp_mpl_get_row_bnds
 294.852 + _glp_mpl_get_row_c0
 294.853 + _glp_mpl_get_row_kind
 294.854 + _glp_mpl_get_row_name
 294.855 + _glp_mpl_has_solve_stmt
 294.856 + _glp_mpl_initialize
 294.857 + _glp_mpl_open_input
 294.858 + _glp_mpl_open_output
 294.859 + _glp_mpl_postsolve
 294.860 + _glp_mpl_postsolve_model
 294.861 + _glp_mpl_put_col_soln
 294.862 + _glp_mpl_put_row_soln
 294.863 + _glp_mpl_read_char
 294.864 + _glp_mpl_read_data
 294.865 + _glp_mpl_read_model
 294.866 + _glp_mpl_terminate
 294.867 + _glp_mpl_warning
 294.868 + _glp_mpl_write_char
 294.869 + _glp_mpl_write_text
 294.870 +;; from glpmpl05 ;;
 294.871 + _glp_mpl_fn_gmtime
 294.872 + _glp_mpl_fn_str2time
 294.873 + _glp_mpl_fn_time2str
 294.874 +;; from glpmpl06 ;;
 294.875 + _glp_mpl_tab_drv_close
 294.876 + _glp_mpl_tab_drv_open
 294.877 + _glp_mpl_tab_drv_read
 294.878 + _glp_mpl_tab_drv_write
 294.879 +;; from glpmps ;;
 294.880 + glp_init_mpscp
 294.881 + glp_read_mps
 294.882 + glp_write_mps
 294.883 +;; from glpnet01 ;;
 294.884 + _glp_mc21a
 294.885 +;; from glpnet02 ;;
 294.886 + _glp_mc13d
 294.887 +;; from glpnet03 ;;
 294.888 + glp_netgen
 294.889 +;; from glpnet04 ;;
 294.890 + glp_gridgen
 294.891 +;; from glpnet05 ;;
 294.892 + glp_rmfgen
 294.893 +;; from glpnet06 ;;
 294.894 + _glp_okalg
 294.895 +;; from glpnet07 ;;
 294.896 + _glp_ffalg
 294.897 +;; from glpnet08 ;;
 294.898 + _glp_wclique
 294.899 +;; from glpnet09 ;;
 294.900 + _glp_kellerman
 294.901 +;; from glpnpp01 ;;
 294.902 + _glp_npp_activate_col
 294.903 + _glp_npp_activate_row
 294.904 + _glp_npp_add_aij
 294.905 + _glp_npp_add_col
 294.906 + _glp_npp_add_row
 294.907 + _glp_npp_build_prob
 294.908 + _glp_npp_col_nnz
 294.909 + _glp_npp_create_wksp
 294.910 + _glp_npp_deactivate_col
 294.911 + _glp_npp_deactivate_row
 294.912 + _glp_npp_del_aij
 294.913 + _glp_npp_del_col
 294.914 + _glp_npp_del_row
 294.915 + _glp_npp_delete_wksp
 294.916 + _glp_npp_erase_row
 294.917 + _glp_npp_insert_col
 294.918 + _glp_npp_insert_row
 294.919 + _glp_npp_load_prob
 294.920 + _glp_npp_postprocess
 294.921 + _glp_npp_push_tse
 294.922 + _glp_npp_remove_col
 294.923 + _glp_npp_remove_row
 294.924 + _glp_npp_row_nnz
 294.925 + _glp_npp_unload_sol
 294.926 +;; from glpnpp02 ;;
 294.927 + _glp_npp_dbnd_col
 294.928 + _glp_npp_fixed_col
 294.929 + _glp_npp_free_col
 294.930 + _glp_npp_free_row
 294.931 + _glp_npp_geq_row
 294.932 + _glp_npp_lbnd_col
 294.933 + _glp_npp_leq_row
 294.934 + _glp_npp_make_equality
 294.935 + _glp_npp_make_fixed
 294.936 + _glp_npp_ubnd_col
 294.937 +;; from glpnpp03 ;;
 294.938 + _glp_npp_analyze_row
 294.939 + _glp_npp_empty_col
 294.940 + _glp_npp_empty_row
 294.941 + _glp_npp_eq_doublet
 294.942 + _glp_npp_eq_singlet
 294.943 + _glp_npp_forcing_row
 294.944 + _glp_npp_implied_bounds
 294.945 + _glp_npp_implied_free
 294.946 + _glp_npp_implied_lower
 294.947 + _glp_npp_implied_slack
 294.948 + _glp_npp_implied_upper
 294.949 + _glp_npp_implied_value
 294.950 + _glp_npp_inactive_bound
 294.951 + _glp_npp_ineq_singlet
 294.952 +;; from glpnpp04 ;;
 294.953 + _glp_npp_binarize_prob
 294.954 + _glp_npp_hidden_covering
 294.955 + _glp_npp_hidden_packing
 294.956 + _glp_npp_implied_packing
 294.957 + _glp_npp_is_covering
 294.958 + _glp_npp_is_packing
 294.959 + _glp_npp_is_partitioning
 294.960 + _glp_npp_reduce_ineq_coef
 294.961 +;; from glpnpp05 ;;
 294.962 + _glp_npp_clean_prob
 294.963 + _glp_npp_improve_bounds
 294.964 + _glp_npp_integer
 294.965 + _glp_npp_process_col
 294.966 + _glp_npp_process_prob
 294.967 + _glp_npp_process_row
 294.968 + _glp_npp_simplex
 294.969 +;; from glpqmd ;;
 294.970 + _glp_qmd_genqmd
 294.971 + _glp_qmd_qmdmrg
 294.972 + _glp_qmd_qmdqt
 294.973 + _glp_qmd_qmdrch
 294.974 + _glp_qmd_qmdupd
 294.975 +;; from glprgr ;;
 294.976 + _glp_rgr_write_bmp16
 294.977 +;; from glprng01 ;;
 294.978 + _glp_rng_create_rand
 294.979 + _glp_rng_delete_rand
 294.980 + _glp_rng_init_rand
 294.981 + _glp_rng_next_rand
 294.982 + _glp_rng_unif_rand
 294.983 +;; from glprng02 ;;
 294.984 + _glp_rng_unif_01
 294.985 + _glp_rng_uniform
 294.986 +;; from glpscf ;;
 294.987 + _glp_scf_create_it
 294.988 + _glp_scf_delete_it
 294.989 + _glp_scf_reset_it
 294.990 + _glp_scf_solve_it
 294.991 + _glp_scf_update_exp
 294.992 +;; from glpscl ;;
 294.993 + glp_scale_prob
 294.994 +;; from glpsdf ;;
 294.995 + glp_sdf_close_file
 294.996 + glp_sdf_error
 294.997 + glp_sdf_line
 294.998 + glp_sdf_open_file
 294.999 + glp_sdf_read_int
294.1000 + glp_sdf_read_item
294.1001 + glp_sdf_read_num
294.1002 + glp_sdf_read_text
294.1003 + glp_sdf_set_jump
294.1004 + glp_sdf_warning
294.1005 +;; from glpspm ;;
294.1006 + _glp_spm_add_mat
294.1007 + _glp_spm_add_num
294.1008 + _glp_spm_add_sym
294.1009 + _glp_spm_check_per
294.1010 + _glp_spm_count_nnz
294.1011 + _glp_spm_create_mat
294.1012 + _glp_spm_create_per
294.1013 + _glp_spm_delete_mat
294.1014 + _glp_spm_delete_per
294.1015 + _glp_spm_drop_zeros
294.1016 + _glp_spm_mul_mat
294.1017 + _glp_spm_mul_num
294.1018 + _glp_spm_mul_sym
294.1019 + _glp_spm_new_elem
294.1020 + _glp_spm_read_hbm
294.1021 + _glp_spm_read_mat
294.1022 + _glp_spm_show_mat
294.1023 + _glp_spm_test_mat_d
294.1024 + _glp_spm_test_mat_e
294.1025 + _glp_spm_transpose
294.1026 + _glp_spm_write_mat
294.1027 +;; from glpspx01 ;;
294.1028 + _glp_spx_primal
294.1029 +;; from glpspx02 ;;
294.1030 + _glp_spx_dual
294.1031 +;; from glpsql ;;
294.1032 + _glp_db_iodbc_close
294.1033 + _glp_db_iodbc_open
294.1034 + _glp_db_iodbc_read
294.1035 + _glp_db_iodbc_write
294.1036 + _glp_db_mysql_close
294.1037 + _glp_db_mysql_open
294.1038 + _glp_db_mysql_read
294.1039 + _glp_db_mysql_write
294.1040 +;; from glpssx01 ;;
294.1041 + _glp_ssx_change_basis
294.1042 + _glp_ssx_chuzc
294.1043 + _glp_ssx_chuzr
294.1044 + _glp_ssx_create
294.1045 + _glp_ssx_delete
294.1046 + _glp_ssx_eval_bbar
294.1047 + _glp_ssx_eval_cbar
294.1048 + _glp_ssx_eval_col
294.1049 + _glp_ssx_eval_dj
294.1050 + _glp_ssx_eval_pi
294.1051 + _glp_ssx_eval_rho
294.1052 + _glp_ssx_eval_row
294.1053 + _glp_ssx_factorize
294.1054 + _glp_ssx_get_xNj
294.1055 + _glp_ssx_update_bbar
294.1056 + _glp_ssx_update_cbar
294.1057 + _glp_ssx_update_pi
294.1058 +;; from glpssx02 ;;
294.1059 + _glp_ssx_driver
294.1060 + _glp_ssx_phase_I
294.1061 + _glp_ssx_phase_II
294.1062 +;; from glptsp ;;
294.1063 + _glp_tsp_distance
294.1064 + _glp_tsp_free_data
294.1065 + _glp_tsp_read_data
   295.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   295.2 +++ b/w64/makefile_VC	Mon Dec 06 13:09:21 2010 +0100
   295.3 @@ -0,0 +1,132 @@
   295.4 +# Build GLPK with Microsoft Visual Studio Express
   295.5 +
   295.6 +CFLAGS = /I. /I..\include /I..\src /I..\src\amd /I..\src\colamd \
   295.7 +        /DHAVE_CONFIG_H /D_CRT_SECURE_NO_WARNINGS /nologo /W3 /O2
   295.8 +
   295.9 +OBJSET = \
  295.10 +..\src\glpapi01.obj \
  295.11 +..\src\glpapi02.obj \
  295.12 +..\src\glpapi03.obj \
  295.13 +..\src\glpapi04.obj \
  295.14 +..\src\glpapi05.obj \
  295.15 +..\src\glpapi06.obj \
  295.16 +..\src\glpapi07.obj \
  295.17 +..\src\glpapi08.obj \
  295.18 +..\src\glpapi09.obj \
  295.19 +..\src\glpapi10.obj \
  295.20 +..\src\glpapi11.obj \
  295.21 +..\src\glpapi12.obj \
  295.22 +..\src\glpapi13.obj \
  295.23 +..\src\glpapi14.obj \
  295.24 +..\src\glpapi15.obj \
  295.25 +..\src\glpapi16.obj \
  295.26 +..\src\glpapi17.obj \
  295.27 +..\src\glpapi18.obj \
  295.28 +..\src\glpapi19.obj \
  295.29 +..\src\glpavl.obj \
  295.30 +..\src\glpbfd.obj \
  295.31 +..\src\glpbfx.obj \
  295.32 +..\src\glpcpx.obj \
  295.33 +..\src\glpdmp.obj \
  295.34 +..\src\glpdmx.obj \
  295.35 +..\src\glpenv01.obj \
  295.36 +..\src\glpenv02.obj \
  295.37 +..\src\glpenv03.obj \
  295.38 +..\src\glpenv04.obj \
  295.39 +..\src\glpenv05.obj \
  295.40 +..\src\glpenv06.obj \
  295.41 +..\src\glpenv07.obj \
  295.42 +..\src\glpenv08.obj \
  295.43 +..\src\glpfhv.obj \
  295.44 +..\src\glpgmp.obj \
  295.45 +..\src\glphbm.obj \
  295.46 +..\src\glpini01.obj \
  295.47 +..\src\glpini02.obj \
  295.48 +..\src\glpios01.obj \
  295.49 +..\src\glpios02.obj \
  295.50 +..\src\glpios03.obj \
  295.51 +..\src\glpios04.obj \
  295.52 +..\src\glpios05.obj \
  295.53 +..\src\glpios06.obj \
  295.54 +..\src\glpios07.obj \
  295.55 +..\src\glpios08.obj \
  295.56 +..\src\glpios09.obj \
  295.57 +..\src\glpios10.obj \
  295.58 +..\src\glpios11.obj \
  295.59 +..\src\glpios12.obj \
  295.60 +..\src\glpipm.obj \
  295.61 +..\src\glplib01.obj \
  295.62 +..\src\glplib02.obj \
  295.63 +..\src\glplib03.obj \
  295.64 +..\src\glplpf.obj \
  295.65 +..\src\glplpx01.obj \
  295.66 +..\src\glplpx02.obj \
  295.67 +..\src\glplpx03.obj \
  295.68 +..\src\glpluf.obj \
  295.69 +..\src\glplux.obj \
  295.70 +..\src\glpmat.obj \
  295.71 +..\src\glpmpl01.obj \
  295.72 +..\src\glpmpl02.obj \
  295.73 +..\src\glpmpl03.obj \
  295.74 +..\src\glpmpl04.obj \
  295.75 +..\src\glpmpl05.obj \
  295.76 +..\src\glpmpl06.obj \
  295.77 +..\src\glpmps.obj \
  295.78 +..\src\glpnet01.obj \
  295.79 +..\src\glpnet02.obj \
  295.80 +..\src\glpnet03.obj \
  295.81 +..\src\glpnet04.obj \
  295.82 +..\src\glpnet05.obj \
  295.83 +..\src\glpnet06.obj \
  295.84 +..\src\glpnet07.obj \
  295.85 +..\src\glpnet08.obj \
  295.86 +..\src\glpnet09.obj \
  295.87 +..\src\glpnpp01.obj \
  295.88 +..\src\glpnpp02.obj \
  295.89 +..\src\glpnpp03.obj \
  295.90 +..\src\glpnpp04.obj \
  295.91 +..\src\glpnpp05.obj \
  295.92 +..\src\glpqmd.obj \
  295.93 +..\src\glprgr.obj \
  295.94 +..\src\glprng01.obj \
  295.95 +..\src\glprng02.obj \
  295.96 +..\src\glpscf.obj \
  295.97 +..\src\glpscl.obj \
  295.98 +..\src\glpsdf.obj \
  295.99 +..\src\glpspm.obj \
 295.100 +..\src\glpspx01.obj \
 295.101 +..\src\glpspx02.obj \
 295.102 +..\src\glpsql.obj \
 295.103 +..\src\glpssx01.obj \
 295.104 +..\src\glpssx02.obj \
 295.105 +..\src\glptsp.obj \
 295.106 +..\src\amd\amd_1.obj \
 295.107 +..\src\amd\amd_2.obj \
 295.108 +..\src\amd\amd_aat.obj \
 295.109 +..\src\amd\amd_control.obj \
 295.110 +..\src\amd\amd_defaults.obj \
 295.111 +..\src\amd\amd_dump.obj \
 295.112 +..\src\amd\amd_info.obj \
 295.113 +..\src\amd\amd_order.obj \
 295.114 +..\src\amd\amd_post_tree.obj \
 295.115 +..\src\amd\amd_postorder.obj \
 295.116 +..\src\amd\amd_preprocess.obj \
 295.117 +..\src\amd\amd_valid.obj \
 295.118 +..\src\colamd\colamd.obj
 295.119 +
 295.120 +.c.obj:
 295.121 +        cl.exe $(CFLAGS) /Fo$*.obj /c $*.c
 295.122 +
 295.123 +all: glpk.lib glpsol.exe
 295.124 +
 295.125 +glpk.lib: $(OBJSET)
 295.126 +        lib.exe /out:glpk.lib ..\src\*.obj ..\src\amd\*.obj \
 295.127 +                ..\src\colamd\*.obj
 295.128 +
 295.129 +glpsol.exe: ..\examples\glpsol.obj glpk.lib
 295.130 +        cl.exe $(CFLAGS) /Feglpsol.exe ..\examples\glpsol.obj \
 295.131 +                glpk.lib
 295.132 +
 295.133 +check: glpsol.exe
 295.134 +        .\glpsol.exe --version
 295.135 +        .\glpsol.exe --mps ..\examples\plan.mps
   296.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   296.2 +++ b/w64/makefile_VC_DLL	Mon Dec 06 13:09:21 2010 +0100
   296.3 @@ -0,0 +1,132 @@
   296.4 +# Build GLPK DLL with Microsoft Visual Studio Express
   296.5 +
   296.6 +CFLAGS = /I. /I..\include /I..\src /I..\src\amd /I..\src\colamd \
   296.7 +        /DHAVE_CONFIG_H /D_CRT_SECURE_NO_WARNINGS /nologo /W3 /O2
   296.8 +
   296.9 +OBJSET = \
  296.10 +..\src\glpapi01.obj \
  296.11 +..\src\glpapi02.obj \
  296.12 +..\src\glpapi03.obj \
  296.13 +..\src\glpapi04.obj \
  296.14 +..\src\glpapi05.obj \
  296.15 +..\src\glpapi06.obj \
  296.16 +..\src\glpapi07.obj \
  296.17 +..\src\glpapi08.obj \
  296.18 +..\src\glpapi09.obj \
  296.19 +..\src\glpapi10.obj \
  296.20 +..\src\glpapi11.obj \
  296.21 +..\src\glpapi12.obj \
  296.22 +..\src\glpapi13.obj \
  296.23 +..\src\glpapi14.obj \
  296.24 +..\src\glpapi15.obj \
  296.25 +..\src\glpapi16.obj \
  296.26 +..\src\glpapi17.obj \
  296.27 +..\src\glpapi18.obj \
  296.28 +..\src\glpapi19.obj \
  296.29 +..\src\glpavl.obj \
  296.30 +..\src\glpbfd.obj \
  296.31 +..\src\glpbfx.obj \
  296.32 +..\src\glpcpx.obj \
  296.33 +..\src\glpdmp.obj \
  296.34 +..\src\glpdmx.obj \
  296.35 +..\src\glpenv01.obj \
  296.36 +..\src\glpenv02.obj \
  296.37 +..\src\glpenv03.obj \
  296.38 +..\src\glpenv04.obj \
  296.39 +..\src\glpenv05.obj \
  296.40 +..\src\glpenv06.obj \
  296.41 +..\src\glpenv07.obj \
  296.42 +..\src\glpenv08.obj \
  296.43 +..\src\glpfhv.obj \
  296.44 +..\src\glpgmp.obj \
  296.45 +..\src\glphbm.obj \
  296.46 +..\src\glpini01.obj \
  296.47 +..\src\glpini02.obj \
  296.48 +..\src\glpios01.obj \
  296.49 +..\src\glpios02.obj \
  296.50 +..\src\glpios03.obj \
  296.51 +..\src\glpios04.obj \
  296.52 +..\src\glpios05.obj \
  296.53 +..\src\glpios06.obj \
  296.54 +..\src\glpios07.obj \
  296.55 +..\src\glpios08.obj \
  296.56 +..\src\glpios09.obj \
  296.57 +..\src\glpios10.obj \
  296.58 +..\src\glpios11.obj \
  296.59 +..\src\glpios12.obj \
  296.60 +..\src\glpipm.obj \
  296.61 +..\src\glplib01.obj \
  296.62 +..\src\glplib02.obj \
  296.63 +..\src\glplib03.obj \
  296.64 +..\src\glplpf.obj \
  296.65 +..\src\glplpx01.obj \
  296.66 +..\src\glplpx02.obj \
  296.67 +..\src\glplpx03.obj \
  296.68 +..\src\glpluf.obj \
  296.69 +..\src\glplux.obj \
  296.70 +..\src\glpmat.obj \
  296.71 +..\src\glpmpl01.obj \
  296.72 +..\src\glpmpl02.obj \
  296.73 +..\src\glpmpl03.obj \
  296.74 +..\src\glpmpl04.obj \
  296.75 +..\src\glpmpl05.obj \
  296.76 +..\src\glpmpl06.obj \
  296.77 +..\src\glpmps.obj \
  296.78 +..\src\glpnet01.obj \
  296.79 +..\src\glpnet02.obj \
  296.80 +..\src\glpnet03.obj \
  296.81 +..\src\glpnet04.obj \
  296.82 +..\src\glpnet05.obj \
  296.83 +..\src\glpnet06.obj \
  296.84 +..\src\glpnet07.obj \
  296.85 +..\src\glpnet08.obj \
  296.86 +..\src\glpnet09.obj \
  296.87 +..\src\glpnpp01.obj \
  296.88 +..\src\glpnpp02.obj \
  296.89 +..\src\glpnpp03.obj \
  296.90 +..\src\glpnpp04.obj \
  296.91 +..\src\glpnpp05.obj \
  296.92 +..\src\glpqmd.obj \
  296.93 +..\src\glprgr.obj \
  296.94 +..\src\glprng01.obj \
  296.95 +..\src\glprng02.obj \
  296.96 +..\src\glpscf.obj \
  296.97 +..\src\glpscl.obj \
  296.98 +..\src\glpsdf.obj \
  296.99 +..\src\glpspm.obj \
 296.100 +..\src\glpspx01.obj \
 296.101 +..\src\glpspx02.obj \
 296.102 +..\src\glpsql.obj \
 296.103 +..\src\glpssx01.obj \
 296.104 +..\src\glpssx02.obj \
 296.105 +..\src\glptsp.obj \
 296.106 +..\src\amd\amd_1.obj \
 296.107 +..\src\amd\amd_2.obj \
 296.108 +..\src\amd\amd_aat.obj \
 296.109 +..\src\amd\amd_control.obj \
 296.110 +..\src\amd\amd_defaults.obj \
 296.111 +..\src\amd\amd_dump.obj \
 296.112 +..\src\amd\amd_info.obj \
 296.113 +..\src\amd\amd_order.obj \
 296.114 +..\src\amd\amd_post_tree.obj \
 296.115 +..\src\amd\amd_postorder.obj \
 296.116 +..\src\amd\amd_preprocess.obj \
 296.117 +..\src\amd\amd_valid.obj \
 296.118 +..\src\colamd\colamd.obj
 296.119 +
 296.120 +.c.obj:
 296.121 +        cl.exe $(CFLAGS) /Fo$*.obj /c $*.c
 296.122 +
 296.123 +all: glpk_4_45.dll glpsol.exe
 296.124 +
 296.125 +glpk_4_45.dll: $(OBJSET)
 296.126 +        cl.exe $(CFLAGS) /LD /Feglpk_4_45.dll ..\src\*.obj \
 296.127 +                ..\src\amd\*.obj ..\src\colamd\*.obj glpk_4_45.def
 296.128 +
 296.129 +glpsol.exe: ..\examples\glpsol.obj glpk_4_45.dll
 296.130 +        cl.exe $(CFLAGS) /Feglpsol.exe ..\examples\glpsol.obj \
 296.131 +                glpk_4_45.lib
 296.132 +
 296.133 +check: glpsol.exe
 296.134 +        .\glpsol.exe --version
 296.135 +        .\glpsol.exe --mps ..\examples\plan.mps
   297.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   297.2 +++ b/w64/readme.txt	Mon Dec 06 13:09:21 2010 +0100
   297.3 @@ -0,0 +1,24 @@
   297.4 +This directory contains batch files and other stuff which you can use
   297.5 +to build GLPK for 64-bit Windows with the native C/C++ compilers.
   297.6 +
   297.7 +Before running the batch file do the following:
   297.8 +
   297.9 +1. Make sure that you have installed the compiler you are going to use
  297.10 +   to build GLPK.
  297.11 +
  297.12 +2. Look into corresponding batch file (just right-click it and choose
  297.13 +   'Edit' in the popup menu; DO NOT choose 'Open'). Make sure that HOME
  297.14 +   variable specifies correct path to the compiler directory; if not,
  297.15 +   make necessary changes.
  297.16 +
  297.17 +To run the batch file just double-click it and wait a bit while the
  297.18 +Make utility does its job. The message 'OPTIMAL SOLUTION FOUND' in the
  297.19 +MS-DOS window means that all is OK. If you do not see it, something is
  297.20 +wrong.
  297.21 +
  297.22 +Once GLPK has been successfully built, there must appear two files in
  297.23 +this directory:
  297.24 +
  297.25 +glpk.lib, which is the GLPK object library, and
  297.26 +
  297.27 +glpsol.exe, which is the stand-alone GLPK LP/MIP solver.